Rubric principle: Right-sizing — "a building-blocks library wins by staying small and referencing mature libraries (FastEndpoints, Ardalis.Specification, Polly) rather than reinventing them. Flag over-engineering and speculative generality as problems. Prefer 'reference, don't build.'"
What was observed
The repo contains a hand-rolled Specification pattern across three files:
src/ResQ.BuildingBlocks.Application/Persistence/ISpecification<T> — a bespoke port interface
src/ResQ.BuildingBlocks.Application/Persistence/Specification<T> — a base class with includes, ordering, paging, no-tracking, split-query, and query-filter flags
src/ResQ.BuildingBlocks.Adapters.Persistence/Specifications/SpecificationEvaluator.cs — an EF Core evaluator that translates the spec onto IQueryable<T>
This is precisely what Ardalis.Specification (+ Ardalis.Specification.EntityFrameworkCore) provides: ISpecification<T>, Specification<T>, and SpecificationEvaluator. The home-grown version covers ~85 % of the same surface, without the benefit of the upstream library's test coverage, projection overloads (ISpecification<T, TResult>), or ongoing maintenance.
There is no Ardalis.Specification entry in Directory.Packages.props, confirming this is a from-scratch implementation.
Impact
- Consumers learning the pattern get a subtly incompatible variant instead of the well-known API.
- Every feature gap (projection specs,
SelectMany, PostProcessingAction) has to be built and maintained in-house.
- The
Specification<T> base class and ISpecification<T> are already frozen in PublicAPI.Shipped.txt, amplifying the migration cost if the decision is ever reversed.
Suggested fix (effort: M)
- Add
Ardalis.Specification and Ardalis.Specification.EntityFrameworkCore to Directory.Packages.props.
- Replace
ISpecification<T>, Specification<T>, and SpecificationEvaluator with thin re-exports or direct references to the upstream types.
- Remove the three home-grown files and update
PublicAPI.Shipped.txt accordingly.
- Update
IReadRepository<TAggregate, TId> / IRepository<TAggregate, TId> to accept Ardalis.Specification.ISpecification<T> — the signature is compatible.
If a hard no-extra-dependency policy exists for the Application layer, at minimum document the deliberate divergence in a code comment so future maintainers understand why the pattern was re-implemented.
area: application
Generated by Design Advisor · sonnet46 · 43.6 AIC · ⌖ 8.59 AIC · ⊞ 6K · ◷
Rubric principle: Right-sizing — "a building-blocks library wins by staying small and referencing mature libraries (FastEndpoints, Ardalis.Specification, Polly) rather than reinventing them. Flag over-engineering and speculative generality as problems. Prefer 'reference, don't build.'"
What was observed
The repo contains a hand-rolled Specification pattern across three files:
src/ResQ.BuildingBlocks.Application/Persistence/ISpecification<T>— a bespoke port interfacesrc/ResQ.BuildingBlocks.Application/Persistence/Specification<T>— a base class with includes, ordering, paging, no-tracking, split-query, and query-filter flagssrc/ResQ.BuildingBlocks.Adapters.Persistence/Specifications/SpecificationEvaluator.cs— an EF Core evaluator that translates the spec ontoIQueryable<T>This is precisely what Ardalis.Specification (+
Ardalis.Specification.EntityFrameworkCore) provides:ISpecification<T>,Specification<T>, andSpecificationEvaluator. The home-grown version covers ~85 % of the same surface, without the benefit of the upstream library's test coverage, projection overloads (ISpecification<T, TResult>), or ongoing maintenance.There is no
Ardalis.Specificationentry inDirectory.Packages.props, confirming this is a from-scratch implementation.Impact
SelectMany,PostProcessingAction) has to be built and maintained in-house.Specification<T>base class andISpecification<T>are already frozen inPublicAPI.Shipped.txt, amplifying the migration cost if the decision is ever reversed.Suggested fix (effort: M)
Ardalis.SpecificationandArdalis.Specification.EntityFrameworkCoretoDirectory.Packages.props.ISpecification<T>,Specification<T>, andSpecificationEvaluatorwith thin re-exports or direct references to the upstream types.PublicAPI.Shipped.txtaccordingly.IReadRepository<TAggregate, TId>/IRepository<TAggregate, TId>to acceptArdalis.Specification.ISpecification<T>— the signature is compatible.If a hard no-extra-dependency policy exists for the Application layer, at minimum document the deliberate divergence in a code comment so future maintainers understand why the pattern was re-implemented.
area: application