Tim Ottinger & Jeff Langr present the blog behind the versatile
Pragmatic Programmers reference cards.
The SOLID principals are a big topic these days (in the post-Spolsky/Atwood v. Martin war of words). I suppose that is a good thing, because these principles have been around a pretty long time. We taught these as principles of Object-oriented Design at least 15 years ago, and they've appeared in a number of Uncle Bob books.
These principles were developed upon observation of how good code should be structured (and partly by sniffing out why bad code is bad). Never were they presented as a methodology. Always the assumption was that code was being written for good reasons and that it was written to work. They focused on "building things right" rather than on "building the right things."
There is more here than would fit comfortably on a hand-written 3x5 card, by the way.
Single Responsibility Principle (SRP): A class should have only one reason to change.
The original formulation was "a class should do one thing; it should do it all, it should do it well, and it should do it only." This was subject to a lot of interpretation and didn't address the dependency problems in software design, so it was reformulated. A feature of good design is that all classes have clear, crisp responsibility boundaries. When code is munged together or poorly organized by responsibility, it is hard to determine where a change should be made.
Open-Closed Principle (OCP): Software entities should be open for extension, but closed for modification.
This was originally formulated by Bertrand Meyer to say essentially that published interfaces should not change. It evolved to a larger meaning that new features should be added primarily as new code, and not as a series of edits to a number of existing classes. A quality of good design is the extent to which new features are bolted-on instead of woven-in.
Liskov Substitution Principle: Subtypes must be substitutable for their base types.
Barbara Liskov's paper Family Values addressed a notion of the proper use of inheritance. There have always been a lot of design errors from overuse or misuse of inheritance between classes. When a base class has methods that don't apply to all of its children, then something has gone wrong. When a class uses an interface, but some implementations are inadvisable or incompatible, then the design is unclean.
Interface Segregation Principle (ISP): Clients shouldn't be forced to depend on methods they don't use.
In a good design, dependencies are managed. To keep irrelevant changes from flowing up into classes that don't really care about them, it behooves the developer to keep interfaces small and focused.
Of course, the problems of conglomerated interfaces don't manifest the same way in dynamic languages because of late binding, but the problem lives on in C++, C#, Java and other statically-typed languages. In dynamic languages interfaces are not declared, but just understood to exist. If my python program only calls an add routine and an assignment on an argument, then it is understood that the argument must include an add and an assignment in its interface. I automatically depend only on the methods I use in my code, and changes to the underlying class do not seep unbidden into my code.
On the other hand, we find that some dynamic languages are adding declarative interfaces, and some do interface with java or C programs through declared interfaces. Maybe the principle lives on after all.
Dependency Inversion Principle (DSP): Abstractions should not depend on details; details should depend on abstractions.
Since abstractions are built with the intention of writing interface users and interface implementations, it is reasonable that most of our code should depend on abstractions (opening the code to open/closed goodness) rather than concrete implementations (making further change a matter of weaving new code with old). Again, problems with this principle do not manifest the same way in dynamic languages, but not everyone uses dynamic languages.
And of course, even if one uses dynamic languages one might find it useful to use an interface that limits exposure to details. This warning still applies to leaky abstractions.
If one follows the SOLID principles, one may find that their code becomes more fluidly maintainable than if they did not. Ultimately, that is what the whole good/bad thing was about from the beginning.
BTW: font of the day is Anime Ace, a free font. I'm not sure that it will appear in the final version of this card because of its all-caps nature.
Subscribe to: Post Comments (Atom)
I'm confused wrt the O & L. Seems the heading of L is missing and the explanation of O is missing, and the existing parts breaks S (pun intended :) Or I'm just off in my understanding...ReplyDelete
Thank you very much. There was a cool "translate the html into html" error which was at least mostly my fault. Corrected now.ReplyDelete