5 ms·
For middle of the road companies with middle of the road developers, I find SOLID is not really a great set of principles to focus on. 'S' is pretty good becau
by tunesmith 10y ago
For middle of the road companies with middle of the road developers, I find SOLID is not really a great set of principles to focus on.
'S' is pretty good because it helps encourage developers to get away from huge classes that have dozens of methods.
'O' is basically useless when applied to a single codebase, because one of the worst parts of middle-of-the-road developers is when they start to realize they can extend classes. You end up with horrendously complicated and deep class hierarchies. I find that when it's time to add functionality, it's far better to just refactor and create new classes for composition.
'L' is deeply confusing, and the difficulty in understanding it is what leads to the deep and brittle class structures above.
'I' drives intermediate developers to create more and more interfaces that have 1-2 methods, which when combined with their difficulties with 'O' and 'L', just leads to confusion and high cognitive load when trying to maintain the codebase.
'D' is good.
- qyv 10y agoCould not agree more, I find SOLID often creates more harm than good with a lot of devs. For example: S: Each class can only do one thing, ever! Gotta do something else? Lets add more classes that all inherit from each other! O: Heh, no one even remembers this one, like, ever. L: Ya, thats how inheritance works! Right? Right... I: Hey, I know how to create interfaces! Interface all the classes! D: OK, just stick the DB connection into the constructer and we've got the D covered, yesssssh! Really though, IMO SOLID is somewhat overblown in many cases. It is just a set of guidelines for good OO design not any kind of iron-clad rules.
- rimantas 10y agoYour comment just shows that SOLID is not understood, not overblown.
- raverbashing 10y ago"No True Scotsman" indeed And I want to slap the "S" people whenever I see a private method inserted merely to call a library So it's "single responsability" except for a set of arbitrary cases pulled out of who knows where.
- hnbroseph 10y ago> "No True Scotsman" indeed that doesn't seem applicable.
- qyv 10y agoI think it is both, actually.
- stcredzero 10y agoLets add more classes that all inherit from each other! Can't do that in Go.
- Ace17 10y agoYou're not doing justice to the open/closed principle. The open/closed principle is a lot more subtle than just "inherit from existing classes instead of modifying them". Actually, you can write open/closed compliant classes without using inheritancy at all (e.g: C++'s std::list, which allows injecting the allocator and the ordering function). I agree, in the general case, it's impossible to write code up-front that is "closed" in an absolute way, i.e which would resist to any kind of feature request. Trying to do so will result in horribly over-generalistic code. However, you can still spot parts of your code that always grow a little in response to some kind of feature requests (e.g each time you add a new input format, you need to add a new 'case' in this function). Then, you can decide to "close" your class against these kind of feature requests (e.g injecting the list of supported formats at construction).
- mikekchar 10y agoI'm going to be somewhat controversial and say that I think the open/closed principle is actually a bad idea. I say that slightly carefully because whenever I shoot my mouth off on a topic that most smart people agree about, usually I find that I've misunderstood something. However, if you will indulge me... I think the intention of the open/closed principle is to stop people breaking the back of the camel one straw at a time. It's tempting when you get feature requests to think, "Oh, it's easy. I'll just extend this class". Clearly this is something that you don't want because eventually you have a monster class with no clear purpose. However, it is almost as easy to break the back of the camel by piling on functionality (either through inheritance or through composition). Now, you have code that is just as coupled, but we have lost the cohesion. Instead of being crappy code crammed into a single monster class, it is crappy code strewn all through the system making it virtually impossible to find. I think the parent post is closer to the truth of what you actually want. When you get new requirements, you want to refactor your design. It should be open to obliteration and closed to a death of a thousand cuts. The main problem with the open/closed principle, from my perspective, is that it perpetuates the idea that we should try to minimise code churn. Many people will read that and think, "Well, duh. Code churn is dangerous." But every time you minimise code churn, you add a design constraint. At best, this design constraint will lead to the pile of straw on the camel's back. At worst, the workarounds imposed by avoiding change necessitate more workarounds, slowly adding exponential growth to the complexity of the system. What I would like to replace the open/closed principle with is a principle that says "Do not nail your APIs to the wall". They must change, if you are to maintain simple code in the face of changing requirements. Sometimes you must solidify an API, but you should always delay that decision as long as possible and you should limit the extent as much as you can.
- catnaroek 10y ago> 'L' is deeply confusing, and the difficulty in understanding it is what leads to the deep and brittle class structures above. Weird. 'L' is a very intuitive statement: If a property holds for all instances of a supertype, it holds for all instances of any of its subtypes. In modern terms, it could be stated as “predicates are contravariant on their arguments” [0], but the basic idea was was well understood as far back as in Ancient Greece [1]. All the issues with 'L' disappear once you properly distinguish between inheritance and subtyping [2]. As the OCaml reference manual says [3]: “Be aware that subtyping and inheritance are not related. Inheritance is a syntactic relation between classes while subtyping is a semantic relation between types.” Although OCaml has structural object types, the idea also works with nominal object types: In Java, a subclass that overrides a non-abstract method ought not to be considered a subtype of its superclass. If I told you “a zebra is kinda like a horse, except it has stripes”, could you conclude that zebras are horses? It's amazing how effectively logic clarifies issues with programming languages. [0] https://www.schoolofhaskell.com/user/commercial/content/covariance-contravariance https://www.schoolofhaskell.com/user/commercial/content/cova... [1] https://en.wikipedia.org/wiki/Term_logic https://en.wikipedia.org/wiki/Term_logic [2] http://www.cs.utexas.edu/~wcook/papers/InheritanceSubtyping90/CookPOPL90.pdf http://www.cs.utexas.edu/~wcook/papers/InheritanceSubtyping9... [3] http://caml.inria.fr/pub/docs/manual-ocaml/objectexamples.html http://caml.inria.fr/pub/docs/manual-ocaml/objectexamples.ht...
- tunesmith 10y agoI don't see how it can be argued that 'L' is intuitive to intermediate level developers. Even for senior developers you still have to stop and think rather than trust your gut. Developers will very intuitively see the bass class as the one that handles the most common cases, and subclasses as the exceptions that "override" and vary things a little bit. My favorite example is the Doctor that can see all patients, and the Pediatrician that sees only children. Intuition would make Pediatrician the subclass of Doctor, when it should be the other way around. [1] [1] http://closuretools.blogspot.com/2012/06/subtyping-functions-without-poking-your.html http://closuretools.blogspot.com/2012/06/subtyping-functions...
- catnaroek 10y ago
- amouat 10y agoKevlin Henney gives an excellent talk called "SOLID Deconstruction" with a similar set of objections https://vimeo.com/157708450 https://vimeo.com/157708450
- jpfed 10y agoI think that S, O, I, and D are all kinda nice guidelines. But if one's code does not respect L, it is simply incorrect. It implies falsehoods.
- talideon 10y agoLSP (the 'L' in SOLID) gets a bad rap only because it's typically couched in terms of classes and inheritance these days. However, if you know anything about Barbara Liskov's work, you'll know that's entirely the wrong tack to take. If you're just using interfaces, it boils down to this: if two things implement the same interface, you should be able to substitute one for the other without it breaking everything. So no, it's neither confusing nor difficult, except in so far as maintaining substitutability requires discipline. 'I' is something that's already encouraged within the Go community.