ibatis-user-java mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ben Munat <b...@munat.com>
Subject Re: Too many methods on a service object
Date Sat, 12 Nov 2005 04:32:20 GMT
Ron Grabowski wrote:
> I've been discussing design patterns (mainly for web sites) with a
> colleague over the last couple days and my brain is fried with trying
> to come up with quick answers. Here's some of the things that we've
> talked about. Hopefully people will share their two cents on these
> issues...
> 
> A common pattern for iBATIS is to use it in a service based
> architecture. Suppose I have a Person and an Address object. Normally
> there would be one or more static methods on the service object:
> 
>  Person person = PersonService.GetOne(personId); *
>  bool success = PersonService.Update(personId);
> 
> My colleague brought up the point that this can get out of hand (i.e.
> you start getting _a lot_ of methods):
> 
>  PersonService.GetMany();
>  PersonService.GetOne(personId);
>  PersonService.GetManyWithNonNullAddresses();
>  PersonService.GetManyWithNonCityAddresses();
>  PersonService.UpdateAddresses(personId, addresses);
>  PersonService.UpdateIfPersonIsMale(person); 
>  PersonService.UpdateIfPersonIsMarried(person);
>  ...
> My argument was that those methods wouldn't be written until they
> needed to be used. In other words I wouldn't just be making up random
> methods and never use them...each method would serve a purpose in the
> system.

Not only would I not add all these before they're called for, I wouldn't even add any 
methods like this. They smack of "hardcoding the search criteria", something that's quite

likely to change. A better approach would be to write a PersonService.search method that 
takes a Person object and calls a PersonDAO.search method. This copies the fields that are

in the person object into a dynamically built select query. The results of this are all 
the Persons in the db that match that criteria.

Hmm, although I just noticed that you have multiple update methods too. Seems like you're

trying to push too much into the service... like you want to have the service methods 
handle every possible logic condition that your action (or the client of the service) 
might need. Down that path lies madness.

> Another good point that I wasn't able to answer on the spot was the
> idea that it would be complicated to populate related objects. I can't
> think of a good example of this but suppose I wanted to get the city
> names of a person's addresses:
> 
>  Person person = PersonService.GetOne(personId);
>  AddressCollection addressCollection = 
>   AddressService.GetManyByPerson(person);
>  ...
> 
> Again, that's not the best example. Imagine the case where I have to
> call through to many service objects until I get my final result. My
> answer to him was that I would replace all those calls with a single
> method that returns exactly what I wanted. Instead of calling multiple
> service objects, I would simple encapsulate the calls into another
> service object:
> 
>  IList cityNames = CityService.GetNamesByPersonId(personId);
> 
> My vague question is...is there a better way I can explain things?
> "Adding methods when I need them" doesn't seem like the best answer.

I think that's a perfectly good answer. As the agile folks say: YAGNI... you ain't gonna 
need it. Which basically means, if you think you can forsee all the functionality you're 
gonna need, forget it... that always changes. Just build what you need today.

I also think that for many systems, most functionality you'll need for most services is 
covered by basic CRUD stuff... or more like retrieve, save, delete, and search, with save

handling both new records and updates.

That city example does seem pretty far-fetched, but I guess if there was a need for that 
(finding all the cities that a person record has in their addresses?), yes it would make 
sense to make a service method, which in turn calls a dao method, which calls a particular

sqlmap that performs the query you need.

> Some other questions I was stumbling on: should the service layer be
> defined through interfaces?

Absolutely! All boundaries -- layer and system -- should ideally be represented by 
interfaces. This allows you to change implementations or substitute implementations based

on a strategy. And services should generally have two implementations right off the bat: 
test and impl.

> Should the service layer throw its own ServiceExceptions or just pass
> through the data layer's exception? What happens if the service layer
> just throw up the data exceptions to the presentation layer? The
> presentation layer shouldn't know anything about the data layer...

Hmm, exceptions are kind of a contentious issue... the argument being that checked 
exceptions were a mistake because you're still hopefully only gonna actually deal with an

exception at one place, so why be forced to catch and rethrow at every layer. Spring, for

example offers a huge Exception hierarchy that is (I think) entirely unchecked.

Anyway, the general pattern I've seen is to create an abstract Exception base class for 
your app, with two subclasses: Logic and System (so like this: MyAppException, 
MyAppLogicException and MyAppSystemException). Any business rule validations throw the 
logic exception, while any unforeseen system errors (db failure, file not found, etc.) get

wrapped in the system exception.


> Thanks,
> Ron
> 
> * - Yes, I'm aware that I posted C# style examples to a Java list.

Eeeewwww... I hate that ICrap.... ;-)

b

Mime
View raw message