Coding: The agent noun class
I refer quite frequently to a post written by my colleague Peter Gillard Moss where he describes the agent noun code smell for class names.
An agent noun is defined by Wikipedia as:
In linguistics, an agent noun (or nomen agentis) is a word that is derived from another word denoting an action, and that identifies an entity that does that action.
Some typical examples of this are classes which end in the name 'Manager', 'Retriever', 'Helper' or even 'Controller' as Carlos points out.
It's often the case that these classes better describe a method which belongs on another object and I quite like Peter's idea that agent nouns are useful for describing the roles that our objects carry out.
We came across an interesting problem related to this a while ago where we wanted to calculate the age of a given customer and then send that data to another web page where it would be displayed.
The date of birth was an attribute on the 'Customer' object and we didn't need any of the other attributes of a customer on this web page so my first thought was that we needed an 'AgeCalculator' class.
public class AgeCalculator { private readonly IClock clock; public AgeCalculator(IClock clock) { this.clock = clock; } public int CalculateAge(DateTime dataOfBirth) { // do some calculation with clock & date of birth here } }
public void SomeMethod() { var age = new AgeCalculator(new Clock()).CalculateAge(customer.DateOfBirth); // and so on }
This approach worked quite well as it allowed us to easily test the age calculation logic in isolation and we could then pass on the age returned to the web page.
The thing I didn't like about this solution is that it seems a lot like an agent noun class.
The giveaway in this case is that the method name is just a variation on the class name. This suggests that this behaviour belongs on another object instead.
It's not as object oriented as it could be but it doesn't seem as bad as some of the other examples such as classes ending in 'Manager' since this object is only solving one problem and we do have calculators in real life.
Some colleagues suggested that perhaps age should be an attribute on the customer which does seem to be a better place for this logic to reside.
On the other hand age isn't used anywhere else in the application and we don't need any of the other attributes of customer as I mentioned earlier.
I'm not sure what the 'right' solution is but there seem to be a few different potential approaches:
- Should age be an attribute of the customer? There could be a tiny type 'Age' which does the above logic.
- Should we have a role/interface 'ICalculateAges' which the customer implements?
- Should we just keep the 'AgeCalculator'?
- Is there some other solution that I'm not seeing?!
–
In reality after we'd discussed all these alternatives it turned out that the requirement was slightly wrong and that we actually needed to send down the date of birth and not the age.
I still think it's an interesting problem though and one that I'm bound to come across again!
[...] This post was mentioned on Twitter by Mark Needham, planettw. planettw said: Mark Needham: Coding: The agent noun class: I refer quite frequently to a post written by my colleague Peter Gillard… http://bit.ly/1zCOfC [...]
Tweets that mention Coding: The agent noun class at Mark Needham -- Topsy.com
8 Nov 09 at 9:15 pm
I think, for a tiny type, CustomerAge is a much better name than AgeCalculator. The main ambiguity would be whether you are talking about the physical age of the customer, or the length of time they have been a customer.
This distinction may be important if you're performing age-related calculations (for pensions/insurance) or if you are calculating loyalty bonuses (choose between CustomerPhysicalAge, and CustomerLoyaltyDuration). I think both of these would be better than CustomerLoyaltyAgeCalculator.
If you just need something to calculate a duration from a Date Of Birth, then PhysicalAge(Date), or CalendarAge(Date) may be better.
I think Age is a poor name on its own, because it is also a verb – people, like wines, age over time.
Your other options probably aren't warranted if you're the only consumer. When there are other consumers, I'd refactor to provide a DateOfBirth type for the Dob field, which has a method "CalendarAgeOn( Date today )" or "AgeAccordingTo(Calendar)" – this will avoid the age changing underneath you during a calculation.
It is this DateOfBirth that may have the RoleBased interface – e.g. DateOfBirth implements ICalendarDate (or something).
I'm skeptical about giving Customer the role based interface for age calculation, simply because there are so many things associated with a customer that may have an age.
Nick Drew
9 Nov 09 at 12:06 am
You were right on considering the testability of the class in your blog post.
Kent Beck himself suggested it in a tweet a while ago (see here: http://twitter.com/KentBeck/status/3579860805).
I would also remember of the Single Responsibility Principle. Objects that are too complex could/should generally be broken down. But how to name such objects?
Anyways, we should be careful at naming things as either smells or practices. There are good arguments on either side, and we should be able to weight them case-by-case. Great post!
pablo
9 Nov 09 at 2:08 am
Although the Clean Code book says that class names should always be nouns, I've on some occasions felt it to be more natural to give a class a verb name. For example ConvertBigIntegerToBytes, CheckInnerClassSerialized and InjectObjectsOnDeserialization:
http://github.com/orfjackal/dimdwarf/blob/master/dimdwarf-core/src/main/java/net/orfjackal/dimdwarf/db/ConvertBigIntegerToBytes.java
http://github.com/orfjackal/dimdwarf/blob/master/dimdwarf-core/src/main/java/net/orfjackal/dimdwarf/entities/CheckInnerClassSerialized.java
http://github.com/orfjackal/dimdwarf/blob/master/dimdwarf-core/src/main/java/net/orfjackal/dimdwarf/serial/InjectObjectsOnDeserialization.java
What do you think, if a class does a verb-like action, is it best to name it as a verb, use an agent noun or figure out another name?
Esko Luontola
9 Nov 09 at 2:30 am
My first instinct is to simply represent this concept with a Value Object. In the scenario described, i would simply create a Date class specific to your application domain, which could calculate the time / duration elapsed from a given Date. eg
Duration age = today.YearsElapsedFrom(dateOfBirth);
or if more precision is required
some thing like
Duration age = today.timeElapsedFrom(dateOfBirth);
Duration is another Value type
I wouldn't use any role based interfaces here, I generally find role based interface make sense for objects with internal state, when invoked produce some of sort of side effect. Value objects on the other hand are immutable, have no state and invoking their methods have no side effects.
isaiah
9 Nov 09 at 5:20 am
One possible way out the name/verb conundrum here is to note that the age of something is relative to a certain date of reference, in your case, the clock. Following that thought, you could consider that your class is really the point of reference for time/age computation, and have a AgeReferential class, which exposes a ComputeAge(DateTime date) method. The purpose of the class would then be to return a consistent age for objects that share the same time referential.
Mathias
9 Nov 09 at 10:12 am
The way I would do it is to have a method on Customer called calculateAge inside which the dateOfBirth will be used to calculate the age. This also fits in with the concept of not exposing privates as far as possible.
Now if the Customer class is bloating up too much, then thats a different problem which can be solved by extracting another domain class from within the Customer. For example, as pointed out by others, an Age object where the logic can be moved. The Customer class' calculateAge can then delegate to the Age class…
Jayesh
9 Nov 09 at 8:06 pm
The key difference in my above comment being that Age is a domain class itself and not an agent noun. Age will contain the date of birth property.
Jayesh
9 Nov 09 at 8:08 pm
I forgot to mention one thing in my comment above.
When I actually come across a situation like this *AgeCalculator* I would usually name it *CalculateAgeCommand*.
I am not sure whether it makes it smell less, but all my commands have a common interface:
interface ICommand {
//constructor gets all dependencies
T Execute();
}
So, I know when an operation is complex enough to deserve its own tests, I promote it from a private method to a class that implements my ICommand interface.
pablo
9 Nov 09 at 8:55 pm
@Esko – I reckon if you were in a language other than Java then those examples that you describe would probably be functions that you would look to add to the appropriate classes?
In which case the names would stay the same and we wouldn't need to find a new class name! I'm not sure what the best thing would be to do in Java though maybe those names are fine in that case.
Mark Needham
9 Nov 09 at 9:30 pm
Thanks for the link btw!
I've also hit this problem before. Like many posts I try and create a class which represents the result (e.g. Age).
So I would do something like: dateOfBirth.AgeOn(Clock.Now)
Peter Gillard-Moss
9 Nov 09 at 9:59 pm
To me it looks like a strategy pattern, i.e. IAgeCalculationStrategy, of which your implementation is just one possibility (for example, you might have another strategy that works on the planet Saturn).
It is probably overkill to break out the interface in this scenario, so AgeCalculator is a fine "generic" strategy for calculating ages.
(I wouldn't change a thing).
Steve Campbell
10 Nov 09 at 4:24 am
@Mark – In a functional language some of them might be functions, but even then they would not really fit into a larger class. Based on Single Responsibility Principle and Open Closed Principle each of those classes does one thing (SRP) and they extend the behaviour of some other class without modifying it (OCP).
For example the last two classes that I mentioned hook into Java's serialization process. In this system, when objects are serialized, there are about five things that need to be checked about every object. Each of those things is implemented as one SerializationListener or SerializationReplacer (similar to the Visitor pattern) and verb names felt natural because each of them does one action, similar to how a method does one action. They are used like this:
http://github.com/orfjackal/dimdwarf/blob/master/dimdwarf-core/src/main/java/net/orfjackal/dimdwarf/serial/ObjectSerializerImpl.java
Esko Luontola
10 Nov 09 at 9:18 pm
Mark,
Let me remind you that Type + Contstraint = New Type.
So, + = Age type.
This transformation also falls nicely into Wrap Primitive with Object refactoring, which attacks Primitive Obsession anti-pattern.
Therefore your Customer class may have a method like
Age getAge() { return new Age(this.dateOfBirth); }
Uladzimir.
Uladzimir Liashkevich
10 Nov 09 at 9:39 pm
This is one of those time when you can drive yourself nuts trying to satisfy contradictory pronouncements on patterns, principles and smells. In the end you have to decide what is important to you, or what makes the code cleaner and easier to read.
For my part, I make a lot of use of agent-noun classes: my most recent code includes StringTokenizer, BindVariableExtractor, BindVariableResolver, FieldValueGetter (which implements IValueGetter), FieldValueSetter (IValueSetter), and others. To me, this is correct, as these classes have no dependencies and can be rewritten, replaced, mocked and tested without impacting the rest of the system. That is what is important to me, and it makes my code easy to read for me and those who come after me.
So I'd stick with AgeCalculator and call it from a getAge method.
Mark Rendle
11 Nov 09 at 5:32 am