I've been using Elixir's Phoenix framework for a few years but most of my projects were on the older MVC style. Phoenix 1.3 introduced the concept of contexts (commonly known as bounded contexts). This changed the way you architect your applications.
I was really confused by this at first (naming is, after all, is one of the hardest things in programming). After a bunch of exploration, I've got a surefire way to improve how you name these things.
What are bounded contexts, exactly?
A bounded context is a conceptual grouping of a set of data models. The conceptual piece is key here because it means you decide on how you want to split up your models. This freedom is also a crutch because it also means there is no right or wrong way to create a context. For example, the name of these two contexts...
...is just as valid as these...
But hopefully, this will post will show you how to get closer to the first example and further from the second.
What is domain-driven design, and how does it relate to bounded contexts?
Now that we know what a bounded context is, it makes sense to define domain-driven design (DDD) as well. DDD is the practice of managing complexity of software applications by relating their underlying data models to domain logic. That's a mouthful; can we break it down further?
The domain is an ontology, meaning how things are grouped in the world. For example, the word anesthesia has a very specific connection to the domain of medicine. Another word, like Mike, can belong to multiple domains, such as the domain of Biblical names, or in the domain of politics as it relates to the NATO alphabet.
When the design is domain-driven, it means we place the model of our domain (e.g. a
PlayingCard in the domain of
Poker) in a context (e.g. the contextual grouping, such as a
Game) to help manage the complexity.
Can't I just have one context and call it a day?
Yes! In fact, that is preferred for very small applications. What do you name your one and only context for your small application? The application! If you're struggling with naming and you're just getting started with say, a script with one model, the context of your application can be named your application. So if we took the above example and gave it a real context and model, it could very well look like this:
So what happens when my app becomes huge?
This is where DDD is useful. Domain-driven design is specifically for handling the complexity of growing applications as they add more and more models. It doesn't really make sense for an app with one model. Once you get to about 4 models, that's a good time to start looking at binding your models to multiple contexts. This isn't a hard-and-fast rule, so don't feel like you have to break out into multiple contexts, but once you get above 4 models, those contextual groupings will begin to surface.
Naming contexts by example
I've always felt the best way to figure things out is to learn by example. I'm going to illustrate 3 extremely simplified versions of popular applications, and we'll reveal how we can organize the data models of these applications into contexts. The main thing to remember is that naming contexts boils down to how you would describe the set of models to a friend in one word.
Example 1: Quora
Quora is a forum where users of the site can have their questions answered by the community. Questions can be upvoted by the community that are deemed intelligent or thought-provoking, helping it gain a larger audience for people to participate. Similarly, popular answers can be upvoted to help bring the best answers to the top, logically grouping the best question with the answer.
Looking at this setup a natural hierarchy emerges. Is there a signal here that we can start creating separate contexts? The first thing I see is that
Answer operate on the same level - they have equal precedence in the total domain hierarchy of this application. Now taking my advice from above, I have to ask myself:
How would I describe
Answerto a friend in one word?
First of all, we can look at the description I gave in the beginning. In addition, we remember that contexts are nouns, so when I'm parsing those first descriptive sentences, I see words like forum and site.
Another technique is to bring these models into reality. Where do you see Q&A in the real world? At tech talks, for example, it's usually at the end of a presentation where the speaker has a discussion with an audience. Using the noun technique in the previous sentence, potential context ideas are presentation and discussion. Now we can apply the domain-driven part of our design to ask ourselves:
What domain does this belong to, and are there any conflicts or ambiguities we need to worry about?
For presentation, this belongs to the domain of things like public speaking and business. The problem is, presentations are also conflated with the MVP (Model-View-Presenter) pattern. It is also a specific format for PowerPoint. Given that this word has specific connotations with programming jargon, we can rule this one out. That leaves us with discussion and forum as our context for our Q&A models. Honestly, either will work here, but one hint is that forum relates more to this particular domain than discussion does, so I think we'll go with forum.
Now we can repeat the process for
Organization. Since these aren't on the same level, we could argue that they shouldn't be in the same context, but we have to give them a context because there really isn't a point in making a 1-to-1 mapping of models to contexts for an application this small. But we also see a natural mapping here: people belong to organizations all of the time, whether it's a company or a volunteering outfit.
How do we describe people in an organization? We say they're organized by some hierarchy and are usually grouped into teams or divisions. That gives me a few nouns: hierarchy, grouping, team, and division. I can already see that team and division are immediately out since that is an example of how organizations are split and don't fully encompass the user-organization relationship. Grouping is good, but the word group itself does creep a bit too close to computer terms such as
GROUP BY or the C#
grouping keyword. So I'll go with hierarchy.
Nice work! We have a clear designation between two contexts that make sense. One thing to point out is that contexts can be renamed or changed later. It's not important that we anticipate the use of these contexts as we add models. Sure,
Hierarchy might limit our flexibility, as it could be a stretch to add in helper models like
Address into this context, but you can worry about refactoring later.
Example 2: Twitter
Twitter is a microblogging service that allows people to express their thoughts in a very limited space. All messages (called "tweets") have a 280 character limit and are broadcast to followers. Followers can then interact with their connection's messages by liking or sharing (via "retweeting") content that they think is valuable to their own networks.
What did you come up with?
Let's again apply the same heuristics from above to decide what our contexts will be. The first thing that stands out to me is the intimate tie between
Tweet. It's the absolute core of this platform. Simplifying the noun technique, my first thought was that this is the microblog. However, given that Twitter has increased its word count from 140 to 280 characters, I feel like the micro portion of this is basically irrelevant, but the blog portion aptly contextualizes this relationship. Plus, it's a natural context for future potential models like
Next, there are the user-related interactions: following/followers is largely abstracted away since it's a
Share are new models, and do have similar mechanisms that feel like they could be grouped. What did I just call these things? Interaction, that's one (in fact, I also used it in the opening paragraph). I also used network which would describe the following/follower relationship, but again, networking is computer jargon and that could collide with a lot of other concepts we are working with. I think interaction is a good one:
This one was a bit easier given our previous look, but again, I really want to stress that there is no right answer. All we are attempting to do here is make it easy for you to figure out the naming, but at the end of the day, there's no actual penalty in naming or grouping these however you like. In Phoenix, there is certainly some cost with talking between contexts, but it's not an insurmountable issue.
Example 3: Google Drive
Google Drive is a cloud file storage provider. You can access files from anywhere in the world on any device, provided you have a Google account. In addition to reading files, you can collaboratively write to files with other users who have permission to read (and write) these files. Further, you can collaborate via tools like comments and sticky notes to provide feedback even if you cannot directly write to the file. Google Drive does not provide universal file capabilities and is mainly focused on reading/writing for documents, spreadsheets, and slideshow presentations.
This one is a bit more complex. We have quite a few more models here with a bit more ambiguity for how we can split things up. Let's start with the easiest one that all exist on the same level:
Presentation. How did I group those in the above description? I called them all files. Normally we'd red-flag this context because it's too computer-specific of a domain, but remember, this service is very computer focused by its very nature, so it's actually okay that we give this a context like this.
The next layer up we have our
IO which handles permissions for file read and write access controls and
Comment which is a special kind of write. Finally, we have the
User at the very top, which touches everything. Now your gut might tell you that reading, writing, and commenting are interactions just like in the Twitter example. But we can't do that for a few reasons:
- The methods for determining read and write access are encapsulated within
IO- they are permission grants to unlock certain functionality, but
IOin of itself is not an interaction
Userhas access to all of these models. Even though this UML diagram lays everything out in a hierarchy, it's not a simple three-tiered relationship, so in a way, we interact with our files as well by virtue of owning them.
Let's offer a different narrative. We mentioned earlier that we can collaborate with other users to perform actions. The noun here is collaboration. Additionally, those actions are governed by permissions. Which do we choose?
This is probably the toughest one of all. Collaboration implies an innate connection with others, even though you can manipulate a file without any other users. Whereas permission makes sense with both user interaction and
IO but seems to leave
Comment out in the cold. The key clue we have is that
Comment is a subclass of
IO, so we can lower the priority of making
Comment work for our context. In other words, since we know permission is a sensible context for both
IO, it stands to reason that permission will be a good context name because
Comment is a type of
IO in this domain.
This provides lots of ability to expand with both file types and ways of handling things centered around the
User, such as authorization and authentication. Both contexts also pretty cleanly separate the levels of hierarchy between data models.
Let's summarize our heuristic into three simple steps:
- Map the domain. We used UML diagrams to lay out the hierarchy of our models to provide visual clues for possible contexts.
- Horizontal or vertical alignment provides clues. If something falls along the same plane or area of your diagram, you can bet it's a context.
- Describe that alignment in one word, preferring the noun with the more specific domain. This is the hardest part, but the idea here is to take the description of our application and pick out the nouns (and sometimes verbs) that associate our related models. From there, we simply prune the word that has the clearest message with the least ambiguity.
Naming contexts is hard. It can be made easier if you follow these guidelines the next time you write an application using domain-driven design.
Make sure you don't stop with just your first iteration. Growing applications require consistent refinement. Sometimes you'll need to split off a context into multiple contexts, while other times you'll need to consolidate contexts. Don't be afraid to go in either direction. Finally, don't be afraid to be wrong, because there is no definitive right answer either. Good luck and happy naming!
Get the FREE UI crash course
Sign up for our newsletter and receive a free UI crash course to help you build beautiful applications without needing a design background. Just enter your email below and you'll get a download link instantly.