Agile Architecture | Agile Transformation
Lean Architecture Principle #10: Architecture emerging from Projects 
Gero Vermaas 28 Jul, 2010
// service interface MyService { MyResult findSomething() } //returned class public class MyResult { //enum type private MyDomainType type; } //the enum enum MyDomainType { static MyDomainType convert(GenerateAxisClass other) {...} }1. Static factory methods on domain class For our domain we are converting between generated Axis classes and our own domain, a sort of anticorruption layer so to speak. For conversion you can choose between several patterns, the one I use and see the most are a separate factory (or converter) classes and static factory methods on the class it self. The static factory method is shown above, a separate factory may look something like this:
public class MyDomainTypeFactory { public MyDomainType convertFrom(OtherDomain other) {...} }Now although both implementations seem okay, the static method approach actually makes your client dependent on the underlying implementation, Axis in this case. Since the MyDomainType is eventually returned by the service, you have now exposed the underlying implementation to your client; the client now also needs the Axis generated classes and is therefor kind of dependent on Axis. 2. Not using Serializable Maybe this one is on the edge but the fact that our domain/dto classes are not implementing Serializable excluced the possibility to use something like rmi remoting. We first need to change all dto/domain classes so they implement Serializable. So I suggest that if you already now that your domain objects will be returned from a Service and are therefor some kind of dto's it is good practice to already let them implement Serializable. It is not a lot of work to let the classes implement Serializable, and saves you a hell of a lot of time updating all client modules if you are going to choose remoting. 3. Nested and unchecked exceptions There have been tons of discussions on the Internet about checked versus unchecked exceptions. I like to use unchecked exceptions for various reasons. But using unchecked and also nested exceptions brings great responsibility; especially when implementing a service layer. Let me illustrate this with an example:
class HibernateDao { void persist(Person transient) throws HibernateException{} } interface PersonCreateService { Person create(....); } class PersonCreateServiceImpl implements PersonCreateService{ Person create(....) { //.. hibernateDao.persist(..); } }The PersonCreateServiceImpl is not obliged to catch the HibernateException. So if something goes wrong in Hibernate the HibernateException will propagate all the way up to the client. Since the client is usually unaware of the implementation details of a Service and might not have a dependency on Hibernate on its own, this can result in a ClassNotFoundException at runtime. The same goes for nested exceptions. Consider the previous example with a refactored PersonCreateService and PersonCreateServiceImpl.
class HibernateDao { void persist(Person transient) throws HibernateException{} } interface PersonCreateService { Person create(....) throws CannotCreatePersonException; } class PersonCreateServiceImpl implements PersonCreateService{ Person create(....) throws CannotCreatePersonException { try { hibernateDao.persist(..); } catch(HibernateException e) { throw new CannotCreatePersonException("...", e); } } }This also causes the same hidden runtime dependency on Hibernate for the calling client. Conclusion So if you are implementing a Service then make sure you don't expose any implementation details.