Can’t let Floyd get the last word… More EJB history

Floyd and I are in a jenn-yoo-ein blog war now, as he responds to my post accusing him of EJB revisionism. This can only mean that I must now respond with vigor and extreme hostility, ripping his arguments to shreds and leaving no doubt in anyone’s mind about our respective ability in blogging, Java, or technology in general.

Not. (Gotcha, Floyd. 🙂 )

Truthfully, Floyd was right when he said

    While Ted phrased his points as corrections to my own, for the most part I don’t think they are, two people of different backgrounds can certainly see and interpret different aspects about why things are, especially historically. We are talking about history, not code. 🙂 …. Perhaps I should have been more upfront on my last entry, but the perspective I was giving was based on how things would have looked like to the developer at various points in history, and how that then affected adoption and growth, etc. It perhaps should have been phrased "a brief history of EJB adoption from the developer’s perspective", not the spec designer, book author, or specification implementor’s perspective. If I am being revisionist, then so is Ted, as we are both revising history with our own interpretations. 🙂

Exactly. I read Floyd’s post to mean that he was describing the development of EJB from its creators’ intent, rather than an interpretation of how developers saw–and largely misinterpreted–what its intent was. After all, it’s fairly obvious in hindsight, I think, that developers, and their management too for that matter, really really screwed the pooch when it came to EJB. Using it when it wasn’t really called for, and expecting that simply using EJB in of itself would provide the scalability and performance desired, will leave any development project pretty grossly screwed up.

Floyd’s also right when he says

    … it is obvious that people reading Ted’s blog will think that every point I made is wrong (Hani certainly did), so I feel compelled to respond …

        Unfortunately, Floyd seems to have fallen into the same trap that everybody else did back then, which was to assume that since EJB built itself on top of RMI (or so it seemed), then EJB must essentially be a distributed object framework just as RMI was, just as CORBA was before it, just as DCOM was over in the Microsoft space.

    I suppose that I invited this by saying early that EJB was designed to be distributed object framework, but take alone that sentence is out of context – as I mentioned later on in the blog, the distributed object framework was just one of the three major categories.

Yes, Floyd, you DID invite my blog-wrath when you said that, because unfortunately I think that’s a mistake that people continue to make unto this day, not just with EJB, but with some of its intended successors, too, the principal one being Spring.

The problem I have with the industry right now is stated rather simply: Not every problem we face lends itself to an object-oriented solution. For a large percentage of developers working today, that is an uncomfortable feeling, and thus gets repressed with a brutality normally reserved for hideous personality defects that we don’t want to own up to. Whether we like it or not, however, the design space that EJB–and Spring–operate in is a space that doesn’t lend itself to the object-oriented paradigm, and trying to pretend otherwise can lead us into all sorts of dangerous places.

Consider another technology whose major architectural principles also don’t follow an O-O slant, that being the HTTP and Servlet space. When you consider the major tenets of object-orientation, usually consisting of polymorphism, encapsulation and a methodology that demands fine-grained methods and objects ("No method should be longer than a page in your editor" and "No class’ responsibilities should exceed what can be written on an index card" being two of the common aphorisms used to describe proper O-O design and implementation), it slowly dawns on you that servlets don’t really follow that approach at all. In fact, if we were to compare a servlet’s overall design, it smacks much more of a 3270 session, which is essentially a procedural space: requests are processed, per-session data used as part of that processing, generating results that are returned. We can put an object-ish veneer over the whole thing, as frameworks like Tapestry or JSF try to do, but the underlying driving forces are still the same, essentially procedural in nature. The Servlet API, then, is an object facade over a fundamentally procedural task, and the way in which we write servlets reflect that: we don’t generally access fields in servlets (that creates a synchronization concern), for example, but instead access data stored in an entirely separate object that the container manages for us (that still has synchronization concerns), that being the Session, of course. We don’t expect to be able to inherit one servlet from another, since each servlet tends to be single-purpose and single-minded; we don’t usually look to polymorphically substitute one servlet in the place of another. (Note that this isn’t to say that servlets aren’t devoid of polymorphism entirely, only that we as the development community using them don’t make use of polymorphism in our usage.)

I find it particularly telling that, for all intents and purposes, the Servlet API looks astonishingly like the ISAPI or NSAPI APIs that predated them, which were intended for procedural languages (by which of course I mean C) instead of object-oriented ones. In fact, to a large degree, they’re identical. The .NET HttpHandler API, the logical equivalent is even less object-oriented:

public interface IHttpHandler
{
  void ProcessRequest(HttpContext context);
  bool IsReusable { get; }
}

You don’t get much more object minimalist than that.

(For the Java developers in the crowd, the Java translation would look like:

public interface IHttpHandler
{
  public void ProcessRequest(HttpContext context);
  public boolean getIsReusable();
}

where HttpContext is an object that contains methods to access HttpServletRequest, HttpServletResponse, Session, ServletContext, and a few other interesting tidbits. The IsReusable property is just whether or not instances of this thing can be pooled, something which the Servlet API defines on its own terms; I suppose you could see returning false from this property as the equivalent of implementing SingleThreadModel. Sort of.)

All of this isn’t to say that the Servlet API isn’t useful or interesting, but simply to say that we pretty much silently rolled with the fact that it was a procedural space, and adjusted our use of the object-oriented approaches accordingly.

Enter EJB. And MTS/COM+, for that matter. Web services guys, listen up–you’re likely headed down the same path if you’re not careful. Ditto for anybody contemplating Indigo.

EJB and MTS/COM+, unfortunately, were perceived to be object frameworks that required a usage model that followed the object tenets. And in each case, as time went on, patterns emerged that sought to debunk that idea and show that taking a strict object interpretation was doomed to failure. Effective COM and Transactional COM+ led the charge here in the MTS/COM+ environment. I hope I did the same with Effective Enterprise Java, but others came before me (in a much less "effective" style, of course 😉 ) saying much the same thing. And before us all came Deutsch’s "Fallacies of Distributed Computing" and Waldo and Wollrath’s "A Note on Distributed Computing" as basic foundation for the later works. (Hint: if you want to make a name for yourself, write an "Effective Web Services" book and say pretty much the same thing. You’ll be hailed as a hero.)

Herein lies my concern: Spring, as well as the other POJO-based containers, tend to lead developers back to an "objects-first" approach, and that tends to encourage object-oriented behavior, such as fine-grained methods, small-scale classes, inheritance, polymorphism, and so on. While I won’t go so far as to say that such things *can’t* be done in a Spring container, my worry is that developers will seek to do it both within the container (which I couldn’t care about in the least) as well as across container instances, which has Badly-Ending Story written all over it, as developers make the same mistakes that the CORBA crowd made, which is the same mistakes that the DCOM crowd made, the same mistakes the RMI crowd made, the same mistakes the OSF RPC crowd made, and so on.

Eventually, some day, we as an industry will recognize the truth of the statement "There is no such thing as a good distributed object model", but until that day, we have to remain on our guard against technologies that will–either by intent or by accident–lead us down that dark and stormy path. And thus the virulence of my reaction to Floyd’s comment; by characterizing EJB as a distributed object framework, even just to say that this was how it was perceived, reinforces that perception and puts us back in the danger seat all over again. So Floyd, maybe you weren’t wrong, per se, but you walked into an area in which those of us who’ve had to try and rescue EJB projects from themselves are a little sensitive, perhaps overly so.

Where Floyd and I do still disagree, however, is in this bit (him quoting me first):

        The hard choice is to realize that EJB’s "heavyweight" or "lightweight" factor isn’t in the API at all, but in the implementation of that API. And frankly, the big vendors have ALWAYS competed, at least with one another, on their "transparent middleware" services. That story doesn’t change.

    As mentioned before, I think the implementation is also a factor, but the entire light weight container / Dependency Injection / POJO "movement" directly contradicts the point that the weight of the API isn’t a factor "at all".

Au contraire. Just as JNDI is lookup via explicit method call, Dependency Injection is lookup via implicit method call (we’ve just reversed the direction)–effectively the same thing, just changing the API, reversing the direction of the invocation. The Spring interfaces that are available for implementation (for lifecycle control, etc) are pretty much equivalent to the EJB interfaces, it’s just that Spring makes them optional where EJB required them (admittedly an error in design). Spring’s major innovation wasn’t the POJO-based design model, or even the Dependency Injection approach, but in the lightweightness of the container. Think about it this way: would Spring developers be so excited about Spring if they had to run it as an external process, a la WebSphere or WebLogic? My casual anecdotal experience suggests no, thus leading me to believe that the API isn’t the major issue here. (Is implementing the SessionBean or MessageDrivenBean interface really THAT costly? If you truly dislike having to implement the methods you don’t care about, write a GenericSessionBean class that does the same thing the GenericServlet class does–provide common-sense NOP defaults. Message-Driven Beans are even simpler, and probably don’t even need a GenericMDB class, but your mileage may vary here.)

Floyd and I will probably disagree on Spring’s contributions, and this wouldn’t be the first time he and I have disagreed, nor would it be the first time I’ve clashed with people on the subject of Spring. Bruce Tate and I have had this discussion on a number of occasions, as have Justin Gehtland and Mark Richards (at the most recent NFJS show, in Des Moines). My point isn’t that Spring isn’t useful–far from it, I find Spring to be entirely useful–but that the efficacy of the tool is in its in-process nature, not its API. To more deeply understand this point, I strongly suggest anybody in the Java space play with COM+, which offers both an in-proc and out-of-proc model (known as "Library" and "Server" applications, respectively) as well as an annotation-based configuration scheme that will likely be similar to how EJB 3 works. (COM+ Queued Components are a bit like MDBs, and in this case, I prefer the EJB approach, but that’s neither here nor there.)

Oh, and by the way: welcome to the blogosphere, Floyd. 🙂