📜 ⬆️ ⬇️

Where is our business logic, son?

Thanks to heaven for it was raining on Saturday, and I read it (and you say thank you for translating). On Sunday, however, the sun was shining and text formatting was postponed.

Special thanks to the author for allowing a separate publication.

An extremely interesting article about what business logic is and where to live. The article, by the way, is already three years old. And I often meet systems where the code is not separated from the data. May lead to real holivaru.

Where is our business logic, son?


Introduction


Over the years of development, we have moved from the desktop to the client-server architecture, then to the 3-tier design, to the n-tier, to service oriented. During this process, many things changed, but many habits remained. Often, resistance to change comes from habits. However, in many cases it is procedural. This article describes what we are doing wrong and possible solutions.
')

About the article


What I will describe here is one of the methods for constructing n-tier systems in terms of design and architecture. This article does not focus on code. There are many methods for constructing n-tier systems, this is only one of them. If you are building a system, I hope you will find a good tip, technique or pattern for using this approach.
While this article may offer several starting points from “standard methods,” everything in this article is based on Microsoft Patterns and Methods and is described in Designing Data Tier Components and Passing Data through Tiers and other documents.

Even if you do not dare to apply all the methodologies proposed here, you should use at least some of them.

purpose


Ask any developer where business logic should be, and get the answer: “Of course, in the business layer.”
Ask the same developer where the business logic is in their organization, and again hear: “Of course, in the business layer.”

You should have no doubts about where business logic should be - in the business layer. Not part of the business of logic - all business logic must be in the business layer. After reading this article, many developers will understand that what they thought was true about their systems is not.

Terms


These terms are often used together, but in this article I will use them as described here.

Link (tier)

When I use the word link, I mean a physical link consisting of a physical server or a group of servers that perform the same function and are grouped only to increase capacity.

Layer

When I use the word layer, I mean a system segment that is limited by its own process or module. Multiple layers can be contained in one link, but any of them should be able to be easily transferred to another link.

Problem development


Desktop

On desktop applications, business logic is contained on one link with all other layers. Because there is no need to separate the layers, they are often mixed and do not have clear boundaries.

image

Client server

In the client-server application, there are two links, which leads to the creation of at least two layers. At the initial stage, the server was considered only as a remote database, and the division was as in the figure - the application on the client and the data on the server. Usually all business logic was on the client, mixed with other layers, such as the user interface.

image

It quickly became clear that you can reduce the load on the network and centralize logic to reduce fixed deployment costs by transferring most of the business logic to the server. Architecturally, the server was a well-prepared place in the client-server system, but the database as a platform offered few opportunities. The databases were designed for storage and distribution, and their architecture did not allow for expansion in the direction of business logic. Database stored languages ​​have been developed for basic data transformations to support what SQL was lacking. The stored procedure languages ​​have developed a business logic for quick execution and not for handling complex tasks.

But this was less of two evils, and part of the business of logic moved into stored procedures. In fact, I am willing to bet that business logic has been narrowed and driven into the framework of stored procedures, exclusively from a pragmatic point of view. In a two-part world, this was not perfect, but still much better.

image

3-link

When the problem of the client-server architecture became apparent, the popularity of the 3-tier approach increased. The greatest and most difficult problem of that time was the number of connections. Now many databases can handle thousands of one-time connections; in the nineties, most databases dropped somewhere in 500 connections. Servers are often licensed by the number of client connections. This all led to the fact that it was necessary to reduce the number of connections to the database.

Connection pooling has become popular; however, to implement a connection pool in a system with many individual clients, it is necessary to implement a third link between the client and the server. The middle link became known as the “middle link”. In most cases, the middle link existed only for managing the connection pool, but in some cases the business logic began to move to the middle link because the development languages ​​(C ++, VB, Delphi, Java) were much better suited for implementing business logic than the stored procedure languages. It soon became apparent that the middle link was the best place for business logic.

Also, the middle link provided the ability to connect customers with low speeds, because Direct connection to the database usually requires a wide channel and low latency.

What is business logic?


Before I continue, let's clearly define what business logic is. Making presentations at conferences and inside the company, I began to fear that not everyone agrees with what business logic is, and, quite often, they do not even fully understand what it is and what it is not.

The database server is the storage level. Databases are designed to store, retrieve and update data with the highest possible efficiency. The functionality is often a SUPUM (Create, Delete, Receive, Update). Some databases are supo and are, but the conversation is not about that.

The databases are designed to serve these operations very quickly. They are not designed to format phone numbers, calculate optimal usage and peak loads, determine geographic location and routes of loads, and so on. Although, I have seen all this and many more complex tasks implemented only with the help or in large part in stored procedures.

Buyer delete


And all this applies not only to complex things. Let's imagine a simple task and one that is often not even attributed to business logic. Task - Remove Buyer. In almost all systems that I have seen, the removal of the buyer is handled solely by the stored procedure. However, in the removal of the buyer, quite a few decisions must be made at the level of business logic. Is it possible to remove the buyer? What processes should be started before and after? What precautions should be observed? From which tables should records be deleted or updated afterwards?

The database should not be concerned with what a customer is; it should only care about the elements used to store the customer. The database should not be able to figure out which tables the customer should store, and it should work with the tables without paying attention to the customer. The task of the database is to store rows in tables that describe the customer. In addition to basic constraints such as cascade integrity, data types, indexes, and null values, the database should not have functional knowledge about what the buyer is in the business layer.

Stored procedures, if any, must operate with only one table; an exception is a procedure requesting a sample of several tables to output data. In this case, stored procedures work as views. Views and stored procedures should be used to consolidate values, but only for faster and more efficient work with data in the business layer.

But even in companies that are proud of the latest achievements in development and technology, and in those that shout at the mouth about their entire business logic in the business layer, a brief database analysis quickly reveals: remove a buyer, add a buyer, block a buyer, freeze a buyer etc. etc. And not only with the buyer, but also with many other business logic objects.

I have often seen stored procedures like this:
sp_DeleteCustomer(x)
Select row in customer table, is Locked field
If true then throw error
Sum total of customer billing table
If balance > 0 then throw error
Delete rows in customer billing table (A detail table)
if Customer table Created field older than one year then
Insert row in survey table
Delete row in customer table


Regularly part of the business logic moves off to the business layer.
Business Layer (C#, etc)
Select row in customer table, is Locked field
If true then throw error.
Sum total of customer billing table
If balance > 0 then throw error.
if Customer table Created field older than one year then
Insert row in survey table
Call sp_DeleteCustomer
sp_DeleteCustomer(x)
Delete rows in customer billing table (A detail table)
Delete row in customer table


In this case, part of the business logic has been moved, but not all. Some tables are processed in the business logic layer. The database should not have any idea what tables form the buyer in the business layer. For all three operations, the business layer must issue a SQL command or call three separate stored procedures to implement the functionality in the above sp_DeleteCustomer.
By transferring all business logic to the business layer, we get:
Business Layer (C#, etc)
Select row in customer table, is Locked field
If true then throw error.
Sum total of customer billing table
If balance > 0 then throw error.
if Customer table Created field older than one year then
Insert row in survey table
Call sp_DeleteCustomer
Delete rows in customer billing table (A detail table)
Delete row in customer table


Deleting rows can use a stored procedure if they are from the same table. However, in modern databases using query caching, this is not a significant performance improvement. In addition, the SQL generated by such systems is very simple, because it works with a single table, and therefore requires almost no optimization. In fact, the database does not become very good from too many stored procedures loaded, and simple SQL commands do not work on them like that.

Transferring even the modification of the tables in the business layer, we will get the following benefits:

Since this method requires three successful calls to the database instead of one, your business logic node must be connected to the database on a separate high-speed segment, such as gigabit. Sending 300 bytes instead of 100 bytes will become unprincipled. Most databases support batch transfer of SQL queries, and all three queries can be sent in one packet, reducing the load on the network. To issue such requests, you should use the data access layer, and not include the requests directly in the code.

Some database administrators and even developers may not accept this level of integration and insist on implementing such batch updates in stored procedures. This is a choice that you must make, and it is very dependent on your database and your priorities. Because almost all modern databases use query caching mechanisms, performance gain in most cases is minimal, and there are clear technological reasons for not loading logic with stored procedures. If you choose to leave such batch updates in stored procedures, you must be very careful to prevent other business logic from slipping into stored procedures, and limit your stored procedures to SOUP operations, without any conditional operations or other business logic.

Formatting


Let's look at another example that I discovered and sowing the seeds of war among developers - is this business logic or not. I’ll tell you why I think this is business logic, not user interface or storage. This example does not apply to easily implemented formatting. An example that I will use is phone numbers.
Each country has its own format for displaying phone numbers in a pleasing manner. In some countries they are even more than one. Below are a few examples:

Cyprus:
+357 (25) 66 00 34
+357 (25) 660 034
+357 25 660 034
+357 2566 0034
Germany:
+49 211 123456
+49 211 1234-0
North America (USA, Canada)
+1 (423) 235-2423
+ 1-423-235-2423
Russia:
+7 (812) 438-46-02
+7 (812) 438-4602

In Germany there is even a special official standard for formatting - DIN 5008.

Of course, the country code is discarded when used locally. But let's assume that you have an international system and you need to store and display the country code. For each country, we will choose one display format.

We agree to format the phones as follows:

Usually the following is done, all non-numeric characters are removed and the number becomes similar to:
Phone: 35725660034

Sometimes a country code is separated and the number becomes:
PhoneCountry: 357
PhoneLocal: 25660034

It seems simple, but this is another task for business logic. Not all countries have a code of the same length. Country codes can be from 1 to 3 characters.

Often, input processing (if the country code is separated) and the display logic are implemented on the client, since The client is written in a traditional language that is well suited for this. The problem is that the client needs a huge amount of data to determine the length of the country codes, and the client will need to be updated every time the display format changes.

Sometimes formatting is done in a stored procedure. The problem with this approach is that the languages ​​of the stored procedures are not suitable for this type of logic, and it often leads to bugs and brakes in working with real logic.

More often phone numbers are stored twice. Once pure for good indexing and searching, and the second in formatted for display. In addition to the problems described above, we get the problems of redundant entries and updates.

In especially sophisticated extreme sports, which are often ridiculous, the telephone number is stored in the format in which it was received. The problem is obvious: phones can not be quickly found, indexed or sorted.

The important thing is that although this is formatting, it does not belong to the user interface, and an attempt at total centralization can shoot the database. This is definitely a business logic. The implementation of formatting in the business layer will not allow duplication of data and will be written in the development language, and not hammered into the data processing language.

Exceptions


Some batch updates are performed many times faster when implemented using stored procedures. In most cases, simple SQL can be avoided, but some types of batch updates require cycles and, when implemented, create thousands of SQL commands in the business layer. In such rare cases, a stored procedure should be used, even if it needs to implement business logic. It is necessary to pay special attention to the fact that it was implemented only the necessary minimum.

I will return in the article to this problem.

Today's systems


Client server

In client-server applications, business logic is usually available on both the client and the server.

image

The real ratio will vary from application to company, the previous example describes client-server applications well. Most business logic was implemented in stored procedures and views in an attempt to centralize business logic. However, many business rules cannot be implemented simply by SQL or stored procedures, or they can be faster executed on the client, since they are based on the user interface. Due to these opposite factors, business logic is distributed between the client and the server.

N-ring

For many reasons, which I will describe later in a separate article, when building n-tier systems, the situation only gets worse in terms of consolidating business logic. Instead of consolidation, business logic becomes even more fragmented.

Of course, each system has differences in how business logic is distributed among the layers, but there is one thing common to all. Business logic is now divided into three layers instead of two. Next, I will present some typical scenarios.

Scenario 1

Typical distribution of business logic over an n-tier system:

image

In such cases, the business layer does not contain business rules. This is not a real business layer, but only an XML (or other streaming format) formatter and a database dataset adapter. Although some advantages such as: connection pooling and database isolation can be achieved, this is not a real layer of business logic. It is rather a foreign physical layer without a layer of logic.

Scenario 2

Another typical scenario:

image

Usually, some business rules of an application go into the business layer, but what was in the database remains in it for the most part.

When reusing a business layer in such designs, business rules should be repeated in the client application. This negates the main purpose of the implementation of the business layer.

image

Also, client applications have the opportunity not to comply with business rules without implementing them or simply ignoring them. With the presence of a real business layer, this is impossible.

Consolidation

Instead of all of the above, the business layer should contain all the business rules.

image7

Such development has the following advantages:

The above scenario is the goal. However, some duplication, especially for data verification, should also be on the client. These rules must be supported by the business layer. In addition, on some systems, individual high-capacity operations, such as batch updates, can lead to exceptions and should be placed in the database. Because a more realistic approach is presented below. Please note that all business logic must be implemented in the business layer, and those minimal sets that are present in other layers are simply duplicates solely to improve performance or disable certain components of the user interface.

image

Moving to the central hub


Slippery slope

When switching to the central node, there is always the temptation to "implement this part in a stored procedure." Then "that" and "this one." And soon you will find yourself in the same situation as you were, without significant changes.

Stored procedures should be used to execute SQL and retrieve data sets in databases that optimize stored procedures better than views. But stored procedures should not be used for anything other than combining and issuing data. When updating data, it should exactly and only update, but not interpret the data in any way.

There are tasks where, to improve performance, some components must be placed in a stored procedure. But such tasks are actually quite rare and they should be the exception, not the rule. Each exception must be verified and approved, and not simply implemented at the behest of the developer or database administrator.

Cheaper


It sounds somewhat strange that buying iron can make it cheaper. But with the implementation of middle-level servers, practically no additional software, except for the OS, is required. And the cost of increasing the capacity of the database server is significant for the following reasons:

When transferring logic to the middle tier, you can significantly reduce the load on the database and prevent its capacity from increasing prematurely.

Simpler

In addition to cost, mid-level updating is usually easier than updating a database.
Databases have an inherent limit on how much they can be increased by simply adding iron. At some point, you need to start using other technologies like division, clustering, replication, and so on. But none of these technologies is simple, and all require substantial investments in iron, migration, and strongly affect existing systems.

Increasing the mid-level server is much easier. As soon as the load balancing mechanism is launched, it all comes down to the task of adding a new server.

Topology


Let's look at the statements I just made using the following diagram. The fill in segments shows the direction or importance of their name in relation to the links in the diagram. The unit price increases when we move from the client, to the middle link, to the database. I use the word unit to indicate a processor or server, depending on the configuration.
(top to bottom: unit price, average bandwidth, deployment complexity, quantity)

image

If the same data is given in relative values, they can be easily compared:

image

I did not give the numbers on the charts because they are very dependent on the network configuration, processor power and other factors that are unique to each organization. Each function uses its own units of measurement. I presented only the general relationship of measurements. It shows well that the middle link has capacity for growth and is much cheaper than a database.

Grow middle


If most business logic is implemented in a database, you will need a more powerful database.

image

When transferring logic to the middle tier, you can seriously reduce the load on the database. The figures presented here are for demonstration purposes only and will vary from system to system, but they can help you get the idea. Although the following diagram and more hardware, the total cost of the system will be less, and it will be easier to deploy. It is much cheaper and easier to build a middle link.

image

Bottleneck


Let's look again at one of the previous graphs:

image

What is the only bottleneck in the system? Which of the links has a pronounced limit of growth? This is definitely a database. It all comes down to the database.

image

Therefore, by moving the calculations to the middle link, we can move away from the boundaries of the data layer.

Difficulties


There are several difficulties to go to the middle link, and not all of them consist in the need to program differently.

Habits

There is a saying: “It’s hard to get rid of old habits.” This applies to the team. In a team, you need to convince not only yourself, but most of the team.

Procedures

Many companies have well-established security policies that enforce security in the database, and using stored procedures as representations does not provide sufficient control. Changing corporate security policies to go to the n-tier world can be very difficult, if not impossible.
.Net , Microsoft, , , .


. , -, . , , , . , . , – ! , .

- , . . – , . , .

, n- , . , - . , - .

, 10 20 . , . . .

, . , , , .

Tools

, . , , .

Solutions


Architecture

, . , . , . - , .


. , : , . , , , .

. , . SQL, , . .


, , , . , , , , , .

. , .

What else to read


, . , , .

, , «». , , . , . , , . , , .

, - . , 2002 Microsoft. , .

, Designing data tier components and passing data through tiers.

Conclusion


. . , . , , , .

, . , - .

UPD: maovrn « ».
UPD1:
:
1. .
2. , .1. Chad Z. Hower aka Kudzu
3. , — . , , , .
4. — .

Source: https://habr.com/ru/post/65432/


All Articles