Community   SpringSource   Projects    Downloads    Documentation    Forums    Training   Exchange   Blogs

Go Back   Spring Community Forums > Core Spring Projects > Architecture Discussion

Reply
 
Thread Tools Display Modes
  #51  
Old Dec 1st, 2005, 08:49 AM
igorstoyanov igorstoyanov is offline
Junior Member
 
Join Date: Feb 2005
Posts: 5
Default

Quote:
I agree with your comments, but sometimes remoting can´t be avoided or the UI can't be plain html files. Suppose that the user interface is developed in C# using .Net technology (for rich clients that can't be based on a web app), and the core app is under JEE. The view need web services facades, core cannot export domain objects with that scenario.
The architectures that you describe don’t shy with its elegancy. However, there are often cases like that in practice. This situation could be handled much better if web services are used or the whole architecture is developed as Service Oriented Architecture (SOA) instead of using remoting. Remember, the first rule in remoting is to try to avoid it if you can. So, whey you have SOA, you don’t have DTOs, rather you have messages. The whole concept is much different then, but you can find more information on the web.

Code:
employeeDao.save(employee); //this one is questionable.
Quote:
There is no persistence logic in the domain objects, only a call the the persistance logic. There is nothing wrong with that.
DAO pattern is a good read. The main reason to use it to DECOUPLE the persistence concern from domain objects. The fact that you know how to retrieve dao is not responsibility of a domain object. This is very basic good practices, so if we don’t agree on that, than we have much different background :-).

Code:
EmployeeService{
    void fire(Employee employee){
        employee.fire();
        employeeDao.save(employee);
        deskDao.save(employee.getDesk());
    }
}
A little knowledge of Hibernate will show that a best practice is to save children objects from the parent. So, in the case above if you save employee object, the desk object will be save as well. You don’t need the call deskDao.save(employee.getDesk());. Again, this is very basic practices for Hibernate and service implementation.

Quote:

If I have a large object graph that is passed from my service to the web layer and I need to initialize some collections because of their lazy loading nature, then I have a coupling between my service and web layer!!!
I am not sure why you have coupling here. For every page, you attach/load the object to Hibernate session and populate/bind the view that you need.
Anyway, there are many ways to deal with lazy loading problems - OpenViewSession is the first step. Another way is to use You will still have problems at some points, but there are many ways to solve them. One very elegant way of doing it is to use AOP:
http://jroller.com/page/cenkcivici?e...s_to_hibernate

Also, if you have so big problem with lazy initialization, you can have session-per-conversation:
http://www.hibernate.org/42.html

Anyway, there a lot of information about lazy initialization problems out there.

Quote:
Alse when developing products with an open api availble for your clients, would you return Hibernate aware domain objects? What if your client suddenly has a lazyInitException. Well ofcoarse we can in that case pre-init all the lazy data. But other problems like hibernate version or last modification data fields shouldn't be visible to the outside world .... so can't we agree that there is a difference between data you work with in and below the service layer and data we work in in the views?
I am not sure what kind of scenario/product, this could happen. It looks to me that in this case again you need to provide services, which send messages to the client, instead of exposing domain object. However, there is a big difference in how you build normal application and how you build a product.

Last edited by igorstoyanov; Dec 1st, 2005 at 08:58 AM.
Reply With Quote
  #52  
Old Dec 1st, 2005, 10:01 AM
Alarmnummer Alarmnummer is offline
Senior Member
 
Join Date: Nov 2004
Location: Hilversum - The Netherlands
Posts: 1,053
Default

Quote:
Originally Posted by igorstoyanov


DAO pattern is a good read. The main reason to use it to DECOUPLE the persistence concern from domain objects.
It is meant to seperate the core logic from the persitance logic, but it doesn`t mean a domain object can`t call a dao (imho). The DAO imho isn`t meant to decouple domainlayer from the data access layer, it`s goal is to seperate aspects.

Quote:
The fact that you know how to retrieve dao is not responsibility of a domain object.
Well... that is one of the main points of this discussion

Quote:
A little knowledge of Hibernate will show that a best practice is to save children objects from the parent.
Quote:
What if that desk need to be saved by the deskdao?
So.. we aren`t talking about hibernate but talking hypothetically. What if the desk also needs to be saved, whose responsability should it be? Should it be part of the personDao? And how deep should it check what to save? Hibernate helps a lot, but what if you are using plain-jdbc or ibatis? And should the semantics of the DAO-interface depend on the or-mapper used in the implementation?

Last edited by Alarmnummer; Dec 1st, 2005 at 10:45 AM.
Reply With Quote
  #53  
Old Dec 1st, 2005, 11:43 AM
hucmuc hucmuc is offline
Senior Member
 
Join Date: Aug 2004
Posts: 107
Default

Quote:
Originally Posted by rebornspirit
Using Hibernate aware Domain objects in the web view for over 1.5 years now has thought me that using those kind of domain objects bring very specific problems like the evil LazyInitException!

So responses to that problem where, initialize what you need in the service layer so that the LazyInitExc doesn't occur anymore. I think this kind of solutions is ten time worse then the DRY problem you have when implementing dto's. If I have a large object graph that is passed from my service to the web layer and I need to initialize some collections because of their lazy loading nature, then I have a coupling between my service and web layer!!! Because for an optimized graph were you do not load / init lazy stuff that you will not need in the web layer, you have a coupling, as simple as that! So if you want your large object graph to be used by all kind of views, you will need to fully init / load the object graph ... and that totally rules out the benefits of using hibernate lazy loading (which is in most cases a bless).

Alse when developing products with an open api availble for your clients, would you return Hibernate aware domain objects? What if your client suddenly has a lazyInitException. Well ofcoarse we can in that case pre-init all the lazy data. But other problems like hibernate version or last modification data fields shouldn't be visible to the outside world .... so can't we agree that there is a difference between data you work with in and below the service layer and data we work in in the views? Anemic models should disappear from the scene and we should always use smart domain objects for all our logic... But I just get the explaination why we MUST use domain objects in the view, I find there is a fundamentally difference between a domain object and an object that represents a view on a domain model or a serie of domain models, I favor the lack of any kind of business logic that can be accessed through domain objects or whatever in the view, the view is for VIEWING things not for making business descissions... well that ofcoarse my 2 cents

So ok, I know DTO's aren't the holy grail .... god bless for that ... and we need a better approach ... but we have got to admit that using hibernate aware domain objects in the web view isn't the right way to go!

It would be great to hear from the Spring guru himself what he thinks about this so ROD IF YOU ARE READING THIS ...

Perhaps we'll never agree on a solution but I guess this thread makes us think about a problem that in this stage of frameworks should already have been cleared out

Grtz
I see the same problems especially with Hibernate. Crap, I had different calls to get the same domain object, each retrieving different graphs because of that stupid lazyInitException. Personally, this is a brain dead and non-intiuitive approach. Actually, I try to avoid having complex domain objects because of these recurring issues when developing for web base applications. Personally, I never bought the argument that the domain object MUST be used in the view layer. If it maps one-to-one, then I'll use it. However, I would still create the evil DTO object (your "view object") for optimization and clarity reasons. It is even worse when you save domain objects. What do you recreate in the post action? A partial graph of the domain object? A full graph of the domain object?

dino
Reply With Quote
  #54  
Old Dec 1st, 2005, 08:54 PM
igorstoyanov igorstoyanov is offline
Junior Member
 
Join Date: Feb 2005
Posts: 5
Default

Quote:
Hibernate helps a lot, but what if you are using plain-jdbc or ibatis? And should the semantics of the DAO-interface depend on the or-mapper used in the implementation?
No, the semantics of the DAO- interface should not depend on the ORM technology. That’s why we have interfaces and different implementation for them. Let say you have employer dao:

Code:
interface EmployerDAO{
	void save(Employer employer);
}
Then you have Hbernate implementation:
Code:
class HibernateEmplyerDAO extends SomeSpringClass implements EmpoyerDAO{
      void save(Employer employer){
	getHibernateTemplate().save(employer); //this will save the desk object as well.
       }		
}
Another implementation with jdbc or ibatis for example:
Code:
class SomeOtherImplementationEmplyerDAO implements EmpoyerDAO{
      void save(Employer employer){
	someSaveMethodForEmployer(empoyer);
	someSaveMethodForDesk(employer.getDesk());
       }		
}
So, you declare an interface that is behaving the same way regardless of the mapping technology.

Persistent Logic in Domain Objects

When you code according to OOP, you should think about object behavior. So, if you should have “fire” behavior, then you have:
Code:
Employee{
    void fire(Employee employee){..}
}
I guess you would not put save() as a behavior to your domain object because it is not required from the business. But your object knows how to save –
Code:
employeeDao.save(employee);
Anyway, before you say that this behavior is encapsulated, lets move to the next situation when you don’t invoke fire() through a service, rather you invoke it through another domain object.

Code:
EmployeeManager{
	boolean isEmployeeForFire(Employee employee){
		employee.fire();
		//do other stuff (to count the employees that are left for example;
		//if number of employee/desk are less then expected
		 return false;
		else
		   return true;
	}
}
It is not very realistic, but I hope you get the point. So in this case, I am performing a operation, that could probably wait for approval from the user and then save the employee object. If we have performed the save already in the fire() method, it is going to be too late for approval or not.

Of course, you can again say you can avoid this and there is nothing wrong with persistence calls inside domain objects. I think that that’s why many of the people have a lot of problem with lazy initialize. The persistence mechanism should be implemented in DAO and should be performed in service with transaction managed when needed.

Quote:
I see the same problems especially with Hibernate. Crap, I had different calls to get the same domain object, each retrieving different graphs because of that stupid lazyInitException.
I am not sure why you have these problems, and why you have different calls. I believe that a great deal of lazy initialization problems could be avoided, if you keep Hibernate session open for the time of the user interaction/request. I just want to clarify that I am talking mostly for web application. IF you keep the session open for the whole http request, then at least the first time of retrieving the object, you won’t have any initialization errors. Then, if you need to continue working with detached domain object, then you can re-attached to the Hibernate session in the beginning of every new request. The last one is not very recommend but if you have so many problems with lazy initialization, then this will be the easiest to do – refresh(), lock() or even update() would do the job.

Anyway, I think that the two framework Spring and Hibernate almost saved java and J2EE right now. They make thing simple, very productive and pleasure to work with. I am kind of surprised to see so many people having problems with Hibernate overall architectural design.

Last edited by igorstoyanov; Dec 1st, 2005 at 08:57 PM.
Reply With Quote
  #55  
Old Dec 2nd, 2005, 11:39 AM
hucmuc hucmuc is offline
Senior Member
 
Join Date: Aug 2004
Posts: 107
Default

Quote:
Originally Posted by igorstoyanov

I am not sure why you have these problems, and why you have different calls. I believe that a great deal of lazy initialization problems could be avoided, if you keep Hibernate session open for the time of the user interaction/request. I just want to clarify that I am talking mostly for web application. IF you keep the session open for the whole http request, then at least the first time of retrieving the object, you won’t have any initialization errors. Then, if you need to continue working with detached domain object, then you can re-attached to the Hibernate session in the beginning of every new request. The last one is not very recommend but if you have so many problems with lazy initialization, then this will be the easiest to do – refresh(), lock() or even update() would do the job.
I'm not a big fan of the keeping the session open throughout the request since it breaks encapsulation. What happens if you go to JDBC? What about scalability. Keeping a session around for a whole request cycle is awfully inefficient with sparadic n further SQL calls instead of a single joined sql statement. I think even Rod and Juergen are both against using such an approach. For practical reason, your approach is definitely usuable but I have a hard time justifying this from an architectural point of view.

Dino
Reply With Quote
  #56  
Old Dec 3rd, 2005, 12:25 AM
igorstoyanov igorstoyanov is offline
Junior Member
 
Join Date: Feb 2005
Posts: 5
Default Still, I believe it should be really about simplicity.

Since lazy loading is mostly Hibernate problem, I will start with this old post (2003) when Spring wasn’t very popular. In this blog, Gavin (I don’t want to start who said what) has expressed his opinion about this:
http://raibledesigns.com/page/rd?anc...ession_in_view


Quote:
> However, I had just one technical quibble. Your persistence
> code starts and ends a transaction / Hibernate Session in
> every DAO method. I would have thought that
> transaction/session management should be done in a layer
> *above* the DAOs, so that we can group together multiple
> calls to the DAO in the same Session/transaction. It seems
> that you would end up with DAOs were much coarser-grained
> than usual, and would contain all the business logic for a
> transaction *inside* the DAO, instead of in a "Command" that
> calls the DAO.
>
> I usually split things as follows:
>
> Action = pageflow logic / session management
> CommandHandler = framework object that manages
> exceptions/sessions/transactions
> Command = business logic
> DAO = persistence logic (no exception handling/session
> management/transaction management)
Of course, Spring framework wasn’t very popular back then, but now we have Spring, which allows us to abstract database mappers to a great extend. In fact, I am a little surprised by your statement:
Quote:
I think even Rod and Juergen are both against using such an approach.
This is from official Spring documentation with author Juergen Hoeller:
http://www.springframework.org/docs/...iewFilter.html

Quote:
Servlet 2.3 Filter that binds a Hibernate Session to the thread for the entire processing of the request. Intended for the "Open Session in View" pattern, i.e. to allow for lazy loading in web views despite the original transactions already being completed.
You still can have more than one session if you are concern too much about scalability:
Quote:
Alternatively, turn this filter into deferred close mode, by specifying "singleSession"="false": It will not use a single session per request then, but rather let each data access operation or transaction use its own session (like without Open Session in View). Each of those sessions will be registered for deferred close, though, actually processed at request completion.

A single session per request allows for most efficient first-level caching, but can cause side effects, for example on saveOrUpdate or if continuing after a rolled-back transaction. The deferred close strategy is as safe as no Open Session in View in that respect, while still allowing for lazy loading in views (but not providing a first-level cache for the entire request).
Anyway, many people have already talked about this topic many times. Very good explanation can be found in this blog:
http://www.jroller.com/page/cardshar...n_view_pattern

Some exerts:
Quote:
Why use the Open-Session-In-View pattern? In short, it's the fastest and easiest way to solve the problems that typically arise from using Hibernate with ANY Model-View-Controller framework (including JSF, Tapestry, Struts, Spring, WebWork and plain old Servlet/JSP). Just what are those problems, you ask? By far the most common problems is the infamous LazyInitializationException.

For performance reasons, Hibernate encourages the use of Lazy Loading.
………..
There are problems with this approach. Some developers have gone on record with scalability complaints with regards to Open-Session-in-View. I haven't seen these problems myself, but the number of threads on the subject suggest that the problem is real for some people. Others feel (myself included) that exposing a chunk of the persistence mechanism as a front-end filter is an architetural no-no. I can live with it because it's so transparent and so easy.
So, again there is no one silver bullet for every situation or architecture. However, for the most web application built out there, this approach to lazy initialization would be perfectly ok and much more efficient.

Quote:
Keeping a session around for a whole request cycle is awfully inefficient with sparadic n further SQL calls instead of a single joined sql statement.
Yes in some situations. You can eagerly fetch the collections that are used most often or have more flexible approach of lazy/not-lazy initialization for some of the objects.
Anyway, this will very depend on the size of your object graph and how many of the objects in the graph you will use in a single request.

Quote:
For practical reason, your approach is definitely usuable but I have a hard time justifying this from an architectural point of view.
Thank you. I can’t tell you how glad I am to here that. I mean, I prefer Agile methodologies in developing software application. I have more pragmatic view of what a good architecture is. So, if it is good for “PRACTICAL reasons” then this is good enough for me.

In the past, I also was raving about Big Upfront Design Architectures or something like that. I used DTO – not only for remoting but for normal web application to completely decouple the view from the domain and things like that. I saw a lot of inefficiency, lost productivity and most importantly, a lot of bugs because of having to manage so much repeating code around. I violated basic principle like DRY, good OOD with creating object that are actually data holders without ANY behaviors, but most importantly, I didn’t bring too much business value to my customers (I am a consultant) with the type of applications that are “justified from an architectural point of view”.

Now, I am questioning what a good architecture actually is. (BTW, not only me: Martin Fowler's keynote on OOPSLA 2005- "does good design even matter?":
http://ivan.truemesh.com/archives/000547.html ) So, I would say that if the architecture works well for your needs, it is easy to be refactored or modified (this totally excludes repeating code in almost every layer) and bring business value to the customer/user, then this sounds like a good architectural design to me.

Another good thing about Agile is TDD. One of its principles is not to write any code before you first write the test(specification) for the functionality(behavior) that is needed from your object. Try writing a test specifying behavior for DTO!

Quote:
What happens if you go to JDBC?
Actually, I would never care about that type of question. If you start thinking about what could happen “IF something”, then you will build a lot of unnecessary code that would not bring too much business value to anybody. And probably (most likely) this “IF” will never happen, so you built it for nothing in 99% of the cases.

And yes, in some cases Open View Session would not be a good solution. In other application DTO probably will make sense (probably as properties in controllers, page beans or something similar but not as pure form of DTO). However, I feel that java community starts to loose a lot because of this over-engineering in every possible aspect. I will probably repeat myself but frameworks like Spring and Hibernate were created about simplicity. Let’s try to keep this spirit.
Reply With Quote
  #57  
Old Dec 3rd, 2005, 03:10 PM
hucmuc hucmuc is offline
Senior Member
 
Join Date: Aug 2004
Posts: 107
Default

Quote:
Originally Posted by igorstoyanov
Thank you. I can’t tell you how glad I am to here that. I mean, I prefer Agile methodologies in developing software application. I have more pragmatic view of what a good architecture is. So, if it is good for “PRACTICAL reasons” then this is good enough for me.
I agree. I just wanted to point out that you are using Hibernate specific functionality and going from a different DAO implementation to another (like JDBC) would not be straight forward, if not possible. From that point of view, you are not really abstracting out the DAO layer properly. Does it mean that this is bad. Of course not. I've done this too. You are still able to TDD quite nicely from this practical approach (which is great and a more important goal IMHO). However, I still don't like the session-per-request approach but hey we can disagree on this!

Dino
Reply With Quote
  #58  
Old Dec 14th, 2005, 04:57 AM
rebornspirit rebornspirit is offline
Member
 
Join Date: Oct 2005
Location: Belgium
Posts: 87
Default TheServerSide.com article

Some additional discussion on TheServerside.com: Spring2 vs Anemic Model http://www.theserverside.com/news/th...hread_id=38047
Reply With Quote
  #59  
Old Feb 13th, 2006, 10:09 PM
cilativ cilativ is offline
Junior Member
 
Join Date: Feb 2006
Posts: 22
Default

Quote:
Originally Posted by Ben Alex
I take a different approach. In my domain objects I generally provide public getters, public setters if the property is not "state managed", and actual methods for modifying "state managed" properties, like fireEmployee(). Now if fireEmployee() should only be called as part of a transaction-controlled workflow, I use access modifiers to make it package protected. I put the services layer in the same package as the domain object. Sometimes we need state managed methods to be callable by other domain objects, like a BankAccount that has a changeBalance() method (because balance is "state managed") that accepts a Posting. Because Posting and BankAccount are different "aggregates" (as per DDD terminology - a very useful pattern in teaching people this stuff I find) we need an intermediate object for passing the Posting to the now-forced to be public BankAccount.changeBalance() method. So we create a posting.BalanceChangeRequest, providing a package protected constructor that accepts the Posting. The BankAccount.post() only accepts a BalanceChangeRequest. Thus you've effectively used access modifiers to extend package protection to the Posting package. I also use Hibernate field-level access, and overall it all works pretty nicely.

On the subject of reusing domain objects for DTOs and web form backing objects, I've found it not worth the hassle. Such form backing objects / DTOs can be created in seconds as they're just simple JavaBeans. It's more important to have a rich domain model that is infrastructure independent.
Interesting approach to limit access to only specific package. You probably made BalanceChangeRequest a final class?
Reply With Quote
  #60  
Old Feb 14th, 2006, 02:38 PM
amitdk amitdk is offline
Junior Member
 
Join Date: Feb 2006
Posts: 9
Default another approach

Interesting thread and a lot of good replies. I'm hoping some of the folks on this thread could also comment on the approach I've taken to the whole problem of seperating domain layer and persistence layer using Spring, without having to inject DAOs into domain objects or having to call DAO persistence methods from the service layer.

Would appreciate some feedback on the same. My approach is published here - http://jroller.com/page/funwithjava?...model_solution

Thanks
Amit
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -5. The time now is 10:11 AM.


Contegix provides first-class managed hosting and partial sponsorship of these forums.

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.