Specification and DDD

In the context of the personal game project, to find out more about DDD templates, I miss Specification for my filters.

Looking back at the examples, it seems that everything (for example, LinQ) is focused on SQL databases. However, with most queries in most NoSQL queries, even a "select * from table" requires a predefined view. However, if the repository displays a web service, even the type of request is much more stringent.

Are there variations of the Specification template to reflect database restrictions other than SQL? I get the feeling that this will require the use of inheritance and static declarations to support different types of persistent backends.

How do I combine sorting and filtering in my repositories? As an example, consider a repository for a list of Order items.

(Query)findAllSortedByDate; (Query)findAllSortedByName; (Query)findAllSortedByQuantity; 

Thus, these are different types of sorting when displaying a table. Since I can handle large results, I never considered sorting or filtering in my views or view models. Initially, I was thinking of the Proyection class, which selects the correct request from the repository according to the user's actions. However, this will not work if I want to combine different sorting strategies by different filters.

Obviously, I need some kind of "specification", but I'm not sure if:

  • Should I use them for my repositories, making them smarter? Or should I use them for my viewing models?
  • How to limit my specification objects to the good persistence of a polyglot?

Initially, I was thinking of fulfilling any request with the Repository acting as a collection-like interface , but now I noticed that the view model can also behave as a “discreet” interface, similar to a collection, while the former are “stateless” collection interfaces.

  • In general, should I try to keep some sort / sort type inside my repositories? It seems like this can add unnecessary complexity if all query results can be loaded into memory.

UPDATE : To revive this question, also consider that although NoSQL views can be filtered and sorted, a full-text search may require an external indexing mechanism such as Lucene or SQLite-FTS, providing only a unique identifier for the objects for the query, which must be sorted and filtered again .

+4
source share
2 answers

In filtering

In a “collection-like interface”, Fowler does not mean something that provides an API that looks like an array or list: it has nothing to do with ICollection<T> , for example! The repository should encapsulate all the technological details of the persistence layer, but its API must be defined so that it is expressive in the business area.

You should consider specifications as logical predicates that are related to the domain (indeed, they are first-class citizens in the domain model), which can be compiled both to check the various qualities of the object and to select objects from the set (a set that can be repository or simple list). For example, in the financial domain model that I developed for an Italian bank, I had DurationOfMBondSpecification , StandardAndPoorsLongTermRatingSpecification , etc.

In fact, in DDD, specifications come from the business requirements (often contractual boundaries) that must be met by software during its operations. They can be used as an abstraction for the filter, but it looks more like a good side effect.

At SORTING

Most of the time, sorting (and slicing, and grouping ...) is just an interest in the presentation. When this is a business problem, the correct mappings (and groups, etc.) should be partitioned off as domain concepts from domain expert knowledge. However, even with it, just a preoccupation with the view, it is much more efficient to process it in the repository.

In .NET, one of the possible (and very expensive) solutions to these problems is to create a custom LINQ provider (or more than one) that can translate all the request, which can be expressed using the ubiquitous language to the desired level of storage. However, this solution has a serious drawback: if you cannot translate all queries from the very beginning, you can never appreciate the effort to change the application using the domain: the time will come when you have to deeply reorganize QueryProvider to process a new complex query (and such refactoring will cost you much more than you can afford).

To solve this problem, in the (incomplete and very ambitious) Epic framework (disclaimer: I am the main developer), we decided to join the specification template and the request object template, providing a general purpose API that allows customers to filter using specifications, sort with using comparisons and trim with integers without the (unpredictable) LINQ overhead.

In the Fowler scheme (see below), we pass both the specification repository (aCriteria) and additional sort requests:

enter image description here

Alternatively, you can simply use custom repositories : this is a much cheaper approach if you don't have thousands of different types of requests.

Bonus Solution

A quick but still correct solution is to "just" use the persistence language, as for queries. DDD for complex operational boundaries and queries (in most cases) does not work: that way, you can simply use the language provided by your SQL or NoSQL database to get the predictions and / or identifiers of the objects you need to manipulate that you need. You will see how the dataset that you request is very different from the dataset needed to provide domain invariants!

That is why, for example, sometimes serialization files may be the best way to save a domain for a given problem.
In the end, what are file systems, if not the most common NoSQL databases !: - D

+5
source

In DDD, a specification is a predicate that applies to a domain object. It covers “filtering,” but not “sorting,” because sorting does not use the logical function of a domain object, but rather choosing a property and sorting direction.

What I usually write when I need filtering and sorting is the repository method on these lines:

 findAll(Specification<Order> specification, SortingOptions<Order> sortingOptions) 

At this point, we don’t need to think about the basic conservation mechanism. The domain repository interfaces should not be configured by your data warehouse, but by the needs of the domain.

If your data source makes it difficult to create queries that filter and / or sort, you can choose to filter / sort the objects as a result of the query in memory at any time. However, instead of doing this in the view model, it is better to create an IMO to create a specific implementation of your repository that will load objects into memory and perform a sort / filter operation right there.

All future additional presentation layers will benefit from this, and it will be much more convenient to configure the repository implementation if it turns out to be a data source (whether it be a NoSQL database, a web service ...) eliminates its drawbacks over time.

+1
source

Source: https://habr.com/ru/post/1496550/


All Articles