18 Mar 2012
The real problem with OO is taking it too far
I just finished watching this talk by Jack Diederich (Python core developer) – somewhat flamebait-ishly named “Stop Writing Classes”. In his talk, Jack shows, through various examples, how introducing a class just for the sake of it actually makes the code harder to read and maintain.
While reflecting on the talk, I realized that the actual problem here is that people take OO too far. I don’t know how OO is taught elsewhere in the world, but from my own experience, a large part of this abuse can be attributed to the way OO is preached in various CS courses. A lot of emphasis is placed on grilling into young heads the virtues of OO and it’s place in the big enterprise world, without actually explaining why OO works when developing large applications. And, do courses on OO actually highlight when it does not work?
In interviews, when asked to solve a tricky problem, I find it disturbing that people immediately start off with skeletons of classes. It has become some kind of protocol that one should be modeling everything in classes and objects to come off as a competent software developer. Jack shows a succinct solution to Conway’s game of life problem. A solution that highlights the programmer’s knowledge and elegant use of Python’s yield, but which will probably be rejected as “poor procedural code” in a lot of places.
In many ways, OO has become a safety belt. By having a few classes, atleast no one can fire you for writing procedural code right? If poorly written procedural code is death by repetition, poorly written OO code is death by multiple levels of insane abstractions.
One technique that has worked for me when solving a problem from scratch is to first actually solve it by using functions that perform highly specific operations. As the solution evolves, I start identifying fragments of code that can either be pulled into a separate class for better abstraction or moved from one class to another. This way, my code moves towards object orientation based on actual need, rather than because of a hypothetical high level “modeling” of the problem. This way, I also don’t end up with a class like this:
class Foo(object): pass |
Simply because I (hopefully) would have felt stupid refactoring something, anything to that.
TDD as if you mean it follows a pattern very similar to the one you described.
http://cumulative-hypotheses.org/2011/08/30/tdd-as-if-you-meant-it/
Thanks for the link. Yes, TDD, when viewed this way is far more logical than as a mandate.
I totally see where you are coming from and I get that OO code is actually usually more maintainable but bad OO code is just as bad too.
I have been pulled up on this in the past and I think sometimes 5 lines of procedural in a method is far easier to maintain than one thing per method/function which is generally what good programming teaches us.
I personally what makes a good coder isn’t the ability to make complex code, solve complex coding issues, following strict coding rules or the latest standards. I think a good coder is someone who writes code for the majority of programmers out there.
TDD in my opinion sometimes stifles the end goal and gets you designing in an illogical way. From what I have seen most TDD ends up with some nice code and a tonne of just bolted on hacks to get the tests to pass.
But aren’t you kind of pointing out that the problem with OO is actually doing it poorly?
“POORLY written OO code is death by multiple levels of insane abstractions” (emphasis mine)
I agree with you that the problem perhaps starts in academia; I’ve never seen a straightforward explanation anywhere – let alone in a course about OO – as to how one should be distributing the responsibilities of one’s code. I feel a lot of the backlash, however, is the result of over-exposure to bad OO code. OO, like sooo many other things we deal with in CS, is merely another tool that is appropriate in some cases (and not appropriate in others). A reliance on Cargo Cult Programming, however, leads people to think that the work is done after they type the word “class”.
I also happen to believe, however, that once your application grows beyond a certain size, it will be more difficult to manage if it’s all procedural.
In reality I think the ideal reason for modeling with classes is to more closely fit with how the mind works, as we can only hold a handful of disparate concepts in our minds at once. In this light we use the model (whose real medium is thought, by the way, not code) to work out code inconsistencies through real world example exercises, and to mercilessly trim where possible.
As pragmatists, we should be doing everything involving code based on “actual need”.