On FILTERING
By "collection-like interface", Fowler doesn't mean something that expose an API resembling array or list: it has nothing to do with ICollection<T>
, for example! A Repository should encapsulate all the technological details of the persistence layer, but its API should be defined so that it is expressive in the business domain.
You should think of specifications as logical predicates that are relevant in the domain (indeed they are first class citizens in the domain model) that can be composed both to check different qualities of an entity and to select entities from a set (a set that can be either a repository or a simple list). For example, in a financial domain model that I designed for an italian bank, I had DurationOfMBondSpecification
, StandardAndPoorsLongTermRatingSpecification
and so on.
Actually, in DDD, specifications come from business requirements (often contractual bounds) that must be enforced by the software during its operations. They can be used as an abstraction for a filter, but this is more like a fortunate side effect.
On SORTING
Most of times sorting (and slicing, and grouping...) is just a presentation concern. When it's a business problem, proper comparers (and groupers so on) should be distilled as domain concepts from the domain expert's knowledge. However, even with it's just a presentation concern, it's far more efficient to handle it in the repository.
On .NET, one possibile (and very expensive) solution to these problems is writing a custom LINQ provider (or more than one) that can translate all the query that can be expressed with the ubiquitous language to the desired persistence layer. This solution however has a major downside, if you can't translate all the queries from the begining, you will never be able to estimate the effort for a change to the application using the domain: the time will come when you will have to deeply refactor the QueryProvider to handle a new complex query (and such refactoring will cost you much much more than you can afford).
To address this problem, in the (work-in-progress and very ambitious) Epic framework (disclaimer: I'm the core developer), we choosed to join the specification pattern and the query object pattern, providing a general purpose API that enables clients to filter with specifications, to sort with comparers and to slice with integers, without the (unpredictable) costs of LINQ.
In the Fowler scheme (below), we are passing both the specification (aCriteria) and the ancillary sorting requirements to the repository:
As an alternative, you could just use custom repositories: it's by far a cheaper approach, if you don't have thousands of different types of queries.
Bonus Solution
A quick, but still correct solution is to "just" use your persistence language as is for queries. DDD is for complex operative boundaries and querying (most of times) is not operative: thus you can simply use the language provided by your SQL or NoSQL database to retrieve the projections you need and/or the identifiers of the entities you need to manipulate. You will see how the set of data that you query is very different from the set of data that are required to ensure domain invariants!
This is why, for example, sometimes, serialization files can be the best approach to the domain persistence for the problem at hand.
After all, what are filesystems, if not the most diffused NoSQL databases! :-D