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

At the risk of being offensive, I've always felt that this "design patterns" cargo cult is Revenge of the Not-Nerds. The people who couldn't hack the harder CS classes because of all the math are striking back with something designed to be as incomprehensible to us as mathematics was to them.

Take the Visitor pattern. I mean, really? I already know how to work with trees. Lisp is all about trees. Ocaml lets us build tagged-union types and pattern match to our hearts' content. Do we really need to dickshit the program with Visitor? WTF does that even mean? Who is visiting and why? Is this the French meaning, where to "visit" someone is patronize a prostitute? (In French, you "pay a visit to" someone, or rendre visite à quelqu'un. You don't "visit" your sister.)

The design patterns cargo cult is horrible. It has such a "how the other half programs" smell about it that I cannot shake the belief that it was designed to make us Smart People pay for something. Anyway, how can it be "best practices" if I can't REPL the code and make function calls and see how the fucking thing works? If you can't interact with the damn thing, you can't really start to understand it, because it's almost impossible to understand code until you know what you're looking at. IDEs just give people a false sense of security about that.

Personally, I like functional programming because it has two design patterns: Noun and Verb. Nouns are immutable data. Verbs are referentially transparent functions. Want side effects? You can have them. Those are a separate class of Verbs: Scheme denotes them with a bang (e.g. set!) and Haskell has them in the IO monad. Real-world functional programming isn't about intolerantly eschewing mutable state, but about managing it.

Now, I'll admit that mature codebases will often benefit from some solution to the Adjective problem, which is what object-orientation (locally interpreted methods instead of globally-defined functions) tries to solve. OO, at its roots, isn't a bad thing. Nor is it incompatible with FP. The Alan Kay vision was: when complexity is necessary, encapsulate it behind a simpler interface. That's good stuff. He was not saying, "Go out and build gigantic, ill-defined God objects written by 39 commodity programmers, and use OO jargon to convince yourselves that you're not making a hash of the whole thing." No, he was not.




The real use case for the visitor pattern is to simulate multiple dispatch in a language that only has single dispatch. In a language like Java, if you want to traverse a tree where each node can be a different type, you don't really want to use a series of if-statements for every single type, so the visitor pattern is used in this case. The visitor pattern allows you to use method overloading instead for each different type instead.


That's one useful case, but the primary use case is keeping your code clean. If it isn't keeping your code cleaner, you're probably doing it wrong.

Serialization, for example, is a spot where the visitor pattern is useful. Take the example of a fairly complex hierarchical document - maybe something like a Word document. You need to support being able to save it to a whole bunch of different formats, and you want to do it as simply as possible.

- Hard-coding the save functionality for every possible format into the document classes themselves would be a mess, and would quickly pollute the data structures with a whole bunch of clutter. That violates the single-responsibility principle.

- Writing completely independent serializers for each format would be somewhat cleaner, but the serializers would end up containing a mess of repetitive code. That violates the DRY principle.

The Visitor pattern is nothing more complicated than a way to keep the code cleaner and more maintainable by factoring all the common elements of the task (saving, in this case), so that your code doesn't end up littered with a bunch of unmaintainable copypasting.

This shouldn't be anywhere near as difficult as what the grandparent suggests. In an object-oriented language, just create an abstract "DocumentSaver" class that has concrete implementations of all the common stuff, and abstract methods for all of the stuff that needs to be different for each file format. Then create subclasses for each of the save formats and voila, you're done.

I think the grandparent is absolutely correct that this is a pattern that is probably unnecessary in a language with algebraic data types and pattern matching. But to say that this means a pattern like Visitor is therefore a hallmark of being a bad programmer is unfair, if not downright risible. Most of us work in mainstream languages - and mainstream languages just don't have those features. For us, Visitor is an easy idiom for reclaiming some of the benefits of that functionality. And frankly, it should barely take more code to whip up a Visitor than it takes to pattern match your way through the problem.


The visitor pattern is a convoluted alternative syntax for "switch".


Why do you need all this complexity in order to do that?

I feel like one of Java's problems is that these design patterns have taken it away from the language's intended design. It wasn't intended to be a dynamic language. Most of Java's ugliness is an extremely incompetent Greenspun's Tenth Rule: solving of problems where the solution is "use a different language, like Clojure or Scala".

There are occasions where Java and C++ are the right languages to use, but most of the time when people are using these over-complex frameworky solutions, it'd be much more elegant to use a different language, and the code would be more legible.


Mentally rewriting the beginning of your last paragraph to "Sometimes Java or C++ is the right language to use, but most..." made it make considerably more sense to me.

As it stands, I think the double-aren't is colloquial or a mistake; I honestly couldn't follow the meaning of the overall triple-negative. :) Not trying to be a jerk - I love reading your stuff, but I spent more than a minute thinking about that sentence before just guessing it from the rest of what you said.


Good catch. It was a mistake. Two or four negations would have been semantically correct (if ugly). Three is wrong.


Design Patterns: 1994 [1]

Java: 1995 [2]

Scala: 2003 [3]

Clojure: 2007 [4]

Unless these hypothetical developers of yours are time travellers, your proposed solution wasn't an option for more than half of Java's life. Sometimes Java is 90% of what you need and you just get on with the other 10% because the alternative (learning a new language, finding a new team or training an existing team to use it correctly, etc.) is simply not worth it to anybody with real world time/quality/scope constraints.

[1] http://en.wikipedia.org/wiki/Design_Patterns

[2] http://en.wikipedia.org/wiki/Java_(programming_language)

[3] http://en.wikipedia.org/wiki/Scala_(programming_language)

[4] http://en.wikipedia.org/wiki/Clojure


But we're in 2013 now. Not 1994/1995 anymore.

I don't care if in 2002 I couldn't use Scala. That was 11 years ago and it's not exactly an excuse for not using Scala today.

There are companies working in finance today who are switching entire Java teams to Clojure. It's precisely because they have real-wold time/quality/scope constraints that they are doing so.

Most Java codebase became what Rich Hickey calls "The elephant in the room". By switching to Clojure they can reduce the size of their codebase by a factor of ten, making the elephant easier to manage.

So we're back to square one: the real issue is that there are still people regularly posting links to "design patterns" and "dependency injection" that get upvoted because a large part of HN only knows about Java/C# + ORM + XML + SQL hell...

As long as people will be doing that, you'll be able to use your argument: "but, hey, in 1995 it was all the rage!".


IMHO, Java combines the worst of statically typed and dynamically typed programming languages. To paraphrase Rob Pike, programming in Java is like dotting all the i's and crossing all the t's in a fairly complex contract but at runtime, the contract can be overridden by dynamic classloading. So you do not get the efficiency of a statically typed language (because the compiler cannot make certain assumptions about the types / classes) nor do you get the expressiveness of a dynamically typed language.

In the case of DI, I would observe that no programs in other languages seem to require or even use this pattern. If you need to implement LGPL at the language level, a better abstraction is modules with contracts... or even better a proper metaobject protocol a la Lisp.


DI is also used quite heavily in C#. And in most - if not all - functional languages, one of the flavors of dependency injection (what a C# programmer would call method injection) is so pervasive that it doesn't even have a name. People just think of it as an idiom rather than a design pattern.

If I may speculate, I suspect that the reason why DI is discussed so much more in the big enterprise programming languages isn't because of the languages so much as the problem space. Enterprise software has a tendency to be enormous, live for a very long time, and involve stitching together components from a variety of sources, none of which are being modified or replaced on exactly the same schedule. Hard-coded dependencies always have the potential to be a maintenance hassle, but that kind of situation compounds the problem immensely. The promise of DI - that if you follow it scrupulously you can produce software that's so easy to modify that you might even be able yank out and replace entire modules without so much as a recompile - becomes very attractive in that kind of situation.

It's also a huge win for huge teams. If you make good use of dependency injection then it's easy for different teams to develop different modules that depend on each other in parallel. All you have to do is whip up some stub implementations of the modules that aren't available and get to work.


> Personally, I like functional programming because it has two design patterns: Noun and Verb.

Erlang's OTP certainly has some very clear ideas about "design patterns".

Design patterns are nothing more than sensible ways of putting stuff together, which seem to exist in any language.


What you have just said is one of the most insanely idiotic things I have ever heard. At no point in your rambling, incoherent response were you even close to anything that could be considered a rational thought. Everyone in this room is now dumber for having listened to it. I award you no points, and may God have mercy on your soul.


>Take the Visitor pattern. [rant about the visitor pattern]

I don't think the visitor pattern means what you think it means.[1] Also, calm down. It's a beautiful Sunday afternoon. Perhaps you should pay a visit your sister.

[1] http://en.wikipedia.org/wiki/Visitor_pattern




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

Search: