Dude, where's my business logic?

Over the years we have moved from desktop, to client server, to 3-tier, to n-tier, to service orientation. In the process though many things have changed, but many habits have remained. This article discusses what we are doing wrong, and the possible solutions.

Through the years we have moved from desktop, to client server, to 3-tier, to n-tier, to service orientation. In the process though many things have changed, but many old habits have remained unchecked. Often this resistance to change is habitual. However many a times it is procedural. This article discusses what we are doing wrong, and possible solutions.

What I present here is one way of building n-tier systems from a design and architect view. This article does not focus on code. There are many ways to accomplish n-tier systems, this is only one of them. I hope you will find some good advice, practices, and patterns using this method.

Ask any developer where the business logic should go and the likely answer would be: "In the business layer of course."

Ask the same developer where the business logic is in their company and they will answer again: "In the business layer of course."

It should go without stating that certainly this is where the business logic should go, in the business layer. However not just some of the business logic, but all of the business logic should go in the business layer. After reading this article, many developers would realize that what they thought was true for their systems, was actually not.

A section of the system that is contained within its own process or deployment unit. Multiple layers may co exist on one tier, but can easily be moved to another tier if some sort of remoting capabilities are used.

In many desktop applications, business logic is contained within one tier with all other layers. Because there is no need to separate the layers, the layers are typically intermixed and with no definable boundaries.

In a client server system there are two tiers, thus forcing at least two layers to be implemented. In the early days the server was simply viewed as a remote database and the division was seen as application (client) and storage (server). Typically all the business logic remained in the client, intermixed with other layers such as the user interface.

It did not take very long to realize that the network bandwidth could be reduced and logic centralized to reduce constant redeployment needs of the client by moving much of the business logic out of the client. As there were only two layers, the only place to move the business logic to was the server. The server architecturally was a well suited place in a client server system, but the database as a platform was a poor choice. Databases were designed for storage and retrieval and their extensibility was designed around such needs. Database stored procedure languages were designed for basic data transformation to supplement what could not be done in SQL. Stored procedure languages were designed to execute very quickly and not for complex business logic.

But it was the better of the two choices so business logic was moved into stored procedures. In fact I would argue that business logic was shoe horned (smashed in, made to fit) into stored procedures as a matter of pragmatism. In a two tier world, it was not perfect but was an improvement.

As problems of the client server approach became apparent, 3 tier designs became popular. The biggest and the most pressing problem at that time was one of connection count. While some databases today can handle thousands of simultaneous connections, in the 1990's most databases began to become heavily stressed at around 500 connections. Servers were often licensed per client connection. These factors made it desirable to reduce the number of connections to the database.

Connection pooling became popular, however to implement connection pooling in a system with many distinct clients, a third tier needed to be inserted between the client and the server. This middle tier became known as, the "middle tier". In many cases the middle tier existed just to coordinate the connection pools, while in other cases the business logic began to move to the middle tier because development languages (C++, VB, Delphi, Java) that were better suited than stored procedure languages could be used. Soon it became evident that the middle tier was the best place to put the business logic.

Before I proceed further, let's exactly define what business logic is. While presenting this at conferences and to companies I have become aware of the fact that not everyone agrees to what business logic actually is, and in many cases it's not even been well thought out what business logic is and what it is not.

The database server is a storage layer. Databases are designed to store, retrieve, and update data as quickly and efficiently as possible. This functionality is often referred to as CRUD (Create, Retrieve, Update, Delete). Certainly some databases are CRUD, but that is another topic.

Databases are designed to be very fast and efficient with CRUD operations. They are not designed to format telephone numbers, calculate optimum usage and peak periods of utility usage, determine geographic destinations and routings of shipments, and so on. Yet, I have seen all of these cases, and even more complex ones implemented mostly or even wholly inside stored procedures.

Yet it's not only the complex cases. Let's consider a simple case, and one that is often not regarded even to be a business logic. The case is that of Delete Customer. In nearly every system that I have seen deleting of a customer is handled exclusively by a stored procedure. In deleting a customer however there are many business logic decisions to be taken. Can the customer be deleted? What are the processes that must be performed before and after? What are safeguards that must be checked first? From which tables the records are to be deleted, or updated as a consequence?

The database should not have any knowledge of what a customer is, but only of the elements that are used to store a customer. The database should not be able to relate which tables should store a customer object and it should treat the tables independently with reference to a customer object. The database's job is to store rows in tables that represent the customer. Apart from the referential integrity constraints, data types, null ability, and indexes that make data retrieval more expedient, the database should have no functional knowledge of what exactly constitutes a customer in the business layer.

Stored procedures if they exist should only operate on one table, with the exception of stored procedures that join tables using SQL SELECTs for the purpose of returning data. In this case, stored procedures are acting as views. Views and stored procedures should also be used for basic tabulation of values, but solely to facilitate faster and more efficient data retrieval and updates by the business layer.

Even in many companies who take pride in their latest design and techniques, and the ones who rave that all their business logic is in the business layer, one quick review of their database instantly turns up delete customer, add customer, deactivate customer, suspend customer, and others not just for customer but for many other business objects.

I often see stored procedures that perform something 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

Many a times some of the business logic is moved out 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, some of the business logic has been moved, but not all. Which tables are affected is business logic as well. The database should not have any knowledge of which tables constitute a customer on the business level. These are better served in the business layer. For each of the three operations, the business layer issues a SQL or calls three separate stored procedures to execute the functionality in the last sp_DeleteCustomer.

Moving all the business logic to the business layer, we have:

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

The delete rows can use a stored procedure if they delete just one table, however with modern databases using query plan caching, there is little performance benefit. In addition, the SQL sent by such systems is very simple since it only works on a single table and thus has such a simplistic plan that there is almost no need for optimization to be performed. In fact some databases suffer more from having too many stored procedures loaded, than they do from executing simplified SQL statements.

By moving even the table modifications to the business layer, the following advantages are gained:

The system becomes database portable with less effort as each of these stored procedures need not be ported to each database.

Future modifications are easier as all the logic is contained in one place, not two.

Debugging is easier as the logic is not split between two places.

Other business logic cannot "slip" into stored procedures because it's "easier".

While this requires three successive calls to the database instead of one, your business tier should be connected to the database on a separate high speed segment, like a 1 gigabit segment. Sending 300 bytes versus 100 bytes will not make a tangible difference. Most databases also support batch commits of SQL and the three statements can be sent to the database in one batch, reducing network calls. A data access layer should be used for issuing such SQL, instead of embedding SQL statements into the code.

Some DBAs and even developers may not accept this level of integration and insist on keeping such batch updates in stored procedures. This is a choice you need to make and depends largely on your database as well as your priorities. Because nearly all modern databases now optimize even submitted SQL based on a query plan cache, there is little performance difference in most cases, yet there are definite technical reasons not to put the logic in stored procedures. If you choose to keep such batched updates in stored procedures you should be very careful not to let other business logic slip into stored procedures and keep your stored procedures functionality purely to CRUD operations, without embedded conditional operations and other business logic.

Let's consider yet another item that I've found to be quite divisive with developers over whether or not it is business logic. I shall demonstrate why I believe it is business logic and not user interface or storage. The item is that of non-simplistic formatting. The example I will use is a telephone number.

Each country has its own format for displaying telephone numbers in a visually pleasing way. In most countries there is even more than one common way. Some examples are as follows:

Germany even has an official regulation specifying the format called DIN 5008.

Of course, the country codes are usually not included locally. But let's assume our system is international so we will store and display the country codes as well. For each country we will pick one format to display the numbers.

Considerations for the formatting of phone numbers:

Input will come in a variety of formats.

Each country has its own unique ways of displaying the numbers.

Some countries' formats are not simple and change depending on the first few digits.

The first few digits (usually the region/area code) are not always a fixed number of digits. In the Russian example, 812 is the area code for the City of St. Petersburg. 095 is Moscow, but parts of Siberia and other regions are 4 digits (3952). This causes the total length of the phone number and the format to change depending on the region code.

With the introduction of new portability laws, new mobile providers, European Union integration, phone system upgrades and more phone number formats and length change fairly frequently on a global basis. In recent years Cyprus has changed their area code scheme twice to accommodate first a more expandable system, and then multiple mobile telephony carriers. With hundreds of countries world wide, you can expect changes to occur on a regular basis.

Typically what is done on the input is that all the non numeric characters are stripped so that the phone numbers become like this:

Phone: 35725660034

Sometimes the country code is separated and stored in a separate field as follows:

PhoneCountry: 357
PhoneLocal: 25660034

This might seem simple, but this brings up yet another business logic issue. Not all country codes are of the same number of digits. Country codes range from 1 to 3 digits in length.

Often the parsing of input (if the country code is separated) and the display logic is implemented in the client as the client is written using a traditional language that is well suited. The problem is that the client requires a large amount of data to determine the length of country codes, and requires a redistribution of the client each time the display routine needs to be updated.

Sometimes the formatting is done in stored procedures. The problem with this approach is that stored procedure languages are ill suited to this type of logic and often leads to bugs as well as inefficient processing of the actual logic.

More often the telephone number is stored twice. It is stored first in a raw format so that it can be indexed and easily searched, and a second time formatted for easy display. In addition to the problems presented previously, additional problems of duplicated data and updating to compensate for new formats also exist.

In some extreme cases, and amazingly frequently enough, the phone number is stored in whatever format the input came in. The problem with this is obvious; the phone number cannot be easily located, indexed, or used for sorting.

It is important that although it is formatting, it's not user interface, and although the urge for any centralization often ends up in the database, this is clearly business logic. Implementing formatting in the business layer eliminates duplicate data, and allows for implementation using a development language rather than shoe horning it into a data language.

Certain batch updates are many times faster when implemented in stored procedures. Most of the situations can be handled directly by SQL, but a few types of batch updates require a looping behaviour that if implemented in the business layer would create thousands of SQL statements. In these rare cases, a stored procedure should be used even if it requires some business logic to be implemented in the stored procedure. Special care should be taken to implement as little as possible in this stored procedure.

In a client server system the business logic is most often split between the client and the server.

Actual percentages vary by application and enterprise, the previous example is a good coverage of client server applications. Much of the business logic has been implemented in stored procedures and views in an attempt to centralize the business logic. However many business rules cannot be easily implemented in SQL or stored procedures, or are faster to execute on the client as it relates to the user interface. Because of these opposing factors, the business rules are split between the client and the server.

For a variety of reasons which I will cover later in the obstacles topic, when n-tier systems are built the situation is often made worse with regards to consolidation of business logic. Instead of consolidation, the business logic becomes even more fragmented.

Of course each system is different depending on how the business logic is distributed among the layers, but one thing is common to them. The business logic is now distributed among three layers instead of two. I will present some common scenarios next.

A common distribution of business logic in an n-tier system is as follows:

In such cases, the business layer contains no business rules. It is not a true business layer, but merely an XML (or other streaming format) formatter and mapper for database result sets. While some advantages can be gained such as database connection pooling, database independence, and a degree of separation with the database, this is not a true business logic layer. It is more of an artificial physical layer without a logical layer.

All the business logic exists in a single location and can be easily verified, debugged, and modified.

A true development language can be used to implement business rules. Such a language is both more flexible and more suited to such business rules rather than the SQL and stored procedures.

The database becomes a storage layer and can focus on efficiently retrieving and storing data without any constraints related to business logic implementations or the presentation layer.

The above scenario is the goal; however some duplication, especially for validation purposes should exist in the client as well. Such rules should be reinforced by the business layer. Furthermore in some systems for reasons of extreme performance benefits such as batch updates may cause an overriding exception and should be placed in the database. So a more realistic approach appears as follows. Note that 100% still exists in the business layer and that the minimal pieces that exist in other layers are actually duplications and exist solely for the purpose of performance or disabling user interface fields according to selections, etc.

While moving to middle tier there is always an urge to "Let's just put this piece in a stored procedure". Then "another" and "another". And soon you are in the same situation you were before with not much having been changed.

Stored procedures should be used to execute SQL and return result sets in databases that optimize stored procedures better than views, such as SQL server. But stored procedures should not do anything other than join data when returning data. For updating data it should do exactly and only that and should not interpret the data in any way.

There are cases where for drastic performance reasons some item should be moved to a stored procedure. However these cases are in fact rare and should be an exception, not a rule. Each exception should be reviewed and approved and not simply done at the will of a developer or database admin.

In addition to the costs, upgrading a middle tier is usually easier than upgrading the database.

Databases have inherent limits on how much they can be scaled by simply adding more hardware. At some point other techniques such as partitioning, clustering, replication and other techniques must be used. But none of these techniques are simplistic, and all involve significant investments in hardware, migration, and/or impact on existing systems.

Middle tier servers however are easy to scale. Once a load distributor is installed, it's simply a matter of adding a new server to expand the capacity.

Let's consider the factors I have just discussed using the following diagram. The shades in the bars above show the direction or magnitude of their caption relative to the tiers in the diagram. Cost per unit increases as we move from client, to middle tier, to the database. I have used the word unit to refer to processor or server, depending on the configuration.

When the same results are charted with relative values, they can be compared easily:

I have not placed numbers on the graph because the numbers are heavily dependent on network configurations, processor power, and other factors unique to each enterprise. Each measure also uses a different unit of measurement. What I have presented here is a general relationship of magnitude of each measurement, overlaid with each other to show relationships. This clearly shows that the middle tier has a capacity to scale, and also being cheaper and easier to do than the database.

If significant portions of the business logic are implemented in the database, you will need a bigger database. The scenario is as follows:

By moving the logic to the middle tier, you can drastically reduce the load on the database. The actual numbers here are for demonstration purpose and will vary with each system, but they should help you understand the point. While the following diagram requires more hardware as a whole, the overall cost of the system is cheaper and easier to deploy. It is much easier, and cheaper to grow the middle tiers.

What is the single bottleneck in this system capacity-wise? Which of these tiers have a discernible limit as to how large it can grow? It's obvious that it's the database. Everything funnels downhill into the database.

Thus by moving the processing into the middle tier we are able to stay farther away from the boundaries of the database layer.

Many companies have long standing security policies that specify security must be controlled in the database and using stored procedures as views do not offer enough control. Changing company security policies to evolve into a world of n-tier can often prove to be difficult, if not impossible.

With .NET security and future offerings from Microsoft there is more focus on enterprise security at the middle tier level than ever before, however many corporations still focus on the database and they are either unaware of the changes or are unwilling to change.

This topic is a touchy one. However touchy, it is something that must be said. Whether you are a DBA (Database Administrator) or a developer please do not interpret what I am about to say as being stereotypical or true of all DBA's. However this is quite prevalent and quite common. If you are a DBA who does not fall into this profile, then bravo! You are a Database President not a Database Lord.

A DBA with a working system is often reluctant to make any substantial changes because it could break their system. Many enterprises have one DBA and many DAs (Database assistants). The DBA is the king of his domain and wields final decision on everything related to database. Only management will ever override the DBA, and management due to their inability to judge technical DB issues will always defer to the DBA.

Most of the DBAs often have very little knowledge of the changing needs of the n-tier system, or simply do not care. To them, any tier is just another client and everything to them is a client server model. They care only about running their database and do make some compromises for the developers but only if it does not cause them any grief.

DBAs do not typically move between companies as quickly as developers and most of them have been presiding over an enterprise's database for the past 10, or even 20 years. The database is a very important thing to them and they are unwilling to make any compromises. They have established their kingdom and are reluctant to let their control go. Getting such DBAs to let go off a level of security and implementation can be a major struggle and will require the involvement of the management.

Other DBAs are not so picky, and will get along with anything that they find to be within reason. But in many enterprises, especially large ones there are dozens or hundreds of developers, and just one, or a few DBAs and the DBAs sit at the top of the enterprise chain of command.

Most of the tools available today are either not conducive or do not promote the implementation of business logic. Many tools simply focus on scalability, connection pooling and database independence and yet do not address the needs of business logic implementation well.

I have found it very useful to have the system architect do regular reviews and flag improper placements of business logic. The sooner it is caught, the easier and less costly it is to fix. If you do not have a person designated as the master architect then the developers of the team can do policing of each other. If something is found to be in an improper place, that developer can alert the team and then the team leader.

Educating the DA (Database Assistants) is very important. DAs have been implementing business logic for so long, that it will be difficult for them to be able to separate what is business logic from what is storage. DAs would typically do whatever is needed of them, usually following the instructions of the DBA.

DAs still remain involved. They still perform JOINs, optimize SQL, and maintain the database. They should also monitor the SQL coming from the middle tier and monitor the database performance. The DAs will also continue to perform database design.

There is often resistance from the management, although this is one of the easier obstacles to overcome rather than the difficult ones. The management will not care if your job is easier, but they will care about the costs, development time, business benefits, and be sure to throw in a bunch of current buzz words as well.

The major obstacle in changing the management will likely be resistance from the DBA. So sell management solid, and let them take care of the DBA.

The ideas in this article are patterns and practices that I have been using for nearly 10 years. Of course they are constantly being refined and updated to take advantage of the newer technologies and adapt to the changing needs.

During my work I go through a lot of papers written by "experts". Most of these papers unfortunately are written by developers who are great at coming up with theories and telling people how they should do things yet never putting their own practices to work. Other papers are written by experienced developers who do not have a wide scope and their practices are quite domain specific, yet they present themselves as having wide spread knowledge and cure for all applications. When developers read such papers, they assume that there is only one way to solve every problem. Developers need to be more open minded and understand that there is always more than one way to solve a problem and that such papers are experiences of other users that should be used as guidelines, not gospel.

I had to mention all these because it's rare to come across something that is truly excellent and that does not fall into one of these traps. One of the best papers I have read in recent years was written in August 2002 and is one of Microsoft's Patterns and Practices papers. It coincides very well and is a good companion paper to what I've presented here and in my other articles.

Changing directions in a large enterprise is often very political and risky. From a developers perspective it's much easier to lay low and let others do the fighting. I doubt many developers will put a full stop to their long used practices. Through this article I wish to give you some ideas to modify your existing processes or at least evaluate certain decisions closer that otherwise might pass with little consideration.

The approaches described here are best applied in new systems, or when rebuilding a whole or partial system. With existing systems, it's usually best to leave things alone unless there is some other overriding factor causing a redesign.

Comments and Discussions

DBA(s) mostly are just plain terrorists. There is very unlikely success in reasoning or technology pattern adoption to theirs mind. DBA isusing key words: security, high performance, cost effective, low maintenance. Any tyrant DBA – I will ask you – do you have all foreign key relations declared in your DB schema? There are too many shoe salespersons on decision making positions which is the source where terrorists DBA can shine.

This is a very good article and covers very well the reasons for having too much logic in stored procedures.
However, the other side of the coin is logic creeping into the client side (what would have been presentation layer).
Even is we do not have any procedures at all, a 25% 75% 0% pattern has a devastating effect on the ability to understand and debug the business logic.

There is real issue with keeping the client as presentation only for many "good" reasons, that we have to find architectural solutions for.

One "good" reason is client "flexibility to query".
Technologies as NHibernate and such, make the business domain model seem as if it is "presentation safe". The next slippery step is to allow clients to compose queries over this model using HQL and use pass through services that execute this HQL against the database.
This is very tempting as it is fast and powerful (no work on middle tier).
It is important to understand that while this looks like a way for enjoying both 2-tire and 3-tire worlds, this actually puts you right back to 2-tire architecture (only with reduced performance and worst security issues).

Another popular reason is client workflow.
As the main thesis of 3-tire is the ability to replace each tire without affecting the other.
This leads to the misconception that the middle tire can and should be oblivious to the client using it.
Combined with the "stateless services" buzz, the middle tire is often left unaware of the business process it is serving and is driven by sporadic service requests.
The client, left to fend for itself, develops the layer of logic needed to handle the workflow, which becomes more complex with each new functionality.
From here, the temptation is high to expose the middle layer as CRUD services (can we have some REST-JSON services so we can integrate with you please...).
Now, if you take a step back, this looks a lot like 2-tire architecture again, doesn't it?

Client drift can be handled in a variety of ways, MVVM, MVP, etc... This article is more about things to think about and guidelines, rather than a framework itself. Please also note the date of the article - it needs updated to include advances since its authoring but is still very relevant.

Chad Z. Hower, a.k.a. Kudzu
"Programming is an art form that fights back"

I suppose something like this might work for an internal application developed by and for some corporation, but it would be a train wreck trying to implement this for something serious, that has to scale.

We have a billing stored procedure that loads for the user hundreds of thousands, possible millions of billing records, paged, of course. It works by dynamically putting together parameterized T-SQL against indexed views stored in the same order that we return the data. The various filters are appended as INTERSET or EXCEPT statements against the relevant view.

In the end, the first page always comes back in about 10ms since we've written our queries as well as we have.

That may be our most extreme example, but it's hardly the lone exception you note in your article. There are many, many places where we rely on T-SQL to load our data as quickly as possible. We're not a dumb internal piece of software; we have paying customers who expect things to be responsive; we have to scale.

I shutter to think how slow our app would run if our sprocs were limited to simple joins, and everything else was done in a business layer.

First, this does work on large systems. It works very well. I've been using such techniques even as far back as the mid nineties. Remember that the middle and back tiers can sit very close to each other so network is very very fast and they could even exist on the same machine but then you are not distributing CPU load as well.

Its not about never using SQL. Of course you use SQL to filter data and reduce the amount of data. And of course sorting etc is valid too. But SQL is a bad place to do more extensive stuff.

SQL is more brittle and ill suited to more complex tasks. I was once brought in on a project that had 500,000+ lines of SQL for the very same reason you quote. We slowly moved it out into Delphi and a middle tier and despite that, the system was faster because we were better able to process things the way we wanted rather than shoehorning SQL to do things it was not intended.

What you're missing is that "filtering" can and often is a more complex task that involves extensive business logic. So you can either you can build that business logic into SQL structures like indexes, indexed views, and stored procedures, or you can build something that necessarily performs and scales less well.

And yes, plenty of mediocre developers have built plenty of mediocre SQL-based systems over the years. And, yeah, I'd even concede that sql is an easier language to misuse and build crappy software with: but none of that is my concern if I have to build scalable software that paying customers will enjoy using.

It does work, and in fact is more scalable and more cost effective as well than loading up SQL and the article covers this in detail.

The bulk of my work in this area in the 90s was for the stock market and fast information. They used to give us requirements at Morgan Stanley etc that "every second you can save us in transactions is worth $50,000" etc type requirements.

Please consider things you have accepted as gospel as questionable. The methodology works, and its just as fast and in many cases faster. Plus its more scalable and less expensive to scale.

The end user won't notice any difference. If there is anything to notice of difference at all, it will be an increase in speed.

Chad Z. Hower, a.k.a. Kudzu
"Programming is an art form that fights back"

I can't speak to the transaction processing application you wrote: it's entirely possible the data access requirements could be satisfied with simple sprocs involving not much more than joins, filters and groupings.

But there are situations where data retrieval requirements involve complicated business logic. Baking that logic into a sproc that does non-intuitive things to take advantage of your indexes and indexed views is not loading up SQL; loading up SQL would be a naive query that forces the DB to do far more IO, more logical reads, more internal sorts, and so on.

Incorrect. You seem to be missing many of the details of the article to which it made great pains to explain.

There is nothing wrong with using indexes for retrieval or sorting. The point is that the DB is storage - period. Let it do what it does best. Store and retrieve data. Use indexes, sorting, filtering.. fine. But leave the business logic out of it.

Chad Z. Hower, a.k.a. Kudzu
"Programming is an art form that fights back"

Good point. Indeed, the main business logic is across all the application. Have you ever seen that several times that if a field displays or not is a business rule managed directly in the front end? (well, just for systems that show/hide controls in the front end)
Good article. Regards!!

I found this article very beneficial as I have been trying to visualize the performance issues
which may occur in case of transferring business logic part to Database. Now on wards , I'll try to move business logic to business layer.
If I use WCF components to implement business logic , will it be a good idea. If you have any existing article on this , please provide the link.

There are several advantages of having as much business intelligence as possible developed into the data-tier. In the real world, the raw data is needed not just for user-facing applications, but also for ad-hoc analysis, reporting, analytics, and data warehousing. If all the business logic is moved off the database tier, ALL that knowledge becomes inaccessible to the teams responsible for transforming data into information.

So in the real world what happens is that the application developers "trap" business intelligence into the middle tier, accessible only to software engineers, and as a consequence, the folks responsible for mining data wind up re-creating much of that business logic on top of that raw data, so they can get their job done too. I can't tell you how many times I've seen system analysts/developers trying to reverse engineer business logic out of applications (and reports).

It still makes perfect sense to keep raw data separate from data-related business logic. What happens is you keep raw data in one database(s)...very little logic here, but you put all your advanced views, functions and procs in a separate database on the same server or a different one. I don't argue for the removal of the middle-tier...it is just that application developers need to keep in mind that they are not the only people that need the logic.

The other consideration is that ALL business logic won't go to the middle-tier because most applications have bulk processing logic (business logic), moving data into and out of the databases.

Also, with the advent of disk-less storage (flash), the data-tier is presently undergoing several orders of magnitude of performance gains...an unimaginable change in scaling considerations.

Another point is the borg argument. Nobody is arguing that the raw data should be stored in the middle-tier so we will always have the data tier. So the database vendors are in the perfect position of incorporating more and more coding capability into their products. So over time, it has become easier and easier to get handle more and more business logic and scaling needs. So there are fewer situations where business logic MUST be placed on the middle tier.

In summary, we need to think in terms of creating an intelligent layer of data that is accessible to all stakeholders such as non-technical business analysts, application developers, report writers and business intelligence developers. This argues for keeping data-related business logic as close to the raw data as possible.

Very well said, my first question reading this was how do you write reports with raw data? The last thing I need is to run reports through BL or call it from database (yuck). So even though I like the article in theory, the reality isn't just apples and oranges...

.. the most ETL can get data from services. If your issue is that you want to know the business logic, What for concern about the process. Ask to the developers a Web Service with the same logic and set your ETL to take that information.
You won't concern about how the joins and validations are made, because you will use the same

I am ADM a system that has nothing but plain data in the DB and the most of joins and getting data is obtain from the business layer. It is painful to review the code and see how it gets the information and the constraints; and the application have low performance due the iteration needed to get all the entities information.

So, yes, it should be a central repository for business logic, but there are a balance. It is valid to put a little of complexity in the queries.