Keep it Simple, Stupid!
A while back I wrote a blog post on coupling and the observer pattern. Looking back, I did a pretty poor job describing what it wrong about it. I will attempt to correct this.
We all want simple and descriptive code. Code that is self documented. Code that makes sense, Code that tells us a story. Lets look at a kind of code I have seen many times, in many different variations, using observer based asynchronous javascript code:
var ListView = {
init: function () {
this.feed.onItemsReady(this.onFeedItemsReady)
},
onFeedItemsReady: function (items) {
// do something
}
// ...
}
At first, this looks descriptive, and it is, kinda. It’s an object describing the implementation of a publisher it is observing. That doesn’t sound right. It is telling us about the implementation details and why it is doing things rather than what this object is responsible for and what it is doing. We already know all that! In their book, Design Patterns Explained: A New Perspective on Object-Oriented Design, Alan Shalloway and James Trott describe objects in OOP as “something with responsibilities”:
The best way to think about what an object is, is to think of it as something with responsibilities. A good design rule is that objects should be responsible for themselves and should have those responsibilities clearly defined. This is why I say one of the responsibilities of a student object is knowing how to go from one classroom to the next. I can also look at objects using the framework of Fowler’s perspectives:
- At the conceptual level, an object is a set of responsibilities.
- At the specification level, an object is a set of methods that can be invoked by other objects or by itself.
- At the implementation level, an object is code and data.
Unfortunately, object-oriented design is often taught and talked about only at the implementation level — in terms of code and data — rather than at the conceptual or specification level.
Ideally we want our code to describe the conceptual level and what the object is. Unfortunately, in the example above we are describing the implementation level, which is a shame. A slightly better implementation of the above object could look like this:
var TweetListView = {
init: function () {
this.feed.onItemsReady(this.renderTweetList)
},
renderTweetList: function (tweets) {
// do something
}
// ...
}
This code tells us by convention that this object is a presentation of a tweet list, and that the callback being called when items are ready will render a list of tweets. Obviously this is just a minor change in conventions and in most cases refactoring our design will take more than just renaming a bunch of variables and methods, but even with this minor change I think this code tells us a better story.