3

Sorry about the vague question, please do suggest different formulations. Anyway here is the kernel of the question:

How many classes representing an entity/resource or whatever you want to call it, should you have? Let's take it on the example of User object.

Often I see you have UserEntity used on the repository level to map to DB entity (sometimes autogenerated by your ORM), that maps to service level UserDTO, which then maps to User object to be returned by the API or View layer. This also gets more complicated if you plug in different APIs where some people opt-in to convert to per API object so CRMUser, ShopUser and so on.

All of those have the same (or similar) fields and no functionality. For each mapping, you need a Converter class and depending on your religion Interface.

So it gets quite complex in the end.

Do you have any opinions/guidelines to follow here?

0

4 Answers 4

7

Getting the right level of abstraction is a classic "Goldilocks" scenario:

If you have too few abstractions, you risk eg leaking details of the ORM into other layers and of creating undesirable coupling between those layers.

If you have too many abstractions, you risk making the code unnecessarily complex: "*A moment ago, I had an XyzUser, now it's a YzxUser! Why?!??". Trying to follow the flow of overly abstracted code is really hard.

So you want baby bear's bowl of abstractions: not too few and not too many; just right.

But what is that "just right" level of abstraction? It's basically as few levels of abstraction as possible, without creating either undesirable coupling, or leaky abstractions in the process. There's no fixed number for this as it will vary from app to app. Instead, every time you feel the need to add a new level of abstraction, ask yourself if it's worth it. Will the benefits of decoupling outweigh the disadvantages of complexity? If you feel the answer is "yes", then add another level of abstraction and stop doing so the moment the answer is "no" and possibly even when it's "maybe". Though the latter reveals the subjectivity of this topic: some people prefer complexity over coupling and others prefer the opposite. So your answer each time will be subjective, but as long as you/ your team are consistent with this subjectivity, it doesn't really matter.

3

More important than abstraction levels is to have abstractions that are not leaky. If most of your application can use the highest abstraction level, and work just fine without looking at any lower levels, then it doesn't matter much how many abstraction levels are below it (that you never look at). If there are two abstraction levels, and most of your application has to look at the lower level to get things right, then two levels are too many.

1
  • Either two levels are too many, or one of the levels has too much in it, and some of the stuff in Level 1 should actually be in Level 2. That's the basic conundrum of putting UI logic in your business classes, for instance. It's a judgement call. Commented Jan 16, 2020 at 13:06
1

Absent any specific requirements, the answer is one. Following the core principles of DRY (don't repeat yourself) and KISS (keep is simple), you should not create multiple classes if you only need one. For many application, a single User class will be the optimal number.

But there may be specific requirements which may make it appropriate to have more. For example if you want to expose an API and have its data model decoupled from the business logic. Here the rule of thumb is that if the classes are exactly alike, you probably don't need more than one. But in cases where the classes represent slightly different concepts and have different attributes, then it may make sense to have multiple.

-1

Objects are defined by their behavior, not by their internal state. That is also your answer as to what levels of objects should exist.

By this thinking any object that just holds data shouldn't even exist. I'm speaking of course from an object-oriented perspective, and I'm painfully aware that "modern" architectures and a lot of developers do not agree with this.

Also, data-only "objects" do not abstract anything. You can't have an abstraction with nothing hidden and no functionality defined.

2
  • "You can't have an abstraction with nothing hidden and no functionality define". If I give you a user ID, rather than all the user data, I'm given you eg an integer. There's (potentially) no functionality and no hidden data encapsulated by that ID, but it's definitely an abstraction. Commented Jan 16, 2020 at 10:49
  • You are talking about a different kind of abstraction. I was talking about an object abstracting the thing it stands for. I.e. an int user id does not abstract a user id, it is exactly the thing as defined. A user id would abstract something if it would have behavior relating to what it is supposed to be in the system. For example UserId.next(), or UserId.findInSystem(system), or whatever. Commented Jan 16, 2020 at 11:19

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.