Entry 12, Day 27
You came back to me, good, good. As I’ve promised, this episode will be about SOLID. What’s that? It’s an acronym for five fundamental principles in object oriented programming coined in early 2000’s by Michael Feathers and Robert C. Martin (aka Uncle Bob). I’ve added Michael’s and Robert’s blogs in Places section, it’s highly recommended reading. Each principle is also covered by an article under “Read more” link. There are C++ examples, but it doesn’t really matter, ideas are valid for any statically typed language.
Now, let’s get down to business. Letters in SOLID stand for:
(S)ingle Responsibility Principle
A class should have one, and only one, reason to change. Class should do one thing. Or broadly speaking, the context (method, class, package, module, etc.) should have a single responsibility and that responsibility should be encapsulated by this context. Why? Imagine a class having five responsibilities. In one sprint, a dev team has five stories to morph into working software. Now if those five devs have to work on one class, there will be merge conflicts. And if one dev does an overall refactoring that interferes with other class responsibilities, there might be serious merge problems. There will be a battlefield. Totally pointless and unnecessary battlefield… Read more.
(O)pen Closed Principle
Class should be open for extension but closed for modification. Which means, that you should be able to change class behaviour without altering its source code. How is that possible? Simple, you can derive from class, you can plug in new objects using existing extensibility capabilities of the class. The most strict version of the principle states, that class once written should only be modified to fix bugs. It would mean, that you have to imagine all ways the functionality would be extended in the future, which is nearly impossible under normal circumstances and changing requirements. And seems to be in contradiction to agile development ideas. Principles and methodologies are nice, but what’s more important is good judgement and knowledge when and how to bend rules. Or, in this case, how to find a strategic closure. Read more.
(L)iskov Substitution Principle
Derived classes must be substitutable for their base classes. So, if you extend a class, you cannot break code that depends on this class in case if your class is used instead of the base class. To grasp the concept, lets recall one of rules of Java method overriding: You cannot use more strict argument types in the method signature if you want to override. You expect that if Dog can eat DogFood, then Rottweiler can also eat DogFood. And compiler is your buddy here, prohibiting you from violating that assumption. This is a special case of LSP. More general case now: Assume you are extending an ArrayList. If invoking add method causes list’s size to grow by 2 instead of 1, you may break the code that uses your class instead of standard ArrayList. And compiler has no way to save the day, you bad boy (or bad girl). Read more.
(I)nterface Segregation Principle
Make fine grained interfaces that are client specific. Or: “Where ignorance is bliss, ’tis folly to be wise”. In software development this is very true. The more your code knows, the more screwed you are when it comes to changes, dependencies, rebuilding, redeployment and all that stuff. If you somehow land with a fat interfaces and fat classes, it is a good idea to extract small, well defined, cohesive and client specific subinterfaces and hand them over to interested parties. Client should be given what he really needs and nothing more. This way, If the big interface changes, there is a good chances that most clients, with small subinterfaces, will be unaffected. Read more.
(D)ependency Inversion Principle
Depend on abstractions, not on concretions. The classic way to think about software, is that high level modules call code from low level modules thus depending on them. Think: main method calls libraries. In big systems (any normal system…) this leads to dependency tree that at some point will tip over under its own weight and fall on your head. The problem multiplies in distributed environments, you have to deploy all the code everywhere, even though you don’t need it most of the time. The solution is to break dependencies chains with separate interfaces and make both high and low level code depend on its abstraction. EJB is the prominent example of this – you can have a simple Java SE client that has no idea about existence of application server and all its burdens and only uses abstract interfaces and simple remote procedures calls to get the job done. It’s like: “here, I give you $2 and you just give me my ice cream, I don’t care about the damn ice cream factory behind it or any other problems you may have “. Read more.
That’s about it. The agenda for the next episode: Agile Retrospective. Performed on this very living organism, after the first sprint of blogmaking.
p.s. Since I like to show my support to nice ideas, I’ve signed the Software Craftsmanship Manifesto. Proud to be the 14431th individual to do so ;)
p.s. 2 Check out Code of Principles for more on the topic.