
Why I stopped using Spring - lavaguru
http://johannesbrodwall.com/2013/12/09/why-i-stopped-using-spring/
======
ivan_gammel
This post is too abstract and neither offers a good explanation of a problem
nor suggests an alternative solution.

The task of dependency injection appears right after the decomposition of a
problem: you cannot avoid it, so you either do it manually by constructing and
wiring all necessary objects (self-managed singleton anti-pattern is quite
common here, let his fathers burn in hell) or using a DI container. Unless you
want to invent your own bicycle with poker and curvy girls (which may make
sense in very specific cases, but not in general), you will use Spring, Guice
or CDI.

How to choose the right solution? It always depends on requirements, not on
generic concepts from theory of OOD. In small project you can follow KISS
principle by sacrificing decoupling and wiring objects manually. In bigger one
you always need to look at the other libraries and environment you are going
to use. If it's a JEE container (a modern one, compatible with latest specs),
your choice can be CDI. If you are going to work with GWT, it's Guice (it's
the best for programmatic configuration, but lacks some features). In all
other cases Spring 4 is the best option.

What's wrong with the talk about reuse vs decoupling? The author addresses the
problem of sustainability of a system to changes by rejecting the core concept
of OOD - the reuse - and avoiding the use of DI, just to avoid some hypothetic
bug in implementation module. However, our industry developed a lot of tools
and best practices to address such problems when writing reusable code: unit
tests, SOLID (SRP is my favorite one), incremental compilers and smart IDEs.
Avoiding reuse is like not using electricity if you afraid of fire.

~~~
sitkack
This was an excellent post, it was abstract but at least he kept it short.

I had an argument about DI with a friend months ago and it boiled down in his
use (Guice) that it was only for testing components.

I think of DI as a big meta-constructor in the sky, it gives dynamic scope to
a lexically scoped language. And the problem with it as we currently use it,
is that it hides intent behind a config file so we can't read what the code is
actually doing, only doing abstractly.

What if the tooling ghosted those abstract classes and put the concrete
classes in their place with reading and navigating? It could effectively
"statically link" in the IDE those dependencies.

~~~
ivan_gammel
In good design the intent is clearly defined in interface on which you depend.
If the code has side effects, if it does something not specified by interface,
if it has more than one role, this code needs to be fixed and it is not a
problem with DI. It's a problem with your design.

As I already said, you always need to wire your objects. You do it, possibly,
without realizing it, but you still do it. If you reject the idea of DI just
because the code is bad and DI is "Not Invented Here", you will not do the
wiring better. Writting custom DI is hard, and it's very likely that you will
end with unmaintainable nightmare that needs to be rewritten completely. For
15 years I've seen this nightmare too much and never seen the successful
projects with custom DI.

~~~
sitkack
So is DI a result of incomplete language design? Should the concept of DI be
baked in?

~~~
ivan_gammel
For enterprise software, for large projects, probably, yes. Together with more
advanced reflection (I imagine MOF/EMF as a native part of Java) to allow
meta-programming and smarter code generation.

------
strictfp
This post is awesome and correctly describes that frameworks try to teach you
certain methodologies by enforcing them. Once you understand the principles,
you're often better of ditching the framework.

This is especially true with DI, which is a design principle and not a
framework, countrary to popular belief.

I would also like to add that specific technologies such as xml are not
inherently declarative. If some api or config is declarative it only means
that it is well designed and that it's easy to express your intentions when
using it. If you want counter-examples, look at imperative ant or declarative
jmock.

~~~
plorkyeran
XSLT's a better example of XML not being declarative, as it's a turing-
complete pure functional programing language. There's also some toy languages
actually intended to be full programming languages that happen to use XML as
their syntax.

------
kenshiro_o
I use spring in large scale Java projects but I rarely take advantage of the
@Autowired feature because I find it very confusing as I define my pojos in
XML configuration files. if I have autowired fields all over the place I have
to look at source code AND XML files to understand what the heck is going on
and from where a given field is autowired.

I suspect this introduces extra complexity. I have not yet had the chance to
try Guice ([https://code.google.com/p/google-
guice/](https://code.google.com/p/google-guice/)) so I wonder if it solves
many of Spring's problems (one of the top issues is verbosity of configuration
files).

~~~
moondowner
From Spring 3 (3.1 I think it was) you don't need to do configuration with
XML. Current version (Spring 4) even supports configuring Spring Security with
no XML at all. You can configure everything in Java and use profiles
(@Profile) when you have multiple configuration scenarios.
[http://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-p...](http://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-
profile/)

Also, don't forget that you can use @Resource (jsr250), not only @Autowired.

The author also says:

> So reuse and decoupling are opposing forces. I find myself siding with
> decoupling.

The developer has to make a balance between reuse and decoupling. In my
opinion everything doesn't have to be 100% reused or decoupled.

~~~
jonhohle
But why would you want to mix your config and code? When does it make sense to
lock these values at compile time, but also use an abstraction layer which
suggests these values are configured at runtime?

~~~
ivan_gammel
There's no sense at all in putting configuration of DI separately from the
code. Normally, 99% of DI configs are not environment-specific (if this is not
the case, "Houston, we have a problem"). In most cases you ship your software
not like IKEA, but like Boeing - already assembled and ready for use. The
customer (possibly, internal one) has to fill the fridge with meals for
passengers and tanks with fuel, not to assemble the engines or avionics.

~~~
jonhohle
Wiring objects together and configuring applications are tangentially related.
Both can be done in Spring config, both can be done without Spring config,
both can be done at compile or runtime.

Dependency glue (wiring) in runtime config helps keep objects decoupled, makes
test writing easier, and eliminates any dependency on a specific IOC
framework. Whether or not the wiring config comes boxed with the code or not
is a completely different concern.

------
bborud
I agree with Johannes. I have never observed sufficient benefit from DI
frameworks to justify the greatly reduced readability it results in.

------
rakila
Go for Guice if you just want DI. You won't regret it. But always remember,
all "auto" stuff might mislead you. For example, you need somebody to start
things for you, so in Spring, the Servlet container will invoke the Spring
Servlet, which will take things up from there. That's the catch, it's not
magic, right? So with Guice, you need to figure out who will so that "auto"
for you. Btw, if you're just building a small library, Guice is definitely the
DI choice. HTH.

~~~
moondowner
There is also Dagger (developed by Square)
[http://square.github.io/dagger/](http://square.github.io/dagger/)

Pretty similar to Guice, but faster.

~~~
MrBuddyCasino
Ha, Bob doing another DI framework? Is it any good?

------
stcredzero
_If the savings from the reuse are high, this is a trade-off worth making. If
the savings are low – it is not._

Cost-benefit uber alles! All of these things -- features, functions,
frameworks, objects, patterns -- _must pay rent!_

------
calebm
I heartily agree. Spring often brings a higher cost in incidental complexity
than it removes from the inherent complexity.

------
badman_ting
One thing that drove me nuts about programming with Spring (.NET, in my case)
was that it was so hard to follow the flow. So much flipping back and forth
between the config and the code. Also, the error messages for misconfigured
applications were frequently inscrutable. This was addressed to some extent
with a build phase that verifies the type names in Spring configs. Lastly,
more than once we were bit by defaults, where an object that should have been
a singleton wasn't, or the reverse. Lots of power to shoot your foot off.

------
qwerta
I found Scala lazy initialization to be great alternative to Spring IoC. Also
constructor arguments are part of class definition and it makes constructor
injection very easy.

------
shitgoose
Welcome to the club:) But you should be careful being too open about it. I
didn't last 15 min in my last interview, when I told them that I didn't use
database in my latest project, since all data (the whole 200 rows) did fit in
one json file. Haven't passed the "Technology Stack" qualification.

And indeed, code without frameworks is so much smaller, cleaner and pleasant
to work with!

------
bsaul
Is there any good, recent ( but past the beta stage), fast, non bloated java
framework anyone here could recommend ?

I've done a medium sized spring project last year, and found the language
quite good, but the framework itself and the general ecosystem really too
cumbersome.

~~~
zeroDivisible
As most of my daily tasks are being done in J2EE environment, I have
goosebumps each time I hear "java" & "framework" used in one sentence. And
that's not excitement, that's fear.

The only framework which I can recommend, is Dropwizard
([http://dropwizard.codahale.com/](http://dropwizard.codahale.com/)), which
tries not to be a framework, just a glue between some really nice libraries
and tools.

~~~
bsaul
Really helpful comment, thanks. I probably overestimated the importance of a
"framework" in the java world, where everything is standardized, and every
standard is implemented through standalone libraries (which is probably
another reason spring became so famous when i come to think of it, with its
original glue-like approach).

I'll start with "raw" java next time i'll want to try playing with rest
services.

------
bitops
I'm not sure I understand the point about reuse and decoupling being opposing
forces.

A simplistic example that comes to mind is a calculator module with a well-
defined interface (interface in the Java sense of the term). Maybe there are a
few different implementations of the interface available in the codebase.

Both implementations are reusable in the sense that I can plug one
implementation in many places wherever the interface is supported. When I need
something else, I plug in a different implementation. The module that has a
dependency on the calculator module should be none the wiser since all it does
is call out to a certain interface.

Am I missing something here? Maybe I didn't understand the OP's point well
enough.

~~~
kilemensi
What you're talking about is decoupling interface from implementation. This is
good (well, it's good if there is a genuine need for more than one
implementation, otherwise it's just decoupling for the sake of decoupling
which is a form of waste. Remember YAGNI)

My understanding of reuse is when the same peace of code is used in different
areas of the project. This could be different classes, different packages,
different modules, etc. Now the more the code is reused, the more tight
coupling between the two pieces of code i.e. change to the interface of the
reused code 'could' mean change(s) to each and every place the reused code is
being called.

Secondly, if you put reuse high up in the design requirement, what you
sometimes end up with are very generic interfaces/classes that can be reused
in lots of places as opposed to very specific interfaces/classes or
unnecessary inheritence trees required to change the base class behaviour in
those places where the required behaviour is 'slightly different'.

Lastly, not so long ago, DI containers did not support package private
visibility. This means all injection (constructor, setter, etc.) required
public visibility. This lead to a lot of developers also 'reusing' code even
in places where they shouldn't just because they could i.e. it's right there!

------
rumcajz
Using DI is like using goto. It gives you more power but at the same time it
makes it impossible to reason about the code.

