Grails is par-excellence platform for implementing applications in Domain Driven Design style . At the center of Grails approach are Domain Classes that drive the whole development process. As you are probably guessing, the choice of word domain in Grails is not just a coincidence.
You start by defining your Domain Classes and then you can use Grails to do all heavy lifting in providing persistence and generating the GUI. It’s worth noting that when the DDD book was written, it was before the Grails or other similar frameworks were created, so a lot of problematic dealt with in a book has to do with issues resolved or greatly reduced by the framework.
Some of DDD concepts resolved by Grails
I will use DDD pattern summary to address different DDD elements. (Quotes italicized in the text below).
Domain model is structured through Domain classes, Services, Repositories and other DDD Patterns. Let’s take a look at each of these in detail.
“When an object is distinguished by its identity, rather than its attributes, make this primary to its definition in the model”
These are Domain Classes in Grails. They come with persistence already resolved through GORM. Model can be finely tuned using the GORM DSL. Take a look at hasOne vs. belongsTo property. It can be used to define the lifecycle of entities and their relationships. belongsTo will result in cascading deletes to related entities and other will not. So, if you have a Car object, you can say that Motor “belongsTo” a Car and in that case Car is an Aggregate Root and Motor an aggregate.
“When you care only about the attributes of an element of the model, classify it as a VALUE OBJECT. Make it express the meaning of the attributes it conveys and give it related functionality. Treat the VALUE OBJECT as immutable. Don’t give it any identity…”
In Grails, you can use “embedded” property in GORM field to manage a value object. Value object can be accessed only through an entity it belongs to, does not have its own ID and is mapped to same table as the entity it belongs to. Groovy also supports @Immutable annotation but I am not sure how it plays with Grails.
“When a significant process or transformation in the domain is not a natural responsibility of an ENTITY or VALUE OBJECT, add an operation to the model as a standalone interface declared as a SERVICE. Make the SERVICE stateless.”
Just like Entities, Services are natively supported in Grails. You place your Grails Service inside the services directory in your Grails project. Services come with following out of the box:
- Dependency Injection
- Transaction Support
- A simple mechanism for exposing services as web services, so that they can be accessed remotely.
“Choose MODULES that tell the story of the system and contain a cohesive set of concepts. “ Grailsplug-in mechanism provides this and much more: a very simple way to install and create plugins, defines how application can override plugins etc.
“Cluster the ENTITIES and VALUE OBJECTS into AGGREGATES and define boundaries around each. Choose one ENTITY to be the root of each AGGREGATE, and control all access to the objects inside the boundary through the root. Allow external objects to hold references to the root only.”
I already mentioned some lifecycle control mechanisms. You can use Grails Services and language access control mechanism to enforce access control. You can have a Grails Service playing the role of DDD Repository that permits access to Aggregate Root only. While Controllers in Grails can access GORM operations on Entities directly, I’d argue that for better layered design, Controllers should be injected with services that delegate to GORM Active Record operations.
“Shift the responsibility for creating instances of complex objects and AGGREGATES to a separate object, which may itself have no responsibility in the domain model but is still part of the domain design.”
Groovy builders are excellent alternative for constructing complex objects through rich DSL. In DDD, Factories are more loose term and does not translate directly to GoF Abstract Factory or Factory Method. Groovy builders are DSL implementation of GoF Builder pattern.
“For each type of object that needs global access, create an object that can provide the illusion of an in-memory collection of all objects of that type. Set up access through a well-known global interface. Provide methods to add and remove objects, which will encapsulate the actual insertion or removal of data in the data store. Provide methods that select objects based on some criteria and return fully instantiated objects or collections of objects whose attribute values meet the criteria, thereby encapsulating the actual storage and query technology. Provide repositories only for AGGREGATE roots that actually need direct access. Keep the client focused on the model, delegating all object storage and access to the REPOSITORIES.”
Grails Service can be used to implement a dedicated Repository object that simply delegates its operation to Grails GORM. Persistence is resolved with GORM magic. Each Domain class provides a set of dynamic methods that resolve typical CRUD operations including ad-hock querying.
“State post-conditions of operations and invariants of classes and AGGREGATES. If ASSERTIONS cannot be coded directly in your programming language, write automated unit tests for them.”
- Take a look at Groovy @Invariant, @Requires, @Ensures annotations, these can be used to declare DbC style Invariants and Pre and Postconditions
- When you create your domain classes with Grails command line, test classes are created automatically and these are another mechanism for expressing assertions in your domain.
Declarative Style of Design
“A supple design can make it possible for the client code to use a declarative style of design. To illustrate, the next section will bring together some of the patterns in this chapter to make the SPECIFICATION more supple and declarative.”
This is where Grails excels because of dynamic nature of Groovy language and Builder pattern support for creating custom DSLs.
Comes “out-of-the-box” with Grails through proposed “Convention over Configuration” application structure in a form of a layered MVC based implementation.
*Originally published as an answer on Stackoverflow: http://bit.ly/mWtLFc