My favorites | Sign in
Project Logo
             
Search
for
WhySalve  
Motivation behind Salve

Salve aims to fix the anemic domain model anti-pattern(1) (2) present in most modern java web-applications.

With technologies like ORM we are able to model domain layer objects that contain application data, but we are unable to enrich them with behavior to act upon that data - the basic principle of OOP. The behavior is factored out into stateless singleton objects called services. This is done for the following reasons:

  • Dependency Management: Objects modeled by the domain layer depend on services provided by other parts of the application, such as jms/email/orm/database. It is much easier to provide these dependencies to an object whose lifecycle is managed by an IOC container rather then to one whose lifecycle is handled by the ORM framework or by the user using the new operator.
  • Instance Weight: Domain layer objects need to be lightweight because they are often passed around between application layers/cluster nodes, and sometimes stored by the user for later reference. This often entails having the ability to be serializable which means these objects cannot carry references to heavy objects that would significantly increase their serialized-size, or carry references to objects that are not themselves serializable or should not be serialized - such as singletons.
  • Testability: The two concerns above can be addressed by allowing objects to lookup their dependencies inside methods (rather then keeping them as fields) via some sort of a static lookup. However this makes it more difficult to test the object because its dependencies are harder to discover and mocks are harder to pass in - compared to objects that use setter methods to set their dependencies.

How Salve Fixes the Problem

The ideal solution would allow domain layer objects to be lightweight, contain business logic, and have dependency injection that works under any lifecycle. One way to achieve this would be to allow the developer to specify dependencies as fields, and then rewrite the bytecode to remove those fields from the class and replacing access to them via a static lookup into whatever IOC container/dependency management system the application is using when the application is deployed. This is how Salve works. Lets take a look at a quick example:

// This is a JPA entity
@javax.persistence.Entity public class Account {

  // this is a dependency we wish Salve to instrument
  // notice no need for @Transient because the field will be removed
  @salve.Dependency
  private EmailService email;

  // this is database id of this account
  @javax.persistence.Id
  private Long id;

  // this is a JPA field
  private float balance;

  // setters and getters

  public void withdraw(float amount) {
    if (amount>balance) {
      email.sendOverdrawMessage(this);
    }
    balance-=amount;
  }
}

Without Salve such an object is not practical: there is no good way to set the EmailService dependency, and there is no good way to have Account be serializable.

When the bytecode of Account class is processed by Salve, it will look like this:

@javax.persistence.Entity public class Account {

  // added by salve to facilitate lookup of email service dependency
  private static final salve.depend.Key _salve_key$email=new salve.depend.Key(...);

  // email field is removed

  @javax.persistence.Id
  private Long id;

  private float balance;

  // setters and getters

  public void withdraw(float amount) {
    // dependencies are looked up lazily and cached in a local var
    // there is also a cache in salve that speeds up multiple repated lookups
    EmailService _email=salve.depend.DependencyLibrary.lookup(_salve_key$email);

    if (amount>balance) {
      _email.sendOverdrawMessage(this);
    }
    balance-=amount;
  }
}

Lets take a look at the changes Salve made to the code:

For instructions on how to setup Salve in your project see the GettingStarted page


Comment by jklappenbach, Dec 28, 2007

Just a nitpick: The class name is misspelled. It should be "Account" instead of "Acount".

Comment by eonnen, May 22, 2008

I think it's a bit presumptuous to call anemic domain model and "anti-pattern" - It's a pattern, sometimes it works, sometimes it doesn't. You may not like it, others do, like all patterns use them when they make sense but I find labeling it an anti-pattern discrediting to otherwise interesting work.

Comment by i...@inversoft.com, Aug 25, 2008

Interesting idea. However, anemic domain models exist and run in many extremely large systems. You still haven't proven that anemic models are "broken". You might want to spend sometime laying out a case against anemic models and then show how Salve can fix it.

You might also want to consider adding information about the pitfalls of Salve. The first one that popped into my mind was when a Salve object lands in a JVM without the appropriate service or access back to the grid/bus. It no longers provides a coherent contract via its public interface.

I'd also consider adding a discussion about alternatives and why you believe Salve is better. The one that stuck out in my mind as I was reading was the pattern of using non-serializable intelligent domain objects within a single JVM and providing a transformation to DTOs if the domain is passed outside that JVM.

Lastly, I would also suggest that you add information about the intended remote invocation pattern you are trying to solve. I would present a remote API and the corresponding client API and then show where Salve fits in.

Comment by eelco.hillenius, Sep 14, 2008

Sorry, but I hate DTOs. The project I'm working on uses a bunch of them, and we're always running behind the facts of coordinating them with the regular domain classes. It's the kind of duplication I could live without.

Comment by alex.objelean, Sep 25, 2008

Why would somebody use salve, instead @Configurable (or AutowireCapableBeanFactory?) annotation in spring?

Here is the link: http://debasishg.blogspot.com/2006/07/spring-20-aop-spruce-up-your-domain.html

Comment by ittay.dror, Jan 26, 2009

@alex: spring solves only part of the problem. it doesn't solve serialization. coming from wicket, this is probably a major concern for igor..

Comment by igor.vay...@gmail.com, Jun 14, 2009

@alex: see ComparisonWithSpringsConfigurable wiki page

Comment by daniel.mfreitas, Aug 05, 2009

Hello Igor. Any chance to integrate Salve with Spring's @Secured or JSR250 annotations (inside Spring)? I ran into frustration trying to create a rich domain model while securing some of its methods. @Configurable and @Secured just don't work together with AspectJ weaving.

Comment by igor.vay...@gmail.com, Sep 17, 2009

@daniel: I just released 2.0 alpha1 which has an AOP framework. The support for @Transactional is already rebuilt on top of the AOP framework, I suppose you can easily do the same for @Secured.


Sign in to add a comment
Hosted by Google Code