Why I love everything you hate about Java
magicscalingsprinkles.wordpress.com
magicscalingsprinkles.wordpress.com
The statement "function composition is a degenerate case of the Decorator pattern" in the blog is bizarre to me. OO languages like Java have to resort to the Decorator pattern to handle their lack of composibility; that seems far more degenerate than a language that supports this kind of composition without hacks.
Also this article is 2.5 years old.
The article reads like it was written by somebody with experience in Java and Scala, but not much more.
Hey there Mr. Strawman.
I write mostly Ruby, and I use dependency injection, factories, and decorators liberally. There's nothing in Ruby that makes these any harder than they are in Java (in fact, I'd argue they're easier.)
Two years ago, when this piece was written, the author had more of a point: some people rejected anything that reminded them of Java out of hand, including design patterns.
These days, I'd argue that interest in classic OO design ideas is experiencing a massive resurgence in the Ruby world.
I don't know about that. I see a whole lot of functional paradigm chatter these days. That wasn't true 5 years ago as I recall.
Then again, I suppose it depends on what color your glasses are: If you're a classic OO devotee you see most of the techniques being put forth as classic OO, and if you know a bit about FP you see it all as the stuff that FP has always been made of, the stuff that OO gurus who cut their teeth on FORTRAN neglected to mention came from FORTRAN.
Here are a few recent examples hinting that the Ruby community is moving on from "Fat models and skinny controllers" to the beginnings of really teaching each other about classic OO...
http://www.confreaks.com/videos/1115-gogaruco2012-go-ahead-m...
http://www.confreaks.com/videos/1233-aloharuby2012-refactori...
http://www.confreaks.com/videos/1112-gogaruco2012-sugar-free...
http://www.confreaks.com/videos/1133-scrc2012-thinking-in-ob...
I'm less certain that DI is "wrong" in Ruby, although it's definitely unidiomatic.
For example, I use factories to create test objects that are complicated to set up (using a gem named factory_girl, actually).
Also, in Ruby, every class is a factory for its own instances. If I define a class called User, I can assign the class object User to a variable:
factory = User
Then I can call
factory.new
and receive a new User instance.
As for DI, it's not wrong, nor is it unidiomatic. Plenty of folks in the community use it, and often.
A commenter elsewhere in this thread says that DI is unnecessary in Ruby because you can just reopen or redefine a class whenever you want. That's technically true, but isn't a good practice, as it can lead to some rather rapid foot shootery.
If you want to swap in different-behaving dependencies, DI is a straightforward choice. Reopening an existing class and mangling it can cause very confusing behavior, and is generally avoided by experienced Rubyists.
Regarding DI: Jamis Buck infamously used DI for net/ssh and posted that he regretted doing so, because DI felt out of place in Ruby. I'm not spoiling for an argument about its virtues.
Regarding "experienced Rubyists" and reopening classes, I think you should have a look at activesupport/core_ext.
It's been said that every programming pattern is a programming language design flaw. This is evidence in favor of that.
Have't tested it yet but it makes a lot of sense.
Redefining a class isn't dependency injection it's a hack to get the compiler to stop complaining. It works but it's very unclear to the person reading the program that a class your code depends on was actually redefined somewhere else.
For testing purposes placing this mock class somewhere at the start of your code is clear but only ever practical in that scenario.
I can also imagine that some programmers might not even think of the possibility that some code they depend on was overridden somewhere else.
In real maintainable code where you want to swap out behaviours it's nice if there was a special way of defining your dependencies. This is the same for all languages.
Deject offers a way so you don't have to fiddle with constructors but instead you have handles in your classes that you can override with different behavior if needed.
TL;DR: Yes, Ruby is powerful and you technically don't need IoC containers. But to make it maintainable for everyone it's a good idea to do so anyway.
I must have blinked and missed whatever happened that made everyone think global variables are now all the rage.
Most Ruby books I've read that have been published in the past couple of years seem to disagree.
Emacs felt slow, clunky, last-century and everything which could be light, nimble and cool Emacs made feel boring and hard. I did not get to like Emacs back then.
In fact I've gone years and years and years actually never fully liking emacs, beyond it being simpler to use than vim (which I still consider insane) while readily available on most shells. It was a safe haven, although a unpleasant one.
Recently though, I've dabbled in clojure. Eclipse is really not good for clojure development. Especially not so for learning how things works under the hood. So emacs is seemingly the lingo-franco in clojure circles, and I was forced to return to my old Java-related enemy. Or at least so I thought.
Out of the box, almost nothing is optimal for clojure development. So you have to add packages (emacs supports packages? nice!), you may have to tweak init.el to do so (emacs is configurable and programmable through its own lisp-dialect? nice!), oh and you may want to add some repos and map package-install over this collection of useful pacakages (no way!).
Once you're there and getting productive, you might encounter things you don't like. Google it and find ready-made lisp-code to import into your init.el, and your problem is solved.
I guess that's not really directly related to this article, but before heading to HN now, I had the realization that emacs, despite it being the horrible tool which Java made me hate, is actually pretty awesome.
You need the right perspective to fully appreciate something. This is crucial and something Java taught me this, although in the wrong way. And just as I realize this, then I see an article about Java and perspective.
I like cute litle coincidences like that :)
https://github.com/technomancy/emacs-starter-kit
On top of this I've added some tweaked versions of yank-indent and indent.el from the emacs-wiki:
http://emacswiki.org/emacs/AutoIndentation
On top of that, I've just added whatever tweaks and hacks necessary to get screen & emacs behaving properly in a FreeBSD shell, since currently my best and most powerful internet-facing host is a FreeBSD machine.
So as you can see, most of it is repo'd already :)
I use C to really get what happens on the metal. I use C++ to leverage C and C++ libraries for perf critical applications quickly. I use Java like C++ where it makes more sense - Android, or availability of libraries etc. I use Python to prototype and quickly express complex ideas and determine their perf characteristics. I use Javascript for frontend web dev which communicates with json back-end APIs that are language/platform independent services that scale out horizontalty.
I have 2 main rules.
If the question is to learn one important thing or another - I learn both. Then when I come across a new problem I solve it with a combination of the tools at my disposal.
Hence this is why I am currently learning Emacs, lisp, clojure, Scala and Haskell to round out my languages with maybe a little Ruby thrown in. This will take me a few years.
In the end programming is just about getting things to screen quickly and correctly. Seen from that viewpoint most languages are very similar at heart.
The Haskell vs. everything else language war really is important though. All the languages you mention are basically the same thing with slightly different syntax or a slightly different runtime environment. Haskell, on the other hand, revolutionizes the way you approach code. Or at least it did for me.
What is remarkable about Haskell is that it builds upon bleeding edge programming language research. While I think that Haskell vs. everyone else is just another language war, I find it a real pity that "mainstream" languages seem to categorically ignore everything that programming language and compiler research has come up with in the last 30 years.
I'm still waiting for someone to find a sweet spot between Haskell and the more mainstream languages. A language that has a dynamic feel to it but is a statically typed (with type inference, of course) safe language that compiles to fast and efficient native code.
Don't get me wrong - I enjoy it. But I've learned a few things throughout my life. First, the one true crowd is always wrong. Two, if it's so good - use it, and prove it.
A lot of functional stuff is a ton of gushing talk - but no product walk.
When Haskell runs on billions of devices or serves trillions of pages or produces trillions in revenue call me. Otherwise, I'll just keep shipping with my lame proven product producing languages.
Functional languages have so far been all talk and no walk.
Once upon a time, at my old company, a guy came to an interview. He was very experienced in PHP, having used it to build websites as a freelancer for something like 10 years. Did he know object-oriented programming? He'd heard about it, it was probably good for larger teams. Because he'd just been working with the same techniques all these years. And the sad truth is, your average programmer is likely to be like this guy. In which case, you want to give him a solid language, which is aimed at preventing him from shooting off his own foot, and does not feature many complicated concepts, like Java.
I'm not sure whether Haskell is really that great since I've never got around to really learn it (though I'd love to once I have enough spare time) but I think the dominating languages will be C-likes for a long time. Haskell is too far off from what average Joe Programmer is used to. Most people don't care about a new approach or don't want to invest time learning since the tools they use already work great.
I've learned a few things too, among them, that the majority usually isn't as right as you'd think. Especially in crafts like programming there are habits involved and habits are hard to change. Me, personally, I really like Haskell from what I know about it, simply because it's different.
However, I think there is no "one true paradigm". OOP goes horribly wrong for some things, just as Procedural gets horribly complicated for others and I'm pretty sure Function has a few drawbacks as well. Our real problem is the "use this, not that" mentality. Use what is appropriate for the problem you're trying to solve. That's why I like multi-paradigm languages like Python.
In Haskell, you can write functional code. If you squint a bit, and don't mind some awkwardness, you can write imperative code. (Actually, in my experience, even the imperative code you can write in Haskell is fairly elegant.) Sure, it does not support OO-style code without crazy contortions. On the other hand, it can support other styles like non-deterministic or logic programming.
As the OP demonstrates, it's quite straightforward to write Java in Scala. At my company we mostly write Haskell in Scala. And having played a bit with Akka, I'm beginning to write Erlang in Scala.
What I'd love to see is a multi-paradigm language that isn't so ugly.
All that means, and all that ever meant, was that the entire language worked around pushing static data into static functions and giving static returns.
I can do that in C, C++, Python, Java and Javascript. The only difference is that it is really the only way I can use Haskell - whereas the other languages are highly flexible, adaptable and actually help me ship product. Most of my APIs work essentially like Haskell - static pre-determined data in, static data out - and the back-end implementation is irrelevant for consumers.
My understanding is that you claim that all these languages can be made to offer you the same benefits as Haskell. I hope I'm not misrepresenting your position, but this is preposterous.
None of these are built around the concept of dumb, immutable data structures and stand-alone function (C/C++ can work with immutable data structures, but most data structures I have seen are mutable). Java is almost completely designed around mutable data structures with associated behaviour (objects), up to the point where you don't have standalone functions.
So, sure, you can have copy constructors everywhere, and static methods (say bye bye to dependency injection...). But it's not idiomatic code. You are fighting against the language and the ecosystem, and the only thing that will likely result is inefficient, bloated code which will get refactored out when it needs to be modified by somebody else than you.
Now, maybe you limit this to your API, but claiming that "the backend implementation is irrelevant for consumers" is a cop-out. Immutable data buys you safety. Maybe you know your code is safe, you don't have any dangling pointer issue anywhere, no concurrency issue, etc. Unfortunately, this might very well not be the case next time you or somebody else refactors your code.
There are certainly reasonable arguments to be made against Haskell (learning curve, Cabal, size of the ecosystem, difficulty of reasoning about performance...). But claiming you get the same benefits in terms of safety out of traditional imperative languages is not one of them. Not to mention higher-level functions, etc, that you certainly are not about to experiment in Java.
The underlying principles however are damn good, but they are not enough to salvage it.
Java? I can see the appeal. It's really come a long way. The only thing I can't get over about Java is the goddamned verbosity of it. It's _excruciating_ to write anything in Java.
Yes, I know. Use a modern IDE. The namespaces are designed that way for a reason. Just deal with it. It's not a product of Java itself but of the libraries. Blah blah.
It's still a painful environment to deal with and, with developer time several factors more important that just about anything else, I value my time highly and I'm not going to waste it on AbstractSingletonProxyFactoryBean bullshit.
Now, yeah. If you're a huge corporation that is bumping up against the law of large numbers, where most of your developers are mediocre and yet still have to work together, then I guess Java is OK.
One thing that does frustrate me is that the compiler enforces a target bytecode level at least as high as your source version. Meaning that even the simpler syntax for initializing generics isn't allowed even though it's pure syntactic sugar and has no impact on the generated bytecode.
Does anyone have evidence (including anecdotes) that Java 7 is simple enough for mediocre developers? Every new feature in Java that I have seen, starting from and including generics, seem like the non-orthogonal hacks that make C++ so frustrating to learn.
FWIW the original, by Rich Hickey, seems to have been "Patterns mean 'I have run out of language'".
Cited here - https://google-styleguide.googlecode.com/svn/trunk/lispguide... - but I can't find an original source.
Clojure has futures too, but the syntax isn't as clunky as Scala or especially Java. All these synchronization primitives are in basically every other language. Maybe I'm missing something but I don't really see what is special about Java here. Has the OP ever tried any "hipster" languages, he might be pleasantly surprised if he did.
dependency injection : currying
factories : type constructor
decorators : higher order functions
there's nothing wrong with DI and the like. what's wrong is the way it's done in idiomatic java. when you do DI in idiomatic scala, there isn't much of a problem.How do any of your analogies work?
http://mikehadlow.blogspot.jp/2010/03/functional-dependency-...
Opinionated frameworks which hide stuff from me are bad. They're good for initial productively, but you pay the price later - you have to understand it to weak it, and may find the architecture doesn't fit your problem.
On the other hand, writing a Spring config file from scratch is a horrific process, especially without the Spring eclipse plug-in.
But now that I understand web.xml's and application-context.xml/*-servlet.xml, and have written plenty of Spring config, my productivity is pretty damn good. So why should I care.
So I wonder if Java just gets the blame because it is the most pure object oriented language. It doesn't put up walls preventing you from doing what OOP really wants you to do. C# is the same way, by the way, you see IThisOnlyExistsToBeGeneric<T> all of the time; AbstractControllerBase is a real class in C# MVC if I remember correctly.
What walls does Ruby and Python have that prevents this? Because I see no reason why people aren't doing it.
As for JavaScript, the fact that people tend to use sealed closures is not a defining characteristic, anymore than having final classes. JavaScript has Prototypes, and they can be extended just fine.
"[java]’s a pop culture. A commercial hit record for teenagers doesn’t have to have any particular musical merits."
And if you do want some logic in the factory, you can just create one without changing the interface. Callee doesn't care when calling x() whether x is a type, factory, or something else. As long as it returns an instance, everyone is happy. (that makes factories disappear from the signatures)
What does your pattern add to that?
- Play Framework http://www.playframework.org
- Jersey http://codahale.com/what-makes-jersey-interesting-parameter-...
- GWT https://developers.google.com/web-toolkit/ or
- Grails http://grails.org/products/ggts
for example?
Not saying any of these are perfect, but it's been 5+ years since anyone had to use JSP/Servlets/Struts.
edit: formatting
Source: I worked at a Web startup circa 2000 where we did exactly that. I think people sometimes forget how far we've come.
http://arantaday.com/the-modern-java-ecosystem
And a bunch of comments here:
This is pretty much why I find Java (and others at similar levels of complexity) distasteful and try to steer clear of anything related to it. It is also why Go appears to me as attractive: it has simplicity everywhere.
At that point you've just added unnecessary bloat.
There is something nice to be said about code that works right off the bat with sensible defaults.
In the article, replace "Factory" with "Middleware" and "apply" with "call" and it's just like what we do in the ruby community.
It's mostly about why I love Clojure's partial / Haskell's currying.
Yes, I see why wee need partials and can't have currying by default. It would seriously mess up destructuring. Yes, I get that. I still miss it though.
The problem is though, when doing it with modules instead then the points he is trying to make totally disappears.