Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring and the anemic domain model

Tags:

oop

spring

So, I've noticed that I definitely have a tendency to pattern my Spring/Hibernate stack objects like this:

  • Foo controller makes a call to "FooService"
  • FooService calls FooRepository.getById() method to get some Foos.
  • FooRepository makes some Hibernate calls to load Foo objects.
  • FooService does some interactions with the Foos. It may use a related TransactionalFooService to handle things that need to be done together in a transaction.
  • FooService asks FooRepository to save the Foos.

The problem here is that the Foos don't have any real logic. For example, if an email needs to be sent every time a Foo expires, there's not a call to Foo.expire(). There's a call to FooService.expireFoo(fooId). This is for a variety of reasons:

  • It's annoying to get at other services and objects from a Foo. It's not a Spring bean, and it was loaded by Hibernate.
  • It's annoying to get a Foo to do several somethings transactionally.
  • It's hard to decide whether Foo should be responsible for choosing when to save itself. If you call foo.setName(), should foo persist the change? Should it wait until you call foo.save()? Should foo.save() just invoke FooRepository.save(this)?

So for these sorts of reasons, my Spring domain objects tend to be basically glorified structs with some validation logic. Maybe this is okay. Maybe web services are okay as procedural code. Maybe as new features get written, it's acceptable to create new services that deal with the same old objects in new ways.

But I'd like to escape from this sort of design, and I'm wondering what other Spring uses do about it? Do you combat it with fancy tricks like load-time weaving (which I'm not that comfortable with)? Do you have some other trick? Do you think procedural is fine?

like image 749
Brandon Yarbrough Avatar asked Aug 20 '09 06:08

Brandon Yarbrough


People also ask

What is an anemic domain model?

An Anaemic Domain Model is a model with no logic in it. Domain classes look more like a bunch of public setters and getters without domain logic where the client of the class has control over how to instantiate and modify the class. In these models, the client has to interpret the class purpose and use.

Why are anemic domain model considered an anti pattern?

The anemic domain model is a programming anti-pattern where the domain objects contain little or no business logic like validations, calculations, rules, and so forth. The business logic is thus baked into the architecture of the program itself, making refactoring and maintenance more difficult and time-consuming.

What is Spring domain?

Usually a domain folder contains POJOs (Plain Old Java Objects). This folder basically stores classes that might or might not be entities, but follow a common structure: fields. construstors. getters and setters.

What is a Java domain model?

A Domain model is a conceptual model of the problem domain. By "java domain model" they just mean the java classes representing that model. There's nothing specific to java in the concept. See also Domain Driven Design for an approach to focusing your development on the business domain needs.


2 Answers

You can get Spring to inject your services into your Hibernate instantiated instances, using AOP. You can also get Hibernate to do the same, using Interceptors.

See http://www.jblewitt.com/blog/?p=129

Regarding "It's annoying to get a Foo to do several somethings transactionally", I would expect your service implementations would know/care about the transactions, and if you're now using the service interfaces within your domain model, that should now be not quite so annoying.

I suspect that deciding when a domain model should be saved is dependent upon what it is and what you're doing with it.

FWIW I have a tendency to produce just the same sort of anemic structures, but I'm getting there, now I know it's possible to do it a more sensible way.

like image 185
ptomli Avatar answered Oct 11 '22 11:10

ptomli


It sounds like your application is designed around procedural coding principles. This alone will hinder any object-oriented programming you're trying to do.

It's possible that a Foo has no behavior it controls. It's also acceptable to not use a Domain Model pattern if your business logic is minimal. A Transaction Script pattern sometimes just makes sense.

The problem comes in when that logic starts growing. Refactoring a Transaction Script into a Domain Model isn't the easiest thing, but it's certainly not the most difficult. If you have tons of logic surrounding Foo, I'd recommend moving to the Domain Model pattern. The encapsulation benefits make it very easy to understand what's going on and who is involved with what.

If you want to have Foo.Expire(), create an event in your Foo class such as OnExpiration. Wire up your foo.OnExpiration += FooService.ExpireFoo(foo.Id) on object creation, possibly through a factory used by the FooRepository.

Really think about first. It's very possible that everything's already in its right place... for now.

Good luck!

like image 38
Kevin Swiber Avatar answered Oct 11 '22 12:10

Kevin Swiber