DEV Community

Peter Harrison
Peter Harrison

Posted on • Updated on

Domain Driven Disaster

How many businesses still use spreadsheets as part of their business operations? The reality is that they are used even at the highest levels in multinational companies. Is this some kind of accident? Did they not receive the memo about the security risks they present, their limitations, their complexity?

Spreadsheets still exist because they put the power to adapt and evolve in the hands of those who need it most. Spreadsheet users are not banging down the door of IT every week requesting that new features be added to Excel so they can get their job done. They have the power to do what they need to do no matter what domain they work in.

But the professional information technology people know better, or so they believe. They want to write software that is designed from the ground up to do a specific narrowly defined job. It begins with the foundation stones, the data structures and schema on top of which the object models and object relational mappings are built. Developers build business logic directly into these domain specific business classes.

A more recent development has been microservices, where a system is broken down into separate mini applications with a well defined subset of functionality. This is a similar concept to encapsulation with classes, in that every class has a well defined contract and that only the contract is visible to the outside. Furthermore microservices are related to domain specific aspects of the system.

Modularity and clear separation of concerns is a critical part of complex systems which allows you to break applications into sections with well defined responsibilities. But should we design our module architecture around a specific business domain? The answer is an emphatic no!

Building in Inflexibility

The first reason domain driven development is a bad idea is that it encourages you to build business logic into the application. Imagine if database software was domain specific, where the database language was applicable only to a single industry. Imagine there were different databases for each industry rather than a standard which allowed all kinds of different systems to be built on top of them. Database servers are an example of good architectural design where their purpose of storing data is not confused with the domain the database will be used for.

Building unnecessary domain level business logic into your software can only result in the software being more brittle and less adaptable to change. Think of spreadsheets where a user can modify how it works in real time, add a new field or add a new graph. Can your applications users add new fields? Can they create new reports and queries? Spreadsheets never require a rebuild or redeploy. Databases do not need to be rebuilt and redeployed simply because you added a column. But business software developers have been indoctrinated into using the fixed schema static domain model. But it does not need to be that way.

Domain Derived Modules

With the advent of microservices it appears that we are making the same mess as early Java EJB technology, in that it is trying to scale by breaking services up based on their contracts. Let us say you have clients, suppliers and partners. Each of these entities has different fields and business rules. The classic approach would be to have separate tables for each of these in the database, to have separate classes for each, which would be mapped to tables and for web services to be exposed for each individual object.

The microservice approach takes this a step further, breaking the system into stand alone applications. Perhaps all these entities will end up in separate services, running on different containers that talk to their own databases. The predictable result is a nightmare trying to do things like create cumulative data sets across multiple services. One common justification for taking this approach is scalability, but what actually occurs is a maze of services calling services, all the time increasing latency.

What usually happens when people start building real systems and run into this problem is the gurus come in and tell them they have been doing it wrong. They didn't quite understand the one true path. It seems our guru never really evaluated whether breaking an architecture apart based on the domain was a clever idea in the first place, or indeed whether using the domain as the foundation for application boundaries was a sensible.

Root of the Disease

Introductory books on Object Oriented Programming often use real world objects as examples. It encourages developers to model the real world in terms of code. I know they probably meant well, but what this did was inculcate modern developers with the idea that the business domain belongs in the binary.

While databases themselves are cleverly universal they did at the same time expect a static schema to be defined, which in reality was just as inflexible as any binary. The ongoing mess with trying to keep data structures up to date as the software is updated is a common experience for developers. It wasn't exactly their fault; after all the popular languages encourage binding the database and the code together.

Ok, clever clogs, what's the answer?

It is all very well waxing lyrical about the failure of modern software architectural approaches without presenting some kind of working example of how else it could be done. Condemning an approach without providing an alternative isn't constructive. And so I present the following case studies based on the idea of decoupling code from the domain.

In 2006 I worked on the a healthcare data integration application. That sounds pretty domain specific, but that health specific functionality was a very small part of the system, limited primarily to several connectors for a protocol used in hospitals and healthcare providers. The rest of the system was a universal integration engine that would work for any company in need of integrating different systems.

The application was an excellent example of a technology called OSGi, which separates the application into different concerns. None of the core modules were related to health at all. All were well defined and had a contract or API. These modules were based on the functionality required by the application, but the actual configuration of the routing and transforms was all in dynamic configuration that users could modify in real time with no deployment. Importantly the modules were not in any way influenced by the intended domain. This domain independence would inform my later experiences.

In a subsequent role I wrote a process orchestration system for a Internet Service Provider. Originally I was brought in to complete a project that had been developed in a way that was tightly coupled with the domain. After a while it became clear that it was so inflexible that we needed a different solution. So we developed a plan for another system which would address the architectural shortfalls of the first attempt.

One of the key architectural principles that we adopted for the new project was universality. The domain would be evicted from the application and into configuration. This project would never be domain specific. We would not hack it to address an immediate need with no thought for adaptability or flexibility. It took three months to complete the first version of the core functionality, another three to complete plug in components and write the dynamic configuration for the business processes.

Just like with the healthcare integration application we ended up with a universal system. It was able to handle the workflow automation needs of any business process. Soon we were developing new business processes faster than we were ever able to before. The workflow engine was released as open source.

Today it is being used successfully in a totally different domain from the original purpose it was developed. Ironically it is replacing spreadsheets because while it has many of the flexible features of spreadsheets it is also secure, central and easy to use. It delivers flexibility and adaptability more typically found in spreadsheets while being totally decoupled from the business domain at the source code level. The domain is in the run time configuration.

Complexity is the enemy of Scalability and Availability

Let us do a little thought experiment about how to scale based on two competing models; functional architecture and domain driven architecture. In the functional architecture we have three web servers fronted by a load balancer and a cluster of three database servers. The function of the web servers is to service API calls. The function of the database cluster is to store data in a single logical database replicated across all three servers regardless of API call.

In the domain architecture we have a router which routes API calls to different web servers depending on the required service. Each of these web servers are connected to a database server to store the data for that service.

So let us think about scalability and availability in these two systems. Imagine that there is a head crash on one of the database servers. In a functional architecture the other two servers take over and everything trucks along as normal while the damaged server is brought back into service. What happens to the domain driven architecture? Well one of the API will go totally offline. Not only that but you will need to restore the database server from backup, potentially with data loss.

Okay, but surely domain driven architecture is better for scaling? Well lets think about it. With the domain driven architecture all the hits for a specific service will go to the same servers. That means that if you are unfortunate enough to get a rush on one specific API it will get over loaded. But with a functional architecture any web server can service any call and the load is spread across multiple web servers and database servers.

And if you have multiple interdependent services I can't even begin to imagine the mess you will get into. We need services which are both universal and well defined. The 'application' should be a dynamic veneer.

Is your solution just bad old Monolithic Architecture?

Not at all. A monolithic architecture attempts to include all the domain specific rules within itself.

Imagine all the uses that spreadsheets have been put. Do spreadsheets contain all the inherent complexity that they have enabled? No. What I am proposing here is that we decouple our applications from the domain and make the user experience a consequence of run time configuration in data.

This is the same model that spreadsheets used, but we are using this principle in business software over the web. We should not be building business rules and domain entities into our code. The domain still needs to exist, but it can be expelled from code into dynamic run time configurations. This is a fundamental change of mindset.

Wrapping up the case against Domain Driven Development

Putting business logic and rules into an application sets them in stone. It undermines the power of managers to use the software in ways a developer might not imagine. How many companies have a culture where managers and users are always in conflict with the software developers as any and all changes no matter how small need to be designed, planned and rolled out as part of a software deployment. Under such circumstances is it any wonder managers have a death grip on their beloved spreadsheets?

This is more than a design principle, it is a fundamental philosophy about the relationship between developers and the user; that we should be empowering users rather than creating barriers. Rather than holding onto the keys to the castle, the domain, we should set them free.

Discussion (15)

Collapse
kspeakman profile image
Kasey Speakman • Edited on

There is no universal solution that fits all cases. DDD works best in certain scenarios and not well in others.

Also, you should fairly point out that configuration-based solutions have negative trade-offs that your customers will notice. For one thing, they typically require an extensive setup and training process to master the implications of the configuration options. Depending on how deep those configuration options are, that may even require training and keeping on staff an expert in your software. Many times end users also have increased training times because such systems give enough "freedom" for users to do the wrong things with the data. So they need to undergo training to learn the right way. These are non-trivial requirements to place on customers.

Because of the "freedom" such systems enable to administrative users, over time the system can rot into a convoluted mess of determining how all the ad hoc rules interact. As a dev, coding new features against such a system while maintaining the integrity of all the user's ad hoc rules is also a daunting challenge, and not the kind I would consider enjoyable.

For some use cases, these trade-offs are minimal and it is a good design to use. I am happy for you that it works for your product. But by no means is it universally the best option, nor is DDD always the wrong choice. Everything has a circumstance where it will flourish... it just may not be one you are facing today.

Collapse
armanerfani profile image
armanerfani • Edited on

I also agree with what Kasey mentioned specially the downsides of the configuration based systems which tend to evolve into ESB like system after a while.
And on the top of that the samples given on the article are integration and orchestration which usually implemented in Application Layer in DDD terminology. These areas usually should have simple businesses like transformation, aggregation ... or keeping the simple orchestration state. So if you do not any businesses in theses areas other than what I menti
oned, it is totally ok to skip DDD complexities

Collapse
fourpastmidnight profile image
Craig E. Shea

I would argue that a DBMS is actually designed around a domain--that being the efficient storage and retrieval of data. That simple. That's why you don't see other "business domain" logic in a DBMS--it's not its domain in the first place. The only purpose of a DBMS is the efficient storage and retrieval of data. Period.

And I agree with @kasey, there is no universal solution that fits all cases. I also agree with most of everything else said in the comment with respect to how all that external configuration can lead to problems. In my organization we moved away from that architecture because of the exact problems Kasey mentioned. And in other organizations I have dealt with software that strived to be as general (universal) as possible. And usually what resulted was a piece of software that was so general it need a lot of additional work to make it more specific to meet a particular purpose, i.e. the generalized software was next to useless. Not to mention, it was confusing for both users and developers.

To be clear, I cannot say that in all situations that a solution consisting of generalized software is bad; and nor can I say that in all situations DDD is good. As anyone who's been around long enough comes to know, the answer is always "It depends." In my particular situations, generalized software did not result in bringing value. I have also been in other situations where DDD did not bring value either. You must have context to understand whether a particular design methodology and/or architecture will result in realizing the expected business value.

Collapse
dbjdbj profile image
DBJDBJ

Peter is not arguing he can develop a SINGLE SYSTEM, so configurable it will be a solution to all the reaquierements.

I am curious how is DDD leading to reusability? Any kind of reusability.

I can describe anything as a model. That does not mean I have to map that model 1:1 to "business objects", to deliver the functionality required.

Generic concepts and types? Generic OO Business Patterns? Well there is no cook-book of recipes for that. So lets not go there. (SAP is based on that idea. It takes a year or more to configure it for one customer)

One thing I noticed with DDD. It is well suited to "Parroting the Architecture". Just skim over the book, have every project code structured into "Domains", "Features" and "DataAccess" and suddenly you are an Architect or even "Head of Engineering". Just stick to the Book ;)

Collapse
neemzy profile image
Tom Panier

How can you guarantee your business logic works as intended in such a scenario? You can't write tests for it, since it isn't part of your codebase.

It sounds to me like you've set up a framework. Probably a good one, but that's not what it takes to meet your users' expectations. I also have trouble to believe runtime configuration can cover every single possible need, business-wise.

Your points against microservices are fair enough, given they're not an universal solution. Neither is DDD (even if it's a global step forward in theory, as it encourages software developers to not intertwine business logic with technical layers). Neither is your own - but I know you agree with that.

Collapse
jstafford5380 profile image
jstafford5380

"The first reason domain driven development is a bad idea is that it encourages you to build business logic into the application."

Literally, what? --- maybe you should acknowledge some scope here because this is literally what many of us are paid to do. This would be a terrible idea if you were building software for people outside of your company (e.g. generic solutions like database software, or products that meant to be pulled off the shelf), but for many of us if not most of us, we build software to run the companies we work for. In that case, the statement that building business logic into the software is a bad thing is patently absurd. That doesn't make DDD bad, that makes using DDD in a non-domain context bad. Like trying to tighten a lug nut with a banana.

Collapse
cheetah100 profile image
Peter Harrison Author

"for many of us if not most of us we build software to run the comanies we work for." Yes yes, so do I, but by using a platform which is not strongly tied to any domain you can deliver systems which are configured at runtime that are easily adaptable and flexible. No development life cycle. This is what agile means. You can make modifications in runtime systems. The more you hard code the business rules the less flexible the software. Configure business rules instead. Configure data structures. Configure integrations, queries, visualizations and so on. In a way this is still 'development', only it hands power back to users.

Collapse
dbjdbj profile image
DBJDBJ

" ... software to run the companies we work for..." , well that seems to be more often than not: Excell.

Collapse
cheetah100 profile image
Peter Harrison Author

To address Kasey and Craig's points. I am not claiming that we can create a single solution to meet all needs, rather that software should be designed around function rather than domain. Therefore video editor software cannot be created from a forms and data type application because it is dealing with video functionally. However, many software projects begin with requirements tightly coupled with the domain. Often this leads to software unnecessarily coupled to the domain, and thus limits itself. Imagine the designer of Word getting requirements to write a specific style of letter and writing a word processor around that specific style of letter for a particular industry.

The critique that pushing the domain into configuration leads to complexity in the configuration is valid. In fact the configuration becomes the place you define the domain rules. Just like you can write scripts inside Excel the systems I'm writing allow embedded Javascript which runs server side, and can be replaced with a REST call, by the right administrator of course. Where once there were developers and users we now have a more diverse environment where developers deliver core functionality and business analysts can construct new systems using these tools.

This article was primarily addressing the practice of using the domain as the foundation of the system. In the past this was necessary because of the way databases were static. Adding complex structures at runtime was not possible. Now it is possible, and with this possibility goes new opportunities to dramatically improve development efficiency.

This is not just a supposition. I'm now running the second project using the same software, despite the domains being totally different. We are now looking to develop it into a generally available tool for the entire organization.

Collapse
femolacaster profile image
femolacaster

Beautiful article.
The question for me on scalability is: do companies want to scale in their domain or beyond their domain like the software you built later did?
Of course, the latter is of greater risk, somewhat in the lines of what a product person would call product differentiation. Possible different products at a higher cost. A higher cost of development time especially in abstracting all of that logic to suit for whatever future needs.

In as much as I always tend to the generic lines philosophically in most things I do(dev.to/femolacaster/generalist-or-...), my bias is reserved when it comes to those things that are done for financial revenue🤑.

The model proposed by you may be the best for large complex systems, systems with less clarity of domain, and open-source projects. And yes I agree with Craig that a DBMS actually has its domain and any scaling outside its intended purpose may not be that significant to the users. And this already exists in the largesse of ERP systems today where the runtime logic is abstracted to concepts like workflow, jobs, and tasks. Going your suggested route seems to me like building a BPM or an RPA tool.
But in this day we live? Where you need to sell the idea and not an abstraction of the idea asap. A time of MVPs. In the light of at least let it do one thing well, early investors, early adopters, early failures….we really should think of DDD.

PS: Also, the need for domain experts goes beyond contributing to the business logic but to all composition of the idea including the architecture or any function that was suggested to be abstracted. Think of accountants saying this is the kind of "excel" we want.

Collapse
cheetah100 profile image
Peter Harrison Author

The point of this environment is to be adaptable, to enable fast MVP projects, but to build in all the features that you would expect in the foundations, such as security, audit trails, complex reporting and data manipulation out of the gate. Domain binding forces you to write repetitive code that is more or less identical in each app, the only difference is the model it binds to. Spring Security makes life better in the Java space, but you still end up with a large number of apps running in a micro service bound to the domain.

Collapse
femolacaster profile image
femolacaster

I agree with your points, Peter. I am thinking that building in all the features that you would expect in the foundations, such as security, audit trails, complex reporting, and data manipulation out of the gate would take more time needed for an actual MVP. You may say this is done only once and can be reused but even these foundational features could have special domain needs. Multi-FA security is more tailored to financial domains, for instance, verbose audit logs are tailored to information systems with high deletes or journaling domains. The point is there might be an over or under engineering building the foundations first.

Thread Thread
cheetah100 profile image
Peter Harrison Author • Edited on

My code is open source - GPL3. Feel free to utilize or even contribute back. It's Java/SpringBoot. Codebase is a little dated in some respects. I'm working on a new UI which isn't part of the core project.

bitbucket.org/cheetah100/gravity/s...

Collapse
redaalaoui profile image
Réda Housni Alaoui • Edited on

Now you can rename the app « administrators » to « developpers ». You just dumped complexity on your users.

Why not create a template project based on a framework like Spring Boot and ask them to setup their business rules? Yeah, that’s called development but at least they may be able to write some tests.

In 14 years in this field, I think this is the most naive article I ever read.

Collapse
razvantudorica profile image
Răzvan Tudorică • Edited on

"Each of these web servers are connected to a database server to store the data for that service. Imagine that there is a head crash on one of the database servers. " - Wrong architecture decision. Each microservice (or domain) should have their own database cluster with replication, not "a database".

" With the domain driven architecture all the hits for a specific service will go to the same servers. That means that if you are unfortunate enough to get a rush on one specific API it will get over loaded." - you can have different (auto)scalling policies for each group of servers, based on usage (for example, the users service/domain probably is much more used for reading, than the payment service).