3

So, at the moment I find myself building my c#/.net (web) application ( or folder/project/package-...) structure often like this, thinking about it in a "somewhat onion-architectural way":

myApp
    - API
        - Controllers for HTTP, REST etc., may even be a whole gui, though ...
    - Domain.Model
        - "Business Logic" for the actual application, being most 
           of the time a (micro)service...
        - Interfaces for Repositories, Thirdparty(see below)...
    - Infrastructure
        - ThirdParty
            - Call to other Services,
        - Persistence
            - Implementations for Repositories
        - Adapters
            - Adapt some Class to a DTO for my domain 
    - Config
        - global configurations...
    - Tests
        - empty... just kidding.

Actually, I like to have this Separation a lot, giving me a good overview about:

  • what is really "of value" at the moment (inside the Domain.Model)
  • what is just "presenting the data" (API)
  • what are "The surrounding, may-be-changing dependencies" (Infrastructure)

So, I'm going to start a new job in a few weeks, going back to the java world and we'll make heavy use of spring (boot/cloud) to create a new application. For thus, I think about using the industry-standard hibernate-ORM, but besides, I found it very helpful to have a lightweight OR-Mapper like JDBI, too. And I actually read a lot about Hibernate being slow at scale, and I know the same behaviour when it comes to entity Framework.

Now I look for Spring boot examples, and I remember one does not need to use an Implementation of a Repository to actually use the repository using Spring Data.

A typical Spring Repository implementation might look like this:

Public interface PersonRepository extends CrudRepository<Person, Long> {

  List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
  ...
}

So, I'm asking myself where to put this interface now? At first glance, I'd put it into my Domain.Model package as the Repository Interface it is.But doesn't spring "in the background" create an actual implementation inside(!) my domain.model, then, thus coupling it to a persistence technology, an OR-Mapper, and so on?

In .NET, I actually just create a simple I[Class]Repository inside my domain, and add the actual implementation in my Infrastructure, like Entity Framework or Dapper. This allows me to very easily switch OR-Mappers, even the whole DBMS. Thus, doing it like this in Spring would result in creating a ton of boilerplate-code for CRUD operations, because I can't use the CrudRepository Interface, or am I wrong here?

So, would it be better to just create a "plain" Repository inside my domain.model? But wouldn't that be just the start for the ton of boilerplatecode I actually want to avoid?

Perhaps I should just not "work against the framework" here, for in last consequence, I'd have to do it for every other Call to spring components, too, when I want to be 100% consequent in abstracting my domain from the actual technology..?

I'm a bit lost here, it actually feels like a knot in my head at the moment. Perhaps I'm even missing something obvious.

I hope you could give me advice by either clarifying how the spring repository implementation works and why it is okay to have it inside Domain.Model, or showing me my structural misconception whilst giving me advice to a better structure for my projects.

Thanks in advance!

  • 1
    I'm facing the same exact situation - how did you end up organizing your code? Coming from the .NET world as well when I was first introduced to these patterns, I've struggled to understand how to best lay this out in my domain. – Mustafakidd Jan 14 '18 at 21:01
  • As Thomas Junk stated, this might not be a violation. But still, I tried to face this problem in a repository I created here: goo.gl/Swk2uo for an example spring boot application of a blogentry on our codecentric blog. There, I defined the Interface inside my domain here: goo.gl/Z1UXUu with just the necessary methods, impl. it in infrastructure package, and to not reimplement crud functionality let it extend springs repointerface in infrastructure, too. Seems a little overengineered, but does the trick a little better I think. – Dominik Jan 15 '18 at 9:52
  • Thanks @Dominik - the issue I see in your sample is that your interfaces in domain do not expose the basic crud/pagingandsorting methods, only your custom ones. Isn't this limiting and preventing you from utilizing that functionality from within your service class? – Mustafakidd Jan 15 '18 at 16:11
0

tl;dr

Does the Spring Data Repository implementation violate the principle of loose coupling?

No. Since there is no coupling with only defining an Interface.


Long version

I) According to your project layout - and your intentions in doing it so - you are tying to achieve separation of concerns (trying to separate tiers roughly with API, Domain / Model and Infrastructure as you call it). Besides there are tests and configuration.

The Three-Tier-Architecture separates between presentation tier, middle tier and data tier. You have two distict tiers, namely responsible for presentation and persistence and "things in the middle".

So from an architectural point of view, the interface declaration either belongs to the "lower end" of the middle tier as it communicates with the data layer:

Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

from Patterns of Enterprise Architecture

or you could put it in the "upper end" of the data tier as in this Picture. Anyways it is distict from the domain objects.

A first step to improve your design would be to put the interface definitions from your Domain-Folder to the Infrastructure - Folder

II) If you take a look at how Spring Data works you find, that in order to activate the magic one has to declare @EnableJpaRepositories("com.acme.repositories").

This allows me to very easily switch OR-Mappers, even the whole DBMS.

You could do this with Spring as with Entity framework.

then, thus coupling it to a persistence technology, an OR-Mapper, and so on?

No. You just conigure the container to choose one "implementation"; but that's not coupling. You are free to provide your own.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.