开发者

Active Record pattern, Repository pattern and testability (in java)

What would be the drawback (in terms of testability for example) to the following approach which intends to get the best from Active Record pattern and Repository pattern ?

Each persistent object exposes save() and delete() method, but no static methods to load itself, or to load a list of similar objects : loading from upper layers is done by directly calling a repository, to avoid static methods in persistent o开发者_运维问答bjects.

The "save()" and "delete()" methods are only facades, they are delegated to the repository.

Is testability really a concern with this approach ? Even with pure Active Record approach : are there information systems where database logic represents only a small part of the whole business logic, and where it would be interesting to mock the database access ?

EDIT : This approach needs that persistent objects inherit from an AbstractPersistentObject which implements "save()" and "delete()", and it prevents business inheritance, but I read it was better to avoid business inheritance, and to replace it with composition, so it may be an advantage, and not a drawback...?

EDIT2 : Maybe this article will explain better which issues I am trying to solve : http://moleseyhill.com/blog/2009/07/13/active-record-verses-repository/


There are two things that raise some concern. The first one is this quote (emphasis mine):

[...] are there information systems where database logic represents only a small part of the whole business logic, and where it would be interesting to mock the database access?

Are you putting business logic in your database? If so: don't do it, it makes it very hard to mock your database. You'd have to duplicate (and maintain!) all of the business logic from the database to your mocks, otherwise your tests are useless.

But how do you know if the mocks correctly implement the business logic? You could write unit tests for your mocks, or reuse the unit tests of your database (you do have them, right?), but that's an approach I'd try to avoid at all costs! Let me repeat: don't ever (have to) write unit tests for your mocks. If you find yourself in such a situation, take a few steps back and review your design, because there's something very wrong.

Putting business logic in the database will only create unnecessary coupling between your model and the database, and immensely complicate your testing layer. Separation of concerns is key here: the model focuses on business logic only and the database focuses on persistence only, nothing else.

Which brings me to my next concern: why do you need save() and delete() methods, which are persistence-related, on your domain model? Persistence doesn't belong in the domain model.

I know, you said that these methods will delegate to a repository, so the domain model (hopefully) doesn't contain the actual persistence logic. But how does it know which repository it should delegate to?

If you are calling a service locater in the save() method, you're making it impossible to save the entity to multiple repositories. You're also hiding the dependency on the repository from the caller, which I consider to be a bad thing.

To solve these issues, you could pass a repository instance to the save() method, like this:

public class Foo extends AbstractPersistentObject {
    public void saveTo(IFooRepository repository) {
        repository.save(this);
    }
}

But a method like this implies that the caller already has a repository instance, so he might as well call the save() method directly on the repository. Any persistence methods on the domain model would be obsolete.

Perhaps I'm oversimplifying your problem. What is it you are trying to achieve? Do you only want the entity.save() syntax, or are you trying to solve a bigger problem?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜