Has the code devolved into a big ball of mud?... What can you do about it?Fri, Aug 19, 2016
Has bad architecture forced your team to write smelly code? There are plenty of symptoms:
- global state everywhere…
- flow of data completely non-obvious…
- parameters to methods constantly mutated…
- super, super fragile code…
- methods being overloaded several times…
- huge, 8000-line classes…
But are these symptoms just the devolution caused by poor up-front modeling decisions made 5+ years ago? I’ve talked about these symptoms, but I haven’t talked a lot about their root causes. Is it really anyone’s actual fault, or is it natural?
Given the chance to start a brand new project, or given enough time to rewrite a legacy project - how can we architect the application so that the big ball of mud isn’t inevitable?
What does the ball of mud look like?
Pretend your company is just starting to invest in custom software. The goal is to smooth out deficient processes to reduce costs. They identify areas in the business that are separated by political or technical boundaries.
They embark on a journey to join these “silos” together so that information is disseminated across boundaries.
The company’s view of the business from a software perspective is one single model that represents a truly integrated platform of software and infrastructure. To achieve this dream, they’ll employ developers and infrastructure to build apps that speed up tasks that are core to the success of the business.
There’s nothing wrong with having this ambition. Mary from Sales having to get up from her desk to walk to Joe in Finance to get Purchase Order information printed out on a green-bar printer is inefficient for sure. It’s how IT approaches the solution from the beginning, the modeling phase, that the ball of mud begins to grow.
Becoming driven by data
For a real scenario, let’s imagine that generating a Quote for a Customer to buy some Parts from your manufacturing company is core to the success of the business. IT is asked to streamline this process by making it easier for Sales to get a Quote to a Customer.
IT starts looking for data… There’s data in their ERP… There’s data in their CRM… There’s data in the minds of Engineers… It becomes essential that they start integrating this data to build the app. They build a concept of what the business looks like as a single unit, with software holding key pieces of data throughout the business:
Conceptualizing the business as where the data lives is a mistake. The business is how business processes happen. The business isn’t defined by table columns in the ERP’s SQL database. It is especially not defined by the terms that IT comes up with on their own.
Time passes and the app(s) are built. The team iterates over several death marches, emotional roller coasters, and go-lives. Meetings are held, SQL jobs are scheduled, SOAP services are written…
The test of time
Think about how natural it is to have specialized Domains in a business. Or, how well would the business do if every person had the same Domain specialization and expertise? Not very well.
If this is true, how can we fit all of our specialized, Domain-specific data into one model? We can’t, which is why we transform data and jump through hoops to make it “fit” where we need it to.
Imagine the company hires a top-notch programmer implement our app for generating Quotes. It comes complete with web services, ETL jobs, and Web Forms combining data from the CRM, ERP, and everywhere else. Very nice!
The coder leaves and more coders are hired to work on new features for the app.
The app gets new web services, new ETL jobs, new integrations in many different frameworks over the 5+ years it’s alive. It starts to break. The old frameworks become end-of-life. ERP gets upgraded and patched. CRM gets a new database and set of schemas. ETL packages get patched for new column names. New coders are hired and more money is spent… and behold the great ball of mud.
But hope is not lost. The company finally hires you. You understand that learning about the business is the most important thing right now.
Learn about the business
Am I saying IT doesn’t understand the business well enough? Yep. The tickets flood the service desk. IT whines about how Bill in Engineering doesn’t understand the business that IT defined with its software. Bill whines because IT’s “app” doesn’t do what it’s supposed to do - let him put a valid Part on a Quote for a Customer.
It’s a language mismatch. The good thing is, we have the ability to create a brand new language to describe our business Domain - the Ubiquitous Language. By eliminating the need to translate the language spoken by the Domain Experts into one that is understood by IT, we need to develop a language that is shared by both teams.
Our solution comes from Domain-Driven Design and the canonical book written by Eric Evans called “Domain-Driven Design: Tackling Complexity at the Heart of Software.” Evans describes the language barrier like this:
“Across this linguistic divide, the domain experts vaguely describe what they want. Developers, struggling to understand a domain new to them, vaguely understand. A few members of the team manage to become bilingual, but they become bottlenecks of information flow, and their translations are inexact”
Therefore, the Ubiquitous Language
”…should be used among developers to describe not only artifacts in the system, but tasks and functionality. This same model should supply the language for the developers and domain experts to communicate with each other, and for the domain experts to communicate among themselves about requirements, development planning, and features”
This post is mostly a primer. I want to continue to take a much closer look at the concepts found in Domain-Driven Design and hopefully write some code.
What’s important in this post is that we describe the pain that we feel with these long-lived applications that would have benefited from adherence to a Ubiquitous Language shared by the domain experts and IT.
What might our example have looked like if we did this? The most apparent change would be clear separation of the business into Subdomains. Subdomains are simply defined as “a sub-part of your overall business domain. You can think of a Subdomain as representing a single, logical domain model.” (Vaughn Vernon, Domain-Driven Design Distilled).
In real life, we would be drawing the maps below with the domain experts. Several iterations would take place and we would likely employ EventStorming to drive the development of our Ubiquitous Language.
The key point I’d like to make with the following diagrams is separation we need to achieve. These separate units become separate Bounded Contexts as we move forward with Strategic Context Mapping and Tactical Design. The identification of these Bounded Contexts is essential for how we implement our Domain Model in code.
As you can see, we are no longer viewing the business as one single unit driven by the 2 or 3 data sources. We are seeing the business as what it has evolved to become naturally, from a process standpoint.
We described the condition where bad architecture warrants bad code. Looking at just the symptoms of bad code, we might blame other coders. But I’d argue that high-quality architecture can act as a shield against poor coding decisions over time. We can use the clarity of the domain model to defend against bad decisions.
We’ll continue this Domain-Driven Design journey from both strategic design and tactical design perspectives. I want to try to unearth some of the decision-making difficulties we run into as we try to go “full DDD” in a complex domain.
So if you’re ready to take this journey with me, make sure you sign up for my newsletter!
- Vernon, Vaughn. Domain-Driven Design Distilled
- Evans, Eric. Domain-Driven Design: Tackling Complexity at the Heart of Software
- Fowler, Martin. Bounded Context