Essentially, all models are wrong, but some are useful.
—George E. P. Box
Domain Modeling is a way to describe and model real world entities and the relationships between them, which collectively describe the problem domain space. Derived from an understanding of system-level requirements, identifying domain entities and their relationships provides an effective basis for understanding and helps practitioners design systems for maintainability, testability, and incremental development. Because there is often a gap between understanding the problem domain and the interpretation of requirements, domain modeling is a primary modeling area in Agile development at scale. Driven in part from object-oriented design approaches, domain modeling envisions the solution as a set of domain objects that collaborate to fulfill system-level scenarios.
In SAFe, domain modeling connects to backlog items at the Team, Program, Large Solution and Portfolio levels and provides a common language for the entire organization. Especially important is its connection with the Nonfunctional Requirements (NFRs) that may affect certain areas where “alternative design approaches” are sometimes used to satisfy the corresponding NFRs.
Domain modeling also provides the Agile organization with opportunities for use of Agile-friendly design patterns and approaches that enhance velocity over the long term. As the system design changes, refactoring and updating the domain model is vital to maintaining a continuing understanding of the system, and goes hand in hand with code refactoring to help control the inherent complexity of software systems.
Domain modeling is one of the key models used in software engineering: if you only model one thing in Agile, model the domain. A relatively small domain-modeling effort is a great tool for controlling complexity of the system under development. It may help in resolving countless ambiguities in both the requirements and the design intent. Domain modeling simply reflects our understanding of real world entities and their relationships and responsibilities that cover the problem domain. Figure 1 shows an example of a domain model for consumer subscription management system:
A number of different views or representations express the essential aspects of the problem domain: Robustness Diagram, CRC Cards, ORM Diagram and so on (see , chapter 8 for more detail). However, the most simple and common is a class diagram or its simplification (as in Figure 1). Such a diagram primarily shows the key entities and their relations.
Effective domain modeling may only occur in the context of the system-level requirements, often captured as use-cases or other means. In this case nouns, captured from the requirements, become valid candidates for domain entities while verbs may represent behaviors and relationships. Together they form a Common Language (sometimes called: Ubiquitous Language – see , chapter 2) that allows engineering, business, and user representatives to speak the same language, minimizing miscommunication.
Domain Modeling in Agile at Large Scale
In a large scale Agile development, domain modeling is continuously used to support:
Domain modeling is typically developed and continuously refined by the System Architect in collaboration with other stakeholders in order to understand the impact of epics and features on the system. These groups use domain modeling as part of the preparation for PI Planning at the modeling workshop in a highly visual and collaborative manner.
The following example (Figure 2) shows how a domain model is used to clarify the impact of an epic:
Requirements and domain modeling actually are mutually dependent. Domain modeling supports clarification of requirements, whereas requirements help building up and clarifying the model. Furthermore, once new requirements are implemented, the domain model may also change as table 1 suggests:
|Backlog Item||Impact on Domain Model|
|Epic||Typically introduces new entities, relationships and responsibilities|
|Feature||May introduce new entities, typically introduces new relationships or responsibilities|
|Story||Typically introduces changes to the existing relationships and responsibilities, may introduce new responsibilities, value objects or changes to the service interfaces|
|Enabler Epic||Typically affects implementation and design aspects of a whole range of entities, services and repositories such as underlying technology or platform, generic life cycle of the entities, API constraints etc.E|
|Enabler Feature||Introduces changes to implementation/design aspects for: a) only certain entities/services typically constrained to one product or system; b) only certain life cycle steps (e.g.: instantiation). Enabler features may also result in a change of responsibilities or may introduce new value objects.|
|Refactor||May extract individual value objects or “helper” objects out of an entity, may change internal interfaces between entities, protocols or APIs.|
Table 1. Impact of SAFe Backlog Items on the Domain Model
Relationships between the entities of the model are critical to effective modeling – without them the model is just a vocabulary of terms with very broad semantics since they lack their “collaborative” context. Relationships drive both effective requirements definition and design decisions (see the example below in figure 5 and the associated description). Relationships in a domain model can be pretty standard (e.g. “includes,” “is a”) or very specific (e.g. ML Admin “defines / patches” the Mailing List in our case). When defining the relationships it is much more important to adequately capture real connections between the entities that convey the meaning of their role rather than to follow format agreements indiscriminately.
The common language resulting from domain modeling is used at all levels of the Agile organization to foster unambiguous shared understanding of the problem domain, requirements, and architecture – see Figure 3.
Common language – even though is crucial to the product development – has natural limitations that every organization should be aware of. For example, the language of marketing materials may sometimes use terms that diverge from the common language, in order to emphasize certain temporal or subjective aspects associated with current market trends or challenges.
Teams that use ATDD inevitably use common language in their specification workshops when defining human readable tests.
The Domain Model and System Design
Domain-Oriented vs. Alternative Approaches
Domain modeling is not only useful for analysis but is often a good conceptual model for the system design. “Domain modeling” is one of the key design patterns/approaches that assumes deriving the solution object model directly from the problem domain while preserving both behavior and data (see ). See  for a systematic and detailed outline of such best practices, known by the term of Domain-Driven Design. This approach provides a natural and very effective way of managing the inherent complexity of software development that is vital at large scale. Figure 4, adapted from , chapter 2, shows a comparison of effort spent on enhancing software functionality versus complexity by different approaches:
- When design is based on the domain
- When design is based on data structure or transaction scripts.
Large scale software solutions almost inevitably have complex domain logic. Thus data- or transaction-centric design approaches imply very high cost of maintenance. Nevertheless, too many organizations end up with highly complex system designs that imply a lot of effort to enhance the system. While in some cases such approaches may make sense – and we will discuss those below – most often such a design in reality is based on personal preferences of the system architects and teams rather than on business drivers.
One of the many reasons to base system design on the domain structure is to foster reasonable usage of patterns that support maintainability and enable highly incremental, concurrent development. So, in our example of the subscription management system, domain modeling and requirements may logically suggest that subscription methods will represent the primary source of change. Thus, given the different scenarios for opt-in and opt-out functionality, it seems quite logical to use a Bridge Pattern, shown in figure 5 to isolate the area of frequent change and reduce the number of entities in the system – (see , Appendix B).
This is just one example of how domain modeling can be effectively used for Commonality-Variability Analysis (CVA) to foster effective system object models. (See , chapter 8 for more detail on the CVA method).
Domain Modeling, System Design, and Nonfunctional Requirements
Nonfunctional Requirements, on the other hand, represent the primary reason to build system design around data structure or transaction scripts rather than the domain model. Typically NFRs like performance or scalability may result in cases where domain logic is spread across a bunch of large SQL-scripts, or where too much logic is in the client-side validation scripts, and so on. Even though the use of such a Transaction Script approach (see , chapter 9) can be legitimate in certain cases, it should be used as an exception rather than the rule. A very few properly implemented exceptions will still allow the Agile enterprise to benefit from a domain-oriented approach.
Refactoring the Model
Developing shared understanding with the help of domain modeling is an incremental process just like developing code that implements the underlying domain logic. This means that just like the code, the domain model is also subject to refactoring as our knowledge about the system improves, and as new domain entities and their relations actualize, as table 1 suggests. In the Domain-Driven Design approach, keeping the system design and the current understanding of the problem domain up to date is relatively easy, and refactoring of both typically happens synchronously or nearly so (see , part III). Designing the effective domain model is both an art and a science. Not uncommonly great insights about the structure and associations in the domain model emerge eventually. However, it is never late to start building the right understanding and to start gradually improving the code towards it – as new functionality allows – to be able to control the complexity.
Domain modeling is a great tool for agile enterprise to carry out a common language and a fundamental structure important for the analysis of features and epics. Domain model is defined and continuously refactored as enterprise knowledge about the domain improves and the system functionality evolves. Domain model serves a vital link between the real world where the problem domain resides and the code – domain-oriented design approaches allow to control rapidly growing complexity and cost of maintenance and enhancement effort. Domain modeling is highly collaborative and visual effort that involves system architects, product management, stakeholders and teams all working towards better shared understanding of the priorities and better ways to implement them. There’s hardly any other model that would cover that many taspects for agile development at scale. Thus, if you only model one thing, model the domain.
Learn More Ambler, Scott. Agile Model-Driven Development with UML 2.0. Cambridge University Press, 2004.  Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison Wesley, 2003.  Fowler, Martin. Patterns of Enterprise Application Architecture. Addison Wesley, 2002.  Bain, Scott. Emergent Design: The Evolutionary Nature of Professional Software Development. Addison Wesley, 2008.  Shalloway, Alan & Trott, James. Design Patterns Explained: A New Perspective on Object-Oriented Design.Addison Wesley, 2004.
Last update: 4, August, 2017
The information on this page is © 2010-2018 Scaled Agile, Inc. and is protected by US and International copyright laws. Neither images nor text can be copied from this site without the express written permission of the copyright holder. Scaled Agile Framework and SAFe are registered trademarks of Scaled Agile, Inc. Please visit Permissions FAQs and contact us for permissions.
This blog describes the journey our Production Engineering team went through to bring Domain Driven Design concepts into their project to help solve some of their problems.
Who We Are
The Production Engineering team are responsible for picking up customer orders created through the web or app interfaces and automating the steps required for them to get to the factories for printing and despatch. This includes preparing the artwork for cards and gifts to be printed with customers’ customisations as well as integrating with third-parties that fulfill non-customisable gifts.
What Were We Doing
When I first started working in the Production team, before we knew what Domain Driven Design was we had a mandate to drag our legacy systems from a collection of windows services and thick client-server winforms apps, kicking and screaming, onto a scalable, cloud based platform.
Problems We Faced
We initially took the approach of analysing the old system and doing a lift and shift of code into services, however this proved to be problematic.
Autogenerated Stovepipe: We faced the problems with a lot of legacy code that was not suitable for a distributed system and a lot of dependencies made it difficult to isolate.
Architecture by implication: We assumed we understood requirements from the legacy solution and so didn’t need user stories, just technical tasks. We made many assumptions but then found ourselves having to spend days trying to unravel legacy code, eventually realising it was impossible to estimate. After a while we just said that anything involving a re-write of legacy code could not be estimated.
Also by using the legacy system as a template we were assuming that it was doing the job correctly. However, in supporting the systems we knew that sometimes the workflows was defined by how the tool worked. Effectively the software was directing the job as opposed to supporting it.
This also led to a bottom up approach, resulting in highly complex logic trying to solve many problems with a single solution.
Analysis Paralysis and Design by Committee: We often had differing opinions on expected behaviour and responsibility, which led to long discussions about small details or deferring decisions because we couldn’t agree or didn’t understand the context.
Symptom Solving Not Problem Solving: We localised analysis to only those parts of the code that we thought was the most inefficient, never really looking at the bigger picture. Often we were just looking at symptoms not really understanding the problems and never really convinced we were delivering a complete solution, just trying to get something out the door to try and keep momentum.
Adopting a Domain Driven Design Approach
We decided to take a more radical approach and agreed to revisit the problems of the past and attempt to start from step one, identifying the real problem behind the original solution and working with accurate core use cases.
We saw some benefits from adopting a Domain Driven Design approach, mostly based around the actual modeling and attempting to bring more context into the problems we were addressing.
We were enticed by the use of a ubiquitous language not only when communicating requirements but also in our code and throughout our solution.
The Product Owner was encouraged by the prospect of writing more user stories and making story review sessions more efficient and effective, resulting in better visibility and more accurate requirements.
A focus on understanding the domain would also give developers a way to improve the quality of feedback loops, encouraging a rich dialog with users, and allowing us to ask the right questions to unearth deeper problems and guide design decisions. We also hoped this would help avoid analysis paralysis and reduce the time from story to implementation.
Modelling with Domain Driven Design
We decided the modelling phase would bring the most value, even if we didn’t go down the Domain Driven Design route completely, and so went about modelling the problem and business domains.
We focused on a single core use case, with a simple problem: “We need to produce and ship a personalised card”.
We started by mapping the process of an order in and out of the fulfilment workflow. We followed an order through our factory, talking with users and managers and researching industry standards.
We were able to use event storming techniques to identify language, important events and actors so we could begin modeling the domain boundaries and identifying where work was being automated, performed through legacy tools or manually performed.
To model the problem domain we mapped out core domains, breaking them down to sub-domains and defining the way in which domains collaborate.
We were then able to map the problem domain against the existing business domain, identifying where contexts overlap and identifying the way collaboration occurs currently.
This helped us identify complexity and hypothesise on ways to simplify it.
We identified aggregates and their responsibilities and identified from the language, a rudimentary domain model for each of our sub domains.
To get a more holistic view of the problem we mapped out external domains that collaborated with fulfilment and discovered a particular aspect of the business model that looked unnecessarily complex. We were able to identify that a change in this complexity could simplify not only our model but also that of several other domains and improve the quality of the product, giving not only operational value but also value through customer satisfaction.
The mapped domains also help identify impact, so if we wanted to change one domain we could better see what would be impacted by it. We also identified where collaboration with the legacy data model was necessary, thus identifying the need for adaptors/anti-corruption layers.
We were keen to use context maps to identify our domains and collaboration, though these were to be kept very simple and not overloaded with information. This led us to using multiple context maps to describe how specific data flowed through the domains of our business.
We eventually reached a point where any further design offered little value and so stopped and discussed the best starting point.
We had a requirement that we had been working on which involved improving the efficiency of producing print files.
We decided this would be an ideal opportunity to look at the problem with a holistic approach and identify impact within the domain.
We identified a subset of sub domains, one of these would be the domain which acts as our entry point into the flow, two of which would be new domains specific to the work we were doing, another was a domain that consisted of some supporting services that we had already migrated successfully to the cloud and a 3rd party tool that was represented by its own domain.
We also identified the Sales domain as being the domain from which we receive orders, and a couple of Customer domains that we needed to collaborate with.
The bigger picture model still remains as a complete view of the bigger problem of fulfilling an order, however some new sub-domains that had been identified were left out, so as not to add unnecessary work.
This pretty much marked the end of our initial investigation and design phase.
At this point, with a keen understanding of what we were trying to achieve, we began implementing bounded contexts for the new sub-domains in the model.
This is where my story ends and the next story begins.