Saturday, October 28, 2006

NFJS Dallas Retrospective

I just finished the No Fluff Just Stuff Dallas Symposium. First, let me say that I am exhausted. Two and half days of in-depth sessions wears me out. Second, this was my third (or fourth, I can't remember) NFJS and this one was business as usual:
  • Excellent (for the most part) sessions focused on a core set of topics - agile, Java, Ruby, Spring, testing, etc.
  • Laid back atmosphere. It doesn't feel like a conference, but more like one big BOF. And you can tell that most of the speakers have a good relationship with one another, probably from spending so much time "touring" together. Overall, it's a really friendly atmosphere.
  • Well organized and well run.
Here are my general take aways regarding specific technologies and the industry in general:

  • AOP is here to stay. Duh! I know this sounds obvious, but most Java developers aren't using aspects. Even so, some speakers said it is mainstream. I don't think it is mainstream - to me people still don't get it or get it but fear it. But it is clearly well rooted and will keep seeping into more and more companies. This is great news.
  • We, as an industry, are still learning web services. I attended a couple of web services sessions, and the questions from the audience indicated that there is still a lot of confusion in this area. Even the speakers at these sessions provided more "guidance" in this area rather than concrete solutions. Unfortunately, I don't think much in this area is black and white with many lessons still to be learned. C'est la vie.
  • Groovy is making a comeback. A few years ago, Groovy exploded onto the Java landscape. For a while, you couldn't read a Java website or blog without seeing Groovy being discussed. Then...silence. I don't know exactly what caused this or where Groovy went. To me, it seemed like Groovy wasted a lot of initial momentum. But Groovy appears to be popping up again in several places, or it has always been there and is popping up on my radar again :-)
  • People are interested in Agile, but people aren't practicing Agile. This is a huge generalization, but the agile sessions are packed yet many people haven't adopted some basic agile practices - unit tests, CI, simple-enough-to-work design. I'm not sure why this is. Perhaps some of it is the typical "management" distrust. But I think part of it is Agile's dirty little secret - Agile is hard. Not hard as in confusing or complicated. Rather, agile practices require a lot of discipline and a lot of developers/teams just aren't that disciplined. I could be wrong.
Lastly, at the risk of sounding like a geek groupie, but there are a couple of speakers I feel are a can't miss if you get a chance to see them. First, Glenn Vanderburg is just freakin' smart. His peak deep inside the rabbit hole that is the inner workings of JavaScript made my brain hurt (which is a good thing I think). His talk on Java Performance Myths was also fascinating. If you have been in Java for some time, none of this information (e.g. GC really isn't slow any more) is new, but it is still worth attending. Second, Ted Neward is worth seeing no matter the subject matter. The depth and breadth of his technical knowledge is truly impressive - he always seem to have an answer (real, not faked) to any question, no matter how complex or obscure. Oh, and try to start an argument with him for fun.

Congratulations Jay on another great conference.

Tuesday, September 26, 2006

Spring, DDD and AspectJ - An Example

In my last post, I discussed the possibilty of using AspectJ with Spring to inject domain objects with service objects to create a richer domain model. This follow up is to explore some example code based on a Customer -> Account example given by Ramnivas.

In this example, we are trying to get the net worth of a Customer object. A Customer object has a relationship with an Account object, but it only has a reference to the Account object's id:

public class Customer {
    
    private Long accountId;

    public Long getAccountId() {
        return accountId; }
    }

    public void setAccountId(Long accountId) {
        this.accountId = accountId;
    }
    ...
}

The value of the account is used to determine the customer's net worth. Suppose we have a CustomerService interface that exposes this operation via its getNetWorth(Customer) method. One implementation of this method would be to place most of the logic in the service layer like this:

public Double getNetWorth(Customer customer) {
    Long accountId = customer.getAccountId();
    Account account = accountRepository.getAccountById(accountId);
    return account.getValue();
}

This is a classic example of an anemic domain model. All of the business logic is in the service layer and the domain objects are simply data containers. But in OO, an object = data + behavior, right? So how do we push this behavior back to the domain layer?

This biggest question in this particular scenario is how can a Customer object obtain a reference to its Account object? Well, there are several ways:
  1. It could be given a reference to the Account object by the CustomerService object. But that really isn't much different than the example above. The CustomerService class is still two involved in the business logic.
  2. This Customer object could actively obtain a reference to the AccountRepository via a service locator. But this introduces a dependency not only on the AccountRepository, but the service locator as well - not a very transparent solution.
  3. The AccountRepository object could be supplied to the Customer object using dependency injection. This makes sense - after all, we are doing this with our Spring beans already in our service/data access layers.
Implementing option #3 is where AspectJ comes in. While Spring manages the lifecycle of service and data access beans, it does not manage the lifecycle of domain objects. These can be instantiated via new or by another framework, such as Hibernate. However, AspectJ can weave advice into the domain object's classes that is executed after their constructor completes. There are several pieces to this puzzle. First let's take a look at the "enriched" SmartCustomer class:

@Configurable("smartCustomer")
public class SmartCustomer extends Customer {

    private AccountRepository accountRepository;

    public AccountRepository getAccountRepository() {
        return accountRepository;
    }

    public void setAccountRepository(AccountRepository accountRepository) {
        this.accountRepository = accountRepository;
    }

    public Double getNetWorth() {
        Account account = accountRepository.getAccountById(getAccountId());
        return account.getValue();
    }

}

Now a Customer object can obtain a reference to its associated Account object via the AccountRepository. But how does it obtain a reference to the AccountRepository? Notice the @Configurable annotation. This is basically a marker that identifies this class as needing to be configured by Spring whenever a new instance is created. This "magic" is possible because AspectJ weaves in advice into the SmartCustomer's constructor. I have not delved into the details, but I suppose this advice is aware of the Spring application context.

Spring knows how to configure each instance of this class from a prototype bean configured in the application context:

<bean id="smartCustomer" abstract="true" class="org.springdallasug.aspectj.domain.SmartCustomer" scope="prototype" >
    <property name="accountRepository" ref="accountRepository" />
</bean>

Now every instance of the SmartCustomer class will be wired with an AccountRepository object. In order to make this happen, AspectJ must weave this advice into the SmartCustomer class. For my demo, I chose to use load time weaving. This is done by starting the JVM with the following option:

-javaagent:PATH_TO_JAR/aspectjweaver-1.5.0.jar

This enables AspectJ to weave advice into classes as they are being loaded into the JVM. For anybody interested, I have packaged up this simple demo. The entire mechanics behind this can be found in the Spring documentation.

So, it is pretty cool that Spring + AspectJ makes it straightforward to apply dependency injection to domain objects. But the question remains, is this the right thing to do? Taking the example above, allowing a Customer object to completely contain the logic of calculating its own net worth means it needs access to its Account object. But this, in turn, means giving it access to the AccountRepository. This is, for me at least, an unusual design decision. While this does create a "richer" domain model, at adds more (potentially complex) dependencies into the domain model.

I don't think the answer is cut and dry. Instead, it probably needs to be fleshed out in a "real world" application. I just might have to try that.

Edit:
Craig Walls pointed out a couple of improvements to this example. First, I added the name of the prototype bean to the annotation to be more explicit (I also added the "id" attribute to the SmartCustomer bean in the Spring configuration file). Second, I made the prototype bean abstract, which prevents the Spring container from ever instantiating an instance - it is now strictly a prototype. Not a big thing, but it is an improvement. Thanks Craig.

Thursday, September 21, 2006

AOP meets DDD

Yesterday I attended the Dallas Spring Users Group. The September speaker was Ramnivas Laddad. The topic of the presentation was Spring AOP and AspectJ. I was interested in hearing about how Spring leverages the AspectJ pointcut syntax in Spring 2.0. I am quite familiar with Spring 1.2's type of AOP. I have experimented with the AspectJ pointcut language, but I wanted to get some guidance on best practices.

Well, this topic was covered quite well. But at the end of the presentation he focused on how to leverage the full power of AspectJ - advising classes vs. advising objects via proxies. One of the last slides he presented was how to use AspectJ to inject dependencies into domain objects. This point was sort of mentioned in passing, but it raises a very interesting debate. Is using aspects to inject domain objects with dependencies (possibly service-type objects) the right way to create a richer domain model?

After the presentation we discussed a concrete example. Suppose you have a Customer object. In the domain, the Customer has an Account, but in the object model, a Customer object only has a reference to its Account's id (following the notion of an aggregate root in domain driven design). Now suppose the service layer supports the method getNetWorth(Customer). Without a rich domain object, the service would be responsible for retrieving the Account object on behalf of the Customer object and returning the value of the Account. Something like this:

...
Account account = accountRepository.getAccount(customer.getAccountId();
return account.getValue();
...

Bu
t suppose we want this logic to exist in the Customer object, as it should with a rich domain model. How would the Customer object obtain a reference to its Account object? The answer is it needs access the AccountRespository, And AspectJ + Spring can help achieve this. Basically, an AspectJ aspect (woven into the Customer class) would be invoked that would inject the AccountRepository bean from the Spring context whenever a Customer object in instantiated.

Now, for those who are knee-deep in full blown aspects, this is probably not a novel idea. But for those of us who have simply lived in the proxy-based aspect world., this opens up a whole new realm of possiblities. The implication of having a rich domain model (as opposed to much of the business logic remaining in the service layer) is quite intriguing. However, it raised many questions:

  • Is going whole-hog aspects right for my application? Going from proxy-based AOP to full-blown aspects is not a small step.
  • Is giving the domain layer access to other services/data access objects a good design?
  • What sort of recursive dependencies will be introduced when the domain becomes aware of these layers?
I am looking forward to delving into these questions. The possibilty of having "real" domain layer is way too interesting to ignore, I am not ready to drink the Kool-Aid, but I am ready for a taste.

Saturday, August 26, 2006

Hard Drive Failure

So a few weeks ago I broke down and bought a new laptop. With 2GB of RAM and 120GB hard drive, this looked like a great deal at $999. Up until today, everything was great and I was loving my new toy. But tonight while ripping a CD it froze. "No big deal," I thought and I just powered the PC down. Well, it never came back up. Instead, the hard drive is dead and I have to send it in for a new one. I just hope this isn't a hint of things to come.

Let this be a lesson to all you kids out there - BACK UP YOUR DATA.