ibatis-user-java mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Larry Meadors <lmead...@apache.org>
Subject Re: Too many methods on a service object
Date Sun, 13 Nov 2005 14:07:42 GMT
WARNING: Long, rambling email alert!

OK, I had to read this a few times and wait before responding, because
my first inclination when I saw that service API was: "If someone
checked code with those methods into *my* project, I would kill them
and feed their remains to the bears...and not because of the .net
naming."

 :-D

Now, with Ron's clarification, I can contribute my $.02US.

I am not sure that I agree 100% with Ben or Paul on the interfaces in all cases.

I understand the principle, and agree with it in the data layer, but
in my service layer, I am enforcing my application's business rules.
Maybe the difference in opinion is just based on what we are putting
where. I do agree that having interfaces for areas where the
implementation could change, but hopefully, that is not at the core of
your business rules - some of them, yes; all of them, no. :-)

Using interfaces for the sake of completeness (i.e., on every layer)
is a mild form of insanity, IMO. :-)

Of course, I am also using Spring to inject those services, so maybe
that is at the heart of my uneasiness with that approach. My service
consumer is managed by spring, and doesn't know or care if it has an
interface or implementation. The service gets injected into the
application, just like the dao implementations get injected into the
service, which begs the question: Why do I use an interface there?

To answer my own question, I guess I feel like I need an interface
there because the DAO is an integration point. It is talking to
something *outside* of my Java (or C#, for Ron) code, and I like to
have a service gateway (http://tinyurl.com/7bz2j) for testing
purposes. An interface/impl pair makes that easier. That is not the
case in the service layer.

Larry


On 11/11/05, Ron Grabowski <rongrabowski@yahoo.com> wrote:
> Thanks for the feedback. Most of the methods on the PersonService
> object were used just as examples to show how one could get carried
> away with added methods. I switched jobs recently and talking about
> design strategies with new people has caused my head to spin a bit.
>
> Getting back to the Person / Address relationship, suppose that the two
> entities are related in the database through a PersonAddress table
> (PersonAddressId, PersonId, AddressId). I usually represent this table
> as a PersonAddress entity with a matching service PersonAddressService
> class. I "cheat" a little bit with the PersonAddress object so it looks
> like this:
>
>  PersonAddressId
>  PersonId
>  PersonFirstName
>  PersonLastName
>  AddressId
>  AddressStreet
>  AddressCity
>  AddressState
>  AddressZip
>
> I add additional properties from the Person or Address objects as
> needed. The awkward part about the PersonAddress object is that I have
> to remember when creating or updating PersonAddress objects that only
> the PersonAddressId, PersonId, AddressId fields are important to the
> database. Values in the other fields exist purely out of convenience
> and are ignored during adds or updates. I always flip-flop on whether
> its better to just do away with the PersonAddress object and just have
> the PersonService class return a list of complete Address objects (or
> vice versa). That would definitelty decrease the number of little
> objects my system has to keep track of. I never liked the fact the
> layers further down the line know that Persons and Addresses are
> related via a PersonAddress table. They shouldn't know about that. An
> argument for such an object would be the case where a Person object had
> a btye[] that contained a large picture of the person and each Address
> object had a byte[] that contained a large picture of the property. If
> there are 50 people and each person has 5 addresses with pictures, I
> shouldn't populate those fields if I'm never going to use them on the
> list page that just shows first names and street names. The
> PersonAddress object comes in handy for that...
>
> --- Ben Munat <bent@munat.com> wrote:
>
> > 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