Ubiquitous Language & the joy of naming

Posted on by in Development

I want to discuss a topic near to my heart, a topic I believe to be the crux of effective software design. No, it’s not a new functional language, it’s not a fancy new framework, it’s not a how-to guide to do micro-services, nor a quantum leap in the field of machine learning.

It’s much simpler. It’s about names.

I Declare Thee the RideCommerce Service...

Names define us. They give life to abstract ideas and concepts and yet also stand in for real, physical objects. They’re language concepts, but more than that, they’re units of meaning. When used precisely, names enable shared understanding and smooth teamwork among people.

Software development is fundamentally a human endeavor. No amount of technical computing breakthroughs will change the fact that software development is still the arduous task of assembling people from a kaleidoscope of different cultural & linguistic backgrounds, then throwing them together to build an arbitrarily complex product in a rapidly shifting competitive landscape.

The landscape is littered with software projects that began ambitiously, but got lost in a towering mess of fragile code. Many teams have found themselves consistently foiled by bugs and system design inconsistencies that originate from a failure to communicate meanings, concepts and ideas well. It’s no wonder that developing reliable, successful software is more art than science.

Crossing our linguistic wires

Let’s imagine an imaginary scene from your company, Delorean (the Uber for time travel). You are a software engineer on the team responsible for writing software systems that handle e-commerce payment processing for your users, who pay for their rides from your company’s time-travel ride sharing service. You are discussing the implementation of a new set of features with your product owner (PO), and it unfolds like this:

PO: Our next big project is to update our driver app to show rider locations on the timeline map.

You: And when do these riders show up on the timeline screen?

PO: When the driver turns on the app and signals that she’s driving.

You: OK, so that means when the app boots up and the DriverStatus service receives a POST we’ll need to simultaneously fetch references from the HailingUser service based on time locality.

PO: Um…

Your poor product owner, removed from the direct details of implementation in your code, gets a hazy explanation of what’s actually going on. He vaguely remembers that the DriverStatus subsystem vaguely corresponds to drivers who use the mobile app and the HailingUser subsystem deals with riders who want rides, but he always gets them mixed up.

Your system’s naming conventions are getting in the way, and they don’t correspond to any real-world concepts that he’s familiar with.

Come to think about it, this same confusion played out among the team in the last iteration planning meeting, where you discussed the intricacies of a specific story:

PO: In this story, we’re going to add a coupon box to the checkout flow.

You: [Thinking out loud] Hm… would that mean we add a /coupon route to the checkout API? We could POST to it and then it will create Coupons in the backend.

Teammate: Wait – I think we call them Discounts in the backend. And the checkout API is technically implemented by the RideCommerce service.

You: Oh right, I forgot. Let’s make the route /coupon and it’ll create a Discount object. And in this story, let’s just remember that the Checkout API really refers to the RideCommerce service.

A completely different implementing engineer, of course, doesn’t read the note in the project backlog story (who has time to, anyways?). In the course of implementation, he gets tripped up in semantics and spends the better part of a half day re-implementing the Checkout flow as an entirely new service, before realizing his mistake in code review and backing out his changes.

Months later, a new colleague is tasked to fix the link in the checkout flow, but files an incomplete fix because she was not aware of the fact that Coupons actually meant Discounts. The bug makes its way to production, where the code begins causing havoc in your critical checkout systems.

What went wrong here?

  • There was a different software system (RideCommerce) with a name that did not map cleanly back to the customer process (“checkout” flow).
  • The system had two conflicting names for the same concept: Discount and Coupon.
  • Extra documentation was created to note the discrepancies between concepts and names.
  • This extra documentation and system knowledge did not propagate to all members of the team.

A better, Domain-Driven way

Domain-Driven Design Book

Eric Evans’ book Domain-Driven Design introduces the concept of a Ubiquitous Language – a shared, common vocabulary that the entire team shares when discussing software.

This “entire team” is made up of designers, developers, the product owner and any other domain experts that exist at the organization. Take note that it is important that your team have a domain expert. Your product owner may be your domain expert (and typically is). However, you may have other domain experts such as:

  • Any team that builds reporting or analytics off of your software.
  • Upstream data providers.
  • Anybody further up the reporting chain whose purview includes the software you’re building, or its effects. Think: the Director of Finance, the COO, the head of Customer Support.
  • The users of your software.

Developing a Ubiquitous Language with a Glossary

Get your team together – the domain experts and the technical experts – and set them about creating a document that tracks your team’s language. This is the living document of all the terminology your team uses – along with all its definitions. This is known as the Glossary:

From now on, use only the term definitions listed here in your stories both in person AND in your source code. Be explicit about how you use your language!

I’ve been on many projects where the sloppy usage of a term from project inception led to the usage of that term in the code – codifying that messy, slippery term throughout the life of the project.

The purpose of the Ubiquitous Language is to get the whole team on the same page – what each thing means, and bridge the gap between the jargon used on the development team and the customers.

UbiquitousLanguage - Domain + Technical

Your Glossary is a living document. It is meant to be living – either on a continually updated Google Doc or a wiki page. It should be visible for all to see – you should print it out and post it on the walls!

Refactoring your team to use the right terms

A great time and place to start using this new Ubiquitious Language is in your everyday conversations with your domain experts, or with the technical team.

Let’s listen in on a planning meeting with the product owner:

You: So when a User logs into the app and broadcasts that they’re ready to drive…

PO: You mean Driver. When a Driver logs in.

You: Right. Good catch.

The little correction seems a little silly (after all, you both know only Drivers use the broadcast feature of the app), but the laser focus on using the right words means that your team is always on the same page when talking about things. As your team starts using the defined terms in the Glossary, the same words start to slip off your tongues, making working together easier than ever.

Later that afternoon, your teammate taps you on the shoulder:

Teammate: I’m about to start working on the checkout flow. I suggest we rename the Discount class to Coupon.

You: Great idea. That way, we aren’t tripped up by the naming mismatches in the future.

Congratulations! Your team is making its first steps to Ubiquitous Language nirvana: your code needs to reflect your domain language.

Teammate: I do have a question about the coupon, though. Do you think it’s applied to the BookingAmount, or is it added?

PO: [Overhearing conversation] You had it right. It’s applied.

You and your teammate then go and update the glossary, scribbling an addendum on the wall (or updating your wiki):

Future teammates will thank you for your precision with your terms.

Refactoring your code to use the right terms

Your teammate and you then walk over to her desk; as a pair you proceed to refactor the existing account code. We’ll use Ruby for the sake of this example.

In the beginning, the Checkout code looks like this. A pretty straightforward implementation of the parts of the checkout flow that apply a coupon.

You take a first pass and rename the Discount class to Coupon.

Here’s the current concept of how the Checkout works:

Now there’s something funny here – your domain language suggests that a Coupon is applied to a BookingAmount. You pause, because the code reads the opposite – “A Coupon calculates its amount for a BookingAmount”.

You: How about we also refactor the calculate_amount_for method to reflect the language a little better?

Teammate: Yeah. It sounds like the action occurs the other way – the BookingAmount is responsible for applying a Coupon to itself.

In your next refactoring pass, you move the calculate_amount_for method into the BookingAmount, renaming it applied_coupon_amount:

Finally, you change your Checkout implementation to match:

Here’s the new diagram:

UbiquitousLanguage Diagram Pass3

Remember: we wanted our code to match the domain language: “A Coupon is applied to a BookingAmount“.

When you read the implementation in plain English, it reads:

The Checkout‘s total amount is its BookingAmount minus its applied Coupon amount.

Phew! Designing a strong Ubiquitous Language was hard work! In fact, you had spent a serious amount of time debating and clarifying with your domain experts:

  • Is a Coupon applied to a BookingAmount, or is it added to one?
  • Should we call the monetary value of a Coupon its amount, or cost?
  • Is the pre-tax, pre-discount amount in the BookingAmount called a price, or a cost?

Whatever you agreed on, that’s what you changed your code to reflect.

In closing…

In this brief time we had together,

  • We discussed why names are important – especially in a complex endeavour like software development.
  • We covered why it’s important to arrive at a shared understanding, together as a team, using the same words and vocabulary.
  • We discovered how to build and integrate a Glossary into the daily rhythm of our team.
  • We refactored the code twice – illustrating how to get code in line with the domain language.

And there is much more!

Domain-Driven Design is a collection of practices that illustrate how design and architecture flow from language. A strong Ubiquitous Language at the core of the project provides a stable foundation for all concepts and systems that are built upon it. Teams find themselves accomplishing their work with enhanced precision and clarity. This is just the tip of the iceberg – future posts will explore DDD architectural patterns and tools that can help you better design your systems.

What experiences have you had working with a Ubiquitous Language? Share your experiences below!


  Comments: 4

  1. Thank you for creating and sharing this blog post.

    I do not think that semantic accuracy is universally adopted concept. I come from a family of lawyers and I believe this somewhat explains why I am familiar with the idea. At the moment I cannot think of one popular icon that is known for their emphasis on semantic accuracy. It is easier for me to think of pop icons known for strength, singing talent, or deductive logic. Given that not everyone knows about semantic accuracy, it is possible that one person could look at the same example you used in software engineering and attribute the code bugs and communication troubles to another cause. I agree with your conclusion, the issues are caused by language ambiguity and incompatible semantic schemes. Creating the paradigm of Ubiquitous Language and formalizing the idea of semantic accuracy is a good call in my opinion. It will facilitate the sort of meta conversations that likely need to take place in order to encourage more people to adopt the practices that Ubiquitous Language embodies.

    When I went to work for my first large SaaS firm, there was no Glossary and things were named without respect to function. Ubiquitous Language likely could have sped up communication, decreased bugs, and resulted in more quality features in production at a faster pace.

    I am curious to know if there is any trouble or if the author of the book has any experience in applying this concept in SaaS international business. For example, differences in what concepts are deemed equivalent, a word not existing in a different country, different tax systems, and different compliance or regulatory systems.

    • In my experience, both as a developer and as a writer for developers, working in multinational/multi-cultural teams for the last 20+ years, accurate semantics are a necessary but not sufficient factor in project success.

      Every successful project that I have ever participated in or observed had one and only one (human) language used for team communications. In every instance where “the whole team” used one language, but sub-groups often switched to another language that was not shared to the same degree of fluency and literacy by all, the project failed; typically in spectacular fashion.

      Even within a single language, a lack of precision more often than not will induce miscommunication and differing expectations. “Do what I mean” is a useless instruction to any individual other than the speaker, at a time other than when the phrase was uttered. The teams I’ve succeeded with have universally regarded imprecise or inconsistent language as a declaration that the speaker is unclear about the concept being expressed, and requires respectful, patient assistance in clarification. Having the formalism of an explicit Ubiquitous Language for a specific project has been far more of a help than a hindrance. I’d be very interested in understanding the circumstances of any project where that was not found to be the case.

  2. Hi Maureen, thanks for taking the time to reply.

    I completely agree with you – semantic accuracy is certainly not the only cause of miscommunication or failed software projects.

    You bring up an interesting point – about the company operating in different areas that have different concepts for the same name, or lacking formal concepts in different operating regions. I certainly suggest reading the Domain-Driven Design book, because that’s exactly what the Ubiquitous Language is meant to address.

    In fact, the Ubiquitous Language is a misnomer – it’s actually meant to be the language for the business unit (called a Domain, or Subdomain) but scoped _only_ to the context of that unit. Therefore, you could have separate business operational units with different codebases who have different Languages (and glossaries). In fact, DDD suggests that one term may mean something in one Subdomain, and another thing entirely in another Subdomain. It embraces the complexity of the real world. In that world, your Subdomain, or your business unit (and its software systems) will have their vocabularies defined one way, but another Subdomain may define that concept or term a different way – and that’s totally OK.

    I’ll follow up with a future blog post talking about domains and subdomains – feel free to reach out to me if you want to keep the conversation going. Thanks, Maureen!

  3. reminds me of when UML first became popular and everyone realized how superior Use Cases were over classic Requirements documents. I could easily see Ubiquitous language being developed during the Use Case development (hey, you already have customers and devs in the same room, so why not?) and by the time UCs are complete you’d have a comprehensive glossary. Make no mistake, Use Cases are still way more important for any Project, but ubiquitous language is a great supplement. And given that Agile requires constant interaction with POs it just makes logical sense to have a common jargon for discussing any app.

Your feedback