Building Backbone Plugins: Eliminate The Boilerplate In Backbone.js Apps (2014)
PART 5: APPENDICES
Appendix E: Theme And Variation
There are two hard problems in software development:
1. Naming things
2. Cache invalidation
3. Off by one errors
The “off by one” addition is a variation of the a quote by Phil Karlton, which says the two hard things in computer science are cache invalidation and naming things. The variation was popularized by Martin Fowler in a short blog post.
Naming things truly is difficult. Names provide meaning and expectations. Things that are named randomly or by different convention will appear unrelated. It is important to name things properly, then. And naming things with a theme can often help.
The theme of the project often leads to the names of the individual items. Naming the items by this theme makes them easier to remember and understand, if the theme is chosen properly. If a theme is chosen poorly, though, it can cause as many problems as were solved - or more.
Selecting vs Picking
Part 2 of the book is devoted to building a plugin named “Backbone.Picky”. The name comes from the idea of “picking” the models and that are needed. However, the original method names, attributes and other aspects of the code did not follow the theme of being “picked”. Instead, the theme changed to “selection” in the API. Models could be “selected” and “deselected” with a .select() and .deselect() method. This works, technically. Computers don’t care what names are given to things. But from a human perspective - which is the only perspective that matters, honestly - naming is very important. By switching from a “picked” theme to a “selected” theme in the method and attribute names, several problems were created.
A Variation On Theme
The idea of a “theme” isn’t anything new in software development. This practice has been around for a long, long time. It has also undergone many different name changes, including the use of “metaphor” at the height of the eXtreme Programming (XP) days.
Whatever it is called, the theme of a project is something that often needs to be chosen carefully. I’ve heard many a story, for example, of XP teams picking a strong metaphor for a code base and having it bite them in the butt. For example, one person I talked to recounted a metaphor of a “warehouse” for a system. They had objects, services and code centered around equipment and actions that would be found in a warehouse. The problem was that this system had nothing to do with warehousing. Having a forklift.liftAndShelve() method for a system that dealt with customer relations (or whatever it was) may have been fun at first, but it quickly fell apart and became a source of problems.
In the end, themes or metaphors are important because they create continuity. But they can be taken too far if applied incorrectly. Be sure to pick a theme that makes sense for the system at hand.
The first of many problems that can be created by not sticking with the theme is confusion in the API and use. The name of the project creates a sense of expectation in the language used around the project. If a developer is talking about picking items in a collection, then it would make sense the .pick() them. Saying .pick() implies an opposite method of .unpick(). It sounds a little odd to say “pick” and “unpick”, though, so the names were changed to “select” and “deselect”. This lead to a number of questions and issues in the project, as developers that were using it were wondering why the theme for naming was different. It was confusing having to think about the project name and then use method and attribute names that didn’t follow the theme.
So, then change the name of the plugin to “Backbone.Selectable” or something like that, right? Then the names of the methods and attributes can revolve around the more natural language of “selection”: a model can be “selected” and “deselected.” This creates a much more subtle problem, though - one of semantics, expected behavior, and overriding methods.
When it comes time to give a Backbone.Collection the methods that allow it to select models or deselect models, the “select” theme breaks. Backbone.Collection already has a method called .select() - and it has nothing to do with marking models as selected. Rather, it is used to return an array of models that match a certain criteria.
It’s arguable as to whether or not the semantics of “select” are being broken in this case. Is the act of “selecting” a model and merely marking it as selected vs getting a reference to it really any different? The end result is an identification of which models are selected, after all. The real problem is in the behavioral change, then. If this plugin created a method named “select” and added it to the collection instance, it would be replacing the existing select method and it would change the behavior of that method. It would be possible to write this method in a way that preserves the existing behavior of the collection’s “select” method, of course. This may or may not be acceptable, and may or may not be difficult. It does add yet another requirement to the code, though. It also creates an unexpected modification to the behavior in the “select” method of collections. A developer that has become accustomed to the “select” method as defined by Backbone.Collection directly, may find the new behavior to be problematic. At the very least, it would be surprising to see that a method they have been using for however long, suddenly has additional behavior and semantics.
Knowing When To Move On
The solution to all of the problems that were created around the theme of “selection” was not to continue hacking on the code and documenting the changes in bold letters as was originally done. This only served to exacerbate the problems - like putting a band-aid made of sand paper and rubbing alcohol on a large wound. Rather than fixing the actual problem, this creates a worse situation that tends to lead toward other bad things.
The real solution is to change the method names and attributes to match the theme of the plugin. And sometimes, changing the theme of the plugin to start with. Instead having “select” and “deselect” methods, they will be “pick” and “unpick”. The language used around these methods will also be changed. The behavior of the methods can then be focused to the needs and not have to worry about breaking semantics or behavior in existing methods.
“Picking” a theme (see what I did there? :P) and sticking with it can spell the difference between success and failure in a project. A well chosen theme can create a sense of cohesiveness and unity. But a poorly chosen theme can have the opposite effect. Even if a theme seems to be well chosen at first - as was the case with Backbone.Picky and the “selection” theme - it can prove to be terrible in the end.
Don’t Mix Themes
One of the easiest mistakes to make in choosing a theme is creating a set of expectations in a project name, and then missing those expectations in the project API. If a theme is chosen for a project, then name should reflect the same thing as the API.
In the case of Backbone.Picky, the project name did not match the API theme. This caused a lot of confusion and questions. It would have been better to name the project something entirely unrelated to “selection” or “picking” than to have a name that came close to the theme, but with different words and names.
Don’t Let A Good Theme Go Bad
Picking a theme for a project is often easy at the outset. It may seem obvious what a project theme should be. But even the best themes can go bad over time. Always be on the look out for the limitations of a theme and be ready to fix the problems when they occur, not just work around them. This may mean a deeper examination of the names used from the theme, or choosing another theme entirely.
Be Wary Of Re-using Existing Function Names
When a plugin or add-on uses the same name for a function that is used by the types that are being augmented, problems can ensue. If the plugin is mixed in to the targeted type or instance of that type, the results can be detrimental causing a number of unknown and difficult to track down bugs. Whenever possible, use method and attribute names that are not typically part of the base types.