If you’ve developed software for long enough, you’ve most certainly heard of a “business logic layer.” It’s supposed to be the layer (or “tier”) containing an application’s business logic and is sandwiched between a “persistence layer” and a “presentation layer.” Some call that the “standard three tiers of an application.” But what it really is, however, is a bad design that leads to bad software. Or at the very least, dangerously poor semantics.In lieu of your standard WTF article, allow me to explain why.
First and foremost, we need to define the term “business logic.” Unlike so many other entries in the IT lexicon, “business logic” has no standard meaning. We’re left with what you think it is, what your colleague wants it to be, and what some article you read says it is. So, for the purpose of this article (and hopefully beyond), here is my definitive definition.
business logic (n.) — any program code (“logic”) that pertains to the purpose (“business”) of a software application
It’s a fairly broad definition for a fairly broad term. If you think about it, virtually every line of code in a software application is business logic:
- The Customers database table, with its Customer_Number (CHAR-13), Approved_Date (DATETIME), and SalesRep_Name (VARCHAR-35) columns: business logic. If it wasn’t, it’d just be Table032 with Column01, Column02, and Column03.
- The subroutine that extends a ten-percent discount to first time customers: definitely business logic. And hopefully, not soft-coded.
- And the code that highlights past-due invoices in red: that’s business logic, too. Internet Explorer certainly doesn’t look for the strings “unpaid” and “30+ days” and go, hey, that sure would look good with a #990000 background!
So how then is possible to encapsulate all of this business logic in a single layer of code? With terrible architecture and bad code of course!
No One Likes Business
When it comes down to it, us software developers don’t like writing business software. It’s terribly, mind numbingly boring. Just look at the dreadful specs we’re given to work with:
When a Sale is Cleared, only Managers with Void Approval and Executives may issue a Cancellation Request. If the Propagation Status for the Transferable Receivable is not Pending and the Expense Allocation Type is Reversible, the Cancellation Request is issued for Processing; otherwise, it is issued for Approval.
I’m sure those of you who managed to make it through that spec did not have visions of IF-ELSE code blocks swirling through your head. I’ll bet some of you, without even seeing the rest of specs, excitedly envisioned a CancelationWorkflowProvider that inherited from the abstract RequestWorkflowProvider and implemented the IPermissionRequired, IPropogationStatusRequired, and IExpenseAllocationTypeRequired interfaces, and was powered by the all-encompassing WorkflowManager. Why? Because that’s so much more challenging than writing a simple IF-ELSE code block.
Michael A. Jackson (no, not that Michael Jackson) observed this exact phenomenon in his 1975 book, Principles of Program Design.
Programmers… often take refuge in an understandable, but disastrous, inclination towards complexity and ingenuity in their work. Forbidden to design anything larger than a program, they respond by making that program intricate enough to challenge their professional skill.
So what does this have to do with the “business layer” being a poor design? Everything. By implying that a system’s architecture should include a layer dedicated to business logic, many developers employ all sorts of horribly clever techniques to achieve that goal. And it always ends up in a disaster.
The Enterprise Rules Engine, Revisited. Again
Yes, I realize that the Enterprise Rules Engine — the ultimate example of a soft-coded business layer — has become my go-to example for bad software. But it’s for good reason. The ERE truly represents the absolute worst kind of software. It was as if its architects were given a perfectly good hammer and gleefully replied, neat! With this hammer, we can build a tool that can pound in nails.
One “problem” that was immediately apparent to the designers of the ERE was user-input validation. Certain forms had certain fields that were required in certain circumstances, and end users needed those fields identified with an asterisk. While coding the validation rules in the HTML form’s onsubmit() method would most certainly do the trick, the ERE team found that to be completely unacceptable. After all, business logic had no place in the presentation layer.
So the ERE designers built around it. Each “business entity” class had a method that returned a complex tree structure representing which fields were required in which circumstances. Another class in the presentation layer utilized this method to generate JavaScript validation code for each field. Of course, this meant that they’d have to solve another “problem:” how would the JavaScript generator know which fields corresponded to which HTML controls?
The answer to that was surprisingly simple. They built a two-way data-binding utility that would save to and load from fields on the business entity with controls on the page. It got pretty tricky when it came to dropdown lists, file uploads, and the like, but they coded around that as well.
As the ERE developers continued on their quest of freeing the presentation layer from business logic, they came across another “problem.” In order to display and constrain certain fields in the user interface, they had to implement business logic. Thing like, the “years old” field should only be two characters big. So they coded around that, too. In addition to a validation rules, the business entity classes returned field lengths so that the presentation layer knew how to size the controls.
As more business logic “problems” arose, the ERE team pushed the business logic a layer down. Eventually, they found the perfect balance. Using XML “display templates,” they could simply serialize their business entities into XML, mash the two together with an XSLT, and send the resulting XML “display instructions” to the presentation layer to convert into a usable UI. I’ll let you imagine how well that worked out in the end.
The Persistence Plague
Unfortunately, the obsession to create a single layer encapsulating the all business logic has crept its way to the back-end. Not content with “mucking up” the database with business logic, some developers have gone the route of “persistence.”
The idea behind persistence (at least, as far as most in the industry have defined it) is that business layer objects (e.g. instances of a Customer class) are persisted in some storage mechanism. Note that this is a drastically different approach than simply coding classes to retrieve and save the appropriate data from a database. With persistence, very little (if any) business logic needs to exist in the storage mechanism.
One of the most flagrant examples of this persistence paradigm is a framework called Prevayler. Its premise is simple. The framework serves as a container for all business objects and stores them in memory. Changes to these objects are accomplished through a Transaction interface, where the framework makes the change (e.g. set the Status property on a Customer object to “Accepted”) and logs it.
While it may seem like a novel concept (it certainly is clever), it’s a terrible solution for most problems. Any framework — Prevayler certainly isn’t the only one — that attempts to remove business logic from the database will consequently remove useful information as well. Tom Kyte elaborated on this point exactly in The Ultimate Extensibility:
One table (no need to pester those mean DBAs asking them to create tables or indexes or anything). It can hold any object on the planet:
I have a table with a blob field, and type among other details. Say,
CREATE TABLE trx (
trxId NUMBER(18),
trxType VARCHAR2(20),
objValue BLOB,
...
)
Blob Fields contains a java serialised object, different objects based on types, though all of them implements same interface. We access this object always thru' j2ee container, so it works fine so far.
Unfortunately, the "architects" of this system discovered that:
Now users want to use reports using sqlplus, crystal reports etc. So they want a solution to this blob issue.
The core problem with all persistence approaches, as Tom pointed out, is change. A relational database — something actually designed for indefinite storage of a changing data model — can easily be modified with a few ALTER TABLE queries and accessed by virtually any other application. The data stored for a persisted object, however, is meaningful only to the object’s class and can’t readily be accessed or manipulated with anything else.
It’s actually a rather familiar problem. MUMPS has “business logic free” persistence. Other ancient languages do, too. Relational databases are a solution to that problem, not another problem to be overcome.
All About Semantics
The Enterprise Rules Engine and the Persistence Plague are fueled by two factors: bored and clever developers, and dangerously poor semantics. Thinking of an application as existing over three separable layers — persistence, business, and presentation — encourages development towards that goal.
As demonstrated, it’s completely infeasible to encapsulate an application’s business logic into a single layer. It’s also logically impossible.
By the time a developer creates the perfect persistence layer — something that takes in any type of data, tucks it away somewhere, and provides an easy mechanism to retrieve it — he has created a separate infrastructure application. Recreated, actually. The operating system’s file system already does exactly that.
By the time a developer creates the perfect presentation layer — something that takes in any type of data and displays it in a flexible manner — he too has recreated an infrastructure application. ASP/PHP/etc with HTML already does a fantastic job of implementing that goal.
There is absolutely nothing wrong with having a multi-layered application. In many cases, anything but that would be a bad design. It’s absolutely critical, however, to not think of these layers as persistence, business, and presentation. Database, processing, and user interface are much more appropriate terms.
The Ideal Approach
Separating application code into different layers is important: it’s a core principal (“loose coupling”) of structured programming. But it’s just as important — if not more so — to keep in mind that almost all of an application’s code will be business logic. There are already enough tools out there; your application does not need a generic layer.
A good system (as in, one that’s maintainable by other people) has no choice but to duplicate, triplicate, or even-more-licate business logic. If Account_Number is a seven-digit required field, it should be declared as CHAR(7) NOT NULL in the database and have some client-side code to validate it was entered as seven digits. If the system allows data entry in other places by other means, that means more duplication of the Account_Number logic is required.
It almost goes without saying that business logic changes frequently and in unpredictable ways. The solution to this problem is not a cleverly coded business layer. Unfortunately, it’s much more boring than that. Accommodating change can only be accomplished through careful analysis and thorough testing.
With simple, consistent code, change analysis is a breeze. A simple trace through the layers of code with a text-search tool will generally reveal exactly what needs to be changed, and where. A solid test plan will identify what changes broke the system and how, and allow developers to respond appropriately.
No, it’s not fun and not challenging. It’s just good software.
相关推荐
Chapter 7 The Mythical Business Layer Part III Supporting Architectures Chapter 8 Introducing Domain Model Chapter 9 Implementing Domain Model Chapter 10 Introducing Cqrs Chapter 11 Implementing Cqrs...
The Mythical Man-Month Essays on Software Engineering, Anniversary Edition.pdf
The classical English edition.
《人月神话》是软件工程领域的一本经典著作,由弗雷德里克·布鲁克斯(Frederick P. Brooks Jr.)撰写。书名中的"Man-Month"概念是作者提出的一个关键观点,意指在软件开发项目中,简单地增加人员并不等同于按比例...
Chapter 2 The Mythical Man-Month 13 Chapter 3 The Surgical Team 29 Chapter 4 Aristocracy, Democracy, and System Design 41 Chapter 5 The Second-System Effect 53 Chapter 6 Passing the Word 61 Chapter 7 ...
刚拿到,还没看呢,先给大家分享一下,如果质量不高,请及时提醒我
不用我说了。 英文影映版。 第一部分。
人月神话,是由清华大学出版社于2002年11月出版的一本关于计算机软件的图书,作者是布鲁克斯。适合任何软件开发行业的从业人员阅读,对软件开发人员、软件项目经理、系统分析师更是必读之作。
- **书籍名称**:“人月神话”(The Mythical Man-Month),由Frederick P. Brooks, Jr.撰写,Adams Wang翻译。 - **作者背景**:Frederick P. Brooks, Jr.是北卡罗来纳大学Kenan-Flagler商学院的计算机科学教授。他...
在软件领域,很少能有像《人月神话》一样具有深远影响力和畅销不衰的著作。Brooks博士为人们管理复杂项目提供了最具洞察力的见解,既有很多发人深省的观点,又有大量软件工程的实践。本书内容来自Brooks博士在IBM...
在软件领域,很少能有像《人月神话》一样具有深远影响力和畅销不衰的著作。Brooks博士为人们管理复杂项目提供了最具洞察力的见解,既有很多发人深省的观点,又有大量软件工程的实践。本书内容来自Brooks博士在IBM...
《人月神话》是软件工程领域的一本经典之作,由弗雷德里克·布鲁克斯(Frederick P. Brooks Jr.)撰写。这本书在1975年首次出版,时至今日,它仍然是软件开发团队管理和项目规划的重要参考书籍。...
##### 第一章:泥潭(The Tar Pit) **泥潭现象**: - 定义:无法按时、按预算完成项目的状况。 - 比喻:软件开发如同泥潭,你越是挣扎,就陷得越深。 **成因**: 1. **规模与复杂性的渐进增长**:随着时间推移,...
《神话般的人月》是弗雷德里克·布鲁克斯(Frederick Brooks)的一部经典著作,被誉为软件工程领域的里程碑。这本书并非专注于具体的编程语言或技术细节,而是深入探讨了软件开发过程中的人力、时间管理和团队协作...
The Mythical Man-Month continues to be popular after 20 years. Over 250,000 copies are in print. People often ask which of the opinions and recommendations set for th in 1975 I still hold, and which ...