Naming in a Codebase: An Architectural Matter
Why naming is not merely a style choice, but a design decision in its own right — patterns I have observed over the years.
One of the most debated topics in code reviews is names. “Let’s find a better name for this variable”, “this method name sets the wrong expectation.” These conversations can feel like a stylistic preference — as if someone is just being a perfectionist. But I think the vast majority of these discussions are really about something else: design.
When a name is hard to come up with, the object or method’s purpose is usually unclear. A naming problem is, in fact, a design problem.
A bad name is the surface of bad design
Consider this method signature:
public function process(array $data): array
What does process do? What does $data contain? What does the return value look like? We have no idea. We have to open the code and read it.
Now think about what happens when you try to fix the name. “Process order data”? But there’s user validation inside it too. “Save form”? But it doesn’t write to the database — it only transforms. “Transform form data into an order model”? That’s better, but you end up with something like validateAndTransformOrderData — which means the name itself is already raising a warning: this method is doing too much.
If you can’t find a name, the object or method probably does not have a single responsibility.
How to tell a name is strong
A good name has a few key properties:
It communicates intent, not implementation. Not getUsersByActiveStatus, but findActiveUsers. Not calculateAndReturnTotal, but total(). Tell the caller what it does, not how it does it.
It creates no surprises. When you call save(), what do you expect? For data to be saved. If that method also sends an email or writes a log entry — the name didn’t prepare you. That’s a breach of trust; a small one, but they accumulate and erode confidence in the codebase.
It speaks the language of the domain. In a fintech application, amount and total can mean different things. In an e-commerce system, order and cart are not the same. When names come from the domain’s language, the code becomes easier to discuss with someone who understands that domain.
Problems I frequently see in class names
Manager, Handler, Helper, Util: These are red flags. These names say “I’m not entirely sure what this class does.” What does UserManager do? Everything. What does PaymentHelper do? Something. These classes bloat over time because anyone can throw anything into them.
// Vague
class PaymentHelper
{
public function process($data) {}
public function validate($data) {}
public function format($amount) {}
public function log($payment) {}
}
// Clearer — each class has one responsibility
class PaymentProcessor
{
public function charge(Money $amount, PaymentMethod $method): PaymentResult {}
}
class PaymentValidator
{
public function validate(PaymentRequest $request): ValidationResult {}
}
Verb-heavy class names: Class names like CreateOrder, ProcessPayment, or SendEmail are typically an action pattern or command pattern implementation. These are fine in their proper context; but if all your class names follow the verb+noun form, you may just be splitting a large procedural codebase into smaller pieces. Object-oriented design is not always that.
Consistency between a method’s name and signature
When a method’s name and its signature don’t align, that too is a design signal:
// The name says "find" but it throws an exception — this is "find or explode"
public function findUser(int $id): User
{
$user = $this->repository->find($id);
if (!$user) {
throw new UserNotFoundException($id);
}
return $user;
}
// More explicit names
public function findUser(int $id): ?User // can return null
public function getUser(int $id): User // throws if not found — getX semantics
This distinction seems minor, but it shapes the expectations of whoever consumes the API. A caller of findUser will write a null check; a caller of getUser will think about try-catch.
A name is a record of a decision
When you rename something, you sometimes realize you’ve done more than just rename it. Maybe you split a class. Maybe you moved a method. Maybe you added an abstraction layer. The name acted as a mirror that showed you your design.
That’s why I don’t see naming as a “style” discussion. A naming discussion is most often a design discussion — and having it early is far cheaper than having it months after the code was written.
Good names turn a codebase into something that explains itself. That is one of the quiet but lasting ingredients of sustainable software.
Comments
Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.