Bridging The Gap Between Domain & Technology Expertise
Learn how use cases, domain-driven design and LCNC platforms address the gap between subject matter experts & software engineers and thoughts for further improvement.
Hi there, it’s Niels. 🤗 Welcome to my newsletter. This newsletter helps with the creation of valuable software solutions, making better software investments, and improving the developer experience. Questions? Ask them here.
It’s important to deeply understand the problem before codifying a solution. A software developer first needs to build a mental model of the problem domain before capturing the insights in a programming language.
In my previous article, I talked about “The Hexagonal Architecture”. The hexagonal architecture dictates that there should be a clear separation between a software solution's inner application layer and the surrounding infrastructure layer.
The application layer:
is described by functional requirements
subject matter experts (SMEs) hold the required knowledge of the problem domain (= core domain)
The infrastructure layer:
is described by non-functional requirements
software engineers (SE) hold the required knowledge of the technology domains
There is a gap between these two layers that must be bridged to deliver cost-effective and valuable software solutions in time. Excellent collaboration and communication are needed between subject matter experts and software engineers.
Mental Maps
For codifying the integration layer, software engineers do not need any help from subject matter experts to create a second-degree map of reality.
first degree: the mental map of the domain (technology domain)
second degree: code as a map of that mental map.
When software engineers need to codify the problem domain, they depend on the input of subject matter experts which makes things considerably harder. Now, there is a need for a third-degree map:
first degree: the mental map of the problem domain by subject matter experts
second degree: translation of that mental map so that software engineers understand it
third degree: code as a map of the software engineer’s mental map (based on the mental map of the subject matter experts)
Translation of the problem domain between subject matter experts and software engineers is very challenging. Information gets lost often. It also takes time, serious effort and interest for a software engineer to gain deep understanding of the problem domain.
Different approaches have been introduced to improve this mental mapping process:
Use cases: textual formalization of the functional requirements to align SMEs and SEs
Domain-driven design: increasing the understanding of the problem domain by SEs and creating a common language for both SMEs and SEs
No-code & low-code platforms: reducing the need for mental mapping of the problem domain by SEs
These are great approaches and initiatives but there is still room for improvement.
Use Cases
Use cases are often replaced by user stories although they serve a completely different purpose:
User stories are about the needs and benefits of the end-user and grew their popularity with the rise of Agile. These are expressed in one single sentence using the format: As a [type of user], I want to [need], so that I [benefit].
Use cases on the other hand contain all the answers (about functional requirements) developers might have while codifying the solution.
They are both useful and can both be used in parallel.
A use case describes how an actor interacts with a system to achieve a goal. That goal is equal to the need for a user story. A use case contains:
a goal: equals the need in a user story
an actor: human or external system
preconditions: the state the system has to be in for the use case to occur
default path: the regular series of steps the system will take
alternative paths (optional): conditions will lead to branching
postconditions: actions the system takes at the end of the use case or the various states the system could be in after the use case concludes
Even when low-code or no-code is used and there are very limited dependencies on software engineers, this formalized textual description has tremendous value. It helps to think the use case through before jumping to coding the solution.
Domain-Driven Design
Every solution starts with insight into the problem domain. Subject matter experts own the knowledge and expertise about that problem domain.
A lot of domain information gets lost between subject matter experts and the software engineers that translate the domain into code. Many books have been written trying to solve the difficulties of this translation. Domains can get pretty complex to reason about and they often need changes. When something changes in the domain, the code should also reflect that which needs a change. It takes time for software engineers to deeply understand the domain.
Domain-driven design (DDD) is a well-known software design approach. It focuses on modeling software to match the domain based on input from subject matter experts. The idea is that the structure and language of software code should match the business domain. That way, a ubiquitous language is created that is understood by both software engineers and subject matter experts. It introduces concepts like aggregate roots, entities, value objects, and repositories. These concepts might be known to software engineers that have read about and studied DDD. But on the other hand, these concepts do not ring any bell for subject matter experts.
I’ve read the following popular books about domain-driven design in the past:
Technology is not hard for software engineers, understanding the problem domain is.
I’ve enjoyed reading them, and I’ve tried to apply them as much as possible in past projects where it made sense. Still, domain-driven design is hard. What makes it hard is the road to understanding the domain and then making sure the code reflects that domain.
Low-Code & No-Code Platforms
Low-code and no-code platforms try to limit the technology skills needed to build, test and deploy a solution.
No-code platforms don’t require any coding skills. They allow configuring, composing, and interconnecting pre-built components.
Low-code platforms also allow certain extensions of existing components or allow you to build new components. For that, coding is necessary.
Most platforms are a blend of no-code and low-code. Because without any code, you run into limitations very quickly.
While you don’t need much coding skills, be aware that you still have to learn how to work with the platform. Typically, the more flexibility is offered, the steeper the learning curve.
My opinion is that:
No-code platforms can be useful for subject matter experts but these platforms have serious limitations regarding what you can do. The best no-code platforms solve very specific problems for a very specific industry.
Low-code platforms are not a good fit for subject matter experts but can be useful for software engineers to speed up their work.
Here is why I think subject matter experts should stay away from the infrastructure layer:
Subject matter experts (unless their domain is software engineering) will never be able to create reliable integrations when the non-functional requirements are beyond basic.
Selecting the best database or choosing between asynchronous communication over a message bus or using a synchronous REST-API requires high software expertise. Even when using no-code drag-and-dropping, subject matter experts have no clue about the performance implications of attaching an integration (e.g. database query, REST-API call) to a business workflow or a graphical user interface element action (e.g. button click, form-submit).
Conclusion
Software engineers and subject matter experts should collaborate closely to create software solutions. Everything starts with a deep understanding of the problem domain.
Subject matter experts hold domain expertise and lack technology expertise.
Software engineers hold technology expertise and lack domain expertise.
Technology expertise includes writing and testing code but also integrations with external systems while satisfying non-functional requirements.
Uses cases are a great way to textually formalize the goals of actors, how to get there and what might go wrong. They contain all the answers to questions about the functional requirements developers might have while creating the solution.
Domain-driven design showcases how difficult it is to create a shared understanding of the problem domain between SEs and SMEs and make the code reflect this.
Low-code & no-code platforms can be useful but it’s dangerous to let SMEs control when and how integrations to other systems are called.
In an ideal world:
Subject matter experts can model the domain including data and behavior themselves.
Software engineers take care of the integrations so that the non-functional requirements can be satisfied
To facilitate this, transparency is needed for both subject matter experts and software engineers about:
the high-level functional and non-functional requirements
overview of the actors and external systems that will interact with the solution that is in scope
definition of all the interfaces between the application layer and the infrastructure layer
🤔 What Else Is On My Mind?
I have been thinking if it would make sense to create a programming language aimed at subject matter experts that would enable them to model the domain themselves.
The article above was part of this thinking exercise.
The language characteristics that would help in my opinion:
Turing completeness, so it should not be a domain-specific language (DSL). It should be applicable to model any specific problem domain.
Statically typed to be able to better guide and protect subject matter experts. It would also allow auto-completion while developing.
Simple: no 10 ways to accomplish the same thing
Clear separation between data and behavior. I will motivate this one in depth in a future article.
data components:
which are mutable
they can have multiple instances
adding behavior to data elements will not be possible
behavior components:
no inheritance, the assumption is that domain experts have trouble understanding this
composition of dependent behavior components will be possible via the constructor
all behavior components will be singletons
data can only be used inside behavior as a function parameter, not in the constructor
This is just a snapshot of my thinking at this moment. I’m looking forward to your thoughts about this!