Saturday, September 4, 2010

My issues with Spring

One of the things I've had to come to turns with as a professional Java developer, is navigating the massive chaos of frameworks out there. It doesn't really matter which corner of the development stack we're talking, in Java we're sure there won't ever be just one official standard; if we're lucky, we can identify a state-of-the-art de-facto standard and if we're *truly* lucky, our choice will remain a good one for longer than a few years.

One of those de-facto standards appears to be Spring. There is little doubt, that IoC (Inversion of Control), or more specifically DI (Dependency Injection), can be a great tool to decouple concrete dependency layers. However, in my opinion Spring introduces just as many problems as it solves, and here's my take on why.

Everything and a Kitchen Sink
While Spring does address IoC/DI, it also does a gazillion other things as well - as evident by looking at the Spring maven repo. On one of the project I was on, my Maven POM ended up holding 15+ dependencies to Spring related technologies, leading me to categorize Spring as containing everything and a kitchen sink. Spring is so many things in one, that it's hard to fathom let alone explain the boundaries; there's Spring JDBC, Spring MVC, Spring Security, Spring Remoting, Spring AOP, Spring DI, Spring RESTfull and probably much more that. Each part may very well be useful in their own right, but one can not help but to be weary of this creeping featuritis.

Abstraction layer madness
Most of the frameworks we use, take the shape of some sort of abstraction layer shielding us from hairy details further down. However, from navigating a Spring projects various configuration files and Stack traces (btw. confirmed by Nasa of being visible from space), I get reminded of a short conversation between two luminaries within our industry.

Computer Scientist Butler Lampson is known to have said:
"All problems in computer science can be solved by another level of indirection"
.

Whereto David Wheeler supposedly responded wisely:
"...except for the problem of too many layers of indirection."
.

In other words, perhaps we should be careful not to get blinded by magic frameworks which, when everything gets added up, turns out to be as much a disadvantage as an advantage. In this day and age, arguably it's the frameworks rather than the programming languages, we spend the most time understanding - but where we should spend our time, is in solving our clients problems.

Configuration madness
The inventor of Java, James Gosling, is known to have said something along the line of
"Every configuration file ends up becoming a programming language"
Now, if you've dived into Spring, you know this is very much true. Inevitably you'll find yourself looking up documentation trying to figure out what XML to write, where to write it and in which order. There's a trend towards depending on intelligent IDE's in order to conquer this type of complexity, but honestly that feels more like treating the symptom rather than fixing the actual problem. This goes for annotations too btw. which is often abused as a type-unsafe embedded DSL sneaked in by language designers who gave up on trying to innovate by adding first-class language constructs.

Conclusion
No bashing of framework overuse can be complete, without a reference to the Hammer Story. While I understand that we do need frameworks and they can indeed help us solve many problems faster and better, Spring is one of those I just can't recommend. Perhaps it's just me and my interpretation of KISS, but since a picture says a thousands words let me end with one.




So if you're one of those who heard about Ioc and DI, but haven't quite made the jump yet, I urge you to try an alternative to Spring, one that does indeed reveal up front how deep the rabbit hole goes. Google's Guice is a good candidate, and it's a testament to its simplicity that it has been ported to other corners of Java i.e. Android.

Update: It seems even Maven is now using Guice.

Update: I had no idea that jotting down my experiences and associated feelings about Spring would cause such controversy. It's clear that Spring is working fine for many and/or is worth the extra complexity. For the record, I don't hate Spring but just find that perhaps we should question whether it's really needed before pulling in dependencies from left and right.

So take this for what it is; a developer questioning whether we can't solve our problems in more elegant and lean ways than what the Spring stack has to offer. I think that often we can. Although at the concrete level I primarily address Spring IoC/DI above, the mere vastness of Spring makes it impossible to go into every aspect even if I had the knowledge to do so. "Pick and choose what you need" is a valid argument of course, but for now I remain unconvinced. Try to imagine the state of your applications dependencies a few years from now. Or try to imagine adding a new green developer to your team and how hard it will be for him to become productive.

The one mantra that truly never failed me is to Keep It Simple Stupid.


15 comments:

Moandji Ezana said...

Spring has become more complex and less friendly than that which it sought to replace - EJB.

+1 for Guice

Oliver Gierke said...

Hi Casper,

let me take at look at this from the other side: Spring is - and always has been - modular from the ground up. Whereas EJB has (yet again) quite lately realized the necessity for developers to rather choose from a set of tools rather than being handed one single one and applying this to each and every problem out there. Software development *is* complex, so developers need choice to find the right tool for the job, not oversimplified "solutions" that hit the wall as soon as you face one extraordinary requirement. I rather choose 15 JARs dedicated to my problem(s) from 50 to get the job done than picking one and end up with a pile of classes on my classpath that ain't got nothing to do with what I need to achieve.

Of course you can use Guice if all you need is DI (or 3 JARs of Spring). But in almost every application I dealt with, a plain DI container would not have been sufficient. Data access, integration scenarios, batch (is there even a competitor to Spring Batch?) JMX, all that stuff gets a lot easier with Spring or its ecosystem projects. A positive effect aside, as soon as you understood the core principles, starting with new areas (integration, batch, web services) is much easier as the programming model is consistent across all ecosystem projects.

A last word on configuration. XML is definitely not the most scalable way to configure your app. But yet again, it's a question of choice: you can use annotations, or even plain Java code to do that. There's plenty of ways to skin a cat and I prefer choice over over-simplification.

To round things up: Spring project (landscape) is a lot more than DI and it clearly states that. So I don't really get the point why this should be a bad thing in general. If you need DI only, its core, beans, context + the logging framework of your choice. So I wouldn't see Spring as one huge Swiss army knife but rather as a toolbox, you maybe only select the screwdriver 90% of the time but in case you need a saw you can be sure, there is one, too.

Regards,
Ollie

Casper Bang said...

Thanks for the criticism Oliver. I know plenty of people with the same arguments as you come with, and they are not bad of course.

However, this post is written by a developer who was more or less forced into a project full of Spring tech - and as I dived further in, I kept asking myself what all of this really solves that I could not otherwise solve with vanilla Java. I HATE the notion that I have to consult a hierarchy of XML files in another hierarchy of Maven modules, to get a sense of how things are wired up when I hit "run".

My favorite IoC is actually using Java's service provider pattern, it's so universal and simple, you don't need a DI container and you can let the classpath (meaning Ant or Maven etc.) determine the concrete dependencies you are pulling in. If we must have configurations, let's not spread them all over.

Regarding web-services, I am not convinced either. Using Jersey (JSR-311 REST reference impl) you get flexibility and features unmatched by Spring. For instance, Spring can not automatically determine how to serialize a java.awt.BufferedImage based on Accept headers, it will instead serialize to an array of java.awt.Point via JSON representation, usually ending with an error. I found out you have to write and register a handler for this but I never succeeded in getting it to work.

So I may be biased, but I much prefer spending my time on the actual requirements of my customers needs than juggling configurations. In any event, Spring is just not for me and I will do whatever I can to avoid it in the future.

Shantanu Kumar said...

Anybody has comments on PicoContainer?

Tim said...

This a very nice article. I'm getting ready to do a beginner's class on Spring and this is a nice article to provide some counter points.

As for EJB, Spring is quite a bit nicer from my perspective because you can run outside the JEE container and easily move around between containers if that's your need.

Spring has a HUGE ecosystem, that's far bigger than EJB or just about anything else. On the other hand, SpringSource is doing some very cool things such as AMQP, Groovy/Grails, and Virgo RT/OSGi.

Since most of Virgo is now an Eclipse project and Spring DM has become Eclipse GEMINI / Blueprint you can see Spring shedding some of it's coolest tech to other groups.

But I'd have to admit, getting started with Spring now would be quite daunting to the newcomer. If someone doesn't understand DI and other Spring concepts, it can take quite a while to figure it out. Granted, a sharp developer can figure it out pretty quickly, especially with all the screencasts around these days, but it's still huge and there are several corners I have yet to dig into.

Andy said...

>Spring is quite a bit nicer from my perspective because you can run outside the JEE container and easily move around between containers if that's your need.

Yes as long as the container you are running in is Spring, a proprietary container. I'm amazed at the logical blind spot that is required to make this argument.

If the ability to take your stuff and play elsewhere is important, doesn't that knock grails out of the picture since you can't take grails code and use it in other environments (its a grails app, the code will always be a grails app).

I don't worry about too much bloat from Spring, any more than I worry about the bloat with Java EE. In both cases, if you aren't using it, it doesn't exist, not on the classpath, not in the server. It may exist on the hard drive but then you can just delete it.

Dexter b. said...

I agree with Andy, the blind spot in the logic used by Spring fans is awkward. Is JBoss AS specific code also portable because I can move my code together with JBoss itself to different JVMs?

Atleast Java EE code is portable between truly different Java EE implementations (Glassfish, Geronimo, JBoss AS, ...).

For me though the most attractive aspect of Java EE is not specifically the portability, but rather the nice and clean programming model. Compared to Spring, Java EE just feels more like one consistent thing, wheras Spring feels much more like a patched together ball of stuff.

I much prefer to use simple EJBs and typesafe CDI to complex Spring beans and string based DI.

Glamdring said...

I think some clarifications are due before one starts complaining about spring:

- you can use spring-core and spring-beans without any other dependency. Especially in spring 3 the dependency graph has been cleared so that you get the jar of only what you need. So if you don't need any complex additions, don't use them. And it becomes as simple as Guice

- You are not forced to use XML. Most of things are now configurable via annotations, which makes it completely visible what and where is injected.

- If you want to use JPA, JMS, or any other thing without using the integration components that spring offers.. you will be in even deeper trouble. Take JPA transaction management for example.
So, the complexity is introduced by other frameworks, not spring. Spring is making their usage transparent - a simple @Autowired ServiceName service; and that's it.

- configuration, as I started in the previous point is necessary for the various other frameworks that are used. I myself would prefer one single configuration file, rather than cache.xml, persistence.xml, alabala.properties, etc.

- the fact that you've been thrown in a project that is not well-written should not affect your view on spring. One can get things wrong even with core Java.

ionut.margelatu said...

Spring is quite modular and these days if you want to use only DI with Spring then you only need 3 modules, i.e. 3 jars. I truly believe that this is reasonable.
Once you start with that, you can add new modules when you need to support or to integrate other technologies.

My very simplified 2 cents

Glamdring said...

If you don't need the extra modules, especially in spring 3, the dependency graph is very clean, so you can go with only 2 or 3 jars, and there you have it as simple as guice.

Sudheer Krishna said...

My personal opinion is spring is a blessing for developers who are into new technology.

As its mantra says "get away with the plumbing code" .Spring hides all the complexities associate with integrating new technology.

Once i had my basics perfect , anything new like Hibernate, Active MQ ,JMS integration , Spring Batch, Spring Integration everything seemed so simple.

I feel i just don need to understand some low level details ,which spring transparently hides behind.

Casper Bang said...

It's true that one could just use the DI part, but you need a mighty informed and disciplined set of developers NOT to accidentally draw in other stuff from the massive Spring umbrella.

It's just my experiences that one should think twice before embracing it all naively. At a much more practical level for instance, requirement for PermGenSpace seems to go WAY up when using Spring.

Greg Helton said...

Casper, Your saying that Spring is too big is like saying IT is too big. What parts should be left out? Your saying Spring is too big because developers have to use the documentation makes me wonder what IoC, MVC, JMS, JDBC, AOP, etc functionality I could use in a project without having to use the documentation of the various frameworks? If you had refactored your project to eliminate the dependencies on the 15 Spring artifacts, how many dependencies would have been required? I see that Spring provides great support for POJO development and although I don't like all of what I sometimes have to do, I don't know of any better solution. What is your better solution?

Greg

Anonymous said...

Hey Casper,
I believe for newbie entering into Spring, it might be something really hard and frustrating to learn or understand the principles of Spring. Thinking that Spring is all about DI is also incorrect.
I would recommend any newbie who wants to learn Spring to first read the architectural book "J2EE without EJB" and understand where EXACTLY Spring shines.
Spring(Interface21) code was nothing but code snippets that was shared along with this book. By reading through the book you will understand what problems J2EE developers face(d) and how Spring pitched in with it solution.
Spring , sure , now is bloated but keep in mind , it is still modularized and very organized. You can pick up any aspect of IT that you want from the Spring portfolio and use.

Regards,
Franklin

Jonathan Calvert said...

PermGen needs *definitely* go up.

"It's true that one could just use the DI part, but you need a mighty informed and disciplined set of developers NOT to accidentally draw in other stuff from the massive Spring umbrella."

This is what code review is for. Any time a library gets added, it should be examined, questioned. Are you pulling in this project because it's going to keep you from writing code? Could I write my own JMS polling? Yes, but every line of code written doing that is not focusing writing business logic.