Skip to content

[design-advisor] Hand-rolled ISpecification/Specification/SpecificationEvaluator re-invents Ardalis.Specification #57

Description

@github-actions

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)

  1. Add Ardalis.Specification and Ardalis.Specification.EntityFrameworkCore to Directory.Packages.props.
  2. Replace ISpecification<T>, Specification<T>, and SpecificationEvaluator with thin re-exports or direct references to the upstream types.
  3. Remove the three home-grown files and update PublicAPI.Shipped.txt accordingly.
  4. 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 ·

  • expires on Sep 4, 2026, 8:18 AM UTC

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions