Today, we’ll talk about exposing the class’s implementation details in its name.
1. The question
This topic came up in a question about the CQRS pattern, but it’s equally applicable to other patterns as well. Here’s the gist of it:
Why does
DatabaseRetryDecorator
expose its structure and implementation details in the class name?What if I change the class’s implementation and replace the decorator with something else? Will I have to rename it just because I changed its implementation?
And just for the context, decorators are classes that allow you to introduce cross-cutting concerns in your application layer.
Here’s a usage example for the database retry decorator:
[DatabaseRetry] public class EditPersonalInfoCommandHandler : ICommandHandler<EditPersonalInfoCommand> { public Result Handle(EditPersonalInfoCommand command) { /* Editing the customer's info */ } }
The DatabaseRetryAttribute
above connects the command handler to the DatabaseRetryDecorator
. If the command handler throws a database exception, the decorator re-runs that handler again.
The idea is similar to how middleware works in ASP.NET. Here’s the decorator itself:
public sealed class DatabaseRetryDecorator<TCommand> : ICommandHandler<TCommand> where TCommand : ICommand { public Result Handle(TCommand command) { for (int i = 0; ; i++) { try { /* _handler is the underlying command handler */ return _handler.Handle(command); } catch (Exception ex) { if (i >= 3 || !IsDatabaseException(ex)) throw; } } } }
In any case, this is a great question and it ties back to the article I wrote awhile back: Ubiquitous Language and Naming.
Indeed, why should you call the class DatabaseRetryDecorator
and not just DatabaseRetry
?
The same argument can be applied to other classes as well, for example CustomerRepository
, CustomerFactory
, or even EditPersonalInfoCommandHandler
for that matter.
Do they really need to specify the patterns they implement in their names (repository, factory, and command handler)?
2. Naming guidelines
There are 2 relevant guidelines here.
First, you should never use pattern names when naming classes in the domain layer.
In fact, you should only use terms from the Ubiquitous Language when naming domain classes.
So, it’s probably not MoneyGeneratingBipedalEntity
, and not even CustomerEntity
or CustomerAggregate
. It’s just Customer
.
Second, you can use pattern names when naming classes in the application layer.
That’s because the application layer is outside the reach of the Ubiquitous Language, and there’s simply no corresponding notion for its classes in that language.
Also, pattern names help you better understand the intent behind classes in the application layer, since those classes don’t have a direct connection to your domain model.
Note that you should follow the YAGNI principle at all times, even when naming application layer classes. This means that you should put the minimum amount of descriptors in class names.
The most common example of violating YAGNI is calling a repository CustomerSqlRepository
.
Unless you use multiple storage paradigms, such as SQL and NoSQL, there’s no need to specify that your repository works on top of a SQL database.
--Vlad
https://enterprisecraftsmanship.com
Enjoy this message? Here are more things you might like:
Workshops — I offer a 2-day workshop for organizations on Domain-Driven Design and Unit Testing. Reply to this email to discuss.
Unit Testing Principles, Patterns and Practices — A book for people who already have some experience with unit testing and want to bring their skills to the next level.
Learn more »
My Pluralsight courses — The topics include Unit Testing, Domain-Driven Design, and more.
Learn more »