|
Software Architecture |
||||
|
||||
| Logical View | ||||
The logical view includes many levels of abstraction, from the large grained components down to the detailed interaction between objects. Just for architect entertainment, this page starts with layering.
Layering in architectures is a common concept. Almost every textbook or article on the logical internal architecture of an application will show these major layers:

The Presentation layer displays data and accepts user input via keystrokes and mouse gestures and manages application-specific navigation issues. The Business layer contains and enforces business rules, and the Data layer manages persistent storage of data, perhaps to a database.
(There is a good deal more to layering in full architectures. The ArchitecturalLayering page has more sophisticated layered views.)
Working from the bottom back up ...
The Data layer is relatively free from logic. In client-server days, it was common to put business intelligence into stored procedures and database triggers. These were the best available unit of reuse. Database owners were the stewards of the data, the last bastion of protection from applications that might make a mess of things.
But now we push that responsibility up to the business layer. Business components are the stewards of data and enforce all rules of access and transformation. If a new application wants to read or update data, it must work through the business layer, and may not apply SQL against the database itself. This matches object oriented thinking - objects encapsulate data and logic - even though the layer does not necessarily have to be an object oriented implementation.
The presentation layer is the most application-specific. While a business component may encapsulate the rules of an ongoing business process, like sales or customer service, the presentation layer describes individual tasks in the process, like order entry or account inquiry.
A layer may have compile-time dependencies on the layers below it, but should not have such dependencies on layers above it. For example, the Presentation layer may have compile-time dependencies on the Business layer, but the Data layer must not. (Except when the Dependency Inversion Principle applies!)
This gets interesting when asynchronous communication is required. I've done several applications where the presentation layer in a fat client makes a request for data to the business layer for service, and then continues on about other UI things. The business layer does whatever database or legacy access it has to do, and notifies the presentation layer when the data is present.
Using a listener or publish-subscribe pattern, the presentation layer passes a reference to a listener object in the original request. The business layer holds this reference until the service is complete, and then calls a method on the listener. Does the presentation layer now have a dependency the UI layer? Fortunately, no. The business layer defines an interface which the call-back object must implement, so the listener in the presentation layer has a compile-time dependency on the interface in the business layer. All is well.
A question often comes up regarding where to enforce certain rules. In particular, the GUI developers may want to include data validation to improve the user experience. They want to capture data entry errors as soon as possible, and it is usually impractical to call the business layer on every keystroke. So, should we move some rules out to the GUI?
Remember the business layer is the enforcer for all rules. We may know and trust the GUI developers today, but we cannot necessarily trust future clients to know and correctly enforce the rules. The business layer cannot shirk its responsibilities. So the business layer absolutely must enforce all rules - February 30 is not a good date, amount of deposit must be greater than zero, etc.
The presentation layer is welcome to duplicate such rules to improve their responsiveness or error handling ability, up to their own pain threshold for maintaining duplicate code. If a rule changes, the business layer is required to implement the change, and the GUI layer will have to try to keep up. Duplication is definitely bad, but can be tolerated in situations like these.
One neat solution is to have both layers use the same rules, perhaps externalized to a rules engine. Some web architectures use rules housed in the business layer to dynamically generate JavaScript code for the browser, so the same version of the rule is enforced in both places.
Later note, not yet integrated into the paragraphs above. I believe these ideas come right from STRUTS practices. This sounds like an excellent starting point. In web apps:
It is pleasant, though not always possible, to work at a logical level of design. One can draw an arrow between layers and say A calls B for some service without worrying about how a request actually gets from A to B. In the physical view we allocate our processes to processors and define the network. Physical choices impose real restrictions on logical options. If the only protocol that can tunnel through the security on some network is HTTP then layers designed to have conversational interfaces will not work.
Often the physical architecture is fairly well known ahead of time because of company standards or the need to build on existing structures. Then the interfaces between layers can take advantage of the capabilities of the environment. Even so, there is a risk of designing an architecture that will not survive the first technology change, so it may be wise to assume communication between layers is expensive.
We may not know how expensive until we get to the physical view, but lets assume inter-process calls take an order of magnitude longer than calls within a process, and calls across a network are another order of magnitude slower. All this is certainly in the range of "noticeable" in the end system. This assumption leads us to minimize communications between components, and drive services to large-grained requests, rather than a cloud of detailed method calls.
| |