skip to content

When designing a Domain Service, how should the ubiquitous language guide its name and method signatures, and what's the tell-tale sign that you've actually built a technical helper class wearing a domain costume?

level: middleimportance: must knowfreq 65%

answer

  1. name = verb/process from business talk
  2. domain types not primitives in signature
  3. Manager/Helper/Util = red flag
  4. one-sentence responsibility test
  5. unnamed drift -> junk drawer

basics

~20 s

Name the service after the business action it performs, using words business people use - not generic tech words like Manager or Helper. If you can't explain the name in one sentence, it's not a real domain concept.

solid answer

~40 s

A Domain Service should be named after a verb or process from the ubiquitous language - the shared vocabulary developers and domain experts use - so a domain expert reading the class name recognizes the concept: PricingService, FundsTransferService, UniqueEmailChecker, not a generic 'validate' method in a utility class. Method signatures should take and return domain types (Money, Email, Account) rather than primitives, since primitive-obsessed signatures signal drift into procedural territory. The tell-tale sign of a technical helper masquerading as a domain service is a class named XxxManager, XxxHelper, or XxxUtils, or one whose responsibilities keep growing because 'it's just a place to put logic about X' rather than representing one specific business process - that drift is how a domain service becomes a dumping ground while the entities around it go anemic.

go deeper

for a junior

Should recognize Manager/Helper/Util suffixes as a smell once pointed out, and prefer domain-object parameters when writing new code.

for a middle

Should proactively name new services from the ubiquitous language and push back in review when a class's responsibility can't be stated in one sentence.

for a senior

Should recognize early drift toward a junk-drawer service and know how to split it back into cohesive, well-named pieces without a big-bang rewrite.

for a principal

Should set team-wide naming conventions and review habits (e.g. banning generic suffixes) that prevent the anemic-model drift at the architecture level.

## What the ubiquitous language is The ubiquitous language is the vocabulary that developers and domain experts agree to use consistently, in conversation and in code, so that a class, method, or variable name means the same thing to both groups. For a Domain Service this discipline is **not cosmetic** - naming is the primary signal of whether the service actually represents a coherent domain concept or is just a bucket for code that didn't fit anywhere else. A well-named domain service reads like a sentence from a requirements conversation: - 'transfer funds between accounts' becomes `FundsTransferService.transfer(from, to, amount)` - 'check that this email isn't already registered' becomes an `EmailUniquenessChecker` or similar If a domain expert would frown at the class name or ask 'what does that mean?', that's a signal the abstraction was invented by the code, not discovered in the domain. ## The method signatures carry it too This extends past the class name into the method signatures. A domain service that takes `String email` and `long accountId` as parameters, rather than an `Email` value object and an `AccountId` or `Account`, has usually lost its connection to the model - it's operating on primitives the way a database access layer would, not on the rich types the ubiquitous language defines. Keeping domain types in the signature is what: - lets the service compose naturally with the rest of the model (an `Email` value object can enforce its own format invariant, so the service doesn't have to re-validate a raw string) - keeps the service's purpose legible from its type signature alone ## Why the name carries so much weight The reason this matters so much is that a Domain Service, unlike an entity, has **no natural anchor** - it doesn't own persistent state or an identity that forces a coherent boundary around it. An entity's responsibilities are bounded by what data it holds; a domain service's responsibilities are bounded only by what its author decides to put in it, which makes discipline in naming and scope the only thing standing between 'a clean stateless domain operation' and 'a junk drawer.' Naming from the ubiquitous language forces that discipline: | A name like | What it invites | |---|---| | `OrderProcessingService` | vague enough to justify adding almost anything | | `BackorderReplenishmentPolicy` | specific enough that an unrelated method addition would visibly not belong | ## The trade-off The trade-off is that finding the right name takes real conversation with domain experts and iteration - it is genuinely slower than reaching for a generic '...Service' or '...Manager' suffix, and teams under deadline pressure often skip it. The cost of skipping it doesn't show up immediately; it shows up six months later when: - the `OrderManager` class has forty methods - ten different developers have each added 'just one more thing that's kind of related to orders,' - and nobody can describe what the class is responsible for in one sentence At that point the service has become what Martin Fowler and others call a **'God class'** or, in DDD terms, evidence that the domain model has become anemic - because if `OrderManager` does everything an `Order` could ever need done to it, the `Order` entity itself has been reduced to a data holder. ## The concrete tell-tale signs The concrete tell-tale signs to watch for in review are: 1. suffixes like `Manager`, `Helper`, `Util`, or `Processor` that describe a technical role rather than a business process 2. methods on the same class that have nothing to do with each other conceptually (e.g., `calculateDiscount` and `sendConfirmationEmail` on the same `OrderService`) 3. parameters that are primitives or DTOs instead of domain objects 4. and an inability, when asked, to state the service's single responsibility as one sentence using words a business stakeholder would use A useful concrete example of doing it right: in a shipping domain, instead of a `ShippingManager` with a `computeCost` method buried among a dozen others, a `ShippingCostCalculator` (or, if the rule is really a pure function of a `Package` and a `Destination`, arguably a method on a `ShippingQuote` value object) keeps the name, the scope, and the vocabulary aligned with what the business actually calls the concept - which is the entire point of grounding the design in the ubiquitous language rather than in implementation convenience. ## A name is a hypothesis One more practical wrinkle worth naming: the ubiquitous language is not fixed once and for all - it evolves as the team's understanding of the domain deepens, and a domain service's name should evolve with it. If, during a modeling session, the team realizes that what they've been calling `PricingService` is really two distinct concepts - a `DiscountPolicy` and a `TaxCalculator` - the correct response is to rename and split, even though that touches every caller. Treating a domain service's name as permanent, rather than as a hypothesis to be refined, is itself a way naming discipline erodes over time; the healthiest teams revisit service names during retrospectives on the model, not just during initial design.

  • How would you catch a domain service that's drifting into a junk-drawer class during code review?
    Read the class's method list out loud and ask if they all serve one coherent business process; if two methods need 'and' to connect them in a sentence describing the class's job, that's a split candidate. Also check whether new methods keep getting added under a vague justification like 'it's about orders' rather than a specific rule.
  • Is it ever acceptable to name a domain service after a design pattern rather than a business term, like PricingStrategy?
    Yes, when the pattern name itself is understood and accepted by the team as part of how they talk about the concept - the key requirement is that the name still points at one specific, recognizable piece of domain logic, not that it avoid all technical vocabulary entirely.
  • What's the risk of naming a domain service too narrowly, e.g. one method per tiny class?
    Excessive fragmentation can obscure a broader domain concept that ties several small operations together, and forces callers to wire up many collaborators for what is really one cohesive process; the fix is usually to find the encompassing concept in the ubiquitous language rather than to keep splitting.

Naming a domain service from the ubiquitous language is like labeling a shipping box with exactly what's inside ('Winter Coats, Size M') instead of 'Misc' - the specific label is what stops someone from later stuffing unrelated things into the same box.

saying these in an interview costs you the question

  • Names services XxxManager/XxxHelper/XxxUtils as a matter of habit
  • Can't state the service's responsibility in one sentence using business vocabulary
  • Method signatures take primitive strings/IDs instead of domain types
  • Treats 'it's about orders somehow' as sufficient justification to add a method
  • Never checks a proposed service name with anyone who knows the business domain

context