domain-driven-designrepositorycode-organizationproject-organizationlayer

Domain Driven Design - how the layers should be organized?


I'm very much new to software development. I think layered architecture is a great way to reduce the complexities that arise in the process of object oriented software development and, not to mention, to keep your code organized.

I'm interested to learn about Domain Driven Design approach and I've run into some problems to get myself introduced to it (of course, beginner level ones).
Here it is -

I want to build an application to save person related data in database and display person details in a WPF DataGrid (I know, DDD is definitely not for the apps of such scale, but just to keep things simple for an amateur like me). So, I created a domain class "Person", something like –

    public class Person
    {
        public Person(dataType paramA)
        {
            this.PropertyA = paramA;
        }

        private dataType _fieldA;
        public dataType PropertyA
        {
            //encapsulates _fieldA    
        }

        public dataType PropertyX
        {        
            //some code that manipulates private field    
        }

        private dataType MethodPQR(dataType param)
        {        
            //some code    
        }
    }

Now, my understanding of DDD says the architecture (the simplest version of it) should be as follows (please, correct me if I'm wrong) -
enter image description here

Note:

  1. I want the DataGrid to be bound to some ObservableCollection, to reflect any kind of changes instantly.

  2. It's a WPF application but not necessarily be in MVVM pattern and I deliberately want to use the code behind.

My questions are -

  1. What kind of codes belong to the Application Layer?

  2. My guess is, I should definitely not bind an ObservableColletion of my domain object (i.e. Person) as the ItmsSource of the DataGrid. What type of object then I should extract from the domain object, and how?

  3. To keep a decoupling between Presentation Layer and Domain Layer probably there's a convention like never instantiate domain objects directly in the presentation layer. What are the non-direct approaches then?

  4. If the code-behind talks to the Application Layer then should the Application Layer talk to the Data Repository? But what if some kind of domain access is needed which is not data access related (may be not in this app, but it may occur, right?) In that scenario, who's that X guy (sub-layer/module) in Domain Layer that the Application Layer should talk to?

I know my questions are of very much amateur level, but they are questions indeed, raised from problems I'm facing to get a clear picture. So, if anybody has time, any response will be appreciated.

EDIT : I'm not sure if Data Repository should have a reference of Domain Model.


Solution

  • Speaking in terms of more "classical" DDD, yes domain objects are typically not allowed anywhere outside of the domain. But it is not an absolute rule that domain objects are not used in the presentation layer. For example, Naked Objects represents a school of thought where domain objects are used directly. I myself adhere mostly to a philosophy where domain objects are not used directly, so I am not familiar with all the practices they suggest, I personally would think binding to a domain object directly would be ill-advised, but ... Just keep in mind not everyone views this as a requirement.

    If you do not allow domain objects outside of the domain itself, you would typically use DTO or Data Transfer Objects which are simply classes only with properties and such DTO classes do not have domain behaviors. DTOs often mirror the domain model structure exactly but do not have to.

    Business logic is supposed to be implemented in the domain model, so much of what is in the application layer is involved with coordinating various services, typically to bring the data to and from the client applications. Many people use some form of SOA or at least web services for this. These call the repositories but also require other components such as assemblers to take the domain objects returned from repository calls and copy the property values into DTOs, which are then serializable and returned to the caller. The caller is often a presenter or controller but if you are not using MVC or MVP the caller would still be in the presentation layer. The reverse trip is more complex - the UI may send back DTOs that represent updates or DTOs that represent new objects to be added. The prime purpose of the application layer is mediating these back and forth activities.

    As far as "non-data access" of the domain layer, there are a couple of typical examples. Most people usually refer to the "X" component you may be thinking of as a Domain Service. A Domain service differs from an Application Service by it's proximity to the domain model and the presence of actual business logic.

    For example, if an application involves some kind of order placement, there are actually two concerns - order placement and order fulfillment. Application Services mediate the transfer of the data needed to formulate an order placement to the UI and then return the order that the user wishes to place. But that is only mediating data transfer and that is where Application Services end. A Domain Service may then be needed to apply business rules and construct additional domain objects that are needed to actually fulfill that order.

    In general, I find that to be a useful concept or metaphor that can be applied to many scenarios - an Application Service facilitates a request of some sort, in terms of the request submission only. A Domain Service on the other hand facilitates the actual request fulfillment.

    The only other mode of "access" other than data-oriented I have encountered or can readily imagine is process-oriented functionality. This is not encountered in every application but is prevalent in certain fields. For example in healthcare where I work you may want applications that incorporate significant elements of managing both the clinical data as well as the clinical process. I solve this problem by not making that process emphasis a part of my domain model and using different tools for that instead.

    OOP techniques are not well suited for an actual process itself, they are useful for providing data to and capturing data from a process. Object-oriented is after all also primarily noun-oriented. For real-time process management you need "verb oriented programming" more than "noun oriented programming". Workflow tools are "verb oriented" tools that can be complementary to Domain-driven models for applications that are both data-intensive and process-intensive. I do a lot of work that involves both C# DDD models and Workflow Foundation models, but again this is only needed for certain types of applications. Many typical business apps only require domain models and services.

    Finally the most important aspect of DDD is not any technique or architecture. The real heart of it revolves around the Ubiquitous Language and interaction with (in my strong opinion DIRECT interaction with) domain experts to distill out critical domain knowledge. (Most companies that claim to do DDD in my opinion do not because so many companies refuse to allow the business and development to interact directly, but that is another topic... ) It is the extractions and incorporation of domain knowledge, rather than any technique that actually separates DDD from conventional OOP and that is where the real value of DDD arises.

    EDIT

    As far as repository use goes, the diagram is correct. Typically the application layer always goes through a repository for domain objects. First of all, you have to be able to bring data to the application, and most applications also need some level of query ability.

    The domain layer OTOH usually does not interact with repositories. Typically you want the domain model to be self-contained and decoupled from any specific technology, i.e it should represent "pure domain knowledge". Persistence is inherently tightly coupled to some sort of specific technology, so in general, people strive to make their domain models free of any persistence implementation. You have repositories but you typically do not want to call repository methods in the domain model.

    Within the domain model itself, objects are obtained either as new objects (which may be instantiated directly or through a factory) or else reached by traversing associations. Sometimes when creating a new object it is impractical to pass everything needed into a constructor, so this is one case where you might need some sort of data access within the domain model itself. Usually what people do is pass in a data service via an interface so that the domain model may be provided with data access but remains decoupled from the data layer implementation. But for the most part, domain objects act and interact with other domain objects that are already instantiated.