1

I have decided to try to create my own board game implementation. Probably going to use a REST-api to expose the contract. I'll figure out what database, communication, ... tools I'm going to use once I've got my business logic set.

Now, to achieve not being dependent on tools/frameworks in my business layer, I need to abstract the, for example, persistence layer. This is where my dilemma comes in to play. I will probably use Spring Boot but I want it to stay away from my business logic.

To achieve this; should I wrap the typical CrudRepository interfaces which Spring Data provides in an adapter of my own to ensure that my business logic doesn't know anything about Spring? I have never seen anybody doing it in a professional setting(although I'm a beginner so it might be common practice). Or are there other means to achieve my noble goal of the business logic being framework agnostic?

Thanks in advance!

Per request, a purely hypothetical situation:

Let's say my business logic has been coded and it's time to decide on the database. I go for a MongoDB. Natively supported by Spring, and falls under the same abstraction as, for example, the Spring support for relational databases. However, let's say that after a year, I decide to switch to another database. I choose OrientDB, which is not natively supported by Spring. But I am coupled to the Spring data abstraction in my business logic, so I have to change my business logic to switch databases.

If I had an extra layer, which maps the logic of my business domain, to operations on my database, I could just plug-in another implementation.

Specifically, if I need to create an order in my business logic, I could call repository.createOrder(...) in my service without knowing which specific database is behind that repository or which library/framework performs the mapping. All that is taken care of in that extra layer.

2 Answers 2

0

You should forget your misguided goal. The data abstraction you so eagerly wish to reimplement is already provided by Spring Data's repositories. You can't really create "framework agnostic business logic"(1). It would be like writing "programming language agnostic code".

If you were to use something like BPEL you could achieve separation, but that's a different beast altogether.

Your code will be dependent on Spring, because you're using Spring. That's not a bad dependency that should be avoided. If you decided to ditch Spring and use something else instead, you would be doing a full rewrite anyways. Any custom abstractions would've been wasted development time.

Note that in proper architecture you get good abstractions from the layers higher than the repository (service, facade). I'm assuming you're talking about a custom layer between service and repository, which is useless.

Edit: If I were in your hypothetical situation of switching to OrientDB, switch to using OrientRepository, and the switch would be pretty seamless.

You were talking about "framework agnostic", but you seem to concentrate on "persistence agnostic" which is what Spring Data aims to provide. It doesn't provide "all persistence agnostic", because while it's easy to create an abstraction layer like JDBC (although even with that you might want to dig into the implementation classes for database specific functionality), widening the abstraction also means more restrictions as the abstraction can only provide the functionality that all the implementations have. Just like how CrudRepository provides very basic operations and its subinterface JpaRepository provides additional JPA specific operations.

In the real world even switching the database to a different one is usually quite uncommon and would require a lot of work and preparation, even though there are good standards and abstractions. Switching to a completely different persistence mechanism would be an even bigger task, something that an additional abstraction layer would not be able to mitigate in any real way.

In your case, you'll be writing something basic like dao.save(entity) anyway, and the repositories already abstract that quite nicely. You might not get a complete drop-in replacement, but that's not how things work in real development anyway. I'd avoid over abstracting things to account for imaginary future requirements. That just results in overengineering and your actual goal (the board game) is left behind.

7
  • How so? If I just use Spring to wire the beans in my business logic, the dependency would be very much okay in my eyes. Relying on specific contracts Spring Data provides sounds worse or is it just me? Commented Jul 4, 2019 at 17:14
  • @KevinStrijbos Since you're writing a game, a standard approach is to write a game engine and then the game would depend on the engine (and not how the engine is implemented). But that's a different task, and you probably would not get any advantages (reusability, ease of development) in your case. You have to rely on some things to write any worthwhile code. Besides, your business logic shouldn't know/care about Spring. It just knows that BoardService.movePiece() moves a piece. The service implementation can be switched if needed.
    – Kayaman
    Commented Jul 4, 2019 at 17:36
  • Thanks for the explanation. But shouldn't the service layer contain the business logic? The controller calls the service, which contains the business logic, which uses the data layer. That's how I've always done it, is that the wrong way? Commented Jul 4, 2019 at 17:47
  • Partly yes. Generally the business logic is in facade and service layers, but depending on project size some layers might be left out. It's not really worthwhile adding a layer between the service layer and the DAL (repositories) because the service will have to have some clue about implementation details (besides, higher layers are allowed to know about lower layers, the other way around is more problematic). If you can come up with a situation where you think an additional layer would provide advantageous, add it to your question and I'll dissect it.
    – Kayaman
    Commented Jul 4, 2019 at 18:05
  • 1
    Yeah, I see the confusion about my use of the term "framework agnostic". I used the persistence layer, which is implemented using that framework, as an example, it's not my focus. But I do agree that my specific example leans very close to overengineering while changing databases probably means altering the implementation of the business logic anyway. It's all nice in theory but probably very expensive in practice :) Thanks for the answer, marking it as resolved. Commented Jul 4, 2019 at 21:05
0

Actually your goal is fine so long as you understand what it will get you and what it will cost.

But you're going about it the wrong way. You want your business layer to be independent of your persistence layer? Fine. Then stop thinking about Spring. Stop thinking about persistence.

Make your game work without any persistence at all. Work out what your business rules are. What your model needs to be. Sure state dies when you turn off the computer but you can still get pretty far this way.

Now that you know what your game is what do you want saved? What API should you offer so that state can be saved and rebuilt. Done this way you focus on your real needs and not on what some framework offers out of the box.

You may have to do more work. You may miss out on some Spring features. If you want this to work you have to be ok with that.

But now, if you ever want to, you can swap out Spring for something else. You could even create your own persistence code.

I know this works because I've done it. It's not cheap. But it works. Sometimes it's even worth it.

What does this get you?

You create a place in the code that doesn't know about Spring and doesn't know about persistence then changes to those things won't impact that place. In that place you put your business rules. No one should be able to look at the code for this place and tell that you're using Spring or Mongo DB. Do that faithfully and you won't be coupled to either one. At least not here. Do this and your business rules will be protected from change that has nothing to do with your business rules. As a bonus, people that haven't studied Spring or Mongo DB will still understand the code here.

What does this cost?

By deliberately avoiding making choices to make things easier to use Spring or Mongo DB you end up having to create a translation layer between your pristine business logic and code that bows to the needs of Spring and Mongo DB. This translation layer is what will be impacted by changes to Spring and Mongo DB. Creating that layer is work. It comes at a cost. It robs you of some of the tempting benefits of these tools. If you're fine being as tied to these tools as you are to your programming language then that work has been wasted.

No autowiring?

If you're surprised that I have kicked not only Mongo DB but Spring as well out of your business rules since Spring isn't just about persistence then let me be clear: construction logic doesn't belong in your business rules any more that persistence logic does. Spring can help without your beans knowing it exists.

There are ways to make use of all of these tools without letting them seep into every part of your code base. But fighting the tools desire to be everywhere is work. You don't get isolation for free.

2
  • Could you expand a bit on "what it will get you and what it will cost". Since you've already tried it, what are your experiences with this approach? Commented Jul 4, 2019 at 20:31
  • @abstractchristmastree better? Commented Jul 5, 2019 at 5:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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