I grew up playing Magic: the Gathering. As a kid I noticed something interesting about the card names – there were no generic names. There were no cards named “Zombie” or “Elf” or “Wizard”. There were cards named “Fugitive Wizard”, “Llanowar Elves”, “Gravebane Zombie”, and even “Storm Crow” but no “Crow”. Modern card names are even more specific and evocative; witness “Crow of Dark Tidings” and “Flameheart Werewolf”. Why? Because the designers need to leave space open for new cards. If there were a card named “Zombie”, that’s it. That card shows what a zombie is. If you want to make another zombie card, it will live in the shadow of the original “Zombie”.
This has applications in software engineering. The names we choose for classes frame how we’ll think about them, and what sort of responsibilities we’ll assign to them. If you have a class named User, then it makes sense to put things related to the concept of “a user” on that class. That’s a problem though. It makes sense to put anything related to that concept on the User class. You’ll end up with login information, billing preferences, email settings, and permissions. It’s long been known that large classes are problems. They’re more difficult to read because they have more logic in the same place, they’re more difficult to change since the logic is more likely to be intertangled, and those make them more likely to be buggy.
Class names set the stage for the logic the class develops over time. We have to remember that we don’t just write code once and then it’s done. Code is continually evolving, continually being changed to meet new needs. At each stage, developers will ask themselves, “where does this logic make sense?” As Stephen Wolfram noted, “the names of functions … directly determine how people will think about a function”. Developers will look to class names as one sign for where logic belongs. They’ll look to the concept embodied by the class as another. If the name and concept are broad, developers will put lots of pieces of logic in the class.
Another point to make about generic class names is that they aren’t descriptive. If you open up a class named User, you don’t have an immediate idea of the data it might contain. There’s a lot of things it might contain. You’ll have to read over it to find out, and remember for next time. That imposes a lot of cognitive burden on working developers. They have to keep in mind the details of large classes or else read over them to be sure. If the name were something like LoginCredentials, then it’s pretty obvious what it will contain. The name guides the reader by bounding the role of the class.
We should look for our code to provide a rich set of clues to make itself understood. Names are an important piece of the puzzle. Taking a cue from Magic: the Gathering, if we try to rename User with a more evocative name, we’ll quickly realize we need to break it up. We’ll probably end up with smaller, more focused classes, which is also a boon.
This article was written by Alex Kudlick.