How to Differentiate Business and Service Layers in Layered Architecture

Exploring the relationship and differences between business logic and services.Photo by Tekton on UnsplashA while ago I wrote an article about what I think is the biggest mistake that software developers adopting layered architecture make, which is bas…


This content originally appeared on Level Up Coding - Medium and was authored by Giedrius Kristinaitis

Exploring the relationship and differences between business logic and services.

Photo by Tekton on Unsplash

A while ago I wrote an article about what I think is the biggest mistake that software developers adopting layered architecture make, which is basically turning everything into god objects (god object is the anti-pattern where we have an object that does and knows everything) by confusing services with business logic and merging the business layer and the service layer into one.

Expensive Mistake That Often Plagues Layered Architectures

What I saw people say about it pretty much confirmed my statement, which is that everyone understands and defines layered architecture differently. Don’t get me wrong, that’s not necessarily a bad thing.

The point of this article is to expand on the previous one and explain how to do layered architecture, so if you haven’t read it already now is the time to do it, but I’ll try to make this article understandable even if you haven’t read the previous one.

Common Approach To Layered Architecture

The idea for the previous article was born because of the frustration I felt when I had to deal with hard-to-modify and practically untestable code.

There was a common theme: layered architecture and services. Those two things practically defined whole projects. Literally, every class that did not fit into the default framework’s folder structure was a service and sat in a folder called services. Every single one.

Only 3 layers existed: the presentation layer, the persistence later, and the service layer. The service layer handled literally everything. The file structure looked roughly like this (slightly simplified to not include framework-specific things):

Image by Giedrius Kristinaitis

One problem with the folder structure is that it doesn’t explain what the application is about, which can make it harder to find stuff when there are a lot of files.

Another problem is that when people see a general folder, for example, services, in their mind it registers as a dumpster for everything, and thinking stops there.

Here’s what the content of the services folder looked like:

Image by Giedrius Kristinaitis

The following image illustrates the execution flow through the layers:

Image by Giedrius Kristinaitis

Whenever any logic was added to the code, a service class would be created for it. For example (don’t take it as an example of what you should do), let’s say we want to add a feature that calculates the total amount that was spent on furniture.

For that, a class would be created called something like FinanceService, or a SpendingsService, with a method in it called calculateFurnitureSpendings, or a method called calculateSpendings that accepts some kind of category, but the category is not the point, the point is that there would be a service class with a method to calculate the total.

Doesn’t appear to be too bad, does it? It is bad because the service class acts as a logic dumpster. Tell me, what would happen if someone decided to add a feature to create a report of total spendings? There would probably be a new method added to create a report.

What would happen if there was a third feature related to spendings? Yet another method in the service. I think you can see where this is going — a god object is starting to form in the shape of SpendingsService.

As you can see, there’s no sense of business logic as a thing of its own at all, just the service layer doing literally everything. No one can tell anymore what a service is even supposed to be — it literally merges with the concept of the business logic and you can’t differentiate the two.

When you don’t know the difference between a service and business logic anymore it becomes a breeding ground for god objects. Well, at least, that’s what I’ve seen.

Why Is Everything A Service?

This way of doing layered architecture is all over the place. However, I don’t blame layered architecture for any of that.

I think that the problem here is people trying to define an architecture where everything has its place and you don’t have to think where to put things. Obviously, when anything that does any logic is a “service” and you have a folder called “services”, then you don’t have to think where to put things, because it’s a standard.

I think it’s a problem in software as a whole, people try to create a universal process of doing things, but the reality is that there’s no such process or architecture.

We can’t just start creating a single class for everything related to a domain object, name it SomeDomainObjectBusinessClass, and start dumping everything into it. Business logic is too complicated to do such a thing. Business logic requires thought. However, in practice, people do it all the time, except they call the classes services, and the layer is the service layer. I think that’s a terrible way of doing things.

Problems That Arise From Treating Everything as A Service

It might not be that bad when you’re adding new code to the application, however, it becomes very painful to deal with when you have to modify existing code, because the service god objects are too static, and too many things depend on the way they are written.

Unit testing becomes almost impossible when all your business logic is in the form of god objects, because it requires a lot of setup, and mocking to test even the simplest of things.

Unit tests that are written for logic that consists of god objects mirror the implementation too much, thus becoming useless, as you have to modify the tests every time you make a tiny change in the logic that doesn’t even change the outcome of the code.

All the projects I’ve seen where the service layer contains business logic had either no unit tests, because they were too difficult and time-consuming to write and maintain, or terrible unit tests that were often over 100 lines of code per single test and were written only because a senior developer said that developers should write unit tests, or someone set a code coverage target believing that code coverage magically makes things better.

A lot of people might be thinking “whatever, it’s just unit testing, no big deal, we’re not writing them anyway”.

The thing with unit tests is that they show you how difficult or easy it is to modify your code. If you can’t write a unit test for your code, you won’t be able to modify it easily.

If you think about it, writing a unit test is like writing other production code that interacts with the piece you’re trying to test, so the difficulty of writing a unit test tells exactly how difficult it’s going to be to modify the unit under test. When unit tests are difficult to write the tests are not the problem, the problem is the unit under test.

The absence of unit tests doesn’t mean that you only can’t be sure that you didn’t break something unexpectedly, it also indicates a difficult-to-modify codebase.

Tests that were painful to deal with were the reason I started to hate the misuse of the service layer, but, really, it’s more of a problem with how people designed the code, not the service layer itself, it’s just that everyone did it because “this is how layered web apps are done, the service does the logic”.

The service layer is not business logic itself, and business logic should not exist in the service layer in the form of god objects.

You should decide what layers exist in your architecture, you decide what the execution flow through the layers is. Just don’t keep the business logic in the service layer.

Of course, that raises an obvious question.

How I Think About Layered Architecture

We need to understand what a service is and what the service layer is. As I said, as far as I can see, even though the concept of layered architecture is simple, it’s also very popular, and because of its wide usage people have different understandings as to how layered architecture works, so I won’t try to push some way of doing it and say “this is how it must be”.

However, I will present my mindset when I approach layered architecture. You decide if you want to adopt anything or not, because the most important thing is to do what works for you and your project.

What is a service?

We need to define what a service is. I’ll use my definition of a service from the previous article, quoting myself:

A service is a set of functionality that clients can call to do something, be it performing a computation or retrieving some data. It’s an abstraction. Abstractions exist for a reason. They hide the way something’s done.

By this definition, everything could actually be treated as a service just like people do, right? Theoretically, yes. I’ll address this in a bit.

What is the service layer?

It’s not supposed to be a gateway to business logic. What do I mean by “gateway”? A gateway is a pass-through proxy that’s not an abstraction, it doesn’t hide anything, it just passes a request to something else. For example, a gateway could look like this:

Image by Giedrius Kristinaitis

Creating such a thing is pointless since it doesn’t do anything useful. The example I gave earlier tries to eliminate the problem of a pointless gateway by having the business logic in the service layer by merging business logic and services together.

So what’s the purpose of the service layer? The purpose is the same as the one of a service — to act as an abstraction. The layer is a collection of abstractions.

It’s important to define what the abstractions are trying to hide, because that’s how we decide what the true purpose is, where to place the layer and what calls it. However, wait a minute. Aren’t all layers supposed to hide something from other layers? Yes, they are.

All the layers are supposed to hide how they do things from other layers.

If you think about it, since all layers already abstract things away from other layers, they theoretically are services themselves.

So what’s the point of having a separate service layer full of services if everything’s already abstracted away by other layers? It seems like it has no purpose. To me, it doesn’t if my application is not doing anything outside of the usual layers: presentation, business, and persistence.

I like to think about it this way: the service layer is supposed to hide things that are not a part of any other layer, for example, calls to external systems. Then it’s acting as an abstraction for the business logic that sits in an external system. That’s the true meaning of the “services are supposed to encapsulate business logic” statement to me.

There’s no point for the service layer to be hiding anything that other layers already hide. For example, the persistence layer already hides the details about data storage, so it’s not the job of the service layer.

Let’s come back to the service layer acting as a layer between the presentation layer and the business layer. It’s pointless, because the business layer already hides the execution of the business rules from the presentation layer. If it doesn’t hide the execution of the business rules from other layers, then something’s wrong. In this context, the statement “services are supposed to encapsulate business logic” means nothing, and, sadly, people interpret it literally exactly in this context.

The service layer is not the place for business logic. Service layer != business layer. If your business logic sits in a class called SomethingService, I think you should seriously reconsider what you’re doing.

What even is layered architecture?

I really don’t like how people use the service layer as an excuse to stop thinking and start growing god objects that do everything and are impossible to work with in the long run.

It’s also important to note that layered architecture (or any architecture) is not a folder structure. A folder structure cannot enforce anything, folders alone don’t protect from leaking details from one layer to another. Folders just help us to find stuff, and a layer can have a lot of folders.

Layered architecture is not a framework-specific thing. It’s not about controllers, it’s not about DAOs, it’s not about web apps and HTTP requests, and it’s not about services. It doesn’t have to have the service layer if there’s no need for it.

Layered architecture is an idea about dividing an application into a set of logical layers that hide the way things are done, thus protecting other layers from changes. That’s it.

It doesn’t matter if an application doesn’t follow the standard presentation/business/persistence pattern, it can still use layered architecture as long as the underlying idea is in place.

Putting It All Together

As an example, let’s take a web application (because that’s what most people are familiar with) that tracks user shipments.

A user can log in and see the status of every shipment in a dashboard. Also, every time a user checks the status of their shipments, the shipping provider gets notified about it. The code examples are presented in a pseudocode/Java mixture so that more or less everyone could understand it no matter the programming language they’re using, and also, without any specific framework in mind.

With everything in mind, our layers could look like this:

Image by Giedrius Kristinaitis

Keep in mind that the arrows indicate the direction of the flow of control, they don’t necessarily mean the direction of dependencies. Also, the arrow from the service layer to the persistence layer is just as an example of what could be done, in this example it’s not.

Let’s take a look at the folder structure:

Image by Giedrius Kristinaitis

The first thing is the folder structuring. As you can see, I used vertical structuring. Vertical structuring means that we’re structuring things by the feature they belong to, not by the layer that the thing belongs to.

Such structuring helps to have a better understanding of what the project is about, because when you look at the folders you immediately know what the features are and can figure out what the business domain is.

In theory, vertical structuring should help to avoid dumping code for unrelated features into a single class, because a class doesn’t exist in every feature folder, but it really depends on one’s thinking process, vertical structure alone won’t solve everything by itself.

Here are the expanded views of each feature folder:

Image by Giedrius Kristinaitis
Image by Giedrius Kristinaitis
Image by Giedrius Kristinaitis
Image by Giedrius Kristinaitis

Let’s address the elephant in the room. I just used the folder name “BusinessLogic” here to make things clear, it doesn’t have to be like that.

Here’s the code for all the files in the example (keep in mind that it’s pseudocode, and not in any specific programming language or framework):

Explanation

Let’s unpack the example and try to understand what it means.

Obviously, there are no general dumpster folders for every layer that also apply to each feature. Instead, we have more dedicated folders for the layers inside each feature folder. This is to prevent the layer folders from growing since it doesn’t allow throwing code into it that doesn’t belong to a specific feature.

Let’s have a look at what each individual layer looks like.

Presentation layer

Image by Giedrius Kristinaitis

The presentation layer has only the things that are related to displaying things and getting instructions from the user. Obviously, the presentation layer calls the business layer (it’s impossible to have a UI that’s completely independent of a business domain), but it doesn’t know how the business rules are executed, and that’s the important part.

For example, we have a business rule that every time the user accesses the shipment statuses a notification gets sent to the shipping provider about it. The presentation layer has nothing to do with the rule.

The code that handles the rule cannot sit in the presentation layer, because it’s not related to the presentation layer, it’s our business rule. If the presentation layer did handle the rule, then every time the rule changed, we’d have to update both the presentation layer, and the business layer.

The presentation layer also doesn’t know how user login happens, it just passes the user input to the business layer, it just knows whether a login attempt was successful or not, which is obviously something that the UI should know.

The presentation layer doesn’t know how the business layer gets the shipment statuses.

If you notice, the presentation layer is not completely independent of the business layer, for example, it knows that the ShipmentStatus class exists. We could have a thought to place a layer between the presentation and business sides that converts things from the business layer ShipmentStatus class to a type that the presentation layer expects. However, it wouldn’t accomplish much, because that layer would be dependent on both the presentation layer and the business layer, it would just be an extension to the presentation layer that converts outside data to the format that the presentation layer expects, which could sit in the presentation layer itself, so it wouldn’t really be worth it to create a separate layer for that, it wouldn’t add any more abstraction, we’d still have to maintain it if types in the business layer or the presentation layer changed.

In a nutshell, some dependencies on the business layer have to exist in the presentation layer. Creating a service layer between them wouldn’t solve anything, as it would require the same amount of maintenance, and the service layer wouldn’t even be reusable, because it would be very tightly coupled to the use case of serving the presentation layer.

Business layer

Image by Giedrius Kristinaitis

The business layer has only our business rules, which are:

  • the user can authenticate
  • the user can access their shipment statuses
  • shipping provider gets notified about shipment status accesses

The business layer doesn’t handle anything else. No framework-specific things, no dependencies on other layers. It could be copied and plugged into another project, and that other project could satisfy the interface expectations that the business layer has, and that would be it, another project could use the same business logic without requiring to change the business layer even a single bit.

The independence in the business layer is achieved by using the dependency inversion principle. I have an article about the dependency inversion principle if you want to read more about it:

Dependency Inversion Principle Explained and How Tutorials Get It Wrong

That’s what the interfaces in the example are for. If you don’t want to use the same level of business layer independence, go for it, it all depends on your situation.

Service layer

Image by Giedrius Kristinaitis

The service layer doesn’t act as a gateway to anything, it just serves as an abstraction for an external system, which is the notification system for the shipping provider. It serves as an abstraction for a set of functionality that is not a part of the application and doesn’t belong to any other layer.

The notification can’t sit in the business layer, because the knowledge of how the notification is sent is not our business rule, it’s a technical detail. Our business domain doesn’t specify how the notification is sent, nor should it, therefore, it’s not a part of the business logic and doesn’t belong in the business layer, and this is where the service layer comes in.

Business logic should be independent of technical details.

Persistence layer

Image by Giedrius Kristinaitis

The persistence layer is pretty simple, it just fetches some data and also saves the logged in user info to session storage.

Layers don’t know how other layers work

The most important thing is that layers don’t know what’s happening inside other layers.

The presentation layer doesn’t know how the business layer handles things, it just knows that the business layer does certain things, but that’s really unavoidable, you can’t have a UI that doesn’t know what the business domain is about.

The business layer doesn’t know anything about the existence of other layers, it doesn’t know any technical details, for example, it doesn’t know that the user state is saved in a session, it doesn’t know how the notification to the shipping provider is sent, it doesn’t know anything about the database. It exists alone as an independent unit.

The persistence layer doesn’t know details about any other layers either, it only knows about storage-specific things, like the database and the fact that the user state is stored in a session.

The service layer also doesn’t know details about other layers.

Another important thing is that each layer can be easily tested in isolation.

The last, and the most important thing, is that the concepts of a service and business logic are not mixed together.

What You Can or Cannot Do

The example I gave illustrates the ideas and mindset I have when I approach layered architecture.

You could have differences in the way you do it. For example, you could go for horizontal structuring instead of vertical, that’s up for you to decide. You could also not be as strict with layer independence as I am, and that’s ok.

The most important thing is to capture the essence of layered architecture. Layered architecture doesn’t specify how many or what layers you should have. It has nothing to do with the type of the application, you can apply the ideas in both in web applications and desktop applications, it doesn’t matter. It also has nothing to do with the tech stack. It’s not a folder structure either. It’s nothing more than an idea of organizing the application of logical independent layers.

You should do whatever your application needs as long as you don’t create god objects anywhere. If you decide that there should be a layer between the presentation layer and the business layer it’s fine if it’s not a pass-through gateway without any purpose. The same goes for any other layer. However, I advise against merging the service and the business layers into one, unless you know the risk and can manage it.

As for the statement some people have about the service layer which is that “the service layer is supposed to encapsulate/contain business logic”, which makes the service layer act as a gateway to the business layer, one can only speculate where it comes from. I do have my thoughts on it, but this article is already long, so I’ll keep them for another time.

Again, I want to emphasize that the business logic should not sit in the service layer. If it does, then you risk creating god objects.

The service layer is often just an excuse for people to stop thinking and start writing logic carelessly. Sorry to disappoint you, but writing business logic requires thought and design, we can’t get away with following a process or a folder structure.

We shouldn’t try to create a universal process or an architecture, because the reality is that whatever rules we come up with, there will always be things that don’t seem to follow them, and that’s why problems arise. In my opinion, layered architecture is too simple of a concept to be strictly followed.

Level Up Coding

Thanks for being a part of our community! Before you go:

🚀👉 Join the Level Up talent collective and find an amazing job


How to Differentiate Business and Service Layers in Layered Architecture was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Giedrius Kristinaitis


Print Share Comment Cite Upload Translate Updates
APA

Giedrius Kristinaitis | Sciencx (2023-01-12T14:26:08+00:00) How to Differentiate Business and Service Layers in Layered Architecture. Retrieved from https://www.scien.cx/2023/01/12/how-to-differentiate-business-and-service-layers-in-layered-architecture/

MLA
" » How to Differentiate Business and Service Layers in Layered Architecture." Giedrius Kristinaitis | Sciencx - Thursday January 12, 2023, https://www.scien.cx/2023/01/12/how-to-differentiate-business-and-service-layers-in-layered-architecture/
HARVARD
Giedrius Kristinaitis | Sciencx Thursday January 12, 2023 » How to Differentiate Business and Service Layers in Layered Architecture., viewed ,<https://www.scien.cx/2023/01/12/how-to-differentiate-business-and-service-layers-in-layered-architecture/>
VANCOUVER
Giedrius Kristinaitis | Sciencx - » How to Differentiate Business and Service Layers in Layered Architecture. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/01/12/how-to-differentiate-business-and-service-layers-in-layered-architecture/
CHICAGO
" » How to Differentiate Business and Service Layers in Layered Architecture." Giedrius Kristinaitis | Sciencx - Accessed . https://www.scien.cx/2023/01/12/how-to-differentiate-business-and-service-layers-in-layered-architecture/
IEEE
" » How to Differentiate Business and Service Layers in Layered Architecture." Giedrius Kristinaitis | Sciencx [Online]. Available: https://www.scien.cx/2023/01/12/how-to-differentiate-business-and-service-layers-in-layered-architecture/. [Accessed: ]
rf:citation
» How to Differentiate Business and Service Layers in Layered Architecture | Giedrius Kristinaitis | Sciencx | https://www.scien.cx/2023/01/12/how-to-differentiate-business-and-service-layers-in-layered-architecture/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.