Sunday, January 29, 2006

I Don't Get Spring

Preface: Please note that this entry is well over a year old. I've since addressed all of my concerns with a new framework named Guice. Try it out. You'll find a direct comparison between Guice and Spring here.

By "Spring" I mean the Spring Framework, specifically the dependency injection container. First off, I mean no offense to Rod et al (you're all good people), but frankly I haven't been able to get my head around your framework. Even worse, I've noticed what I consider to be a dangerous and blind increase in the rate of Spring adoption. I've yet to read a critical article or book on Spring. It seems like everyone loves Spring except me; am I missing something? Maybe Spring adoption is a knee-jerk reaction to J2EE. "J2EE is bad, and the Spring guys say their stuff is better, so Spring must be good." It doesn't work that way.

Second, I'm talking about Spring specifically, not dependency injection. I love dependency injection, and I follow the patterns every day. Good riddance to service locators!

I can't tell you how many times I've had a developer tell me, "I used Spring on my last project and it worked really well," without being able to articulate what exactly they like about it or how it actually helped them. So far as I can tell, they like setter injection because it makes their code more flexible and testable, but that doesn't necessitate Spring. I guess for those who don't have the "dependency injection" mindset ingrained, using a framework that encourages (forces?) you to do the right thing helps. This encouragement doesn't outweigh the laundry list of negative impacts Spring has on your code though.

The Spring folks openly snub their noses at J2EE, but from what I can tell Spring isn't exactly lightweight and simple either. The Javadocs are unnecessarily overwhelming. Does all of this really belong in a user API? At least J2EE cleanly separates API from implementation. Spring advocates tout that Spring doesn't "touch" your code, i.e. you don't have to implement any Spring-specific interfaces (with the exception of life-cycle interfaces, etc.). News flash: the XML configuration is my code, and from what I can see it often ends up constituting a lot of code, all of which is Spring-specific.

Why would I want to express all of my dependencies in XML? Do I use Spring for all of my objects or just the coarse-grained ones? From what I can tell, neither the Spring documentation nor any Spring articles give any solid advice in this area. Am I supposed to use Spring to create all of my objects? Do we not like Java? I want to validate this stuff at compile time, load time at the latest, not while I'm running my code. Does Spring support that?

Obviously I want to load some dependencies like JDBC driver implementations dynamically (i.e. without requiring compile time checking), but these make up a small fraction of the dependencies in my system. What about the rest, the majority? I'm using a strongly typed language; why would I want to throw all of this perfectly good type information away? If I wanted that, I'd use Ruby. Doesn't the Spring configuration start to look suspiciously like writing Java code in XML? Is Spring for developers who aren't comfortable with Java? I'm not convinced adding a layer of XML makes things any simpler.

Back to dependencies on Spring APIs; don't I have to call the container to create my first object (assuming the rest of the Spring-managed objects in the graph are injected)? I want some way to check that the object I'm requesting is the right type at compile time. I don't want to cast. Ever. Do I really even need a container? In Spring you look up objects using a unique ID. I assume most developers define a String constant for the ID in their Java code. That doesn't help me keep the ID value in my java code in sync with the value in my XML. Why do I need both this ID and a container? Why use two objects when one will do? Should we really group all of this information together into a container? Do Java packages and classes not suffice?

It bothers me that I have to reference Spring implementation classes in my XML configuration. I don't care about the plumbing. In Spring's defense, I've heard they have so more concise, domain-specific XML coming in 2.0, but I haven't seen it yet. Why didn't this come up sooner?

What's with all the inheritance? And the permutation upon permutation of long winded class names? Not my style.

Where's the JDK 1.5 generics support? I know you have a lot clients running 1.4 and even 1.3, but that's what branching is for. Generics have opened the doors to all sorts of new possibilities for frameworks like this. They're my favorite new JDK feature. Embrace them.

Have you ever looked at how much work Spring does every time you create an object? I want fewer instanceofs at runtime and more Class.isAssignableFrom()s at load time. Not that the internal implementation matters that much to end users, but it works as a litmus test for the quality of the rest of the framework. A good refactoring to the bean creation pipeline would result in easier to follow and more performant code and would enable reuse without resorting to so much inheritance.

What's with auto-wiring? Does anyone actually use that, or is just another notch in the feature headboard?

How does Spring handle scopes? I heard it will finally support HTTP request and session scopes in version 2.0. I was surprised to here that it didn't support this already. What have Spring users been doing this whole time? Does the new version enable me to define my own scopes? For example, what if I want a "conversation" scope like Seam supposedly supports?

Let's not get into the MVC or AOP frameworks. [Un]fortunately I'm not using a dependency injection container at all at the moment. Don't think PicoContainer is getting off easily. It has most of the same problems, but I think Aslak and Jon have moved on to Ruby pastures. Are there any other frameworks that don't have these same problems?

Fortunately, simply adopting dependency injection design patterns gets you 90% of the way, further if you don't need encouragement to do the right thing. That's the approach I recommend. I certainly don't see myself adopting Spring anytime soon. I'm better off without it. If you do, go in with your eyes wide open. Be skeptical, critical. Just because someone has a popular Open Source framework, they have slick marketing, and they're supported by a big vendor (IBM pushed Struts on me for a number of years after all), it doesn't necessarily mean they know what's best for you or even that they know better than you.

Update: A coworker sent me a link to a Chinese translation of this entry.

48 Comments:

Anonymous Anonymous said...

Damn straight!

My pet peeve is the whole 'lightweight' nonsense. Take a simple java app, adding Spring to it is in fact a hugely heavyweight proposition. You've just gained 2mb, and your objects are a hell of a lot more expensive to instantiate. Plus all the plumbing you have to gain, and the maintenance thereof makes the prospect unpleasant to say the least.

Sure, maybe it's lightweight compared to an ejb2 application and the bootstrapping thereof (full container, etc), but don't fool yourself into thinking that just because it can be created in a JUnit testcase, it's 'lightweight'.

12:22 PM  
Anonymous Anonymous said...

Mmm... lightweight. Does that meant nothing/no-body of substance/mass gets attracted to it?

Seriously though, I share your feelings anout Spring, and what scares me most is the fervor of Spring zealots. All of the following statements are real. Spring is uniquely designed for scalability; with Spring you will never have to use threads; the Spring IOC engine is its unique advantage; only Spring would give you a lightweight AOP framework out of the box (take that Bob!), etc, etc.

I have no doubt that Rod & co. are nice people and talented developers. But sometimes it feels like we are back in 2000 and Spring is new old entity beans. Insanity rulez.

1:25 PM  
Anonymous Anonymous said...

Didn't you know you can attain enlightenment just by reading Spring's source code? ;)

1:30 PM  
Anonymous Anonymous said...

I think for junior folks using an IoC container like Hivemind or Spring keeps them thinking dependency injection. On the other hand the XML can get totally out of control. I would love to see more written about good dependency injection style programming outside of Spring!

1:33 PM  
Anonymous Anonymous said...

I use Spring for one thing.... Transaction support with Hibernate. It makes using Hibernate much easier, so I use it. I agree that the xml can become out of hand, but to me... it's worth it.

3:06 PM  
Blogger Bob said...

There has to be a less intrusive way to use Hibernate. Can't you just keep a thread local session and set it up and tear it down in a servlet filter? I wouldn't know as I don't use Hibernate. What do people who use Hibernate but not Spring do?

3:37 PM  
Blogger Brian Vaughn said...

What I like about Spring:

1) Declarative transaction mamagement without an EJB.

2) Build in support for JDBC so I don't have to worry about opening/closing my connection, prepared statement and result set.

3) AOP framework

4) IoC framework

5) Massive online documentation

These are my top five. I've used Spring for about a year now and think it's the best thing since sliced bread. Until something better comes along I'll be uning Spring into my projects.

Is Spring the holy grail? Probably not but it sure beats EJBs and it's easy to write tests for all of my code.

PS I've used Hibernate without Spring and we used a filter to keep the session open. This is a LOT easier to setup in Spring.

3:50 PM  
Blogger Bob said...

1) Why do you need this? Why don't people just start and stop a tx in a servlet filter? Some say that would be too coarse grained, but is that a real issue, or are you just optimizing too early? I don't see how you could get any simpler than mapping a filter and forgetting about txs until the performance becomes an issue or you really need to think about them (if you're using JMS for example).

2) Don't you use Hibernate? In any case, this is trivial to write. You shouldn't have to worry about closing the statement and resultset explicitly, only the connection.

3) Wow. Have you tried their AOP framework? http://weblogs.java.net/blog/crazybob/archive/2004/10/onjavacom_an_in.html

4) This whole post is about the IoC framework. I don't get it. Why do you use it? Please explain it to me.

5) No documentation can hurt a good framework, but good documentation cannot help a bad framework. Sorry.

4:41 PM  
Blogger Keith Donald said...

I personally believe in Spring's IoC container to drive the configuration of a non-trivial system because, primarily, it aids in adhering to this central design principle:

- Separate the configuration of a system from the use of that system.

By having a centralized blueprint representing a valid system configuration, I find it straightforward to see which implementations of that system's components have been selected for use and how they are configured. For what it's worth, we're talking about coarse grained components here (services), not fine-grained value objects.

Now right, that blueprint doesn't have to be externalized, and right, you don't have to use a container at all to follow this principle, but the Spring container does offer advantages. Here's my best attempt at describing them:

- Via declarative instructions you provide, the container handles component creation, configuration, and assembly for you--caring for the instantiation and wiring drudgery. I personally find this to be valuable; if Spring wasn't doing this for me I'd be doing it by hand, via a custom factory/driver for different deployments. And I do that sometimes--there is a place for custom factories, and Spring doesn't get in the way there. If a IoC container feels overkill to you for the problem you are asked to solve, you can still use the other modules of Spring in standard library style (as a previous commenter mentioned, talking about the JDBC and Transaction management facilities). You can still practice DI, and you should. *Definitely* use what works for you and be able to articulate why you are using it.

- Spring's container usage pattern is consistent, as the configuration instructions are represented in a simple, well-known format, and consumed in exactly the same way regardless of the environment you are deploying to. Simply feed those instructions to the container, lookup the system entry-point by type, and you have a system ready-for-use as output, with all the implementation details fully encapsulated. Spring also provides bootstrapping helpers for most environments -- like the context loader listener -- so you rarely need to interact directly with container APIs. Support for container hierarchies allows you to connect systems through their entry points using dependency injection.

- Components get created in the right order, with no dependency on the container; and a component's dependencies are expressed via setters and/or constructor arguments. Possible without a container, yes, but I like not having to care for this, and I like how Spring promotes that model. There is also built-in support for managing components with different lifecycles--from one-shot prototypes to threaded to support for injecting proxies that are backed by objects sourced from another scope or location (including conversation). Stepping back from the specific, these kinds of things are possible because the container has several smart extension points, most notably the FactoryBean concept (which allows you to make Spring aware of objects sourced from an arbitrary location out of Spring's control--like your own custom factory, or JNDI).

For what it's worth, by 'smart' above I mean Spring allows for extension, but does so in a way where the core does not become some 'god like' framework with a bizillion inter-dependencies. As someone who very much enjoys the craft of software design and appreciating strong designs, that discipline and attention to detail really impressed me early on. Hani implied you have to add two MBs to your classpath to use Spring, which is not accurate--there is a clear listing of dependencies (and a fine grained, module-based packaging strategy including in each release)---the core container, usable in isolation is 220KB. Use what you need.

One clarification I'd like to make regarding Spring's positioning: Spring is not just a dependency injection container, it is a full-stack application framework, of which the container is one module. Much care has been taken in structuring the framework where folks can use the parts they need and nothing else--and it has gotten where it's gotten today because of the community and some damn talented, hardworking, disciplined developers I've had the pleasure of working with for two years now (and yes, they're good people too).

In between the jabs, Bob is making a general message I agree with here. When you use any third-party product you must evaluate it carefully and you must understand why you are using it and the technical value it is providing vs. a list of researched alternatives (possibly including roll your own). You should also weigh other factors, like community, documentation, and support.

Keith
About to be a Dad
Spring Web Flow Lead
http://www.jroller.com/page/kdonald

6:24 PM  
Blogger Patrick Lightbody said...

I think Spring's IOC container (that's all I use and can speak to) is "OK". It does what it needs to do, and it does it fairly well. What I really want, however, are two things:

1) Refactoring support. By that, I mean the ability to define my dependencies via code rather than XML. This is likely a personal preference, but this is also why I actually _liked_ Aware interfaces.

2) Reloading support. This is supposed to be coming in 2.0, but probably not at the level I'm hoping for. Basically, I want Spring to know when a class definition has changed (see WebWork's QuickStart utility for why this is nice) as well as when dependent files have changed, such as sql-map.xml. This would allow for rapid development without redeployment.

A third nit-pick I might add is I don't like the direction Spring is heading with the pre-compilation step as the recommended way to solve the anemic domain model. See my blog post here for more detail on this.

6:42 PM  
Anonymous Anonymous said...

There has to be a less intrusive way to use Hibernate. Can't you just keep a thread local session and set it up and tear it down in a servlet filter? I wouldn't know as I don't use Hibernate.

The less intrusive way is to use SessionFactory.getCurrentSession().

We basically agree with Bob, to us it seems that Spring makes using Hibernate more complex, not less complex. Of course, when I have come out and tried to say this in public, I have been absolutely hammered for doing so, and called all kinds of names. There seems to be some incredible level of politically correct groupthink going on where if you make some mild criticism of The Spring Way, you must be working for the devil. Surely it is reasonable that wr could at least be allowed to discuss this in the open without being villified? Thankfully, I now know I'm not alone, and that there are other people out there who agree (and people I respect at that). Interestingly, I was also ridiculed for claiming that there were people using Spring mainly for Hibernate session management - and yet in this thread we see someone volunteering that this is indeed the case in their case. Sheesh.

By the way, I also disagree with the assertion that there is something inherently "better" about dependency injection. No other software development community on earth thinks that DI is an important thing. Someone, someday, please explain to me how this:

@Inject(name="foo") private Foo foo;

Is significantly better than, or indeed any different at all to this:

private Foo foo = (Foo) Component.getInstance("foo");

They are no different at all, in fact. One version saves some characters.

6:47 PM  
Blogger Bob said...

Keith, I think you can have all of those features and none of the deficiencies I mentioned in my blog post.

When I talk about the idea of going "containerless," I'm not saying we should throw away all those features (OK, maybe we should throw way auto-wiring). I'm saying now that we have generics, we shouldn't be afraid to rethink the API to better meet our needs. For example, we could have a factory per bean where the factories collaborate behind the scenes.

I really tried not to "jab," and I hope none of the Spring developers take it that way. Otherwise, TSSS could be kind of awkward for me this year. ;)

Congrats on the baby!

7:20 PM  
Blogger Keith Donald said...

To anonymous:

Management of a shared Hibernate Session is just one of the benefits Spring's Hibernate integration provides.

Here are the other benefits:

- Configuration of a Hibernate SessionFactory as a standard Spring container bean definition. This boils down to this: if you're already familiar with Spring for configuration, you get to leverage it again to configure Hibernate. Practically, this means developers can use the same configuration format they already have experience with, and can leverage Spring's built-in configuration support for things like externalized property resolution (for example, for sourcing hibernate properties from externalized property files for use by application administrators).

- Support for implementing and configuring Hibernate based DAO's using standard dependency injection techniques, and a optional helper for executing Hibernate-based data access calls in one-line of code (HibernateTemplate).

- Automatic integration with Spring's declarative transaction management abstraction, which allows you to switch transaction management strategies and/or transaction demarcation policies without effecting application code. By using Spring's TX management, you gain a good deal of power for expressing transactional units of work: support for all six standard transaction propagation behaviors, standard isolation levels, a declarative readOnly optimization capability, support for transaction timeouts, and support for transaction suspension with local transactions (as well as nested transactions with savepoints)--all with a non-invasive, PlainOldJavaObject programming model.

- When using the HibernateTemplate helper, you benefit from automatic use of Spring's exception root-cause analysis facility, for translating Hibernate-specific exceptions into Spring's generic DAO exception hierarchy (which is common hierarchy for a reporting root-cause failures accross a variety of data access strategies, not just Hibernate).

- Session close supression, making it impossible to close a session before transaction completion.

Each of those adds architectural leverage and convenience, beyond what Hibernate offers on its own. Call it the Spring way, if you want to, but those are the facts and each of those facts adds value (exactly how much value depends on your specific requirements, but I'm assuming most apps are transactional in nature and have business logic that should be tested in isolation--both addressed/enabled well by Spring's declarative TX facility).

Note: as an alternative to HibernateTemplate folks can still benefit from Spring-managed transactions with use of Hibernate 3's standard SessionFactory.getCurrentSession(), the "less intrusive" way as you say. Spring provides first-class support for such usage, and it is fully transparent, applied automatically when you use Spring IoC to configure a LocalSessionFactoryBean. Bottom line that means your HibernateDao's won't depend on Spring at all, then--Hibernate's "template style" usage is just one option for those who want to take advantage of the leverage they get by using the exception translation facility. Spring by no means imposes its usage as a requirement. But you should understand what you are giving up by not using it.

For more information, see Juergen's post here: http://forum.springframework.org/viewtopic.php?t=6931&highlight=hibernate

As far as the benefits of IoC over DependencyLookup, I outlined some points here awhile back:
http://www.jroller.com/page/kdonald?entry=ioc_we_get_it

In summary, dependency injection, over ad-hoc dependency lookup, enables unit testability and reduces overall coupling. Basically, you decouple yourself from any lookup service, so you don't depend on a lookup service implementation to be initialized just to execute your component. Now, sure the lookup service itself can be reconfigured to support a test/mock scenario; however, if the service's initialization logic is hardcoded and it creates a service that depends on another service that depends on yet another service in a hard-coded fashion, you can get into all kinds of trouble, as all of a sudden you have to initialize the world just to test your own component's logic in isolation. Dependency injection addresses these issues by externalizing the responsibility of resolving the implementation of what a component "needs to work" from the component itself--by introducing the role of an assembler (the container).

Martin Fowler's article on the subject might also prove helpful: http://www.martinfowler.com/articles/injection.html

Keith

7:40 PM  
Anonymous Anonymous said...

Here, here Bob!!!

In my opinion the benefits that IoC / DI bring should be the focus, not the various frameworks that have sprung up (pun intended) to ingrain it into your apps. If you follow the principles of DI, it makes your code amenable to many different frameworks (like the existing "lightweight" containers) or even your own, however minimal it needs to be.

I gave a presentation to the St. Louis Java User's Group about a year ago on "Designing with Dependency Injection" and focused on the DI aspects without really going into the frameworks too much. You can find links to the presentation in PowerPoint and Keynote off my blog at:

http://puredanger.com/blog/wp-content/uploads/2006/01/DesigningWithDependencyInjection.ppt
http://puredanger.com/blog/wp-content/uploads/2006/01/DependencyInjection.zip

In general, I have written a lot of code using DI and interfaces and find that it pulls the configuration and assembly of applications up to the highest level of your apps, making everything below it more testable and less coupled. However, I rarely have more than one implementation of a component interface when I'm first putting an app together (other than testing impls).

If you follow these principles, you can assemble the app in many ways and choose the one that is most suitable. Some different possibilities:

1. Code it by hand - just wire the objects together yourself. I always start this way while things are changing fast. With a modern IDE, probably easier than writing a big honking XML config and using Spring.

2. Use beanshell (or groovy or ...) - using script is like #1 but means you don't have to recompile to change your assembly, which in some cases is handy (complicated build / deployment environments).

3. Use a combination of code and a custom properties/XML file. You don't really need to decide how to assemble every dependency in your app do you? Of course not! Probably 90% of your app has effectively hard-coded dependencies and you need to swap out key resources (persistence, authentication, whatever). Leverage that to build flexibility only at the points you really need it. By designing with DI, you can also expose the flexibility already in the design at someplace later.

4. Use Spring or Pico or Hivemind or another DI framework. In some cases, this may be the right answer (although usually some mixture of 1-3 will work).

I guess my point is that there are a lot of ways (with fewer dependencies and more transparency) to use DI to assemble an app.

8:31 PM  
Blogger Bob said...

Keith, I don't use Hibernate, but if I did, I don't think any of those features are compelling enough to use Spring.

Thanks for reminding me of Cedric's "Inversion of Control containers... still not getting it" post. I think it was Spring he didn't get either, not DI.

Finally, I don't question the virtues of DI. I question Spring's approach.

9:42 PM  
Blogger Eugene Kuleshov said...

In my practical experience Spring's container provide a good deal of features, allow to declaratively wire components in a single place, which makes possible to see the application structure. Yes, these XML definitions are quite verbose, but there are number of ways to make it easier to swollow. Another out of the box feature I particulary like is the AOP framework that can be used as a drop-in even in J2EE application (zero deployment and build configuration) and it is tightly integrated with Spring's DI container, so if my advice would need a DataSource or something else, it can get it injected by Spring. I guess Spring team should address performance issues, but generally they've done not so bad. :-)

10:38 PM  
Blogger Bob said...

Yes, it's nice to be able to configure in a single place, but that doesn't justify all the other problems.

For the AOP framework to be well integrated, you need to build the DI framework on top of it so you can use AOP to implement stuff like the template/getter injection and so you only need one class proxy, not two. Has Spring addressed these issues yet?

10:58 PM  
Blogger Keith Donald said...

All I can do is present the facts on Spring's motivation and feature set, you are certainly entitled to your opinion and your choice.

Just a quick note to your last comment. Yes, Spring AOP integrates with the IoC container through the 'smart' extension points I mentioned. So the AOP framework is actually usable standalone (in library style), with a integration layer between the two facilitating "bean style" usage--which I think is quite clean (and naturally facilitates use of other AOP frameworks, too, like AspectJ and of course, DynaAop;-))

Yeah, getter/template injection is supported (has been since Spring 1.1 I believe) but to be honest I'm not a big fan of it. A bit too magical for my tastes, relying on cglib subclassing. For cases demanding something like that I personally prefer proxy injection, with the proxy standing in for a target object with a different lifecycle (to mask the specifics of that lifecycle's semantics--for example, prototype, load balanced, pooled, threaded, etc.). That's easily possible with Spring (statically or dynamically), and the transparency you get feels quite clean to me.

I'd be interested in reading more specifics about what you see possible with JDK 1.5 generics and a IoC container--you have clever ideas, and you design good APIs. And it'd be cool to read constructive posts sharing ideas for future innovation in this space, which Spring could obviously help drive as the leading framework in this space (and is already driving, as you did mention Spring 2.0's new custom configuration schema and trasparent scoping capabilities--yes they exist, driven by concrete customer demand, and available now for developer use with sample applications illustrating recommended usage.)

Spring 2.0 will be ready for production use by early Spring 2006 (hopefully two years to the exact date of Spring 1.0), and it's going to really raise the bar on a number of dimensions. You can also expect professional reference documentation to be available by the time we go release candidate, as with all Spring products.

No hard feelings. Yes, the baby will be here any day now! Everything is ready (including Keri, I just hope I am!). Her name will be Annabelle (a proper southern name ;-)). I hope to make TSSJS but we'll see what lil' belly says about that ;-)

Cheers,

Keith

11:50 PM  
Anonymous Anonymous said...

I think Keith has pretty much cleared up all the points but I want to touch on some other areas.

I don't recall any situations where 'Spring folk' have openly snubbed J2EE, certainly not anyone on the core team. In general we have been critical of *EJB2* but not of J2EE as a whole. Indeed, Rod wrote one of the most popular books on J2EE design and, he and Juergen wrote a book about using J2EE but without EJB. Spring has excellent support for integrating with J2EE infrastructure and as a team we try to work as closely as possible with vendors to expose all the cool features available in app servers via Spring.

One of the things that constantly bugs me is the bashing of XML configuration. Yes, the Spring config can get out of hand, but then I'm pretty sure we all seen some *dreadful* Java code. With a little bit of thought Spring configuration can be easy to grok, well laid out and generally a good place to put your blueprints as Keith says. With sensible use of defaulting, not all components needs to be configured with Spring - it does make sense to try to default configuration wherever possible. With the new 2.0 extensions the infrastructure-level configuration is substantially simpler and should remove a lot of the need for users to understand the Spring plumbing. As I demonstrated as TSE, XML is actually a pretty good choice for a configuration format since you get excellent tooling out of the box with decent IDEs, especially when you use schema to back the XML specification.

As Keith points out, for many environments you *don't* need to do the first bean lookup because we are able to bootstrap the environment. This is pretty nice since it means that, in general, you don't need to see the BeanFactory interface.

Long winded class names - surely just a preference thing :) We try to make class names as descriptive as possible so that people can get a feel for what they do. You're the first person I know of to complain about the JavaDoc - most people find the JavaDocs a useful tool exactly because they are so extensive.

Generics - as you point out, 1.3 and 1.4 compatibility is really important for us so it is unlikely that the *core* API will use generics any time soon. However, we've done a bunch of stuff with generics for 2.0. We have a Java5 API for JDBC usage which is really quite nice using generics, varargs and autoboxing. We've tried to make extensive use of available generics metadata to infer types for values configured in XML.

Regarding object creation performance, I'd be interested to hear some concrete examples of problems there and I'll happily integrate any (practical) improvements that we can come up with. In general, Spring doesn't get too heavily involved in object creation during application runtime, with most of the overhead occuring at startup time. There will almost certainly be another performance tuning stage pre 2.0.

With regards to being critical of Spring - we try to remain as critical of the framework as we can - indeed Juergen and I had a design meeting just the other day to look at features we think can be improved. As you can no doubt imagine, this can be quite difficult given the immense amount of positive feedback we get and the large number of successes our clients are enjoying. At the end of the day, whilst discussions such as this are extremely valuable, results are really what matters.

As Keith says, no hard feelings whatsoever :) I'm not at TSS this year but JavaOne.... ;)

Rob

1:38 AM  
Anonymous Anonymous said...

Bob,

your critism certainly comes from someone with fantastic Java skills, experience, pattern knowledge and architectural understanding.

the gist of your argument seems to be "Why should i use this framework when i can do all this suff myself, better"

Unfortunately you are probably in the top 5% of developers. In most in-house development teams the best person doesnt have your ability, let alone your rank-and-file developer.

Spring gives them the ability to do things better and consistantly, make less architectural mistakes and generally concentrate on building business requirements. I have seen Spring bring much happiness to developer teams across London and i'm sure across the world.

You seem to have a lot more questions than critism and, to me, its more a lack of best practice for using Spring than framework issues. Like many frameworks that are trying to be many things to many people it is just as possible to do things badly, but harder to do them *really* badly.

But i think its the oldest proverb that works best.

"Don't knock it 'til you've tried it"

6:10 AM  
Anonymous Anonymous said...

Like a lot of criticism on any kind of software technology there is a lot of smart people in the Java community spending a lot of time and energy on explaining why they do not like or understand the use of technology X.

If it does not float your boat or help you with your particular problems. Do not use it. If you have no problems whatsoever with any technological challange (like it so often seems. Since the alternative is so often "- I can do that myself. It's easy."), you definately do not need it.

I only know that without some of these libraries/frameworks I would not have successfully completed any of my Java projects. Or very few of them.

But then I am one of the more average developers but still in a position where there is no other option than delivering working solutions, on time. Very often without any kind of training on any of the platforms you have to run on (god bless the internet!). For us the reason is that there is no time for training. We have to deliver yesterday. And in the end we often do. So the employer sees absolutely no reason for training the next time since we did it without training the fist time. I think there are many developers on my level working under these circumstances out there...

In the end for me, Spring and other solutions are godsends...

7:10 AM  
Anonymous Anonymous said...

I use Hibernate without any framework for injection such as Spring. Here is how I do it.

First, I derive a class from HttpServlet. I add a method to retrieve an instance of my DBManager class (it has all of the lookup/query methods, along with management of persistent objects). This method will create an instance, store it to a session attribute, and return it. If the attribute has already been set, its value is returned.

Next, I override its service method. The service method check for the existance of the attribute. If it exists, it commits the transaction. If the service code (doGet et al) fails or the transaction fails, the transacation is rolled back.

Lastly, all of my servlets that want DB connectivity derive from this class. When they need access, a call to getDB() gets them it. They don't worry about transactions or anything.

Lastly, somebody mentioned maintaining DB sessions over separate HTTP requests, but within a single session. This should be avoided. Each HTTP request is supposed to be autonomous and allow for indeterminate disconnects by the client. Maintaining a session could potentially lock records for about 60 seconds after the client has decided to go home, if your code handles implicit session tear-down appropriately.

7:16 AM  
Anonymous Anonymous said...

On a related note...I see all these O/R mapping frameworks/tools...
Is writing a decent SQL statement and a simple DAO really that hard?
Or is it worth learning a framework specific Query Language which tries to mimick SQL?

9:04 AM  
Anonymous Anonymous said...

This is coming across as sour grapes, because developers are not using Dynaop, but they are using Spring.

9:22 AM  
Blogger Bob said...

Rod, Keith, Rob, Stuart, and everyone who posted, thanks for the excellent responses. I actually see more value in Spring's ability to encourage users to do the right thing than I did before.

Rod, thanks for correcting me on the AOP front (though I must admit I'm not a huge fan of AspectJ either--over my head). I deliberately steered clear of AOP in the post because I haven't kept up on it, but I got pulled in in the comments anyway; I apologize. Still, the real value there for me would be in using AspectJ not Spring.

My diatribe was not sparked by the Spring framework itself or the Spring team. I can't tell you how many people look at me like I'm crazy when I say I don't want to use Spring. I always find myself defending my position when it should be the other way around. Combine that with all the articles devoid of constructive criticism. I guess it's testament to the strength of the Spring community you've created.

9:27 AM  
Blogger Bob said...

Anonymous ORM guy, I would definitely recommend an ORM framework over hand coded JDBC. You will write less code and it will be more maintainable and performant.

Sour grapes guy, you're an idiot. ;)

9:34 AM  
Blogger GrOG said...

+1

9:47 AM  
Blogger Unknown said...

Bob, you asked some good questions and i think some of them will be picked up by the developers over there at I21. You are right that there is no spring design pattern book out there telling you how course grained your spring managed objects should be. So i understand some of your gripes but only some of them. I am using Spring for my latest projects and i dont see too much downsides (sorry, the spring jar file size is not a problem for me). I dont have problems with javadocs either because if you understand the branching of the areas, you only look at a small portion of it. Regarding XML, take a good spring-aware XML editor and the XML is not that terrible and i also havent used Spring 2.0 xml style yet.

But is Spring complex? It definitely is, but its nothing compared to a full j2ee approach with all that nasty appserver config stuff. There will never be the super-easy way when developing enterprise systems. But IMO spring is better to handle.

@hani

if i reach the point where object instantiation is a problem in one of my projects, i would be very happy. For now, all my consulting gigs and my own projects suffered from more user-driven problems and not object instantiation but i am sure you know that ;-) You also work for real-world companies like banks.

Marc Logemann

10:13 AM  
Blogger Bruno Patini Furtado said...

My long detailed defence on spring here.

7:35 PM  
Blogger Soronthar said...

This post appeared just when we were about to test if Spring adds a "significant" overhead that can degrade performance of a massive batch job.
The numbers so far seems to indicate that there is no "significative" difference between using the traditional singleton approach or using the Spring BeanFactory.

Regarding Hibernate, it's ok to open and close your session in the filter, but never, ever start the *transaction* in the filter unless you have a way to start the transaction selecively according to the requested URL.

5:03 AM  
Blogger Bob said...

Rafael, singletons obviously don't matter because Spring only creates it once at load time. I was talking about "prototype" scope.

Regarding transactions, I'm not sure what URLs you'd not want to run txs on (static?), but you need transactions even when you're reading many times.

8:50 AM  
Blogger Tim Chadwick said...

I think that anytime a given pattern is reinforced with a given framework, it is generally a good thing. I think that FAR too often - with any buzz-word, it catches on to the point to which people start using the proverbial hammer to pound in a screw.

In this particular case, I think Spring is a decent framework for sure, however I have never considered it lightweight. That goes for total functionality and the amount of code it generates. Most of the time, when code can be abstracted into another "language", it is a good thing because then the code itself is consistent, but of course abuse of the XML in this case doesn't help either. I think Martin Fowler's thoughts on language cacophony is a topic that should be brought up more often. The amount of xml, annotations, and other subsets of programming constructs that piece an application together contribute to confusion that is not necessary and sometimes all out detrimental. An example is that de-coupled code (using XML) is often more reusable, however when outside of a referencable container/system - it is HORRIBLE to debug!

10:46 AM  
Blogger Bob said...

Ben, you're exactly right. My complaint is that too much stuff is unnecessarily public. Thanks for the feedback.

10:08 PM  
Blogger Soronthar said...

Bob,

Regarding transactions, I have encountered three problems to start them in a filter/Controller Servlet and not where is needed:

* Most of the time you'll run the transaction for longer than needed, thus causing a contention of resources at the RBDMS level.
* Sometime you need to control the isolation of the transaction to scale better.
* In the J2EE 1.3 spec, the Filter behavior for forward and include is not clearly defined, so in some containers you end up opening more than one transaction for the same http call.

4:57 AM  
Blogger Bob said...

Rafael, your first two point are one in the same. I'd venture to say this isn't an issue for the majority of web applications. If it becomes an issue, you can always shore things up at that time. No need to prematurely optimize. Surely as more web container move to NIO this will be even less of an issue. What's easier, switching web containers or manually demarcating transactions throughout your code? If you take the first route, you don't run the risk of code accidentally running outside of a transaction. How do you test for that anyway? You can also only run the transaction during your business logic and commit it before you render the result, assuming you've cleanly separaated the two (go MVC!). If it's not a web application, proxy at the service layer.

As for your 3rd point, simply make your filter capable of reentrancy.

2:56 PM  
Blogger Thinker said...

Try understanding the code someone else wrote using spring... I almost went bald pulling out hair

You have to keep jumping back and forth between java and XML. If you write a pure java code you can use Ctrl + Click or Ctrl + T in Eclipse to easily navigate. But here you have to match up the IDs and then copy the class name, go back and find it.. thats too much... auto wiring makes it totally unreadable.

8:18 AM  
Blogger Pankaj said...

This is a great discussion thread and obviously there are people of all experience levels talking here...
Like an earlier poster in this thread, I agree that Bob probably represents 5% of the user community. If I can be presumptuous enough to represent the 95%, I'd like to say the following in defense of Spring:

1. Spring has exposed to the user community the J2EE APIs that were mostly the domain of AppServer developers. Most of these apis are exposed via Spring's own classes, so there is certainly a learning curve there.(And hence the massive (and great)javadoc). For instance, I can now start and stop a User Transaction without having to delve into JTA apis or manage them. I can instead use a TransactionProxyFactoryBean.

2. IoC is certainly not a new concept.. but Spring has made it easy to use. I read this great article by Sony Mathew (who has also posted on this thread) and he has suggested a great way to inject contexts into apps.. and it works.. but just because there is a config file in xml, I wouldn't throw away the ease of configuration and do it the hard way.

3. The context file being in xml really has upset some folks who call Spring 'proprietary' at least, in part for that reason... I'm sure most of you know that the setters that are used by the BeanFactory implementation can well be written in Java code. There is even a Spring supplied propertyFile reader for the BeanFactory config. Secondly,even tho xml is supposed to be proprietary, xml parsers are not. So for me xml is better than java code for configuration, especially when tools (plugins exist) that can parse the xml file and expose dependencies. (The spring plug-in for eclipse is a great example)


4. AOP is also not a new concept, but again, Spring makes it easy to implement. If method interception can take care of 80% of use cases, why bother with (the more abstruse) field level interception?

5. For me Spring IoC and Spring AOP really delivers 80% of the goods. The other Spring addons like Spring MVC, Spring Webflow, Remoting, support for Mail, support for Hibernate, JMS and JMX are really applications written using the first two fundamental principles.

FWIW, here (http://java.sys-con.com/read/180377.htm) is an article that I wrote for JDJ that talks about just Spring IoC and AOP. In it I have tried to focus on how Spring can provide infrastructure services without interjecting a heavy one-size-fits-all EJB container.

Also, there is a performance section that is included here:
http://technochord.blogspot.com/

Source code for the standalone ready-to-deploy webapp is at:
http://res.sys-con.com/story/feb06/180377/source.html

my 2c

1:19 PM  
Blogger Bob said...

I'm not a fan of Spring MVC at all. I prefer WebWork.

3:43 PM  
Blogger Bob said...

Mark, http://crazybob.org/2006/02/i-was-too-hard-on-spring.html.

As for "too much Javadoc," I'm talking from an API design standpoint. Spring is a library that's been implemented more like an application; much which is public shouldn't be, I have doubts about the future flexibility, etc.

As I said in the entry linked above, I get it now. But that doesn't mean I like it. ;)

7:16 PM  
Anonymous Anonymous said...

I am so decoupled I believe I am life-form independent.

Toadman, I agree with everything you said, and this quote of yours (above) had me laughing to tears.

:)

8:39 AM  
Anonymous Anonymous said...

This blog, and most of the responses, just amaze me. They reflect almost everything that is wrong with the software industry today... Basically, Software Engineering is not just for software engineers any more. The great Edsgar Dijkstra must be turning in his grave. What a shame! People who "don't get" things - by their own admission - still somehow feel in a position to bash what they don't get! Look, Spring or no Spring, there are certain basic principles of computer science and SE-ing that every decent SE should follow in order to build good, reliable, maintainable, flexible software. Some of those basic principles dictate that you should design and code for abstractions rather than hardcoded implementations, seoarate business logic from presentation, separate the applicatino configuratin from the application itself, promote reusability and modularity - for the sake of maintainability, fast error detection, and flexibility, etc. There is nothing new here. Now, Spring is just one very intellingently put together framework/set of tools/whatever you call it, that makes it easier to do all the things that you should be doing anyway. That is, if you are a decent software engineer.

Unfortunately, there are very few really good SEs these days - compared to the hords of really bad ones. Years ago, one of the fathers of Computer Science, the brilliant Edsgar Dijkstra publidhed an article in which declared that about 90% of all SEs are lousy SEs. I was in grad school when I read that article, and I almost got offended. Where does it put me, I thought. Of course, now I realize how correct Dijkstra was. Except, since the late 90s, the software industries has turned into millions of seatshops where the vast majority of programmers are absolutely incompetent hackers - with many years of experience... writing lousy, unmaintainable spaghetti code. There are, of course, companies where very technical and intelligent managers do a great job hiring brilliant people. However, the vast majority of "non-technical" companies with "IT" departments are driving themselves into the ground by hiring talentless and unmotivated clowns with nothing but lots of buzzwords in their resumes. Those people, under "supervision" of incompetent development managers or incompetent architects/bureaucrats, create unimaginable garbage, get praised for the long nights and weekends they spent fixing their own bugs, and build applications that require full-time "sustaining" teams to support for years to come. Each bug fix produces more new bugs, errors are hard or impossible to trace, nothing is reusable... Ahh well... I know this because, in my line of work I work on different projects at different client sites, and there is always the same picture.

The motivation behind efforts like Spring, as I have said, was to make it easier for software engineers to design and build applications that conform to the standards of elegance, reliability and maintainability so passionately promoted by people like Dijkstra. Spring was concieved and designed by the people with a very clear vision of what real Computer Science and Software Enginering should be. Every good SE I know has embraced Spring - not just for the features, but for the great example how to approach application design. It is not about what to use fore configuration - XML or Java, it is about designing your app so that one does not break when the other is modified, or when the requirements change. Of course, a bad programmer will misuse anything, including Spring. So, don't point at lousy implementations as proof that Spring is no good. Don't quote another incompetyent developer who has used Spring on a project but can't explain why and what for. He's just another imposter with a cooked resume. Just try to "get" Spring first. What's more important, make sure you get the basic principles of software engineering first - that are behing Spring. Seriously. And then provide your feedback.

Now, one interesting observation. There are two very distinct kinds of Spring bashers that I have come across within the past few years. The first type are programmers who have been in the business long enough to consider themselves "experienced" but who still have a way to go (they just don't know it yet.) These folks have not yet passed the stage (the stage that all of us, software engineers, have or will have to go through) when they think that their ideas are the best, any criticism is unacceptable and met with fierce resistance. These guys aren't yet at the point when they start appreciating healthy exchanges of ideas, and the fact that there are people out there from whom they can and should learn some really good and useful stuff. Often, these guys stay on the same project for years, become complacent but very proud of their input on that particular project. When facing a new ernvironment where fresh ideas are "imposed" on them, they become extremely argumentative. Simply because it is now someone else's ideas that people are turning to...

The second type is probably the most dangerous type. Those are the not-so-competent but very political and insecure lower- and mid-level technical managers, and architects, and tech leads that spend most of their time in meetings vs. writing code. These people have never been good programmers. In fact, they never even liked programming. They have always enjoyed going to the meetings, discussing "the big picture", project mile-stones, meeting clients, presenting the product written by the "code monkeys." Such people move from project to project, get promoted, add all sorts of cool stuff to their resumes, eloquently speak about every hot technology out there... They just don't write code. Or, perhaps, when they do, you'd wish they never did... But, boy, do they like to talk about stuff. You see their postings in forums like this, theserverside.com, and many others. Their postings usually contain phrases like "my developers", "I always instruct my team", "when I conduct code reviews", etc. It is clear that they are in charge, and they know what they are talking about. They just don't write good code themselves. And these people scream louder than anyone else when some new face suggests a fresh idea. Not because they really "get" the idea after having spent weeks analyzing it, but because the idea comes from someone else, and they are suddenly not the ones everyone is listening to. God, how many times have I seen this...

There is a small variation of the second type: the more technical engineers/managers/leads. They do write code, they are indeed intelligent, but way too much consumed with their egos not get annoyed when someone comes up with a new idea that they hadn't thought of first. Their ego and insecurity stands in the way of them calmly analyzing the issue and perhaps agreeing that the opponents have a point...

The author of the original blog ("I don't get Spring") seems to belong to that particular category - the last one mentioned. And his blog has attracted all sorts of representatives of all three types - to vent, bitch and moan... They seem to have found one place where the likes of them would listen and agree, and support their insecurities. It's a shame.

By the way, one of the great things about Spring is that it is totally non-ivasive. Spring does not force itself on you. You can use only small parts of it - to the extend you think you may need it. And, it you can add more Spring support as the necessity arives. That's the whole point of any intelligently written software. You don't need to de-couple everything. Just use your best judgement. The point is, Spring helps you to do othings the right way - when and where you chose. It is still up to you to decide what your application needs. But if you are sweating to decide whether your code should be reusable and elegant, or look like a big steaming pile of spaghetti, and you don't see the difference... then, perhaps, software engineering is not for you.

3:23 PM  
Blogger Bob said...

Connie, thanks for the thorough feedback. When I said, "I don't get Spring," I meant I don't get why so many people (like you) love it so much when it clearly leaves so much to be desired. Perhaps one of these days we'll have a better alternative.

2:29 PM  
Blogger Bruno Patini Furtado said...

I have been emailed about a copy of your post. This guy really COPIED your phrases several times.

http://rumblingsofaconfusedmind.blogspot.com/2006/10/why-do-i-hate-spring.html

9:58 AM  
Blogger Unknown said...

hey bob, will yu teach me Guice?, the press makes me feel its sexier than Spring but for me too since I have learnt spring, its been difficult for me to learn Guice too. :). How do I start with Guice from a Spring perspective of DI especially. Is there any migration guide for spring users?

2:50 AM  
Blogger Sendhil Murugu said...

I had similar thoughts about Spring.

-Its definitely not lightweight
-Instead of creating the instance code during compile time you delay it through Spring framework which manages instance creation but what does it buy me? can i control the number of instances? can i make it as a singleton?

Bottom line, the thing people like about Spring is the "wiring" objects, you can see it as a "blue print" for your system but it does not come without a cost, you got to manage few more configuration file nightmare.

11:28 AM  
Blogger A_flj_ said...

Why I do like spring: it provides two separate mechanisms to do the same thing (i.e. wiring up your app), each one useful in different situations. (Although I agree it's in no way lightweight).

For example, say we have a user service used in a spring web app to provide access rights, authentication, authorization, user-specific locale settings, application preferences, HR data about users and whatnot. Depending on the deployment, it may be that you need different implementations for it - even ones which you don't control/cannot package. No problem - you manage this dependency via XML, and have the class/package providing the service deployed by another provider, while still having it seamlessly integrated with your app.

OTOH, dependencies which are internal to the app, but which you don't want hard-coded, you can still manage via annotations or via autowiring.

There's another thing that happens when you use spring in a project on which several people work at the same time. You get to establish some discipline about what gets into the XML and what gets annotated - beans tend to fall into a very small number of distinct and specific categories, apart from some beans which form the application's infrastructure. This doesn't need to be enforced, it happens instinctively. In time, it leads to an application structure which is much easier to read from the XML - only essential info is there, not all dependencies, including the non-essential ones.

Furthermore, you can split this birds-eye view on your application into several parts, if it becomes unreadable, to make it manageable.

All this would be a lot less important if your application was of manageable size, no matter how complex, the team working on it was stable, and the programmers of exquisite quality. But in most spring projects this isn't the case - there's significant programmer turnover, programmers are mostly average or only slightly better than average, and although most applications are of low complexity they are huge. In such cases, whatever helps to make a project more manageable is valuable.

11:47 AM  
Blogger Unknown said...

Spring has similar assumptions to Microsoft IDEs: If we auto-generate, auto-wire, & auto-inject everything any idiot can learn to generate a hardened business application in no time at all. Of course when anything complicated fails only the guy with 20 years experience who knows how to pull a convoluted rats nest apart can figure out how to fix it. Kudos my friend. You can teach yourself to use good design patterns, like dependency injection, without turning over control of your code to a robotic automaton that will generate unnecessary baggage and miss important nuances.

8:49 PM  
Blogger Unknown said...

I think I should clarify that I have nothing against abstraction and the evolution of languages from 1GL, to 2GL, to 3GL to ?. My first 8 years in the chair I wrote assembler and debugged in machine code, and I wouldn't want to go back. Nor would I disavow objects, or modern patterns like separation of concerns. What I can't take is 'gratuitous abstraction.' That's abstraction for abstraction's sake. An abstraction should not be redundant with what it's abstracting, should make your job easier, make your code less complex without exploding the size of it, and not interfere with well established patterns at the same level of abstraction. In my opinion JQUERY is a good abstraction of Java Script because it fits those criteria. Some abstractions however simply add complexity without really adding any or all of those values.

10:04 PM  

Post a Comment

<< Home