Building Software that Shouts the Language of your Business
By Michael Ryan, Head of Architecture and Robin Morrison, Managing Director of Kenzan
Your Company Struggles
Your company struggles to build quality software.
The problem is not staff — you have talented engineers, knowledgeable agile professionals and top business leadership. They are all paid at or above the market rate. Everyone is very motivated to succeed — and frustrated with lack of results.
Yet when engineers, agile professionals and business leaders work together they fail over and over again. Ask each group what the most important features of the software are and why they are not implemented correctly; they all answer as if they worked at different companies. They don’t even use the same language to describe the problem. Your company is stagnating as a result.
Your Software Disappoints
“If you think good architecture is expensive, try bad architecture”
- Brian Foote, Chairman/President/CEO at HUMBL Inc.
Your software suffers from one or more of the following problems.
Software can’t be updated to perform required business functions. Some of our clients struggle with software that was once acceptable but no longer meets current business needs:
- Manual entry of data or cumbersome workarounds are necessary to get customers through basic workflows.
- Meeting new regulatory requirements or even adding new features require tedious manual workarounds by engineering or other staff.
- Staff end up entering information customers could have entered for themselves if the software provided for it.
- Attempts to incorporate new features either fail or can’t be attempted because engineering resources are fully occupied just keeping the software running.
Software poorly integrated into existing systems. Integration with existing systems can be difficult. The result is often unnecessary workarounds or poor performance. Symptoms include:
- Requiring customers to take unnecessary actions such as entering the same information multiple times in the same workflow.
- Poor integration with existing systems slows the flow of actionable information to key decision makers.
- Upgrades to one system require corresponding upgrades to multiple systems. Each upgrade needs to be intricately sequenced to accommodate a complex web of dependencies.
Software cannot be updated without introducing new defects. You have good engineers but, quarter by quarter, their performance degrades:
- It takes weeks to get even small changes or bug fixes through development and testing.
- As a result the number of production deployments per quarter decreases. The size of each deployment grows correspondingly, increasing both the time and difficulty to test and the odds a defect is released into production.
- With more code and more defects released with each production deployment, the percentage of deployments resulting in customer complaints and emergency hot fixes increases.
- Because the amount of code released with each production deployment is increasing the time to investigate, fix and test production defects also increases.
- The increase in production defects prompts management to increase the amount of time spent on testing, most often manual testing “just to be sure” the automated tests are running correctly. This further slows the deployment rate, increases the amount of code in each deployment, increases the odds of a production defect, and increases the time to fix that defect.
This becomes a downward spiral. Dissatisfied customers don’t understand why your software can’t be made to work properly. They are aggravated by wasted time, expense and overall poor quality. Your customers are likely to switch providers if given the chance.
Your Teams Fail to Deliver — or Even Understand One Another.
Why is all this happening?
One problem is developers, product owners, and business people each have a different understanding of how the software actually works and what it is supposed to do.
Each group has their own name for particular software features and there is little shared knowledge or even language. Worse, each group doesn’t realize the extent to which they disagree with the other groups on what is most important to build or fix first. Each group not only thinks their perceptions are correct but those perceptions should be intuitively obvious to all.
When developers, product owners, or business people speak about the software, they use terms and language only understood by themselves. Listeners from other groups are left to translate into their own terms as best they can. Getting agreement on implementing even small changes is very difficult when no one even uses the same language.
Talented team members but ineffective teams
As a result engineering teams are unable to build essential features, repeated attempts to solve the same problem always end in failure, and adding new features or fixing defects is time consuming and error-prone. Every production release is followed by a wave of calls to customer support.
The problem is often not with your engineers, your agile professionals or business stakeholders. The problem is the way each group works with one another — a symptom of their lack of shared understanding about the business and the software it builds. They don’t speak the same language and the software reflects that.
Domain-Driven Design Leads to Better Software
You are not alone, and many of our clients have found themselves in similar situations. Kenzan has taken an industry-standard approach, Domain-Driven Design, and tailored it to solve exactly this sort of problem.
Domain-driven design can be a complex process. Kenzan has broken it down to a few critically important steps that produce rapid results.
Bring domain experts and technologists together.
“Domain experts” are people who know the business, the products and the customers. Domain experts know your core competency, what the customer needs and how that maps to what your software does.
Domain experts and the technologists who design and build the software need to be aligned as one team. In many companies software architecture is disconnected from the business. Domain experts do not understand the software — even in technology driven businesses. This is obvious when a business user speaks about software functionality using one set of terms and then a developer speaks about the same functionality using a completely different set of terms.
To bring domain experts and technologists together can be a lengthy process, but it always starts with the next step: building a common language.
Build a common language.
It is very hard for a team to fix a problem if they don’t even use the same terms. So our first step is to create a dictionary of agreed-upon terms so everyone speaks the same language. We call this dictionary of terms a “ubiquitous language”, meaning the same terms are used by everyone associated with the software.
Simple misunderstandings can cause expensive software defects. For example, software that manages corporate sales contests and prizes might integrate with both the Sales and Finance departments. In this case the simple term “close” could refer to finalizing a sale, the end of a business quarter or when a sales contest concludes. Disambiguating the term “close” is critical to avoiding defects as well as having each department fully understand what the software is doing. Multiplying this example by dozens or hundreds of overloaded terms provides a glimpse into the problem many companies face.
The ubiquitous language is embedded in the software code as well as documentation. Software’s code must speak the language of the business — not the language of the engineers who write it. As staff comes and goes it will be the ubiquitous language encapsulated in code and documentation that results in continued understanding of the software and often continued culture.
Build a domain model of real world needs.
Once everyone agrees to speak the same language a real world model of business needs can be created. We call this a Domain Model.
Domain models vary between two extremes:
- Anemic models that lead to architectures with multi-purpose common components handling most of the logic and domain objects that end up being little more than POJO’s or the equivalent (simple data objects with getters and setters and little logic). Since there are no clear responsibility boundaries, logic related to any one domain is often scattered across multiple components.
Anemic models fare poorly when mapped to distributed architectures like microservices. The result is often a “distributed monolith” that is worse than the application you started with.
- Rich or robust models where domains are represented by self-contained components with a single business purpose that contain both the data and logic necessary to perform their function. Rich models tend to map well to distributed architectures like microservices.
The Kenzan approach is to analyze, design and refactor only those domains that will provide the biggest return to our clients. We call these “Core” domains — domains that are fundamental to your company’s position in the marketplace that give it a critical edge over the competition.
“Generic” domains (domains that facilitate the operation of the business that can often be performed with off-the-shelf software — such as an invoicing system) or “Supporting” domains (domains that relate directly to core business functions but do not require your top engineering talent to build or maintain) are often not fully modeled and refactored.
“The design is the code, and the code is the design. The design is how it works.”
-Vaughn Vernon, Implementing Domain-Driven Design
Map the domain model to software architecture.
There are exceptions, but most often the target architecture is some form of microservices. In such an architecture each microservice has the following characteristics:
- A small but complete application in itself.
- Is as decoupled from other microservices as possible.
- Has a single business purpose.
- The service’s single business task is meaningful to business users — there should be no services with only a technical or infrastructure purpose.
- Has all the data and logic required to perform this business purpose.
- Has a clear interface and dependencies so it runs independently of other services and an engineering team can maintain it independently of other engineering teams.
There are well designed and poorly designed microservice architectures. A poorly designed microservice architecture is often worse than whatever architecture you started with.
To build a good microservice architecture it is important to accurately model the underlying domains. Unlike earlier modeling paradigms, Domain-Driven Design practitioners realized that accurately modeling an entire enterprise is theoretically possible but not practical.
The better approach is to break apart the larger domain model into smaller sections called “bounded contexts”. Bounded contexts often are drawn around functional areas of a company, for example a “sales” bounded context or a “shipping” bounded context. A group of bounded contexts are arranged in what is called a “Context Map”.
One of the interesting things about bounded contexts is they help determine how microservices communicate with each other and the granularity of information exchanged.
For example, when a sale is completed communication between microservices within the sales bounded context tends to be synchronous and fine grained. A sales representative’s commissions need to be updated, territory sales numbers recalculated, pipeline information brought up to date, customer information modified. It’s possible to accomplish this through an asynchronous messaging scheme but messaging disparate pieces of information all related to one action can become cumbersome. Often it is easier and more direct to accomplish this with synchronous interactions between services.
On the other hand, when a sale is made communication between bounded contexts tends to be coarse-grained and asynchronous. In this case all the “shipping”, “inventory”, “finance” and other bounded contexts need to know is something like “10 widgets were sold on 12/01/22 for $150 each to customer X”. There is often no need to acknowledge receipt of the message. Once the message is received shipping proceeds to send customer X the 10 widgets, inventory decrements its totals by 10, finance records $1,500 in new revenue and other bounded contexts perform their own business tasks on the same information. We could accomplish this through synchronous interactions, but it would be slow and there is no need. It is easier and faster to post the message and let each subscriber act on the information as they need to.
As you can see, in this case going through the domain-driven design process has allowed for groupings of services that interact with each other in an optimal way, a way that accommodates future changes to your business model. Success in software and business is often won by those who adapt to change the best.
Implementation: Building software that shouts the language of your business.
Using the Context Map as a guide, your software is gradually altered to increasingly reflect the real world needs of your business while maintaining continuity of service.
It sounds easy but it is not. There is a lot of work and a lot of negotiation that goes into this process.
Domain modeling provides other benefits aside from well designed software that meets customer needs. These include:
- When a company knows what its most important tasks are it can assign the best engineers, agile professionals and product owners to those tasks.
- There is less miscommunication between technical and non-technical staff. When everyone speaks the same ubiquitous language the shared understanding extends to front line engineers. The code they write uses the same terms and is so clear even business people can understand it. Engineers and business people use the same terms everywhere — no special terms are used by either group.
- The same terminology carries forward as staff enter and leave the company. There is no drift in understanding as time passes.
To be successful all staff must understand what the software needs to do as well as what the software does not need to do — and why. This becomes possible when your software is modeled on the real world needs of your business.
The end result is software that reflects the mental model of the business experts. The design is the code, and the code is the design. The design is simply how it works.
If you’d like to discuss the concepts included in this article, please reach out to the authors below:
Head of Architecture
Managing Director of Kenzan