Monday, April 23, 2012

Convention over implementation with Spring Data

I think that most of us are familiar with the term "Convention over configuration", but just to remember (from wikipedia):
The phrase essentially means a developer only needs to specify unconventional aspects of the application. For example, if there's a class Sale in the model, the corresponding table in the database is called “sales” by default. It is only if one deviates from this convention, such as calling the table “products_sold”, that one needs to write code regarding these names.
When the convention implemented by the tool you are using matches your desired behavior, you enjoy the benefits without having to write configuration files. When your desired behavior deviates from the implemented convention, then you configure your desired behavior.
For example, the maven project structure uses convention - where our source files, test source files and resources should be placed in order to be compiled, tested and packaged automatically. We save a lot of time, and create potentially less bugs, just by following this simple convention. Of course, if we need something special, we can always overwrite it in a way that we need.


But this is only about configuration... I would like to extend it a little bit and talk about convention over implementation (my own term - at least I haven't seen it anywhere else yet ;) ). So that we could write less code to achieve more, do it faster and with higher quality. I am lazy after all...


Common code

The most common piece of code, that developers write is the Database Access Object (DAO), sometimes also called Repository (for me it is not exactly the same, but it is another topic). Let's say that we have some entity called MatchView and it contains some fields with getters and setters. We want to be able to save it, load it by id, and search for entities by some criteria - probably with some sorting and/or paging involved.

So each and every time we are manually creating the interface and implementation of it (usually for JPA, or Hibernate). This interface may look like this:

public interface MatchViewDao {
  void saveOrUpdate(MatchView matchView);

  MatchView findById(UUID matchId);

  OurInHousePageableList<Matchview> findMatchesForTeam(
    UUID teamId, OurInHousePageAndOrderingInfo pageAndOrdering);
}

Of course we have to write the implementation of it that uses JPA, or Hibernate manually - and we cannot forget about OurInHousePageableList and OurInHousePageAndOrderingInfo. A lot of code that has to be written, tested and maintained, isn't it?

Don't write this code

Guys from Spring Data have done their homework. They gave us the possibility to use only the interface, which has to follow some very simple conventions and it will be wired "automagically" - without writing the code actually.

Spring Data is an umbrella project which addresses the access to data in general. It supports relational databases, document databases, key-value stores, data grids and other.

We can use one of general interfaces, extend it and we will be able to access our data without writing a line of code for it. For most cases it provides everything that we need and of course if we need something special, we can always write it by ourselves (for example some very sophisticated in-memory searches).

We can save entity, load it by id, load all entities, and load sorted pages of data. But the best thing is that you can specify which fields should be used to create query - only by the method name convention. And you can of course make this query pageable too.

Speaking about paging - we don't need to write our in-house solutions for queries. It is provided in the framework.

So let's return to our example. The interface definition could look like this:

public interface MatchViewDao 
    extends PagingAndSortingRepository<MatchView, UUID> {

  Page<MatchView> findByTeamId(UUID teamId, Pageable pageAndOrdering);
}

All methods from super interfaces are inherited and what's more - we added new method. That method will query all MatchView entities that have a value of field teamId equal to the given one as argument, and return specified page as the result. And we achieved it through following simple convention - property expression in the method name. We can add more fields to the method name and combine them with logical operators.


The last step is to create the bean in spring context. The easiest way is to do that through a special namespace. It may look like this:

<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns="http://www.springframework.org/schema/data/jpa"
  xsi:schemalocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/jpa
    http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

  <repositories base-package="some.package.with.repositories">
  </repositories>
</beans:beans>

We can adjust it in many ways - exclude whole subpackages, exclude classes by some filters, or configure them manually. And of course you need to configure your data source. ;)

We can access the data and we don't have to write a single line of code - isn't that brilliant?

Where to use it?

Wherever you can! It saves time, developers write less buggy code (that normally would have to be tested and maintained), and of course it is fun.

Personally, I find it extremely useful to use it on the Read Side of CQRS. After all we are not supposed to need anything more fancy here.

On the Write Side we may find it usable, but only if we are not using Event Sourcing for Aggregates.

I think you can easily see that in Anemic Models it can also be very handy. ;)

If you also find it useful and want to learn something more, I encourage you to view this presentation, and give me a comment on how and why would you use it.


7 comments:

  1. I have seen this presentation... It could be ok... for another CRUD... But unfortunately presenter attached DDD context - therefore all stuff in this presentation is piece of crap:P

    Let's assume that we are doing *real* aggregates and not using Event Sourcing. Assuming that loading aggregate is simple R (from CRUD) is naive. In DDD we usually need to inject something, check Specification etc. In other words: Repo is domain objects that models some domain logic - domain logic can not be generated by dentition! At other hand: DAO in most cases is just a technical artifact with "stupid" logic that can be decorated.

    So Spring Data is great for DAOa, but naive for implementing DDD Repos. Spring guys (with all respect to their awesome job they are doing) seems to can't grasp a difference between DAO and Repo:P

    And one last thing about presentations: Transactions at the Repo level? WTF?!? Another guy who red just DDD quickly hehehe

    ReplyDelete
    Replies
    1. I actually agree with you in everything . :D

      As I wrote at the beginning, DAO and Repository is not the same - and you explained the difference very well. Thanks for that.

      We may use Spring Data Repository (should be called DAO) as a tool when creating DDD Repository. The DDD Repository can be pretty dumb actually and if does not provide anything more fancy than CRUD, it can just wrap the DAO, don't you agree? :)

      And if we only want to add some Dependency Injection, then we can use ORM mapper to do that (for instance some Hibernate interceptor). It doesn't change the fact that it should be done in Spring Data of course. ;) Maybe it will be added in the future.

      I use Spring Data in the Read side only, since I prefer Event Sourcing at this moment on the Write side. And I must say - it saves A LOT of work in that place. ;) That's why I recommend it so much. ;)

      And I won't even mention about Transactions at Repo level... :)

      Delete
    2. Trying to bring back less emotional judgement of what is crap, I'd like to counter some of the arguments given.

      "Repo is domain objects that models some domain logic" - No, it's not. Just read up on the definition of repository on the domain driven design website [0] you'll find what can be summarized to "A Repository is a mechanism for encapsulating storage, retrieval, and search behavior which emulates a collection of objects." Much more, read up on what is said in the Solutions section and you get the problem space we're trying to address: remove unnecessary burden in implementing data access, making it easy to treat data stores like collections of objects, making it easy to define subsets of these entities through query methods, specifications or the integration with Querydsl.

      Transactions: I'd like to "Another guy who red just DDD quickly hehehe" with the question whether you actually read up the docs on the approach to transactions? First of all stores, that don't support transactions will never see anything of that at all. Second: some stores *require* transactions to store entities and benefit from read-only transactions being applied for plain read operations or queries. Now we could entirely ignore this, dance around and let people implement an ugly facade for the repositories just to use them even for the most simple use cases. The goal of the project (actually all Spring projects) is to remove unnecessary burden and ease things while still giving the developers full control over what is going on. So what exactly is wrong with automatically applying default transaction configuration when it's needed or beneficial? The entire point of redeclaring transaction configuration on a repo interface is to allow users to tweak the behavior if needed. Beyond that, application transaction boundaries are usually defined on a higher abstraction level - once again: by the developer.

      DDD in general. I don't know which of the talks of me you have seen but you will definitely not have seen me claiming we're a DDD framework or the like. The DDD repository pattern (as of the definition linked to above) is a core piece of it, as is the idea of Specifications. Another aspect of the DDD story is that esp. the pagination concept is lacking in almost every data access API (in fact I haven't seen any that does approach this at all) and we actually provide value objects to make that concept explicit and also implement the necessary data access code (to retrieve the meta data needed to come up with pagination result info).

      So summarizing I wonder what is so utterly stupid about the idea of removing the need to write unnecessary code and defaulting to proper behavior implemented based on a well known DDD pattern which effectively makes sense in non-DDD scenarios as well? We're very open to any feedback, suggestions for improvements but a bold and simple: "It's all crap and these guys don't know the shit they're doing" is just not bringing anything substantial to the debate.

      [0] http://domaindrivendesign.org/node/123

      Delete
    3. @Sławek:
      "In DDD we usually need to inject something, check Specification etc." Actually Spring Data implements specifications on data level thanks to predicates. Of course it does not solve all possible cases but its very useful especially in conjunction with QueryDSL.

      About injecting something: do you mean your something like InjectionHelper presented in ddd-cqrs-sample? With compile/load time weaving and @Configurable annotations you can automatically inject dependencies to domain object.

      Actually most of repository-related code in your ddd-cqrs-sample could be reduced to minimum if you would use Spring Data JPA

      Delete
    4. @Configurable - Yes, I know... in wiki we explained why we decided not to use it - in short: too much magic, especially for people who are outside of "Spring culture" but also want to read some code.

      Delete
  2. Thanks for answer.
    My opinion is about concepts, nothing ad persona.

    "Doing Repos right" triggered my emotions because *right* word imho is connected with huge responsibility - imagine for example junior developers who are not prepared for judgment and don't have context.

    "not have seen me claiming we're a DDD framework or the like" - ok, now I understand intention of the presentation. "DDD" was just a fancy label, therefore I don't have any objections. If we cut off DDD context than I guess that everybody will agree that presented techniques are really productive and actually well thought and well crafted.

    I'm a big fan of Spring (using since 2003), I admire Rod Johnson (and all team) job, so I would like to contribute somehow:
    I think that introducing more DDD concepts (modeling in general) to Spring would be advantageous for all community.
    When understanding deeper nature of what DDD Aggregate is, we may also infer more intuition about Repos and other DDD Building Blocks.

    In general assembling domain object is not just loading it from DB. May be so in simple cases.

    According to transactions: in DDD we split logic to 2 layers: Application and Domain; Tx is feature of the Application; Repo is a Domain concept.

    ReplyDelete
  3. I think that you both agree actually in most cases. ;)
    The one thing that you may see differently is the definition of repository. And this can be an academic discussion. ;)

    The great thing in spring is that it allows the developer to choose if he wants to use a feature. And if he doesn't want, then it does not force him to do that.

    I would personally like to see some dependency injection mechanism in spring repositories. They would get much closer to DDD-like reach repository style.

    ReplyDelete