Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix formatting #9550

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ index:
- encapsulate-domain-models
- use-specification-pattern
- anemic-vs-rich-domain-models
- ubiquitous-language
---

Domain-Driven Design (DDD) is a software development approach that focuses on the domain of the problem, rather than the technology. It is a way of thinking and a set of priorities, aimed at accelerating software projects that have to deal with complex domains.
20 changes: 16 additions & 4 deletions rules/avoid-generic-names/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,30 @@ Generic names like “manager”, "helper", “processor”, “data”, and “
## Why generic names are problematic
Words like "manager" and "processor" imply something that handles various tasks, which can make it tempting to pile unrelated responsibilities into one class. "Helper" makes this worse as it becomes a catch-all for a collection of disorganized functionality.Names like "data" or "info" are similarly ambiguous, as they could apply to nearly anything, from a database connection to a simple string. Specific names are always preferable, as they make the code easier to understand and prevent code bloat from accumulating unrelated functionality.

:::bad
:::greybox
Imagine you’re writing a class to handle orders in an e-commerce system. You name it `OrderManager`. While this name suggests that it might have something to do with orders, it doesn’t clarify how it interacts with them. Is it creating orders, updating them, processing payments, or all of the above? The generic term “manager” gives us no clear indication.
:::
:::bad
Generic names only tell you what part of the domain or code base a class or method works with, not what it does
:::

:::good
:::greybox
A better name could be `OrderProcessor`, but if the class specifically handles only one aspect — say, sending orders for shipment — a more precise name would be `ShippingOrderHandler` or `OrderShipmentService`. This name directly reflects its purpose, making it immediately clear what the class is responsible for.
:::
:::good
Specific names are better than generic names
:::

:::bad
:::greybox
Let’s say you’re building a system to track medical records, and you create a class called `PatientData`. The name could apply to anything — health information, appointment history, test results. There’s no way to tell what role this class actually plays.
:::
:::bad
The name 'data' could literally mean just about anything
:::

:::good
:::greybox
If the class is responsible for managing a patient’s appointment history, a more accurate name could be `PatientAppointmentHistory`. This name immediately tells us the scope and purpose of the class without relying on catch-all terms.
:::
:::good
A class name for the specific data that it represents is much easier to understand
:::
2 changes: 1 addition & 1 deletion rules/avoid-micro-jargon/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Code that relies on nicknames, abbreviations, or internal jokes can create unnec

:::greybox
**How this differs from ubiquitous language**
Using ubiquitous language is about naming concepts in ways that align with terms used by domain experts and stakeholders. While this might seem like micro-culture jargon at first glance, it’s different for an important reason. Unlike insider terms, ubiquitous language refers to widely recognized ideas within the domain, making code clearer for anyone familiar with the field. Avoid in-grouped terms that don’t convey meaning to people outside the team, even if they seem descriptive to those who are “in the know.”
Using ubiquitous language (see our rule [Do you use ubiquitous language?](/ubiquitous-language)) is about naming concepts in ways that align with terms used by domain experts and stakeholders. While this might seem like micro-culture jargon at first glance, it’s different for an important reason. Unlike insider terms, ubiquitous language refers to widely recognized ideas within the domain, making code clearer for anyone familiar with the field. Avoid in-grouped terms that don’t convey meaning to people outside the team, even if they seem descriptive to those who are “in the know.”
:::

:::bad
Expand Down
12 changes: 9 additions & 3 deletions rules/avoid-using-your-name-in-client-code/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,18 @@ When building solutions for clients, it’s tempting to include personal or comp
## Why It Matters
Names that reflect the client’s brand or domain are clearer and more meaningful for the client’s internal teams and stakeholders. They also reduce the risk of naming conflicts and make it easier for future developers to understand the purpose of a component in context.

:::bad
:::greybox
Naming a custom entry field `GoldieEntry` or `SSWEntry` might make sense in a personal or shared library but is out of place in a client project.
:::
:::bad
Naming client IP after yourself or your company is not cool
:::

:::good
:::greybox
Instead, using something like `NorthwindStepper` is more client-aligned and indicates that this is a customized variation of a standard control.
:::
:::good
Naming client IP with the client's branding is better
:::

**Note:** This approach is ok to denote a branded version of something, but often it's better to indicate the customization itself in the name. See our rule [Do you use meaningful modifiers for custom implementations?](/use-meaningful-modifiers).
:::
8 changes: 5 additions & 3 deletions rules/consistent-words-for-concepts/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ Imagine you’re working on an e-commerce app, and you’ve been tasked with add

Later, you open a pull request, and a colleague calls, confused, asking why you’ve re-implemented an entire feature. After some back and forth, they show you the existing `SendOrder` method, which already handles notifications.

:::bad
```csharp
public void SendOrder(NotificationType type)
{
// existing implementation
}
```
:::bad
The name used for this method is not consistent with the name used for the same concept everywhere else in the code base
:::

## Outcome
Expand All @@ -53,17 +54,18 @@ In this case, the terms “order” and “consignment” may seem related, but

In this scenario, the `SendOrder` method should have been called `SendConsignment`, assuming “consignment” was already used in the codebase.

:::good
```csharp
public void SendConsignment(NotificationType type)
{
// new implementation
}
```
:::good
The name used for this method is the same name used for this concept throughout the code base
:::


To clarify, it's not necessarily wrong to have a `SendOrder` method, if the term order is ubiquitous. It might represent a pipeline for example, tracking a workflow from submission by the customer to receipt by the customer, and everything in between. But if “order” was the chosen term, the team should have used it consistently across the code. Any introduction of new terminology, such as “consignment,” should be a proactive, team-wide decision that includes any necessary refactoring.
To clarify, it's not necessarily wrong to have a `SendOrder` method, if the term order is ubiquitous (see our rule [Do you use ubiquitous language?](/ubiquitous-language)). It might represent a pipeline for example, tracking a workflow from submission by the customer to receipt by the customer, and everything in between. But if “order” was the chosen term, the team should have used it consistently across the code. Any introduction of new terminology, such as “consignment,” should be a proactive, team-wide decision that includes any necessary refactoring.

## DRY Principle Implications
In a worst-case scenario, someone unfamiliar with the `SendOrder` method might merge the `SendConsignment` code without realizing it’s redundant. Now, two methods exist for the same function — each handling notifications differently. This violates the DRY principle, as you now have two distinct pieces of knowledge on handling order shipments, potentially leading to divergent behavior and increased maintenance overhead.
49 changes: 49 additions & 0 deletions rules/ubiquitous-language/rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
seoDescription: We often use ours or our company name to denote a custom version of something. Unless you're publishing a library, this is never a good idea.
type: rule
archivedreason:
title: Do you use ubiquitous language?
uri: ubiquitous-language
created: 2024-11-05T00:00:00.0000000Z
authors:
- title: Matt Goldman
url: https://ssw.com.au/people/matt-goldman
related:
- encapsulate-domain-models
- use-specification-pattern
- anemic-vs-rich-domain-models
- consistent-words-for-concepts
- avoid-micro-jargon
- when-to-use-technical-names
guid: f8555180-50c2-423e-84e2-d73a9018222f
---

Ubiquitous language is a core principle in domain-driven design (DDD) that encourages developers and stakeholders to use the same vocabulary when discussing business logic and domain concepts. By using a shared, domain-specific language across code, documentation, and conversations, you ensure that everyone has a common understanding of core concepts. This approach reduces misunderstandings and makes the codebase more accessible to those familiar with the business domain.

<!--endintro-->

## Why Ubiquitous Language Matters
Ubiquitous language helps bridge the gap between technical and non-technical stakeholders, creating a consistent and clear understanding of the domain. When everyone uses the same terms — whether in code, documentation, or discussions — it’s easier to align on requirements, troubleshoot issues, and onboard new team members. Without it, terms can become muddled, causing confusion and misinterpretation.

:::greybox
Let’s say you’re working on an insurance system, and the domain term “policyholder” is used consistently among stakeholders. However, in the codebase, you see different terms used interchangeably: `AccountOwner`, `Customer`, and `InsuredParty`. Each of these terms could technically represent the policyholder, but the inconsistency can lead to confusion and misunderstandings about the exact role of each entity.
:::
:::bad
Terms in the code do not reflect domain language used by stakeholders
:::

:::greybox
To follow ubiquitous language, you would use `PolicyHolder` consistently across the codebase, aligning the code’s vocabulary with the language used by domain experts. This approach eliminates ambiguity, making it clear that `PolicyHolder` refers to the specific entity recognized by all stakeholders.
:::
:::good
Ubiquitous language is used, and developers and stakeholders are on the same page
:::

### Benefits
* **Improved Communication:** By using the same terms as domain experts, developers and stakeholders communicate more effectively, reducing the risk of misinterpretation.
* **Increased Readability:** Consistent terminology makes it easier for anyone familiar with the domain to understand the codebase.
* **Enhanced Maintenance:** When domain terms are used uniformly, developers spend less time deciphering concepts and more time building functionality.

:::greybox
💡 **Tip:** You can use the [Contextive](https://github.com/dev-cycles/contextive) extension for IntelliJ and VS Code (other IDEs coming soon) to assist with this. The linked repo also has a discussion between Chris Simon (the author) and [SSW's Gert Marx](https://www.ssw.com.au/people/gert-marx/) about both the extension and ubiquitous language in general
:::
30 changes: 24 additions & 6 deletions rules/use-clear-meaningful-names/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,50 @@ It’s easy to invent clever codes to keep names short, like `cstmrMgr` to repre
## Be verbose
Today, there’s no reason to squeeze names into character limits or cryptic codes. While you shouldn’t use full sentences for a class or method name (test cases might be an exception, see our rule [Do you follow naming conventions for tests and test projects?](/follow-naming-conventions-for-tests-and-test-projects)), full, meaningful words make your code far more readable and maintainable.

:::bad
:::greybox
Imagine you’re creating a game and need a variable to store the player’s health. You might decide to use an integer called `NRG`. It’s short for "energy," which might seem clever — it’s easy to write, and you know what it means. But this has some problems:
* Other developers might misinterpret "energy" as something else, like power or ammo. Wouldn't "health" better represent the intended meaning here?
* If you add enemies with their own energy, what will you name their variable? (Spoiler: `nmeNrg`.)
:::
:::bad
Using clever abbreviations is unnecessary, and can easily cause confusion
:::

:::good
:::greybox
A better name for this variable is `PlayerHealth`. It clearly describes the specific kind of "energy" (health) and who it belongs to (the player), making it instantly understandable to anyone reading the code.
:::
:::good
A clear and precise name avoids confusion and conveys its meaning clearly
:::

:::bad
:::greybox
Now let’s say you’re working on an invitation and activation feature. You need a variable to store the validity period for an invitation, so you create one called: `ttlDays`.
While `ttlDays` might seem logical as shorthand for "time-to-live in days," other developers might interpret it as "total days," or spend extra time deciphering its intended use.
:::
:::bad
Unnecessary abbreviations can often be ambiguous
:::

:::good
:::greybox
Just call it `TimeToLiveInDays`. It leaves no room for misinterpretation and makes the purpose of the variable obvious on sight.
:::
:::good
Use a clear, unambiguous name
:::

:::bad
:::greybox
Consider a class named `UserValidator`. At first glance, it seems sensible — it’s presumably responsible for validating a user. But when you think about it, "UserValidator" doesn’t really tell us much. What exactly is it validating? Is it responsible for validating login credentials, profile information, or something else entirely?
:::
:::bad
Vague or generic names that lack specificity can easily lead to confusion
:::

:::good
:::greybox
A clearer approach is to ensure each class has a specific responsibility. If it’s meant to handle all user-related validation rules, something like `ValidationHandler` indicates it’s an engine responsible for executing multiple rules and returning a result. But if the class is responsible for validating only a specific aspect of a user, a name like `UserNameLengthValidator` makes its role unmistakable; it tells us this class should validate only the length of a username.
:::
:::good
More specific names convey clearer meaning with greater precision
:::

:::info
**Remember:** Names should describe what something represents without mental gymnastics to decode it. A clear, meaningful name is one of the simplest ways to make your code more readable, maintainable, and welcoming for future collaborators (and for yourself).
Expand Down
12 changes: 9 additions & 3 deletions rules/use-meaningful-modifiers/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,18 @@ When creating custom controls, avoid vague or generic names like CustomStepper o
<!--endintro-->

## Why It Matters
Meaningful modifiers make it clear what a class, module, or compoent does or how it differs from a standard version. This helps developers understand its role without digging through code and reduces the chance of naming conflicts with other libraries.
Meaningful modifiers make it clear what a class, module, or component does or how it differs from a standard version. This helps developers understand its role without digging through code and reduces the chance of naming conflicts with other libraries.

:::bad
:::greybox
Naming a custom `DbContext` implementation `CustomDbContext` or a specialized input control `CustomInput` doesn’t provide any real information. It’s unclear what is customized, making it harder to understand and maintain.
:::
:::bad
A modifier that doesn't tell you what has been modified is of no value
:::

:::good
:::greybox
A more descriptive name, like `WriteOnlyDbContext` or `BorderlessTextInput`, indicates exactly what’s different about the component, making it easier to understand its function at a glance.
:::
:::good
A modifier that clearly conveys what is different from the original can save developers time reading through the code
:::
11 changes: 9 additions & 2 deletions rules/use-nouns-for-class-names/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,20 @@ A fundamental principle of object-oriented programming is that a class represent
## What is a noun?
A noun is a word that names a thing. Common examples include tangible items like Table, Cup, or Computer and abstract entities like Record, Database, or Cloud. In your code, class names should clearly reflect what they represent, giving developers an immediate understanding of the class’s role.

:::bad
:::greybox
Imagine you’re building an e-commerce application, and you create a class called `ProcessOrder`. While it might seem reasonable, this name is misleading — it suggests an action, not a thing. The class’s responsibility is not the act of processing but the concept of an Order itself.
:::
:::bad
A class that appears from its name to be an action is confusing
:::

:::good
:::greybox
Naming the class `Order` better represents its role as an entity that holds order-related data and behavior. Later, if you need to perform an action on the order, you might create a `ProcessOrder` method within the`OrderService` or `OrderProcessor` class (see our rule [Do you use verbs for method names?](/verbs-for-method-names)). This keeps the naming consistent with object-oriented principles.
:::
:::good
A class name that clearly represents a thing is much easier to understand
:::


## Events: The exception that proves the rule
In domain-driven design (DDD) and event-driven architectures (EDA), you’ll often see exceptions to this rule. Events like `OrderPlaced` or `UserRegistered` are commonly named with verb phrases to represent specific actions or occurrences within the system, rather than entities with persistent state. This naming convention is acceptable, as it indicates a change or trigger rather than a static object. For other class types, however, sticking to nouns keeps the codebase clear and consistent.
20 changes: 16 additions & 4 deletions rules/verbs-for-method-names/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,30 @@ Code becomes easier to understand when names align closely with their meaning. S
## What is a verb?
A verb is a word that describes an action or process—something that’s done. Examples include walk, run, think, listen, and breathe, as well as process, calculate, send, and save. While your method names shouldn’t all be single verbs (since that’s often too vague), they should be verb-based, using a verb as the foundation of their meaning.

:::bad
:::greybox
Imagine you’re working on an e-commerce app and need to write code to handle shipping products to customers who have completed an order. You create a method called `Ship`. While Ship is a verb, it’s also a noun, making it ambiguous. Additionally, it’s not descriptive enough to convey the method’s purpose clearly.
:::
:::bad
A method represents an action, so naming it like a thing will cause confusion
:::

:::good
:::greybox
A better name for this method is `SendCustomerOrder`. It’s specific, making it clear what the method does and within what context.
:::
:::good
A method that is named as a verb clearly tells you that it does something, and what that thing is
:::

:::bad
:::greybox
Suppose you’re working on an electronic medical record system, and you need to create a way for nurses to document medications that have been administered to patients. You name the method `Administration`. This is problematic for two reasons — it’s a noun, and it’s ambiguous. “Administration” has multiple meanings, and the method name doesn’t make it clear what this action involves.
:::
:::bad
A method that not only isn't a clear action, but uses a word that needs context (and none is provided) is guaranteed to cause confusion
:::

:::good
:::greybox
A more precise name for this method is `AdministerMedication`. It clearly describes the real-world action it models. Another option could be `RecordMedication`, but this is less effective. First, “record” can be either a noun or a verb, and second, it lacks context — it could imply logging delivery to a pharmacy or entering a new medication type into the system.
:::
:::good
Method names that describe the action and provide any needed context help avoid confusion
:::
Loading
Loading