Sun Jan 25, 2004 2:19 pm
Let's say we're using Struts, or an essentially similar framework,
for a web application.
Let's say we've got our domain layer up and running. Whatever
the underlying persistence mechanisms used, you ultimately
end up with domain objects that implement getters for accessing
their attributes, and these getters, at some point, are gonna
incur a database access operation.
Is this a Good Thing, a Bad Thing, or an It Depends Thing,
from the point of view of a JSP? (Whether or not you're using
custom tags is here irrelevant.)
Say we've generating a view on a project's attributes. Is not
the purpose of the domain layer to encapsulate and abstract
the domain data (project, in this case) for the entire UI
layer? Thus the JSP will be nice and neat and say something
like project.getAddress() or similar, which, in principle,
could incur a database query if the information wasn't already
previously fetched.
However, if an error occurs (say the database is crashed), then
it's too late to redirect to an errorpage JSP.
So the relevant handler should somehow pre-fetch all the
domain data that the JSP is gonna need, store it in the session,
and then the JSP can safely fetch all the stuff from the session.
If we need domain data A, B, and C, but loading of C from
persistent storage catastrophically fails, then the handler
can redirect to an error page (or whatever).
But doesn't this sort of water down the whole idea of having
the domain model in the first place? Now you need a whole
second set of domain classes that are *not* "connected" to
the persistent storage to represent the domain data for the
JSPs ...
I've racked my brain and the literature for some solution to
this, but haven't come up with anything I like.
Ideally, you could somehow arrange things so that you could
present some kind of a restricted view of the domain objects
to the JSPs, in such a way that you guarantee that the data
is all preloaded into memory (the session) by the handler,
but where you wouldn't need any kind of duplication of the
domain classes ...
Maybe I'm just confused. (It's quarter past midnight local
time (EET). Bedtime.)
AllanHalme
One option is, as you suggest, to create a second set of objects that
contain the data that the JSP page needs.
This is basically the J2EE Data Transfer Object (or
ValueObject) pattern.
On the one hand it is duplicating the structure of your domain model classes
but it does help encapsulate domain model (e.g. prevents the JSP page from
calling setters) and avoids complications that result from JSP pages trying
to access the database, such as the one that you mention.
Using DTOs also prevents other problems such as transaction rollbacks and
retries that cause the JSP pages to be executed twice.
Another option is that some persistence frameworks such as JDO and Hibernate
support "disconnected" objects. One downside with this approach is that if
you haven't retrieved all of the data before "disconnecting" the object from
the database you will get some kind of error when your JSP page tries to
access the missing data. You do not have the typesafety provided by DTOs.
You are also giving the presentation tier access to the business logic,
which might not be all that desirable.
Finally, you could let the JSP page access domain objects that are connected
to the database and allow database accesses to happen. Whether this is
acceptable depends on the frequency of database errors and if they occur too
late to allow a redirection to an error page. Also, as I mentioned above
there are transaction related issues that require careful handling. For
example, in a JDO application you would have to enable non-transactional
reads.
ChrisRichardson
> Let's say we've got our domain layer up and running. Whatever
> the underlying persistence mechanisms used, you ultimately
> end up with domain objects that implement getters for accessing
> their attributes, and these getters, at some point, are gonna
> incur a database access operation.
>
> Is this a Good Thing, a Bad Thing, or an It Depends Thing,
> from the point of view of a JSP? (Whether or not you're using
> custom tags is here irrelevant.)
I say it's a good thing.
> Say we've generating a view on a project's attributes. Is not
> the purpose of the domain layer to encapsulate and abstract
> the domain data (project, in this case) for the entire UI
> layer? Thus the JSP will be nice and neat and say something
> like project.getAddress() or similar, which, in principle,
> could incur a database query if the information wasn't already
> previously fetched.
Yes, that's why it's a good thing - it's nice and neat.
> However, if an error occurs (say the database is crashed), then
> it's too late to redirect to an errorpage JSP.
>
> So the relevant handler should somehow pre-fetch all the
> domain data that the JSP is gonna need, store it in the session,
> and then the JSP can safely fetch all the stuff from the session.
No, that would be gross.
> If we need domain data A, B, and C, but loading of C from
> persistent storage catastrophically fails, then the handler
> can redirect to an error page (or whatever).
>
> But doesn't this sort of water down the whole idea of having
> the domain model in the first place? Now you need a whole
> second set of domain classes that are *not* "connected" to
> the persistent storage to represent the domain data for the
> JSPs ...
>
> I've racked my brain and the literature for some solution to
> this, but haven't come up with anything I like.
Well, the fact is that an exceptional condition can occur downstream of a domain
object accessor, if that accessor causes database I/O to get the thing being
accessed. So the accessor simply needs to throw an exception.
<java_assumption>For example TOPLink chooses to use all RuntimeExceptions, and
it is possible for domain object accessor methods to throw runtime
TOPLinkExceptions when using TOPLink. The only other choice is to declare that
the method may throw checked exception (e.g. CouldNotAccessException - see
http://c2.com/cgi/wiki?HomogenizeExceptions) which may cause a ripple of such
declarations throughout your codebase. But, that's exception handling in Java -
another conversation altogether.</java_assumption>
However I wouldn't destroy the conceptual simplicity of layering and domain
model navigation just to get around the reality that domain object accessor
methods can encounter exceptional conditions when not using an OODBMS.
> Ideally, you could somehow arrange things so that you could
> present some kind of a restricted view of the domain objects
> to the JSPs, in such a way that you guarantee that the data
> is all preloaded into memory (the session) by the handler,
> but where you wouldn't need any kind of duplication of the
> domain classes ...
Why do you feel the need to guarantee that? Let the data be loaded on demand...
Best Regards,
RandyStafford
I've found the costs of DTOs to far outweigh the benefits every time I've seen
them. The code duplication stinks, and represents a major development burden.
The "assembly" logic to instantiate DTOs from domain objects, and especially to
flush DTO state into domain objects in write transactions, can become
horrendously complex, especially if you have use cases / editors that can update
complex aggregations where some things in the aggregate may have changed and
some may not have. The response time contribution of instantiating all those
ephemeral objects, and garbage collecting them later, can be significant.
DTOs arose as parameter types in remote method signatures, so that something
other than other remotables, simple data types, and entire fully-connected
domain model graphs could be passed and returned between remote client and
remote server. If they have some kind of benefit w.r.t. transactions, that's
coincidental. I don't buy that "using DTOs also prevents other problems such as
transaction rollbacks".
All that complexity is accidental. There's no law that says JSPs and Servlets
have to run in one VM while services and domain objects run in another VM. The
simplest thing is to let the entire layer stack run in the same VM. Then you
don't need DTOs and all the costs they incur.
RandyStafford
I agree that DTOs have the drawbacks you outlined.
However, one benefit of using DTOs is that all of the database accesses are
guaranteed to be done and the transaction committed before the JSP page is
executed.
For instance, the servlet/action/etc calls the business tier that begins a
transaction, acesses the database, commits the transaction and returns a
DTOs containing the data to display.
The JSP page then generates the response using the data in the DTO.
If on the other hand you let the JSP page directly/indirectly access the
domain objects and database then you can run into some tricky transaction
issues.
For example, if you do not commit the transaction until after the JSP page
has completed you might get an optimistic locking failure requiring you to
rollback and retry the transaction,
which means re-executing the JSP page.
In order to do this you would have to guarantee being able to reset the
HttpServletResponse and prevent the web container from sending partial
output back to the browser.
Alternatively, you could commit the transaction prior to invoking the JSP
page and thereby minimize the probability of having to rollback.
The JSP page would then have to use some non-transactional read mechanism to
access the database.
Whether or not you do this efficiently depends on the underlying persistence
framework.
In addition, since the application is using multiple transactions it is not
able to get a consistent view of the database.
Another benefit of using DTOs is that they enable the domain objects to
remain hidden.
If a JSP or some other presentation tier component has direct access to a
domain object it can bypass a service and update a domain object in ways
that violate the business rules.
ChrisRichardson
But if you need to access the same domain model remotely through either a thick client interface, or through a distributed service, then you'll need the DTOs. The trick is to define all these remote service interfaces and then examine their data needs. The DTO hierarchy can then be refactored to reduce the number of DTOs needed with some extra data being sent in some instances.
DTOs are also useful in component based development to reduce the coupling between components. However, as Randy suggests, the benefit may out weigh the cost if the components are rarely deployed independently.
JimAmsden
Chris,
I didn't quite follow your logic. Wouldn't a JSP page or servlet execute just as fast as the mediators that copy data out of the domain model into the DTOs? Wouldn't the possibility of concurrency collisions be about the same?
On hiding the domain layer: I see your point, but to some extent, its exactly the domain layer you don't what to hide because it contains the business knowledge. Yes, you want to hide the data source layer and its data mapper mediators (at least as much as possible), and you want clients to use the business services layer first, but this can prevent "object mining" to use the business domain for purposes that weren't captured in the services layer. As long as the business objects in the domain model are responsible for their integrity, and expect rather than delegating it to "controller" service classes, this should be OK.
In any case, it would seem that there are some reasonable design choices here where one approach would be preferable over another.
JimAmsden
> But doesn't this sort of water down the whole idea of having
> the domain model in the first place? Now you need a whole
> second set of domain classes that are *not* "connected" to
> the persistent storage to represent the domain data for the JSPs ...
That's a good question, Allan. I have been struggling with same problem. I
have been using JDO, something like this:
In Struts Action:
openConnection
fetchDomainObject
forwardToJspView (view uses JSTL and EL)
closeConnection
So, the JSP page is rendering a "live" domain object. If the getters on the
domain object (which are implicitly called from JSP EL) fail for any reason,
I have a problem. No error handler gets invoked. EL doesn't even show the
error. It just blanks out.
Solution 1: Copy the data out of "live" domain object into DTO - Pain in the
butt
Solution 2: be really sure no errors will occur - impossible
Solution 3: in JDO 2 , there will be a "detach" mechanism - not out yet.
So, all three solutions stink. Any suggestions?
DaveFord
Hi Dave (and Allan),
I might have one suggestion: don't let your design be overly influenced (in a
direction you don't like) by something that might only rarely occur (if ever).
My company's J2EE application has been in production for longer than the 2.5
years I've been here. When I got here, the architecture distributed the web
container from the EJB container and used DTOs (so I've seen, again, the various
kinds of pain that causes). I've since undistributed the architecture and begun
eliminating DTOs from pre-existing functionality (the team loves the
simplification, BTW). About a year ago we had a major release go live that
featured a major new subsystem of some 100 new use cases, written from the
ground up on a DTO-less "new" framework. In all the functionality that is using
the new framework, it is possible for a JSP, during rendering, to make an
invocation that will ultimately cause database I/O through a domain object
accessor method. And do you know what? We have *never* had a database outage
cause a runtime exception to be thrown out of those accessor methods. In fact,
we've never had a database outage in production at all during the last year.
And we typically get over 1000 logins and 30000 JSP views per day. So I'd
rather not torture my architecture and development team to handle a scenario
that's just not real. The pragmatic thing to do is to prefer the clean, simple
approach.
RandyStafford
> Solution 3: in JDO 2 , there will be a "detach" mechanism - not out
> yet.
Happily, Kodo already has detach functionality available. Hooray!
> So, all three solutions stink. Any suggestions?
Do you have an error-page directive configured in your WAR, or a
specific errorPage attribute in your JSP? You should be able to set up
a general-purpose error page that dumps the exception etc.
If you want to get fancy, do something neat with cookies or something
to figure out if it should show the exception (to developers) or just
show an apology (to end-users). (I've found that it's better to use
cookies than some sort of system login information for this, since,
well, if your DB is down, then you probably won't be able to
authenticate yourself, so you won't be able to see the full exception.)
PatrickLinskey
> I might have one suggestion: don't let your design be overly
> influenced (in a direction you don't like) by something that might
> only rarely occur (if ever).
>
> [...]
>
> I'd rather not torture my architecture and development team to
> handle a scenario that's just not real. The pragmatic thing to
> do is to prefer the clean, simple approach.
This, I agree with completely. Randy, you've managed to perfectly
elucidate that which I've had as a gut feeling all along -- it
sounds obvious when somebody actually manages to put it into words,
but that's the mark of true wisdom.
Yet again we see that the combination philosophy of
(i) Always do the simplest thing that could possibly work
(ii) YAGNI
(iii) common sense (highly underrated these days)
is truly powerful.
And besides, if we can indeed configure a generic error JSP that
the web container can direct to upon an exception in a JSP, then
all's well.
And even if not, then what's an exception if not exceptional?
The system doesn't have to do anything particularly sophisticated
if an exception occurs -- after all, it's an exceptional situation.
During the 6 months I've been on the project, and from what I've
gathered of the previous 18 months before that, our application
has rarely if ever crashed on a database access error (one sole
case comes to mind) -- all our real problems (that the customer
complains about) revolve around performance and usability, which
are getting addressed by our architectural refactorings.
Thanks for all the comments, guys.
AllanHalme
Hey - I could get used to that moniker! :)
Another factor may be Struts. We don't use it, on purpose. We have our own
framework that uses our own Front Controller servlet. All our URLs go through
that servlet. So, we have a chance (in that servlet's doGet() method) to do
some last-ditch exception catching (and error message displaying, etc.) before
the stack unwinds back out to the web container (and its error page
configuration, etc.) - because it's always downstream of the Front Controller's
doGet() that RequestDispatcher.forward() to the next JSP is invoked. So
exceptions thrown by that JSP servlet's service() method propagate back to the
catch clause in our Front Controller's doGet(). Now, I grant the socket may
have already been written to, but we can at least append an error message. And
we do have property-driven "modes" (development, test, production, etc.) that
differ from environment to environment and control the system's response to an
exception (display exception information versus apologetic message), as Patrick
Linksey suggested, except we do it on the server side not the client side. I
don't know if all that kind of thing is possible with Struts.
RandyStafford
> Happily, Kodo already has detach functionality available. Hooray!
True. I'm showing my students that feature this week. How close is Kodo's
detach functionality to the 2.0 detach? Is there a preview release of JDO
2.0?
> Do you have an error-page directive configured in your WAR
Yes. I think my issue here is EL. I need to read the EL spec (or JSP Spec?).
If I do this:
Last Name: <%= p.getLastName() %>
Then, if getLastName() throws an exception, the exception propagates to the
errorPage. However, if I use this (EL):
Last Name: ${ p.lastName }
Then, the exception is quietly ignored. The expression evaluates to empty
string and the page renders, but the errorPage is never called. I think
that's how EL is supposed to work. Can anyone verify that? Is EL supposed to
silently suppress exceptions? It's a bummer because it's very handy
otherwise.
Chris Richardson said:
> For example, if you do not commit the transaction until after the JSP page
> has completed you might get an optimistic locking failure requiring you to
> rollback and retry the transaction,
> which means re-executing the JSP page.
I don't do updates from JSP's - only rendering (getter methods). For reads,
there isn't anything to rollback.
DaveFord
> > Another factor may be Struts.
I don't actually use Struts either. I just use it for conversation's sake
because most people know what it is. I have a Front Controller that allows
for pre and post-render processing, and interceptors.
DaveFord
>Chris,
>I didn't quite follow your logic. Wouldn't a JSP page or servlet execute just >as fast as the mediators that copy data out of the domain model into the >DTOs? Wouldn't the possibility of concurrency collisions be about the same?
Speed is not the issue. It is to do with how transactions can give you a consistent view of the database.
If you are using DTOs, then the code that updates the database and creates the DTOs executes is a single database transaction and so can give you a consistent view of the database.
If you are letting the JSP pages access the persistent domain objects then either:
(a) The transaction spans both the servlet, which invokes code that updates the database, and the JSP page, which reads the data. Potentially, the commit can fail due to, for example, optimistic locking errors etc. and you have to re-execute the JSP page.
or
(b) The servlet executes one transaction that does the updates and the JSP pages use either non-transactional reads or do the reads in a separate transactions. Because there are multiple transactions there is the potential for the database to change and for the JSP page to get an inconsistent view of the data.
> I don't do updates from JSP's - only rendering (getter
> methods). For reads,
> there isn't anything to rollback.
>
But what about the servlet/action/controller that gets invoked prior to the
JSP. Can't that do updates?
ChrisRichardson
>> Happily, Kodo already has detach functionality available. Hooray!
> True. I'm showing my students that feature this week. How close is
> Kodo's
> detach functionality to the 2.0 detach?
The detach functionality follows the currently-defined JDO2 proposed
semantics.
> Is there a preview release of JDO 2.0?
Nothing official yet, but we've been rolling JDO2 proposed features and
JDO2-compliant APIs into Kodo since September. That means that
currently, you've got aggregates, projections, setRollbackOnly(),
detachment, PM.getConnection(), all using the JDO2 proposed syntax.
Obviously, we also have lots of other features that are in the JDO2
proposal (direct SQL execution, custom fetch groups, interface support,
etc.), but those features don't currently use the same syntax as will
end up in JDO2.
> Yes. I think my issue here is EL. I need to read the EL spec (or JSP
> Spec?).
> If I do this:
Aah, very interesting. I missed the EL comments in your original email.
Agreed that you'd want to be seeing an exception get through the EL
barriers there. This bears investigation....
PatrickLinskey
Allan Halme wrote:
<snip />
> But doesn't this sort of water down the whole idea of having
> the domain model in the first place? Now you need a whole
> second set of domain classes that are *not* "connected" to
> the persistent storage to represent the domain data for the
> JSPs ...
You don't have to use domain objects in your JSPs. Data dictionaries
would do the job. A formatting strategy turns your connected domain
objects into Maps and Collections of Maps, which you can then use to
display data on your JSP. By the time the data reaches the JSPs, all the
world's a String.
I did this on a recent project and I feel it worked well. If I were to
do it over again, however, I think I would refine the formatting
strategy: not all places that display a Float want to display the same
number of decimal places, for example....
JBRainsberger
If you generally agree with four-layer architecture
(
http://c2.com/cgi/wiki?FourLayerArchitecture), and if you agree that JSPs are
presentation-layer artifacts, then something should serve as the application
layer in a JSP UI. In my framework I have a layer of JspModels, which are
ApplicationModels (
http://c2.com/cgi/wiki?ModelModelViewController) in a JSP
"Model 2" architecture (
http://c2.com/cgi/wiki?MvcInJspModelTwoArchitecture).
Historically in Smalltalk, one of the primary responsibilities of
ApplicationModels was to adapt the domain to the view. Thus the interface
between View and ApplicationModel is crossed by only simple data types (strings,
numbers, dates, booleans, etc.), as Mr. Raisberger suggests,
and ApplicationModels or their delegates are responsible for extracting the
simple-typed aspects of the domain objects that are presented to the user.
RandyStafford
DomainLayerAccessFromJSPsAndHandlers is mentioned on: ThreadView