Hacker News new | past | comments | ask | show | jobs | submit login

This is great but it brings up a serious question I've always had. Taken to the extreme, things like the single responsibility principal, the open closed principal, etc, result in messes like this. I've been wondering if anything has been written around a concrete methodology of doing OOP that doesn't naturally converge onto something like this, and why it happens.



You might enjoy this: http://mollyrocket.com/casey/stream_0019.html

I think the problem is that OOP is automatically considered "virtuous", despite the context. There's nothing wrong with the single responsibility principle and what not, but there is something wrong with thinking that classes and objects are always the best way to approach a problem. Java ends up being the target of jokes because by forcing everything into classes/objects even when it doesn't make sense, it leads to cartooned versions of those ideas.


I believe that humans are terrible at predicting the outcomes of complex systems over time and that software you get paid to write is always a complex system. Therefore, the best way to make your software better is to choose the option that produces less state. This has been my guiding principle of software development for about 6 years. The main problem I ran into is that going too far results in software that's hard to maintain because control flow jumps around.

My solution has been to think of code locality as being valuable. I start off writing something the straightforward way. When I go to implement something similar, I decide whether to abstract the code or not based on how much easier/harder it will be to naively trace the code. If I've done this thing 3 or 4 times, it's a concern and should be separated. If I'm just making something shorter/"nicer"/DRYer I should probably just write stupid code.


It is fancy around these parts to bash OOP and other things that aren't JavaScript/Clojure/Haskell/Rust/etc;

DRY, SRP, LSP, OCP are very valuable. There's a reason there's a score of enterprise-grade software being written with exactly those principles in mind. I am not discounting Functional Programming in anyway. But to dismiss OOP and the design patterns is a fool's errand. It has its place, and rightly so.

Look at what the programming Lords (Ken Thompson! Rob Pike! Lars Bak!) at Google came up with when they sat down to design a language-- Go (which is part-OO, part-imperative [1]), or Dart (OO again). OO detractors often point out that "popular opinion isn't always right" and that "people are afraid of change" and there's some level of truth to that, but the fact is, a lot of developers out there are proficient with OO, and see it as a good way to develop massive programs (1 million plus SLOC) unless some radical shift happens in the coming years [2].

[1] https://golang.org/doc/faq#Is_Go_an_object-oriented_language

[2] http://worrydream.com/LearnableProgramming/


The problem isn't that those principles are bad - they're useful - but the languages we're attempting to use them from are not sufficiently expressive enough to follow them all in a practical way. "Design patterns" and DRY don't mix very well - because the act of implementing a design pattern is largely repetitious. We create XFactory, YFactory, ZFactory for example, with largely the same structure but slightly different logic - then someone takes DRY to the extreme and tries to abstract it away into a FactoryFactory, using reflection or some other tool to get around the host language's lack of expressivity.

This is where the mess begins, because it becomes so cryptic to figure out how to use the FactoryFactory to create your own Factory to create some other types you need. It may be trivial to people who've been hacking with the same languages and frameworks for years, but the principle of least surprise is abandonded for new users attempting to use a framework for the first time.

Functional programming suffers from the same overuse of idioms which are unwelcoming to novices, and often throws away some useful ones in favor of ease of use. FP doesn't necessarily dismiss OOP, and it's often used in combination with functions to write practical programs.

Functional programmers don't see OOP as a problem - it's a very practical tool. The problem is that it's the wrong tool for many problems - particularly if you're just computing functions[1]. That a lot of developers are proficient with OOP and see it as a good way to develop programs is part of the cause - they're blind to alternative methodologies and shoehorning something into an object where it doesn't fit is seen as a being skillful. Also, anything that doesn't conform to the language's narrow view of "the right way" is considered an anti-pattern.

[1]:http://www.yegor256.com/2014/05/05/oop-alternative-to-utilit...


You imply the problem is one of fashion (those kids will see the value of OOP once they get over their javascript phase!), but I think OOP was basically a fashion in of itself. Essentially what we think of as OOP is just taxonomy mixed with structures that carry around function pointers. Yay? It's a nice wrench to have in your toolbox, but it shouldn't be your only tool. The notion that the people that helped invent all this in the first place are continuing to do that doesn't really make me think the principles are sound.


Is C++ OO? If you say yes, defend your position, given that Alan Kay disagrees.


SOLID are not rules but guidelines. Design patterns allow the code to be written in a reusable manner by decoupling some responsibilities. But YAGNI, no code should be written until it is needed.

That's why TDD is absolutely fundamental. In theory TDD can help fight over-engineering, and keep focus on relevant code. SOLID and design patterns are then here to help refactor code when a spec changes. They are recipes.

Obviously TDD fizzbuzz done correctly would have resulted in a single class implemented. Now imagine requirements changes and booze should be printed if the number can be divided by 20,breeze if the number can be divided by 40,bubble when divisible by 56, the easiest way to refactor that single class would be to introduce a CHAIN OF RESPONSIBILITY. Which again is not necessary at first place, if the number of cases remains small.


TDD means you write code that is easy to test, rather than easy to adapt to your use case. Find the use case for your code, code that (and now more), add tests as desired/needed.

In your example we can observe that we still only have one action: print $VARIABLE if $COUNTER mod $VALUE. This doesn't call for anything like a chain of responsibility, since it can be solved by a collection of tuples and a for loop.

My personal guess about the difference between an average programmer and a good one is that the good one knows when to add space for more features (because he can anticipate the customers needs).


I think there's a lot of truth to this. Adding flexibility on one dimension almost invariably makes other kinds of changes more difficult, so you come out far ahead if you can correctly anticipate the direction in which your application is likely to grow.


There is always a time when you go too far and a time when you don't get far enough. If you can, you refactor when it becomes clear.

In the case of Spring though, they have a tough problem to solve. They are gluing technologies together, so they are always going to have factories of factories, adapter of adapter, and that kind of things. And if in the bunch of tech they glue there is an outlier that behaves unlike the other, or a poorly designed one, they will need to handle it somehow.

Another feature that weights on Spring design is that almost the whole framework is public. Generally you would have a core architecture and well defined key extension points. Not with Spring, and that means more "useless" abstraction and therefore more mess.


I use Spring and I'm not agree that it's a mess. It has a lot of functionality but good architecture allows to keep it under control and easily enhance when needed. Spring is one of the best open source frameworks I've ever seen.


Both Spring and JavaEE (as compared to J2EE) have gotten a lot better by using annotations for meta-programming. I was about to give up on enterprise Java programming when the clutter/over-engineering started to get better.

Curiously, I'm going to at least partially credit Ruby for introducing the idea of convention over configuration.


Why curiously? RoR hit hit java web development like a ton of bricks, with its convention over configuration and quick start. The end result are java projects like Play and Spring Boot.

I am not really a ruby guy, but I'm very thankful RoR came along and shook things up.


I don't mind these kinds of guidelines until someone tries to use them to support their argument as if they were scientific facts.

My favorite example is the single responsibility principle, which, while a useful guideline, is 100% qualitative. All classes and functions do more than one thing.

Is making a sandwich one thing? Is putting mustard on the bread one thing? Is opening the mustard jar one thing?

The exception might be if you had a function call bitFliper that turned 0s to 1s and vice versa. But that's probably as close as you could get in most programming languages.


Unfortunately, it's more of an art than a science. The simple rule is: it should be as simple as possible, and no simpler than that. Obviously, everybody has a different idea of where exactly that line is.

Usually though, if you try to make the code clean and as small as possible while still allowing unit tests to be written, you normally hit a decent spot. YAGNI applies very heavily here too and it's often better to make the code less generic and refactor it later when required.


OOP is seldom the best model for software construction. A model (using relational, graph, set operations, etc.) can be implemented using enties given in an OOP language but if the software engineer 'thinks in objects' mess will probably ensue.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: