Skip to content
This repository was archived by the owner on May 16, 2023. It is now read-only.

Review abstraction levels of services #61

@odrotbohm

Description

@odrotbohm

Current Implementation

The services currently expose a mixture of abstraction levels in their APIs that provide an incoherent set of operations and lead to a fractured programming model. Take the TAN redemption use case for example. The programming model currently looks as follows:

  1. A controller loads an instance of the aggregate.
  2. There are some business checks applied.
  3. If they succeed, state is manipulated by calling some setters.
  4. The state is persisted by calling save(…).

That's a very low level interaction model and it's error prone fro a couple of reasons:

  1. You can accidentally forget one of the steps and might not actually realize this. Ideally a business operation consists of exactly one call to some service that either fails or succeeds.
  2. State is manipulated through setters. I.e. we're poking on individual fields. It's the responsibility of the calling code to make sure that the right setters are called, potentially in the right order. Also, as the setters are public, any code can actually call them.

Suggested Enhancement

  1. Revisit all methods that call save(…) on the service, look for which state transitions they apply to the entity beforehand and turn those use cases into service methods. All code that does not need any references to other Spring beans could go into entities ("If you need to call two setters in a row you're missing a method.").
  2. In combination with Avoid layer packages #60, setters could be made package protected, so that the web code is unable to call those individually but is forced to go through the service by the compiler.

Expected Benefits

  1. Reduces the amount of ceremony to be implemented in controllers to realize a use case.
  2. A clear separation of code that is strict (services, entities, etc.) and prevents any kind of misuse through the help of the compiler or by rejecting invalid state. This can then be separated by code that needs to be "forgiving", i.e. also accept invalid data by clients in the first place to produce proper results (usually though some kind of validation).

Again, happy to provide a POC for this in a PR.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestin reviewModerators are investigating how to best proceed with the issue

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions