I'm very intrigued by the fact that everybody talks about things such as EjbInconsistencies
when there still are such glaring flaws, it would qualify EJB as one of the biggest intellectual frauds in Computer Science.
Let's start by the most obvious one: ejbFindByXXX(...) generates n+1 database calls to return n rows.
Even to access an entity by its primary key, you have to go twice to the database.
This is in the case of BeanManagedPersistence
, but even some of the most notorious Ejb 1.1 app servers do the same with ContainerManagedPersistence
The flaw is even admitted by some engineers from Sun, of course it is not advertised as such.
I beg to differ but a CMP finder method in WebSphere will return N rows with exactly ONE SQL call. You can also build BMP ejb Systems such that a single SQL call can retrieve the data for multiple rows, even in multiple EJB's. It simply requires the use of a Row Cache. I think your statements are a bit broad. .. and based on an overly simplistic interpretation of the specification.
This is as stupid as it gets, and it is an embarrassment for Computer Science in general, that many software engineers are still programming with this ridiculous design flaw, and they've been doing so for almost three years.
When I wrote this thing some time ago, the EJB 2.0 was not official. Now this AntiPattern is stamped and approved in the all new EJB 2.0 specification.
. One of the many EjbFlaws
What floors me most about EJB is that it breaks one of the fundamental concepts of object-oriented programming: that state and behaviour belong together. This is what ConceptualIntegrity
is all about.
How can one abstract and then encapsulate functionality in a system if the "objects" don't and/or can't support any real notion of state? Now, of course, EJB's solution for this is EntityBean
s and CMP architecture, but give me a break! This is COBOL reborn in Java for goodness sakes; except it's worse: COBOL was actually decent at moving data around.
By and large, I think EJB - all of J2EE in fact - is simply this: Pandering to big corporate management for a "simpler way" to build applications. They say, "We really can't find many real
OO programmers, so what can we do?" Or, "We have a bunch of COBOL programmers and this OO thing is way over their head, what can we do?" Sun then happily replies, "Well, we have this great architecture, with blue-prints and everything. It's not really OO, it is CICS written in Java. You don't really have to think
about the design; just follow the blue-prints
. You can continue to use your RDBMS and have 100 developers clicking buttons and code-generating a slug of ugly beans. But it will work." -- JeffPanici
Almost every successful big project I've been on had a set of blueprints, i.e. templates or patterns, that people followed for the common architectural scenarios in the system. I believe MartinFowler argued for this kind of approach in a chapter of JamesOdell's Advanced Object Oriented design book. The whole point is that you shouldn't have to continually think about the design (and re-invent the wheel), you could focus on the immediate business logic. Sun's BluePrints? are a fair introduction to OO abstraction & layering principles, obviously not the best, and I don't know any team that "worships" them. They're mainly a guide to get started.
Complaining about EJB not being OO is really glossing over the context of a distributed object system. To scale with objects, as practitioners have figured out, you have three choices:
a) stateless components (like CICS and MTS/COM+ and session beans - they work but they're a pain to write)
b) objects that efficiently sync with an RDBMS, (i.e. they don't perform unnecessary queries, they perform minimal update statements, etc. When done right, this gives negligible overhead compared to a ResultSet)
c) an object database
Personally, I'd prefer (B), and in special circumstances, (C). Entity beans have been (B) and really haven't done a good job of this until EJB 2.0 CMP. EJB 2.0 BMP still requires you to avoid finder methods if you want performance. -- StuCharlton
I don't know about WebSphere
and CMP and I give you credit that it is so. As a matter of fact I can't give app server names because the information came to me from some friends who effectively decompiled the classes.
But if you think I'm overly simplistic, would you care to say whether it is true or not that as result of a call to findXXX(...) in BMP case followed by some access on each of the beans required (assuming the beans have not been referenced yet in the transaction), an application server will generate n+1 database calls.
If it is true, than maybe you can find explanations for this situation (I hope you won't say it is the normal thing to do). Would you care to detail here?
It is true that someone can tweak the ejbLoad/ejbStore mechanism to avoid that,
but this is
- against the specs, the spirit of the specs, and most of the "blueprints" and guidelines
- problematic to be implemented unless you have access to the inner working of the app server the transactional, distributed row cache problem has not been yet completely solved even for less restrictive environments, much less for the stupid limitations of EJB Container
- it doesn't justify the sheer stupidity of the BMP model
I think you're asking too much here. BMP literally means YOU THE PROGRAMMER writes the persistence layer. ALL OF IT!!!! It's not the application server that generates ANY SQL calls in the BMP case - it's YOU as a programmer that does it. If you slavishly follow example code in the Sun books, I won't be surprised by any efficiency or lack thereof that you get. On the other hand, if you take a more pragmatic approach and plan on making some code be app-server specific, while the rest remains portable, then you can actually solve this problem.
So, I'm not talking about tweaking the ejbLoad/ejbStore mechanism at all. I'm talking about simply taking advantage of the fact that you know you're in a transactional context to load things once (in the ejbFindBy... method) and then have the load and store methods pull things out of that cache as long as you are within the same transaction. All this requires is the ability to find out what transaction your EJB is part of. Yes, the best way to do that might be through an app-server specific call, but there are ways to do it fully within the spec, it just requires more programming.
Now even if you hide your identity, I expect you won't come with lame arguments that you know are almost false. And if you capitalize and punctuate your phrases funny, you won't convince me better. Please let me know where you safely store the damn cache between the callbacks ejbFindXXX(), ejbLoad(). By the way, you don't always have access to the transaction ID (another dumb thing in the EJB spec), and the Usertransaction object is not guaranteed to help you do safe maps, but of course you knew that already.
There is an almost safe "escape" in the Entity model that let's you circumvent this stupidity, but this doesn't change the fact that the EJB model almost requires/enforces you to use the n+1 database calls. This one cannot be justified even by the most brilliant workarounds, and by the way, if you show your identity, I'll exemplify the pattern.
No matter how clever the work-arounds you or I may find, they are really workarounds, don't the official documents from Sun and tons of stupid books effectively tell you to generate the n+1 database calls. If you don't want to call them tweaks, that's fine, but you have to recognize that you should have been helped by the EJB model. Instead, the model tells you a really dumb thing to do. Luckily, the model has cracks in it to allow you or me or guys who are thinking to find workarounds.
So your arguments in no way prove that the BMP model is sound, rather it can be worked around.
And the idea of a distributed row cache is a bit much. That goes to the heart of the problem that EJB 2.0 final spec 2 addresses - distributed entities are a dumb idea. If you assume your entities are distributed, then you're in for a whole lot of trouble. If you simply let that drop and put some restrictions on the way you deploy your application (perfectly reasonable) then it becomes merely hard, and not impossible...
Distributed entities and distributed transactions are almost a guarantee when you use EJB. I'm not talking about the fact that entities were expected to be called over the RMI/TCP stack even if local (another pretty stupid thing, not a limitation). I'm talking that you're almost guaranteed that the same entities will be instantiated on several "caches". Of course you knew that also.
- I understand this problem - all beans are remote - has been removed in EJB2.0 with the addition of local interfaces. see EjbTwo. -- DinoChiesa
A quote from Sun's site, basically saying that you HAVE to use CMP whenever you can:
"Another instance of this optimization is calling find methods. Finding an entity provides a reference to that entity, which can be, and most likely will be, used right after the find operation. This usually involves two database accesses:
Finding the record in the database and retrieving the primary key
Retrieving the record data into the buffer.
Of course the guy doesn't say that 2 accesses is only in the case of findByPrimaryKey,
in the case of findXXX is n+1
Even the findByPrimaryKey is stupid.
If this means that they force you to use CMP to get decent performance (please note that in the EJB circles the conventional wisdom has been exactly the opposite), why do they have BMP at all? And why do they leave this design after three years?
You are looking at things with an isolated view point. The whole point is that MTS has no answer to EJB's entity beans. If you want to think it purely from a computer science point of view, think about the abstraction of data that this notion gives you. Then you also get automated persistence support - something that you will never get conceptually in MTS unless they acknowledge the need for abstraction of data component. The point is not that that some vendor is implementing this feature that is not as efficient as a work around presented by Microsoft. The beauty lies in the abstraction when you are programming.
Well how can the beauty of abstraction justify an unnecessary AntiPattern? The fact that this thing is an AntiPattern and is unnecessary is proven by the the fact that CMP Entity Beans can do without n+1 database calls. Unfortunately those also suffer from more anti-patterns of their own.
- You are not speaking from an informed perspective on MTS. Actually MTS is not the "app server" piece of Microsoft's architecture, but is merely a transaction service within Windows. If you are talking about persistence and data abstraction, then MTS is related but not on point. re: "You will never get automated persistence support" - Check out ADO.NET. It provides this today. Yes it is not as broadly OO (sort of) as EJB, but it is simple, easy, fast, and works with the SQL you already know. For more on this check out http://aspx.securedomains.com/devguide/adonet/automaticallygeneratedcommands.aspx .
The whole reason entity beans aren't in MTS/COM+ is because they do not scale. Live with it and move on. Good call by Microsoft. Abstraction is ok, but only so long as it doesn't kill performance. Performance is for users. Abstraction is for programmers. Which do you think counts?
The above is not true. Abstraction is for users when they don't want to pay excessive amounts of money to change their software after it's over a year in production. Further, EJB v2 BMP remains a toad, but EJB v2 CMP does scale. -- StuCharlton