Domain Driven Design with Web API revisited Part 4: the ubiquitous language and our refined problem domain
August 17, 2015 Leave a comment
Introduction
In the previous post we went through a couple of important terms in DDD and also started coding the foundations of the web suite demo app. In particular we discussed the meaning of bounded contexts and the shared kernel. Each domain object will be defined within a specific context, e.g. the load testing context and the web monitoring context as mentioned previously. There may be some sections where the contexts overlap. These sections are contained within the shared kernel that each bounded context can refer to. Finally we started building our code and introduced abstractions for the entities, value objects and aggregate roots.
In this post we’ll first introduce the concept of ubiquitous language and then sort out the key terms that describe our problem domain.
Ubiquitous language
The English word ‘ubiquitous’ is a difficult one for non-English speakers – and probably some native English speakers as well. How is it pronounced and what does it mean? The initial ‘u’ is pronounced like ‘u’ in ‘union’ or ‘united’. The second syllable, i.e. ‘bi’ – or ‘biq’ – is stressed, i.e. not the first as in the case of most English words. Both i’s are pronounced like in “think” and not like in “mine”. The word itself means “existing or being everywhere, especially at the same time; omnipresent” according to the this online resource.
So we’re talking about a language that’s found everywhere. Sort of like a common language where the terms used to describe the domain are common across the business the DDD-based software is designed upon. Let’s see what Eric Evans tells us about the ubiquitous language:
“To create a supple, knowledge-rich design calls for a versatile, shared team language, and a lively experimentation with language that seldom happens on software projects. The core of such a language comes from the domain model. The UBIQUITOUS LANGUAGE carries knowledge in a dynamic form.
…
It is a serious problem when the language used on a project is fractured. Domain experts use their jargon while technical team members have their own language tuned for discussing the domain in terms of design. Translation blunts communication and makes knowledge crunching anemic. Yet none of these dialects can be a common language because none serves all needs. The terminology of day-to-day discussions is disconnected from the terminology embedded in the code (ultimately the most important product of a software project). Even the same person uses different language in speech and in writing, and so the most incisive expressions of the domain often emerge in a transient form that is never captured in the code or even in writing.”
This means that when we describe the domain of the business all the stakeholders in the project must agree on and use the same terms to describe a certain domain object. It’s not OK to call a customer sometimes a “client”, sometimes a “shopper”, all project members must stick to “customer” any time they refer to a customer in any means of communication: in code, in a diagram, in an email etc. Every term which describes a domain must be well-defined and accepted across the project members within a given bounded context. It’s possible that certain domain objects will appear in different bounded contexts. We saw an example of that in the previous post:
“Similarly a load test will require a set of steps, typically URLs that make up a load test scenario and web site monitoring will also need one or more URLs to be monitored. However, the instructions for load tests may be entirely different from the instructions for a web site monitoring case.”
Every one of those terms will be valid within a bounded context and each bounded context will have its own well-defined ubiquitous language. We can also consider the ubiquitous language as a dictionary that contains the definition of each domain object.
Ubiquitous language in the demo app
Let’s apply the above on our demo app. We’ll keep it simple so that we don’t bloat the scope. Here’s the ubiquitous language for our load testing bounded context:
- Customer: the organisation or person that has ordered a load test
- Load test: the web site test that the customer wants to have carried out. A load test can be of different types, see below. A load test has a long list of parameters. I mentioned a couple of them in the previous post, we’ll take a handful of them in our implementation.
- Project: typically customers don’t just order one load test and wave good bye. They will want to view the load test results that will belong to a load test project. So each load test will belong to a single load test project.
- Scenario: the set of steps in the load test programme. This is the basis for the load test execution. In reality a load test scenario can be very complex but we’ll keep it simple in our implementation. This is a crucial dependency for a load test. If there’s no scenario, there’s nothing to be carried out during the load test. We assume that a scenario must contain at least one and at most three valid URLs
- Stress test: a type of load test. We’ll go with the definition of this page: “To determine or validate an application’s behavior when it is pushed beyond normal or peak load conditions.”
- Capacity test: another type of load test, also defined on the same MSDN page: “To determine how many users and/or transactions a given system will support and still meet performance goals.”
- Agent: a server that will generate the load. This is a crucial dependency for a load test. No load test can be executed without a load generator
- Engineer: a load test engineer that acts as the primary contact of the customer during a load test. A customer can choose whether or not an engineer should assist them during the load test. This is not a crucial dependency as the customer may be confident enough to execute the load test without any extra help.
- Timetable: this is an “umbrella” for all load tests. It serves as the overall container for all load tests in the data store. It coordinates the data store related actions for load tests: insertion, selection, deletion and update. If you recall our definition for an aggregate root then this sounds like a good candidate.
That should be enough to start with. We may discover other important terms during coding.
We also need to set up a couple of rules for load tests. In particular, load tests cannot be inserted into the time table, and hence the data store, without a series of checks. In reality a load test will need to go through a complex set of validation steps. Here we’ll start off easy and go with the following set of rules:
- A load test cannot start without a load test agent. Each agent can only perform 2 load tests at a time, i.e. two load tests can overlap, but not 3.
- If the customer requires an engineer then this engineer must be available for the duration of the load test
- A load test cannot start without a valid scenario which includes at least one and at most 3 URLs to be tested
This list only takes up the most important validation rules. I’ve ignored simpler cases like “test duration cannot be negative” or “project name mustn’t be an empty string or null”, we’ll add those as we build the domain objects in code.
We’ll start coding the domain objects in the next post.
View the list of posts on Architecture and Patterns here.