Maven module for DDD projects

How do you plan your Maven modules when doing DDD projects? Do you customize all layers (presentation, application, domain, infrastructure) in one module or create a multi-module layout with a separate module for each level? Or something else?

I notice that the DDD Sample App , developed by Domain Language and Citerus, uses one Maven module, each layer as a separate Java package inside this module. Is this an established best practice or should I consider a more granular module layout?

+4
source share
1 answer

In general, the separation and packaging of modules is a matter of practical deployment and development. Who else will need the code? If I want to change the functionality of Y, is that all in package X?

Caution: The sample application is packaged as one application to make it easier to use as a training tool. But here are some recommendations using it as an example and pretending to be real. I will make some assumptions about this in a vacuum for illustrative purposes, but the responsible DDD practitioner will take a domain expert and assemble a development team to confirm any assumptions about the domain, context boundaries, and the relationship between these contexts. You cannot do DDD yourself.

Get the right simulation

Step one will be to focus on the right choice of modeling right and certain boundaries of the context. I would not worry about the infrastructure layers, since I would be concerned about the different Contexts and their models within the domain. The critical differences in the example application are those that are between these different contexts; there are three contexts in this application.

  • Reservation
  • Routing
  • Third party suppliers / ports / ships, etc.

If you notice that they are clearly separated by java root packages

  • se.citerus.dddsample
  • com.pathfinder
  • com.aggregator

Layers are primarily intended to facilitate communication between these contexts and to more easily resolve infrastructure-related issues, from testing work in the domain, as well as more plausible domain responsibilities. Infrastructure is important, but the fact that the sample application uses XML here and the JMS is in sleep mode there are secondary problems for domain modeling.

An example application makes this separation very clear, it is easy to see where the roots of the aggregates are:

  • Cargo
  • Handlingvent
  • Location
  • Voyage

Breaking Java packages with Aggegrate Roots is good practice. Leg means nothing outside the Cargo aggregate; a schedule means nothing outside the Voyage aggregate; HandingHistory means nothing outside the HandingEvent aggregate. It is good practice to maintain an isolated and verifiable domain model without infrastructure. But you probably shouldn't extend this decoupling to the module level. It would be unreasonable to say that all your domain objects in one bank and your entire infrastructure in another. The burden of development and version can become painful.

Define restricted contexts

The key is how the various context models are split / not split . In the context of booking, a route is a route with a set of legs. In the routing domain, this is a Graph in real Computer Science knowledge, so the domain can solve routing problems using well-studied graph traversal algorithms right from your college Algorithms class.

The two Reservation and Routing contexts are in close partnership, where both maintain a common interface between the two Edges models and nodes, as well as routes and legs. This translation is supported between the managed model in the ExternalRoutingService, where TransitPath becomes the route. Obviously, this is a very important point of integration, which should be well covered in tests and managed through continuous integration.

Another context is third-party integration to inform HandingEvents in the application of the state of the load. This is achieved using the Published Language template. In a nutshell, we don’t care what the third-party freight transport models look like while they tell us about the events related to our publication of the HandlingReport XML help.

The relationship between the third-party context and the Booking Domain is called Conformist, they represent data, following our specific specification, we do not modify our models to make them easier for them. The burden is on them to fit us. However, my hunch about the situation might be a very important provider there, and they actually define the XML model, not us. Only interviews with a fictional team can truly characterize this.

Thus, in the final group, all classes related to aggregation can be close (for example, the same package). Clearly define the boundaries of the context and provide a clear point of integration, define the relationship between the contexts “Partnership”, “Common core”, “Public language”, “Open host service”, “Conformist”, etc.

Based on this in the example, we could probably pack the various contexts in separate maven modules for Cargo Booking, Route Path Finding and HandlingEvent Aggregation. If this made sense, given the practical aspects of the development methodology and team organization, and only if it were.

Look for modules in limited contexts

Get rights to your context boundaries. Identify your units correctly in good verticals. Reduce grip with crisp, well-defined interfaces.

Look for modules in your contexts. They are the most natural candidates for individual modules, and separation can contribute to more stringent adherence and documentation of context boundaries. However, like many software developments, this is not a hard and fast rule and will really depend on the particular case. I can imagine and see / write applications that have different models for writing and reading models (I think, normalized and denormalized for reporting) and contexts for each, which on practical issues can still be packaged in one module.

Another point to fear sharing common roots between contexts is the common DDD kernel pattern and should be used very sparingly, as it can quickly scroll into a large dirty domain model that does not serve the needs of any context well. Please note that the sample application does not share models between the RoutingService and BookingService. Putting all the roots of domain aggregates in a single module may inadvertently encourage this practice.

+9
source

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


All Articles