Excuse any ignorance here, I am fairly new to DDD so be gentle.
I am working on a large configuration driven data management system. The system is built by specifying pieces of configuration (like business rules, processes and validations) in an external syntax. Let's just say that syntax was a conglomerate of a Groovy based DSL and Drools.
I like the ideas of simplicity that DDD offers, specifically separating out infrastructure concerns from the core concepts of the domain.
However, I am struggling to apply some of the concepts of DDD due to the configurable nature of the system. Both behavior (processes), validation, and business rules are defined external to the system. So the entities in the domain intrinsically have not behavior of their own. Rather they delicate to the "Validator" thing or the "Rules Engine" or the "Workflow Engine".
I will clarify with an example. Let's say that my system manages Employees for a Company. Without too much thought, you would imagine that I have an Employee Entity and a Company Entity in my domain.
Following DDD, I am trying to model a scenario where an employee is promoted. You might see a new method come about on the Employee called promote (Employee.promote). We could have a business rule, indicating that an employee cannot be promoted twice within the same year (yes this is all made up). I could therefore have something like:
public void promote( EmployeeLevel newLevel ) {
if ( hasBeenPromotedThisYear( this ) {
throw new InvalidPromotionException
Well, in the application I am working with this business rule would be externalized to a Rules engine. Following DDD, I could do something like:
if( promotionRules.isEligibleForPromotion(this)
To externalize my rules. However, the system is much more generic than this. The "promotion" operation itself is defined as a "Process" through external configuration. So, at compile time, I wouldn't even know if I have a "promote" operation available for this employee. So my employee object becomes pretty bare from a code perspective, delegating all functionality to the configuration. It might look something like:
public class Employee {
public void execute( Process process )
Or alternatively
public class EmployeeProcess {
public void process( Employee employee )
My question is: does DDD even make sense in this application? Should I instead just model the collaboration of processes, validations, business rules (Rules engine) in a non DDD sense?
I like the Onion Architecture, and can use UI -> App Services -> Core -> Infrastructure to keep a nice separation of concerns. But the Core could be the collaborators mentioned above, as opposed to real "domain concepts".
Part of me believes that, in this case, the "domain concepts" ARE the validators, processors, business rules because they make up the ubiquitous language that we talk about when we discuss our system. In this case, I would have Entities with no real behavior (for the most part), and domain concepts in terms of Processors, Validators, Rules Engine that realize the behavior in the system.
Adding a little more info. Given my question above, I was working toward a solution that would look like:
org.example.app
org.example.domain - Employee - Company - EmployeeLevel
org.example.domain.shared - Process - BusinessRule - Validator
org.example.infrastructure
Hopefully, this little snippet adds a little clarity.
So, the Process, BusinessRule, and Validator concepts would lie inside the domain, but would be supporting the domain model in terms of the things the system does.
Domain-Driven Design(DDD) is a collection of principles and patterns that help developers craft elegant object systems. Properly applied it can lead to software abstractions called domain models. These models encapsulate complex business logic, closing the gap between business reality and code.
Domain-driven design (DDD) is a software development philosophy centered around the domain, or sphere of knowledge, of those that use it. The approach enables the development of software that is focused on the complex requirements of those that need it and doesn't waste effort on anything unneeded.
Domain-driven design (DDD) advocates modeling based on the reality of business as relevant to your use cases. In the context of building applications, DDD talks about problems as domains.
Domain-driven design is perfect for applications that have complex business logic. However, it might not be the best solution for applications with minor domain complexity but high technical complexity. Applications with great technical complexity can be very challenging for business-oriented domain experts.
From Wikipedia:
Domain-driven design (DDD) is an approach to developing software for complex needs by deeply connecting the implementation to an evolving model of the core business concepts.
I believe that validator, process, rule are not your core business concepts. Those are rather common software abstractions.
I'm not big fan of "by-the-book" DDD, but in order to be more "domain-driven" your DSL and your rules actually should be built around your business concepts to give more sense to that.
Under the hood, you can still use validators, processes, managers, executors etc., but your DSL/rules will be more readable if you use business concepts in them, rather than software abstractions.
UPDATED: Since you are using Groovy for defining your DSL, you can use Groovy's dynamic method name resolving and builder functionality to create readable rules and classes. Also you can leverage "convention over configuration" principle to hook in some logic. For example, in Groovy you can try to construct something similar to:
if (employee is "promotable") {
start "promotion" for employee
}
is
will be a method on a base domain object that will check for existence of let's say EmployeePromotableValidator class, which by itself can also be a Groovy class that leverage Groovy's DSL expressiveness.
class EmployeePromotableValidator extends Validator<Employee> {
boolean validate(Employee employee) {
employee.age > 25 && employee.workingYears > 2
}
}
start
will be a method on your base rule script that will search for EmployeePromotionProcess
class, that again can be a Groovy class.
Specification pattern in this case is very simple, because it basically becomes part of the language:
if (employee is "promotable" &&
employee is "advanced" &&
employee.salary < 10000) {
start( "salary increase", "10%" ) for employee
}
In general, DSLs with the help of (semi-)functional languages like Groovy/Scala can be used to hide software abstractions and make your business logic more prominent in the code. With plain Java you will end up with a lot of boiler plate code that will eventually hide all your intentions.
It depends on what exactly your business domain is.
If you are building big extra configurable crm something something constructor do everything application - then your business domain is around making that possible, hence nouns like Process
, Executors
etc. are part of your domain.
If you are building application that should track information about employees and their promotability - then your business domain is all about employees, paychecks, performance measurements. In this case treat Process
, Executors
and similar objects as intruders to your domain.
At some level - even programming language itself is an invasive tool that blurs solution of problem which you are drawing in your mind. But it's necessary one - otherwise you wouldn't be able to materialize it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With