General business object requirements

For those of you who have worked on medium to large sized projects, or anyone who has an opinion , I would like to know what types of logic an application needs in the business layer. If the objects expose properties and collections, is a simple validation on write all that's needed I guess the objects also have methods that do various things. If anyone feels like offering any insight into the kinds of things their business objects do besides store bits of information that would be greatly appreciated.

I'd also like to know what types of exceptions are generally thrown when persisting to a database. What about errors in the middle of batch updates How are those reported to the caller that requested the batch update Is the whole batch rolled back, or do the updates skip the error and continue on Does the answer depend on what you're persisting

I await your replies.



Answer this question

General business object requirements

  • Petr Bouda

    So in other words, if there was enough time and it was easier to do, all projects would opt for Data Transfer Objects (DTO) and a domain model which operates on the DTOs DTOs would contain the required validation. There could be Service, Remote Facade, and UI layers above the domain model, where Service and Remote Facade would marshal DTOs back and forth between the domain and UI or remote clients. And somewhere in there would be Data Mappers that map the DTOs to a database and perform caching on the DTOs. Whoever calls upon the mappers to persist the DTOs (would that be the domain or service layer, or both ) would implement some kind of error reporting mechanism, like exceptions for fatal errors, or Notifications.
  • Nishith_Sheth

    Greg Young wrote:

    As for how it can help decouple, think about an example of a person object (with matching PersonRepository)

    My PersonRepository has a method such as ..

    public PersonCollection FetchByLastName(string _Name) {
    //build query object and execute with my OR mapper
    }

    because I have this level of abstraction the client code does not need to know about the OR mapper ... instead it only deals with the repository. As such if I later need to change out my OR mapper (or use multiple strategies which is quite common in optimization situations) the client code is happily oblivious to this detail. It is also very nice to have the repositories as they make for nice looking code as opposed to ..

    Query MyQuery = new Query(typeof(Customer));
    MyQuery.Filters.Add(new QueryFilter("Lastname", Operator.Like, "%young%"));
    MyORMapper.GetObjectList(typeof(Customer), MyQuery));

    Naturally this is just a contrived example but you get the point :)

    I was thinking the repository was returning, say, a PersonMapper, which you would then invoke PersonMapper.FindByLastName(), but I get it now. I think Hibernate looks really good, I will have to check out the NHibernate port, but I suspect it will be just as good.

    I'd like to attend your presentation but I live in Seattle, and there's no way I would be able to get out there.


  • tmigliorino

    Ok, well I wasn't advocating putting much in the Service Layer. I meant pretty much what that webpage says (although it does a much better job of explaining it).

    How can you use a repository to encapsulate an out-of-the-box mapper Doesn't the repository simply organize all the mappers so they can be accessed from a single location If you request a specific mapper doesn't the repository have to return one of the data types created by the mapping software Which means you can't just switch to another out-of-the-box mapper, or am I missing something

    When working with mapping programs, how do they usually deal with domain objects, or which way is preferred For instance, I know some make you put attributes on the classes/properties/fields you want persisted and then use (slow) reflection. Others generate the basic code files for you and may or may not provide sections in the code that you can modify and the mapper will leave those alone when re-generating code. Any other ways Would it be feasible to have the mapper generate code for basic domain objects and let the developer inherit from those to create the rich domain model, then have the developer provide the mapper a factory object that would instantiate the correct class (so the mapper can use the developers subclasses, instead of being tied to the generated code)

    Thanks for all the replies, I really enjoy getting real-world information.


  • Perry G.

    With your mention of the service layer, be very careful to avoid putting to much in it http://www.martinfowler.com/bliki/AnemicDomainModel.html

    The "Data Mappers" are generally encapsulated as "Repositories" in DDD whether they use an "out of the box" mapper such as nhibernate internally is an implementational decision.


  • Dimitris Asimakis

    Now that is covering a lot more ground than just business object requirements.

    Business objects will contain validation, calculation and to some extent business processes. It partly depends on how you slice and dice your application. You could have a layer of business objects that act as a process layer, another set that deal with validation and yet another that deal with calculations.

    Business object generally imply object that do work. If an object only carries data it is a Data Transfer Object (DTO). Of course at that point you are simply using a struct disguised as an object.

    Moving on to your question about exceptions from the data layer. If you are talking about exceptions from ADO.NET, then it depends on which provider you are using. If you are asking about what kind of exceptions you should throw from your code, my answer would be as few as possible.

    I haven't done a lot of batch processing so I will leave that to someone else to answer.

    Hope this helps.

    Tim Murphy



  • Sanjay Narang

    I guess I can take you living 3000 miles away as a valid excuse :)

    The Repository pattern is coverred in DDD (listed above) and in Jimmy's book if you need further reference although I would look through as there are many other common used domain patterns.

    Cheers,

    Greg


  • abrang

    Ok, thanks for the reply. This is a really broad question so I expected a broad answer. It did help though.

    I'm still looking for a reply for the propogation of exceptions in batch processing, if anyone has some insight!


  • hoffi

    Ok, well I wasn't advocating putting much in the Service Layer.  I meant pretty much what that webpage says (although it does a much better job of explaining it).

    No worries ... Just wanted to make sure you weren't heading down a wrong path. The anemic domain concept should always be on your mind as a path to avoid.

    You may notice I am answerring these in reverse order. It is because the second actually goes a long way towards answerring the first.

    When working with mapping programs, how do they usually deal with domain objects, or which way is preferred   For instance, I know some make you put attributes on the classes/properties/fields you want persisted and then use (slow) reflection.  Others generate the basic code files for you and may or may not provide sections in the code that you can modify and the mapper will leave those alone when re-generating code.  Any other ways  

    A few things here.

    1) you might be surprised how little the reflections overhead is in comparison with the rest of the operations occurring (namely the network hit to the database and back). Paul Wilson did some benchmarking with his O/R mapper and determined it to not be significant enough to abandon reflections. That said he also allowed you to write your own custom loading within the object to avoid the overhead if you really wanted to. There is also a good reason for reflection ... generally my members are private, the public properties are often not just getter/setters and calling one means something (i.e. some business logic may be fired). Therefor it is often chosen to set the privates through reflection as opposed to duplicating a set of non-destructive getters/setters.

    2) In general my favorite way of dealing with the object mapping is to have it completely externalized and to not force me to do anything to my objects (attributes, inherit from a base etc) as such I can create my objects however I want to. This non-invasive principle becomes extremely important if you ever want to move your domain to another mapper (since the metadata is externalized it also allows you to map the same domain in different ways to different databases). Wilson O/R, nhibernate, and many others keep their metadata externalized from the objects .. I believe gentle.net 2.0 (actually based around DDD) is going to use a repository pattern for its own metadata so you could feasably implement it anyway you like :D

    How can you use a repository to encapsulate an out-of-the-box mapper   Doesn't the repository simply organize all the mappers so they can be accessed from a single location   If you request a specific mapper doesn't the repository have to return one of the data types created by the mapping software   Which means you can't just switch to another out-of-the-box mapper, or am I missing something

    I hope the above answers some of the questions on this. As for how it can help decouple, think about an example of a person object (with matching PersonRepository)

    My PersonRepository has a method such as ..

    public PersonCollection FetchByLastName(string _Name) {
         //build query object and execute with my OR mapper
    }

    because I have this level of abstraction the client code does not need to know about the OR mapper ... instead it only deals with the repository. As such if I later need to change out my OR mapper (or use multiple strategies which is quite common in optimization situations) the client code is happily oblivious to this detail. It is also very nice to have the repositories as they make for nice looking code as opposed to ..

    Query MyQuery = new Query(typeof(Customer));
    MyQuery.Filters.Add(new QueryFilter("Lastname", Operator.Like, "%young%"));
    MyORMapper.GetObjectList(typeof(Customer), MyQuery));

    Naturally this is just a contrived example but you get the point :)

     

    The book I mentioned above by Nilsson discusses alot of the intricacies of integrating an OR mapper with your domain (both conceptually and implementationally with nhibernate as the example).

    Also depending where are located, I will be giving an overview presentation on DDD this month in the southern US.

    Cheers,

    Greg


  • Y.S. Shim

    I could address the first part of this question but I think in general that some books would probably give a better answer than I can possibly fit into this reply :)

    Domain Driven Design by Eric Evans http://www.amazon.com/gp/product/0321125215/sr=8-1/qid=1144096691/ref=pd_bbs_1/102-3319163-1611303 %5Fencoding=UTF8

    P of EAA http://www.amazon.com/gp/product/0321127420/sr=8-2/qid=1144096691/ref=pd_bbs_2/102-3319163-1611303 %5Fencoding=UTF8

    EP and MDA http://www.amazon.com/gp/product/032111230X/sr=8-1/qid=1144096759/ref=sr_1_1/102-3319163-1611303 %5Fencoding=UTF8

    The upcoming book from Jimmy Nilsson which bridges these 3 in a C#/.NET environment http://www.amazon.com/gp/product/0321268202/sr=8-1/qid=1144096803/ref=pd_bbs_1/102-3319163-1611303 %5Fencoding=UTF8

    As for your errors questions ...

    There are generally a few accepted ways of handling this ... naturally your requirements come into play. I will quickly give you two of the better known methods.

    Just throw an exception

    Many systems will simply throw an exception leaving it to the client to determine what needs to be done. This has many issues although the largest is in dealing with large batch updates as the client only knows to rollback the entire thing. Another large problem with this is that only a single error can be handled at a time (i.e. I fail on record 333 I never get to see the error that exists on record 334). Another problem that exists is that there is no way to handle "warnings"

    Notification Pattern

    The notification pattern (P of EAA) http://www.martinfowler.com/eaaDev/Notification.html allows for the sending of multiple messages back to the client, in many cases I will end up with a "Validate" method that can then return a collection of notifications to the client. This pattern could be used for batch updates as well where it returned back any messages regarding the batch update and its possible failures/warnings.

    The important thing here is that it depends on your requirements ... simply saying record 333 never inserted properly may not be correct for your particular problem space; it may be a requirement to rollback the entirety of the batch update.

    Many people when looking at their validation schemes actually come up with a mixture of both of these methodologies. A common layout is to put object level validation (i.e. business logic and doing your best to make sure your data is ok) with a notification pattern and then falling back to a general exception at the time of the save as if the save fails the entirety of the data within the transaction is generally considerred to be bad even if the data is seemingly unrelated.

    Cheers,

    Greg


  • rene schrieken

    You generally want to pass parameters to a method rather than set properties. You may want to look at COM+ and how to design components to run there.

    For batch processing, it really depends on your needs. Sometimes you'll want to roll back the entire batch, other times, note in a processing log that a particular record had an error, but continue with the rest. So, the old standard answer of "it depends" applies here.



  • General business object requirements