Friday, September 23, 2011

One of the Best Bits of Programming Advice I ever Got

Years ago (early 1992), I attached myself to this crazy skunkworks project that was using this weird language called Smalltalk. "Object Oriented" was in its infancy as a "hot" item. High paid consultants. Lots of people laying claim to what this new object religion was all about. This was 5 years before Alan Kay would make the statement "I invented the term 'Object Oriented Programming' and this {Java and C++} is not what I had in mind."

Shortly after hooking up with this whacky group with the whacky language, still confused about what the difference was between an instance variable, a class variable, and a class instance variable, I found myself in a training course taught by Russ Pencin, of ParcPlace. Russ would say something that I didn't really appreciate at the time. Despite not understanding the point behind this sage advice, I endeavored to follow it. It would take years of experience and exposure to appreciate it's value. The advice?

Don't make objects that end with 'er'.

That's it. The OOP paradigm sprang to life amidst of a culture of what we called "procedural programming." Now days we don't talk so much about the comparison between the two paradigms. Probably in part because Object Oriented languages are now a dime a dozen. The OOP religion, in a multitude of flavors won out. Sadly, I often find myself echoing words I heard Adele Goldberg say around 2000: "Now days we have lots of Object Oriented Programming, but not so many Object Oriented Programmers". If there was one piece of advice I would pass on to the hordes of would be Object Oriented Programmers, it would be the sage advice offered by Russ: "Don't make objects that end with 'er'."

What's in a name anyway? Why is this worth getting excited about? What I've discovered over the years, is that the jst of OOP is that we bind behavior to data. As long as you haven't joined in the Functional Monks in their Monasteries of Statelessness, programs are made of behavior and data. In classic structured/programming, we concentrate on behavior (verbs), and then figure out what data (nouns) we need to make it all work. In other words, we bind data to behavior. But in OOP, we make the locus of programs be the nouns, the data, and then we figure out what kind of behavior we can bind to them, and hope that the problems we hope to solve gel out of the emergent behaviors.

I recently posited to a colleague that in nearly every "er" object case, there was a better name for it. And that giving it a better name would tend to make the design more encapsulated, less spaghetti code, in short more object oriented. It's not a hard and fast rule, but there are a lot of cases where it can improve things.

Take some sort of "Loader" for example. The focus here is on the unit of work it does. It'll have lots of instance variables, lots of arguments, and pass lots of data around probably. Now instead replace that with a LoadRecord and a LoadStream. I'm reasonably confident you'll end up with something that is more akin to what the original Founding Fathers of OOP had in mind. We want to create objects that describe what they are, and then bind behavior to them, rather than focus on what they do, and then figure out what data they'll need to do that.

Some er's that I've learned to avoid over the years:

  • Managers - Every time I see one of these, I cringe. People will usually tell me what it does, long before they can tell me what it is. Is it a registry? Fine call it a registry. Is it a history or a log? Call it that. Is it a factory? Call it that.
  • Controllers - Only good controller object I've made in the last 20 years was an interface to a BallastVoltageController that represented a real world object. The fact that every single MVC implementation in the world has had a different role for Controller ought to tell us something about how well that idea fit.
  • Organizer (and many like them) - Focus is on what it does. This is a great example of how easy it is to turn many of these 'ers' into nouns. Call it an Organization. Now we're focusing on what it is.
  • Analyzer/Renderer/etc - Definitely examples of "worker" objects. What if they had been Analysis/Rendering/etc.
  • Builder/Loader/Reader/Writer/etc - Remove the focus from the objects being manipulated, and tend assume to much responsibility themselves.
There's lots of exceptions to such a rule of course.
  • There are lots of noun words that end in 'er'. Register. Border. Character. Number. If it's really a noun, fine.
  • There are many 'er' words that despite their focus on what they do, have become so commonplace, that we're best to just stick with them, at least in part. Parser. Compiler. Browser.
  • When you are trying to model a domain object that ends in 'er'. I'm fine with a Manager subclass of Personel, which is there to refine a type of personal that has management behavior to it.
Your mileage may vary, I'm sure there are those that disagree with this. Until you apply the mindset for a while though, you'll never really know. Give it a whirl on one of your projects/designs and see what happens.

59 comments:

  1. I've heard Uncle Bob talk about how words like "Manager" and "Loader" are considered "Noise Words" -- along with other vague words that don't end with "er", like "data" and "info".

    I like how you're focusing on the vague nouns that end with "er", because it's hard to generalize the advice of staying away from words that don't end with "er".

    Good article!

    ReplyDelete
  2. Replies
    1. Host/Service (depends on connotation, SyntaxGraphHeuristic, ...?

      Delete
  3. Many -er names are perhaps structurally accurate, but often misleading. If we make those names more precise, then look for patterns in the names, then we can often turn them into more purposeful, meaningful, useful names. I, too, counsel programmers not to like -er names, but rather than avoid them, I suggest that they feel free to improve any name they see that ends in -er, subject to your sensible list of exceptions.

    Thanks.

    ReplyDelete
  4. Horde is spelled horde as in invading Mongolian horde, not hoard as in a dragon's hoard of treasure or hoarding supplies.

    ReplyDelete
  5. Yoghurt, see second bullet in the exceptions list at the bottom. :) Despite "Server" having become a canonized sort of noun, I still think one would benefit from considering some of the other nouns that surround it, thinks like transaction, command, response, protocol, stream, etc. Put the weight of your real objects there, and you'll have a lightweight "Server" at the top at best.

    ReplyDelete
  6. Very well said! It reminds me of an interesting post on naming conventions and OO thinking in Carlo Pescio's blog:

    http://www.carlopescio.com/2011/04/your-coding-conventions-are-hurting-you.html

    He mentions the -er suffix among the dangerous practices (Peter Coad's er-er principle).

    In a comment, when asked about Lexer and Parser, he points out that LexicalGrammar, Syntax, etc would be more object-oriented names, again following Coad's idea to look for the "managed" object behind the manag"er".

    ReplyDelete
  7. Puts me in mind of

    Execution In The Kingdom Of Nouns

    http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html

    ReplyDelete
  8. Interestiong .. i read this the day after i replaced a load of manager classess wit ha service+repository pattern ... seems a bit coincidental. I do like the bold generalism of avoid 'er' and i like how you made it stick. Its a bit of work, but id be interested to see you you shuold do things like provider pattern.

    ReplyDelete
  9. The distinction between "things ending in '-er'" and "nouns" is artificial. All of these are nouns, so calling the ones that you don't think count here nouns makes little sense.

    What you really mean to say is that we should avoid naming classes after *agentive* nouns -- nouns that are likely derived from verbs using the agentive suffix "-er". You're saying we should avoid creating classes for which you only actually know the intended functionality, but not the data encapsulating it.

    I disagree with this argument. In fact, the number of exceptions you list in your post let on how dangerously naive that piece of advice really is. Lots of applications benefit from an object-oriented service layer. Despite the fact that these aren't always named in an agentive fashion, these take an agentive semantic role in the basic flow of an application. Depending on what you mean by classes, you're basically saying that any kind of interface should also be avoided, because the only thing we know about these components are the functionalities they should have. You're also speaking out, then, against things like the bridge pattern, which allow us to plug and play different types of data formatting classes with different types of data rendering classes.

    At best, your advice is a reaction to kludgy lasagna code written by entry-level programmers with a limited skill set. At worst, it suggests we drop a lot of best practices and design patterns in software development because someone once noticed that there are a lot of poorly written classes that end in "-er" .

    ReplyDelete
    Replies
    1. He isn't arguing that the practice should extend to refusing to create classes that have only function and no data, like interfaces. Merely using a naming convention that promotes a mindset whereby one can often avoid scope/binding bloat. It doesn't mean you can't define appropriate classes by avoiding this rule of thumb, nor that you can't define inappropriate classes by following it.

      The only argument I might use against his piece of advice is that from a readability and productivity standpoint, precious space is wasted by being overly obtuse in following the rule (Parser => SyntaxGraphHeuristic), and that there are equally meaningless "non-agentive" names that don't actually improve the description mindset due to their ambiguous nature(Amplifier => AmplificationAgent).

      Delete
  10. I don't think you've made a strong case for your advice - in fact I remain decidedly unconvinced. For instance, you mention the controller part of MVC. I'd like to know how 1) you would rename that and 2) how renaming it would make it better. Granted, in renaming the controller you would probably also redesign the framework.

    This might be good advice, but it doesn't strike me as being valuable. I'm disappointed that you didn't make a more persuasive case.

    ReplyDelete
    Replies
    1. How about just renaming it to Control?

      Delete
    2. Model View Relay?

      Delete
  11. I think you're striving for a simplistic solution to a complex issue.

    ReplyDelete
  12. @Robert I am always impressed by commenters who have telepathic abilities and use them to express to all readers what the writer meant with his post.

    Isn't there a view that unify what you say and what Travis says? From my point of view, if you think your piece of software as a technical building where each part is defined by what it does, yes you end with what you say, an agentive (thanks for learning me this notion btw) terminology. That's true for any paradigms.

    But if you try to embrace OOP, IMHO you'll see your work as a set of autonomous entities that interact through message-passing. Those entities are here to offer metaphoric-interface to real-life "object". IRL, there is no predominence for objects that end in -er, so neither should your entities. The verb should be in the message name, so each time you code say a XXXSorter.sort() method, this is not DRY and thus a kind of failure, don't you think? (if it's rather your code or the OO paradigm that fails, I leave it to your thought).

    This agentive way to name thing has ruled the oo culture precisely because this is a (too) technical way to consider object. That's the view of the framework-designer who has no way to name the controller layer other than "the controller layer". And this is where I think you agree with Travis, naming everything in such layer XXXController is symptomatic of a lack of oo reflexion by sticking to the technical architecture rather than embracing the business domain.

    That is what I like so much with DDD, suddenly there is so many more judicious way to name things.

    Before naming in "-er" which is already on the "how"-side of things, I would first try to find a name that qualify the "what"-side which is more stable and less low-level.

    So to sum it up, my own telepathic sense tells me that Travis says that the goal of an OO design is to think beyond the technical ground, you tell us that the technical ground cannot be abstracted completely, that we have a lot of techniques and patterns that are really helpful... And what I say is that it's ok! ;-)

    So please, tell me what I mean and if we all agree.

    ReplyDelete
  13. Great article, great advice. The amount of "well, actually" comments here makes me laugh. People love to argue and try to show that they are smarter than everyone on the internet. I forget where i heard it but the saying "There is a difference between listening and waiting your turn to talk" comes to mind. well actually reference: http://tirania.org/blog/archive/2011/Feb-17.html

    ReplyDelete
  14. This is why I hate OOP with the fiery passion of a thousand Latin lovers.

    ReplyDelete
  15. This comment has been removed by the author.

    ReplyDelete
  16. This comment has been removed by the author.

    ReplyDelete
  17. ...But not "only a novice would try to hammerer a screw."

    ReplyDelete
  18. This comment has been removed by the author.

    ReplyDelete
  19. This is a correlation-causation problem. The fact that you have a high correlation of words that create poor OOP concepts does not imply that they are the cause of such a poor name. Perhaps you should take a step back and look at what you're saying *without* the emphasis on the last two letters of each word.

    The 'er' suffix is not the problem with a term like Loader or Manager. It's the vagueness that is the problem. What kind of Loader? What kind of Manager? Some words are inherently vague, like "Component", which, by the way, does not end in '-er', but should also be avoided. Some other words (ending in '-er' and not) might be vague but are integral because they represent well known concepts in computer science and engineering. Parser and Compiler are obvious ones-- tacking them on the end of a class should immediately let us know what the class is for. The same goes for Controller, because it is a well known pattern. These "-er" terms convey meaning that improves the understanding of your domain model. I couldn't imagine a replacement for Controller that would convey the use of a controller pattern so obviously. Why would we throw out 20+ years of design patterns? If you cannot accept the idea that names also act as cues for the patterns we use, then you are missing an integral part of building maintainable code.

    You also made no argument about qualifying these names. Yes, "Loader" itself might be vague, but is "DiskFileLoader" all that vague? If I just called a class "Factory" (doesn't end in '-er'), just /^Factory$/, I would be chastised for improperly naming the class. Yet if I qualified it, PersonFactory, this is considered almost unanimously acceptable (unless you just hate the Factory pattern), even by you in this article, it seems. What is the difference? Qualification in both cases makes an otherwise vague word into an understandable concept. This shows that '-er' has nothing to do with understandability of the name.

    In short, what you've basically said is: "Don't name things vaguely". We've known this rule for a long time.

    ReplyDelete
  20. What about converter?

    ReplyDelete
  21. You forgot the most important one: "Helper" :)

    ReplyDelete
  22. Yeah... I did not go as far as this article suggests, but I told my team I NEVER want to see a class with the word "Helper" in it again. Or they won't have an Employ-er :)

    ReplyDelete
  23. @Keith Beller, Better pattern than MVC? Hum... MVVM ^_^.

    Thanks Travis, it's a great advice, maybe not to follow stricly but keep in mind.

    ReplyDelete
  24. I'm with Robert Elwell on this. You were taught about instance and class variables and class instance variables. Why are you prioritizing instances over all else? You're like a carpenter with a nail gun talking smack about screwdrivers. Tools for jobs. And how different is your lust for object models over functions from Functional programmers' obsession with the reverse? What you both ignore is how things get done in the real world.

    I'd second Robert's argument by saying that there are a number of other design patterns you're throwing out the window by forcing classes to be data-driven. Firstly, there's no absolute rule governing how data is broken up into classes -- and it's as likely an inexperienced coder would write a meaningless, arbitrary or inefficient data model as one would write a convoluted set of spaghetti procedures. Secondly, once you've got a large collection of discreet data objects, regardless what the demigods of early OOP would have said, you'd be foolish not to find intelligent ways of working with them in batches without altering dozens of existing inheritance patterns. Especially if they all have something in common, but not everything in common. Especially if you're working on code that's been in production for 5-10 years and the client doesn't want to pay for a massive rewrite to satisfy your "OOP - OCD".

    Procedural programming in the guise of an object: So what? Human beings didn't start making tools so we could be constrained by them; the point is to use them to get something done. Talk about programmers in high castles and monastic hierarchies.

    ReplyDelete
  25. Phew. I thought after reading that I was going to have to abandon my favorite variable name: Thinger. Fortunately, its a noun, and doesn't get "cut" according to your primary criteria. The fact that it is completely non-functional in terms of identifying what it is you're acting on? Well, ok... but its still my favorite. Nyeah.

    ReplyDelete
  26. Last week I've made a similar argument in my own blog post: choosing good names helps with good design while badly designed constructs are usually hard to name and tend to show certain naming anti-patterns:

    "Finding meaningful names for some API constructs is so difficult that it should be completely avoided. This is not a joke. We should stay away from naming types, methods and parameters after they are designed. It is almost guaranteed that if we throw unrelated fields together into a type, the best name we will find for this concoction is some sort of Info or Descriptor."

    You can read the whole blog post here:

    http://theamiableapi.com/2011/09/21/api-design-best-practice-naming/

    Good to see others arriving to similar conclusions...

    ReplyDelete
  27. To some of the commenters: The main point in this article is that in OOP (unlike other paradigms) the focus is on the data and that behavior comes second. Saying that classnames should not end "-er" simply illustrates that point.

    ReplyDelete
  28. I'm pretty sure the teacher in the parable was trying to make a point about what classes should DO, not what they should be named. Hiding behind anonymity and the idea that this is all about naming conventions and not about functionality is pretty weak stuff. If this whole discussion is based in nothing more profound than a passing disgruntlement with how some people name classes, then it wasn't worth the read. If it was about the way people manipulate OOP to be more or less procedural, then it's at least a subject worth consideration.

    ReplyDelete
  29. And this is why I just renamed all my Manager and Coordinator classes. I bring you: The Shepherd pattern. Ends in D.

    ReplyDelete
  30. @Hubert
    "IRL, there is no predominence for objects that end in -er, so neither should your entities. "

    Oh, I don't think that's fair, here are a few off the top of my head:

    Ice scraper
    Toaster
    Burner
    Leaf blower
    Lawn mower
    Vacuum cleaner
    Computer

    ...

    ReplyDelete
  31. One of the most useful modules in python, OptionParser[1], is named like that and I can't really think of anything better. How would it be re-engineered to fit what this article is trying to profess?


    [1] http://docs.python.org/library/optparse.html#optparse.OptionParser

    ReplyDelete
    Replies
    1. CommandLine – the data inside the object contains the complete command line. Then you can have CommandLine.parse_options()

      Delete
  32. Bjartr, OptionParser doesn't say anything about what type of options it parses. Perhaps better would be "CLI" with a method verb called "parse()".

    This is a fun exercise though, here's a couple more for you: RoR's "ActionMailer" and PHP's "PHPMailer"

    ReplyDelete
  33. Part of the problem is Java's brain-dead implementation of OO (I prefer the term Object Disoriented). Every program needs verbs otherwise nothing would happen, but because functions are not first class objects in Java the verbs have to be encapsulated in classes. This leads to a profusion of '-er' and '-or' class names (Comparator springs to mind) which would be better implemented as stand-alone functions.

    In more rational languages this is not so much of a problem.

    ReplyDelete
  34. @Anonymous, well in your list there is a predominence of technical object. So this seems to make my point : when you see the world through a too technical/left-brain oriented lense, you loose your imaginative/right-brain ability and you are stuck with "-er" objects. That's ok if you are talking to technical guys too, otherwise you are not doing your work as a software engineer: we ask you to solve a problem in our field, not to teach us a new terminology. Look at the device in your hand and then at your wife, mom, daughter or any non-technical person in your life: and now decide whether you should call it a pointer or a mouse when talking to her.

    TIMTOWTNI

    ReplyDelete
  35. So....why?

    You got me all built up for your argument but you never really made it.

    You said it will help prevent spaghetti code but you never explained how/why.

    ReplyDelete
  36. "Like the founding fathers of OOP intended"

    Oh you mean Alan Kay? Founder of OOP?

    Look what example was in his original book:

    Object subclass: #MessagePublisher
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Smalltalk Examples'


    You're just wrong. Classes ending in 'er' mean something. Yeah if someone just writes "Parser" class it's generic, but "Factory" is no better. XMLParser or JSONParser make total sense to me.


    Let's take another one of your examples. LoadRecord vs RecordLoader.

    RecordLoader - An object that extends Loader (which probably has a load() method)

    LoadRecord - An object that probaby is in some model that has a bunch of properties. Sounds like there is a Load table and this class represents a row in it.

    Point is that naming conventions are for a reason. "register_controller" in mvc is named that way because it makes sense. This class controls the registration. "Just call it registry_control sounds like it has a specific control in it.


    Er - Usually denotes class purpose is an action
    Non-er - Usually denotes class purpose is storing and organizing data.



    And to those who hate OOP because of this sound like they never learned OOP correctly or use it incorrectly.

    ReplyDelete
  37. Is this thread about naming or about designing objects ?

    Looks to me that the sentence is about design, but most of the comments are about naming.

    ReplyDelete
  38. I'm a little confused by your suggestion to use LoadRecord and LoadStream, isn't this just a more specific description of what the object does?

    ReplyDelete
  39. sanity, I agree that 'LoadRecord' and 'LoadStream' are confusing examples. They sound like verbs not nouns and 'StreamLoader' and 'RecordLoader' would violate the 'er' suffix "smell".

    It sounds more like the real thing to avoid is vague names like 'Loader', whereas 'StreamLoader' and 'RecordLoader' wouldn't bother many people.

    ReplyDelete
  40. I like this advice. Plus those objects ending in -er often denounce actions, and therefore would be better as methods (e.g, Instead of 'StreamLoader', I would prefer having Stream.load(), it makes more sense and is easier to maintain)

    ReplyDelete
  41. There is nothing wrong to make classes ending 'er', while they are just functors that store some data. But functors isn't part of OOP.

    ReplyDelete
  42. I could see myself going with this. Problem is though that when working with others, as a consultant switching teams, there's going to be naming inconsistencies.

    ReplyDelete
  43. I mentioned this essay in my computer science class when Iterator classes were mentioned. Java's Scanner was used as an example since, as I understand it, it has next() and hasNext() methods.

    When I said I thought you wouldn't make an iterator, she said you were out of touch.

    Did I represent your position correctly? Either way, I'd be curious to know what your response is.

    ReplyDelete
  44. Nerdcore Steve, keep in mind that this is coming from a Smalltalk perspective. Where we enjoy the illusion that it's All Objects All The Time. We've been doing powerful collection things for 30+ years without iterators because we have the Obect that Java doesn't really, strong easy to use simple block closures.

    Anyway, No I would personally not make an Iterator. But if I really thought the essence of what you were trying to capture deserved a stateful representation, I might make an Iteration object, see bullet 3 in the first list. What's the difference one might ask? For me, it's subtle, but it's there. It may end up filling pretty much the same role, but how I code its internals might actually work out better. An Iterator is just a Stream anyway. That's what we send #next and #hasNext to.

    There's a comment earlier up about Java's issues by Dave Kirby that says it well IMO.

    ReplyDelete
  45. Scanner, Parser, Loader are perfectly fine class names even by themselves!
    Almost always these are abstract classes. But they make sense: Loader has a load(), Parser a parse(), Scanner a scan(). So I can have an array of Scanners which could be FileScanner, XMLScanner, Etc. That is why people do it.

    The author and the commentators' statements imply a misunderstanding of OOP.

    RecordLoader would have a load() that returns a Record most likely.

    Now you could have a static method in Record called load(). And that could modify the class itself but there are perfectly legitiment reasons why you would do one and not the other (or both)

    ReplyDelete
  46. As you know, entire books have been written on the subject of selecting object abstraction. The spirit of your rule of thumb is not a bad starting point. However, for a more nuanced treatment good starting points are http://www.wirfs-brock.com/PDFs/013-015.pdf and http://www.wirfs-brock.com/PDFs/Characterizing%20Classes.pdf

    ReplyDelete
  47. As far as "Iterator", in Smalltalk that isn't used as much for basic enumeration where we'd just write "do:", but for places where it is used we call it a "Stream"

    ReplyDelete
  48. Excellent pieces. Keep posting such kind of information on your blog. I really impressed by your blog.

    ReplyDelete
  49. Hi, I wonder how do you think about the tons of -er classes in Android API, like:

    http://developer.android.com/reference/android/content/CursorLoader.html
    The class CursorLoader will eventually supply a Cursor, but it's bad to write it to Cursor.load(), since there can be many other class also extends their Loader, and all Loaders share some codes.

    In this case, isn't Loader just a good name?
    Thanks.

    ReplyDelete
  50. Your blog is very informative.This is obviously one great post.i keep on reading articles from here.thanks for sharing.. bpc training

    ReplyDelete
  51. > To some of the commenters: The main point in this article is that in OOP (unlike other paradigms) the focus is on the data and that behavior comes second.

    Are you serious? What kind of nonsense is that?

    ReplyDelete
  52. I'm ages late to this, but the word "Server" may be commonplace but the term "Service End-Point" or "Central Repository" would be less ambiguous. What is a server? What is a client? Most servers are also clients (web servers are database clients) which makes the name rather ambiguous. It's fine when you're just saying things like "our production servers are updated" but for the purposes of OOP you can pretty much always do better. IncomingConnection is better than ServerListener. They might sound the same, but put code in them and you'll start to wonder how something so simple eluded you for so long (and after all that reading, no less)! I second the recommendations above to Carlo Pescio's blogs on this topic.

    ReplyDelete