In I Shall Call It… SomethingManager, Jeff Atwood criticized names such as:
SessionManager
ConnectionManager
UrlManager
Manager tells us that a class does something with something.
Useful.
We mostly stopped calling everything Manager. We now call it:
UserService
PaymentHandler
OrderProcessor
AccountHelper
The suffix changed. The ambiguity survived.
Vague names permit vague code
What belongs in UserService?
register()
resetPassword()
mergeAccounts()
assignRole()
calculateDiscount()
All of these involve a user.
That is where their architectural similarity ends.
They have different rules, dependencies, side effects, security concerns, and reasons to change. But the name objects to none of them.
UserService is not a boundary. It is permission.
Now compare:
UserRegistrar
PasswordResetter
AccountMerger
RoleAssigner
DiscountCalculator
These are agentive names. They name the component responsible for a capability.
Their value is not grammatical elegance. Their value is resistance.
If PasswordResetter starts calculating discounts, the mistake is visible before opening the file.
Inside UserService, it looks perfectly employed.
Names shape dependencies
This dependency graph appears plausible:
UserService
├── EmailSender
├── PaymentGateway
├── PermissionRepository
├── AuditLogger
└── DiscountCalculator
Users interact with all of those things.
This one tells a more specific story:
PasswordResetter
├── UserFinder
├── ResetTokenIssuer
└── ResetEmailSender
If PasswordResetter suddenly needs InvoiceGenerator, someone has to explain why.
That friction is useful.
A precise name narrows the responsibilities and dependencies that look natural. It does not prevent bad design, but it removes its camouflage.
Naming exposes decomposition problems
Sometimes a component cannot be given a specific name without lying.
So we call it:
Manager
Service
Adapter
Handler
Processor
That is usually treated as a naming problem.
It may be a design problem.
If one class registers users, resets passwords, assigns roles, calculates discounts, and merges accounts, there may be no honest short name for it.
That is information.
The difficulty of naming the component is evidence that the component does not represent one coherent responsibility.
Split the responsibilities, and the names tend to appear:
UserRegistrar
PasswordResetter
RoleAssigner
DiscountCalculator
AccountMerger
The names did not create the design.
They made the missing design difficult to ignore.
Names make composition visible
Large capabilities are often built from smaller ones.
OrderPlacer
├── CartValidator
├── PriceCalculator
├── InventoryReserver
├── PaymentCollector
└── ConfirmationSender
The OrderPlacer owns the sequence. The collaborators own their rules.
Without names for those responsibilities, the same design often becomes a long method inside OrderService, separated by comments explaining the components that were never created.
Agentive naming gives responsibilities an address.
That makes them easier to test, replace, reuse, and compose.
It does not mean creating one class for every verb. That would merely replace noun-oriented bureaucracy with verb-oriented bureaucracy.
The rule is simpler:
Give a responsibility a name precise enough that unrelated behaviour looks dishonest.
This is not architecture
Agentive naming is not an architectural pattern.
It is just naming.
But names influence what responsibilities look natural. Responsibilities influence dependencies. Dependencies become architecture.
So “just naming” is doing rather more work than advertised.
Good names do not guarantee good software.
They make bad software harder to disguise.
This matters more with AI
AI coding agents infer structure from the code already present.
Give them:
UserService
PaymentManager
OrderProcessor
and they will confidently place the next responsibility into the nearest vague container.
At considerable speed.
Give them:
PasswordResetter
RefundIssuer
OrderCanceller
and the intended boundaries are easier to infer.
Your codebase is now also a prompt.
Vague names teach vague design. AI merely industrializes the lesson.
Naming is a weak type system for responsibility.
UserService is any.
Top comments (0)