0

I'm wondering how to choose between those "patterns" - please forgive me if I don't use the right terms - when having to deal with complex object coming from the front I want to process.

Simple Beans

Simple beans means the separation between data structures and logic, like this:

class Post(val title: String, val content: String)

class CreatePost(private val repository: Repository) {
  fun invoke(post: Post) = repository.savePost(title = post.title, content = post.content)
}

Functional beans

Beans that also have functions that can execute logic,

class Post(private val title: String, private val content: String) {
  fun save(repository: Repository) = repository.savePost(title = title, content = content)
}

class CreatePost(private val repository: Repository) {
  fun invoke(post: Post) = post.save(repository)
}

On the one hand, the first approach is simpler, but the second one offers a few advantages:

  • decoupling between Post and CreatePost. CreatePost does not have to know the internal of a Post, only that it offers a save function. Post has more control over its internals and use cases.
  • thus it is easy to add a new member to Post and CreatePost will not have to be updated. it makes it less likely to forget to update the save function in those cases.

On the other hand:

  • the flow of the code is more convoluted.
  • the use case naming convention seems less relevant, since CreatePost does not actually do any logic and just calls another function
  • there is no separation of concerns.

As an alternative I can see this approach :

class CreatePost(private val title: String, private val content: String) {
  fun invoke(repository: Repository) = repository.savePost(title = title, content = content)
}

And my controller would just call invoke :

@RestController
class CreatePostResource(private val repository: Repository) {
  @PostMapping
  fun createPost(createPost: CreatePost) = createPost.invoke(repository)
}

This seems like the most relevant approach, but are there any downsides to it? I assume I must not be the first one to ask myself those kind of questions.

1 Answer 1

2

Object orientation, in its most basic and perhaps a little bit crude definition, is the combination of data and its logic. So separating data and logic goes against the very nature of object-orientation.

That by itself does not make it "good" or "bad" obviously. I think your "advantages" section is quite fair. I would add that the second point there is basically what I would call "maintainability". To be able to add things (data and logic to something) without needing to track down where and how it is used. To have things that change together, together.

Now to your disadvantages:

the flow of the code is more convoluted.

This is an argument James Coplien makes in DCI. In OO you would not normally see a "transaction script", or command script for a whole use-case in one place.

Coplien, you and many others argue that this is detrimental to maintainability.

I would say this opinion may originate from the feeling of "losing control". Delegating real responsibilities to objects prevents you from micro-managing what happens. Some perceive this "loss of control" to equal less maintainability.

It is the opposite actually. By delegating responsibilities you ensure that there is no cognitive overload, there is no huge "master control script" or "god object" controlling everything. This creates maintainability.

the use case naming convention seems less relevant, since CreatePost does not actually do any logic and just calls another function

I see that too as a positive. There should not be an object named CreatePost. Objects are not scripts, they are things. CreatePost is obviously not a "thing", it is a procedure in disguise.

there is no separation of concerns.

Depends on what you mean by that, which concerns do you want to separate. I would want to separate business concerns as opposed to technical concerns. The first version separates technical concerns, the second one business concerns.

Since I usually work along business features and bugs, the requirements, tickets are usually (not always) written in business language, I think separating based on business concerns makes much more sense. YMMV.

3
  • Thanks for taking the time to respond! I guess some of my concerns originate from my very first job where the other devs were technical concerns spitting gurus. And while I try to deviate from that, it still sticks to my head 😅 I'm used to managers and services instead of objects as you defined it
    – Vinz243
    Jul 19, 2022 at 11:42
  • One thing seems a bit weird tho : if my createPost method requires additional beans, it does seemingly deviate from spring paradigm with autowired.
    – Vinz243
    Jul 19, 2022 at 12:40
  • 1
    I get both points. I've been a JEE dev since the late 90s. It took me years to "unlearn" all the things JEE (and Spring) advertise as "best practice". My point is, if something makes complete sense, but collides with JEE or Spring practices. Well, the practice is probably unfit for the task at hand. Jul 19, 2022 at 19:09

Your Answer

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

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