Where is Martin Fowler when I need him? :)

Brian Pontarelli wrote:
 > In terms of the logic for the calculateIncomeTax method, it sounds
 > like that is going to be on the server. This means that the client
 > version of the Person class will primarily be a proxy to the server.
 > Therefore, it doesn't necessarily need to be "rich" because the logic
 > is not inside the class itself, but instead defined somewhere else.
 > All that you are gaining using a "rich" approach is that you get to
 > interact with just the Person class. Once you get to this point, there
 > is very little difference between this methodology and using anemic
 > domain and services.

        For this case there is indeed little difference between the anemic 
model and rich model. But for this specific use-case I would flip the 
question on you and ask: what do you benefit from a anemic model? Given 
the point of using C-style functions and global variables versus OOP why 
wouldn't you go for OOP every time?

> I guess that is my main point. The "rich" domain folks talk about  
> putting logic and data in the same place. But when the logic gets  
> complex or changes frequently, you _have_ to pull it out into a  
> service that conforms to an interface.

        You have to pull it into an interface, yes, but not necessarily into a 
service. Nothing prevents you from defining an interface for 
calculateIncomeTax() and providing different implementations in the form 
of rich models.

> Then it makes sense to put that  
> logic on another server so that it can be re-used and can scale. Then  
> you start looking at ways of swapping in new implementations of that  
> interface at runtime to make updates easier.

        That's a requirement I never had in practice. My assumption has been 
that if you have a fail-safe cluster in the first place then you just 
update different servers at a time. I find the idea of swapping 
implementations at runtime as a form of upgrading quite questionable. It 
sounds like it would be much harder to update all necessary classes 
atomically and track/log problems if something goes wrong.

 > And you think about
> service discovery and all that jazz and BAM, your client is anemic.  
> You've pulled the logic as far away from the data as you could. Now,  
> you can still have a "rich" domain on the server. However, if you run  
> into similar cases on the server, you'll just do it again.

        If you absolutely need service discovery then I agree that pretty much 
mandates anemic models, but again I question how frequently this 
requirement comes up.

Gili
        
> I also think this only applies in certain places. Those are business  
> domains with business logic. If it looks like to could ever be  
> distributed, I say make it anemic and service based.
> 
> -bp
> 
> 
> 
> 
> On Nov 7, 2008, at 4:51 PM, Gili Tzabari wrote:
> 
>>
>>      I was actually going to bring up #2 myself in the last post but I
>> forgot. I believe that in most cases Person.marry(Person other) will
>> work but sometimes the implementation requires you to access  
>> information
>> that spans beyond the state of a single person. Because you never know
>> how the implementation might evolve over time I always prefer placing
>> such methods at the Persons level. That is, any business logic  
>> involving
>> a single person goes into Person while logic involving multiple  
>> parties
>> goes into People. That's just a rule of thumb (feel free to violate it
>> if it makes sense).
>>
>>      With respect to #1 I would suggest injecting two different
>> implementations of Persons for the client and server. That is, the  
>> code
>> lives inside the Persons instance, but the concrete implementation  
>> would
>> vary.
>>
>>      Again, I am sort of making this up as I go along but it feels right  
>> so far.
>>
>> Gili
>>
>> Brian Pontarelli wrote:
>>> A few questions:
>>>
>>> 1. Where is the implementation (actual code) for the /Money
>>> calculateIncomeTax();  method located?/
>>>
>>> 2. Why isn't the /marry()/ method on Person like this: /marry(Person
>>> other);/?
>>>
>>> -bp
>>>
>>>
>>>
>>> On Nov 7, 2008, at 3:34 PM, Gili Tzabari wrote:
>>>
>>>>
>>>> I am actually toying around with a 3rd paradigm. I'm not sure  
>>>> whether
>>>> it falls under the category of anemic models, rich domain model or
>>>> something else. Judge for yourself:
>>>>
>>>> // Cat + business logic
>>>> class Person
>>>> {
>>>>  private String name;
>>>>
>>>>  String getName();
>>>>  Money calculateIncomeTax();
>>>> }
>>>>
>>>> \-> Key point: all methods operate on the current Person. Unlike  
>>>> anemic
>>>> models, you store business logic methods at this level so long as  
>>>> they
>>>> apply to a single Person (i.e. calculateIncomeTax()).
>>>>
>>>> // CatService + state
>>>> class People
>>>> {
>>>>  private List<Person> people;
>>>>
>>>>  void marry(Person first, Person second);
>>>>  List<Person> getMarriedPeople();
>>>> }
>>>>
>>>> You would reuse the same Person implementation on both client and
>>>> server while varying the implementation of People. For your cats
>>>> example, you'd have Cat and Cats instead of Cat and CatService.
>>>>
>>>> Gili
>>>>
>>>>
>>>> Brian Pontarelli wrote:
>>>>>> Are you talking about wanting to be able to represent a Cat with
>>>>>> fix()
>>>>>> on the server and without fix() on the client because of business-
>>>>>> logic?
>>>>>> Or are you saying that technical limitations might cause fix()  
>>>>>> to fail
>>>>>> on the client? If it's the latter I argue that it's no different  
>>>>>> from
>>>>>> the server because even there the DB might become unreachable. If
>>>>>> you're
>>>>>> arguing the former, then I argue you need different client-side  
>>>>>> and
>>>>>> server-side Cat interfaces because they are not really the same.
>>>>> What I'm saying is that the fix method must be different on the  
>>>>> client
>>>>> and server. This generally means a different class for the client  
>>>>> and
>>>>> server. If it was the same class on the client and server, all the
>>>>> logic would need to be pull out into a well known interface and  
>>>>> that
>>>>> interface would need to be different implementations on the  
>>>>> client and
>>>>> server, making the domain just a proxy and not very rich.
>>>>>
>>>>>
>>>>>> I guess I am saying that you shouldn't be passing Rich Domain  
>>>>>> Objects
>>>>>> over the wire because (from practical experience) the server- 
>>>>>> side and
>>>>>> client-side interfaces are almost always "different enough" that  
>>>>>> you
>>>>>> can't share the interfaces. Clients usually contain a subset of  
>>>>>> the
>>>>>> server methods and might contain some client-only methods. I  
>>>>>> believe
>>>>>> Rich Domain Objects still hold a lot of value on the server-end,
>>>>>> even if
>>>>>> you can't pass them to clients. Clients and servers can both run  
>>>>>> their
>>>>>> own show (with RDO) and communicate over the wire by passing a
>>>>>> subset of
>>>>>> the state (DTO, REST, whatever you want to call it).
>>>>> Yeah, we agree on this. You shouldn't be passing around rich domain
>>>>> objects because they don't work that way. This incurs a lot of code
>>>>> overhead though.
>>>>>
>>>>>
>>>>>> I argue you always need to define the client-server interface by
>>>>>> hand.
>>>>>> Serializing your state-only Object to the client is very poor
>>>>>> practice.
>>>>>> One reason is that you're essentially exposing an interface to the
>>>>>> client and this needs to be designed and exposed very carefully.  
>>>>>> The
>>>>>> other reason is that you can't rely on having Java on both ends of
>>>>>> the wire.
>>>>> Not sure what you mean by this. You definitely have to define how  
>>>>> your
>>>>> client talks to the server and what your server responds with,  
>>>>> since
>>>>> that is the standard remoting paradigm. In terms of serializing a
>>>>> state only object as poor practice, I think you might be confused,
>>>>> because that's what you said you should do above with the DTO/REST/
>>>>> whatever. DTOs are state objects.
>>>>>
>>>>> Again, here's a concrete example so we are on the same page:
>>>>>
>>>>> RDO
>>>>> -------
>>>>>
>>>>> public class ClientCat {
>>>>>  @Inject RemoteCatService cs;
>>>>>  boolean fixed;
>>>>>
>>>>>  public void fix() {
>>>>>    CatDTO dto = new CatDTO();
>>>>>    dto.fixed = this.fixed;
>>>>>    this.fixed = cs.fixTheCat(dto);
>>>>>  }
>>>>> }
>>>>>
>>>>> public class ServerCat {
>>>>>  @Inject EntityManager em;
>>>>>  boolean fixed;
>>>>>
>>>>>  public void fix() {
>>>>>    this.fixed = true;
>>>>>    em.persist(this);
>>>>>  }
>>>>> }
>>>>>
>>>>> public class CatDTO {
>>>>>  boolean fixed;
>>>>> }
>>>>>
>>>>> public class Client {
>>>>>  public void fixTheCat() {
>>>>>    ClientCat cat = DI.makeCat();
>>>>>    cat.fix();
>>>>>  }
>>>>> }
>>>>>
>>>>> // This class runs on a different server
>>>>> public class RemoteCatService {
>>>>>  public void fixTheCat(CatDTO dto) {
>>>>>    ServerCat cat = DI.makeCat();
>>>>>    cat.fixed = dto.fixed;
>>>>>    cat.fix();
>>>>>  }
>>>>> }
>>>>>
>>>>>
>>>>> Anemic
>>>>> ----------
>>>>>
>>>>> public class Cat {
>>>>>  boolean fixed;
>>>>> }
>>>>>
>>>>> public class Client {
>>>>>  @Inject RemoteCatService cs;
>>>>>
>>>>>  public void fixTheCat() {
>>>>>    Cat cat = new Cat();
>>>>>    cat = cs.fixTheCat(cat);
>>>>>  }
>>>>> }
>>>>>
>>>>> // This class runs on a different server
>>>>> public class RemoteCatService {
>>>>>  @Inject EntityManager em;
>>>>>
>>>>>  public Cat fixTheCat(Cat cat) {
>>>>>    cat.fixed = true;
>>>>>    em.persist(cat);
>>>>>    return cat;
>>>>>  }
>>>>> }
>>>>>
>>>>>
>>>>> I like the second one personally. Less code and easy to manage.  
>>>>> Plus,
>>>>> I can pass my Cat around anywhere I want without transforming it  
>>>>> into
>>>>> other objects. In n-tiered systems, you could potentially pass  
>>>>> the Cat
>>>>> all the way from the front-end to the last tier and then back up.  
>>>>> This
>>>>> is how we built most stuff at Orbitz.
>>>>>
>>>>> -bp
>>>>>
>>>>
>>>>
>>>
> 
> 
> > 
> 

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"google-guice" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/google-guice?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to