Nearly every developer on planet Earth would agree that layers play a fundamental role in the design of any software system that spans over at least a client and a server machine. So layers do matter; no question. Nearly the same previous set of developers, who agree on the importance of layers in software architecture, is probably more than able to introduce at least three layers in any software system they work on.
There will be the presentation layer to contain components for pre- and post-processing the action the user requested through the user interface. The presentation layer at some point will need to place a call to another layer - often, but not necessarily, a remote layer. Proceeding from top (user interface) to bottom (databases), the next layer we likely encounter is generically referenced to as the business layer.
The business layer is the least defined of all possible layers. Its role and content is as clear in principle as it is dark and obscure in practice. In rather generic terms, I believe we could reach some sort of an agreement on the following definition: the business layer contains the domain-specific model and logic that justify the building of the system. Essentially, the business layer contains the implementation of the rules and logic that are just the reasons why customer called us to help with the system. Well disciplined software professionals won't fail keeping the business layer separated from yet another layer - often, but not necessarily, a remote layer.
So the data access layer is the segment of the software system where you concentrate all the logic to read and write from some persistent storage - often, but not necessarily, a relational database.
These concepts should be nothing new for every developer and architect. So what's this article all about? While many of us can grab the gist of business layer fairly easily, some still fail placing the boundary that separates the business layer from the data access layer. In some cases, also the boundary between presentation layer and business layer is misplaced or just misunderstood. Let's start focusing on the parts that form the business layer.
Layers and tiers
Before going any further, though, let me clarify the difference that exists between two terms that are sometimes used interchangeably - layer and tier. Not that using layer and tier interchangeably is a mistake per se in all situations - and, frankly, I often use these terms as they were synonyms. Fact is, however, they are not synonyms. A layer refers to pieces of software that are logically separated, but typically live within the same process and machine. A tier, instead, refers to pieces of software that live in distinct processes or AppDomains or machines. You can allocate a layer on a tier but not vice versa. You can have multiple layers on the same tier. A tier refers to physical separation; a layer is about logical separation. So if you take it literally a business tier is a distinct server where you run the code that forms the business logic. Whenever tiers are involved you should have a remoting technology all around to permit communication. Whatever you call a layer can be moved any time (with some extra work) to a tier. I'll be using the term "layer" for the rest ofthe article, but be aware of the context.
Inside the Business Layer
The business layer is expected to contain three main blocks of code: the application logic, the domain logic, and the domain object model. While in the previous sentence I tried to be as unbiased and generic as possible, I really doubt I succeeded. So let's expand on the terms.
Table 1: Logical components of the business layer
Refers to the behavior you code based out of the use-cases for the particular application. A use-case defines the steps of a given interaction expected to take place between the system and one of its users. For example, the application logic knows about the application-specific workflow you go through to place an order.
Refers to the behavior that belong to the entities you recognize in the domain of the problem. The domain logic is invariant with respect to the application, meaning that you could reuse the same domain logic in multiple applications targeting the same domain. For example, a domain logic for a banking system may be shared by various applications such as ATM, online trading, home banking, backoffice, and the like. As a result, all applications will see, say, an Account entity with a fixed behavior but any application may use the Account entity in a different manner in the context of different tasks.
Domain object model
Refers to set of entities and their relationships that populate the domain of the problem. Depending on the methodology you may use, this can be referred to as the domain model or simply as a plain object model. A domain model is an object model created following a strict set of rules from the Domain-driven design (DDD) methodology.
How would go about coding a business layer? A common approach entails that you split the code in a couple of further layers - the service layer and the domain layer. The service layer exposes the endpoints the presentation layer will call following up user actions. Any endpoint will contain code that scripts entities in the domain space, invoke optional business-specific components and services (i.e., in a banking scenario a business component can be a workflow that attempts to estimate whether a mortgage can be paid back by a perspective customer). The service layer is also responsible for setting up any required dialog with the data access layer.
You code the service layer as one or multiple assemblies. A common practice is having a class for each significant entity you recognize in the domain. Using a DDD terminology, we could say that you might want to have a service layer class for each aggregate root you recognize in the design. Here's a basic layout for a class in the service layer:
These methods will be invoked directly from the presentation layer, that is from the code-behind class of a Windows Forms or Web Forms application, from the presenter or view-model object of a WPF/Silverlight application, and from the controller of an ASP.NET MVC solution. The service layer class will be instantiated manually by the caller or injected in the controller class by some IoC frameworks.
The service layer class will parse the UI input, prepare for data access, and prepare a response for the presentation layer. The service layer gains access to the data access layer. If you opt for a Repository pattern - that is a wrapper around the real access code - then the service layer will be injected (or gain access to) a repository object for the entity. If you opt for not using any repository then the service layer will talk directly to the data access layer - be it ADO.NET code or any O/RM API.
So the Entity Framework Project...
Entity Framework is often presented as an O/RM tool. Not certainly a wrong statement, but there's more I believe. My idea is that EF was not devised to be a classic O/RM like NHibernate and other commercial tools. The point here is not determining whether this was the right or wrong approach; fact is, that in my opinion the word "framework" says a lot about the original intentions and the changes introduced on the fly with EF4.
EF takes you to create or infer an abstract model (the EDMX file) based on which the visual designer will actually create source files for recognized entities and relationships. In v1, you had no control over the generation of files. The auto-generated files define classes that inherit from EF provided classes thus leaving the entire object model dependent on the Entity Framework assemblies. This means that you can't deploy your object model without also deploying the Entity Framework assemblies. This aspect of the problem is referred to as "not being POCO". Agreed that this is all but elegant and savvy, however, is this really a problem? If so, when?
Lack of POCO in the design of the entities limits you modeling power as it makes impossible to integrate legacy classes (not bound to EF) in the resulting object model that EF will attempt to persist. If you are creating a system from scratch this is hardly your scenario so POCO (or lack thereof) is not your main problem. It is not POCO (or lack thereof) that takes you towards sub-optimal design.
When EF auto-generates source code for entities in the model it puts in the same layer entities and the gateway object to the persistence layer. As I see things, this is an even bigger issue. EF4 doesn't solve it in a clear way; it only leaves you some room for manipulating the project so that entities and gateway object (the object context class) end up in distinct assemblies you can deploy to distinct tiers if necessary. The following class does logically belong to the data access layer, not to the business layer.
This means that when you use EF to create the assembly for the domain logic and entities you should manage to move this class to a distinct project. Just impossible to do in EF1, this can be done only with some tricks in EF4 and only if you choose to go with POCO or self-tracking entities. (See Figure 1.)
Figure 1: A project where EF context object has been moved to the DAL project.
Figure 1 shows a Visual Studio solution made of two distinct assemblies - Model and DAL - built from the same source EDMX designer file. The Model assembly incorporates the EDMX item and the POCO artifact item generator. (Same if you use Self-tracking entities.) The item generator produces two T4 template files - context and entities. The T4 template for the context produces the object context object specific for the model; the other T4 template produces the entity classes. By default, both T4 templates belong to the same assembly. To keep them separate - entities are business, context is DAL - create a new project for the DAL and add to it the existing context T4 file as a link. You choose "Add existing item" from the project context menu, locate the context T4 file and add it as a link, as in Figure 2.
Figure 2: Adding an existing item as a link.
Visual Studio will process again the T4 template and add auto-generated files to the current project.
It turns out that Entity Framework oversimplifies the creation of layered applications mixing together elements that logically belongs to the data access layer with entities which clearly belong to the business layer.
Is everything wrong with EF, even in version 4? EF4 is significantly better than v1 and for a number of reasons. At the end of the day, there begin to be features in EF4 that, properly used, can enable some sort of tool-assisted, domain-driven design in .NET. These features, however, are not yet fully integrated in the designer and the framework itself. I'm referring to the T4 machinery discussed earlier but also to the upcoming Code First feature. EF1 could be used only in a very limited number of realistic scenarios. EF4 is much more widely usable, but you need to be aware of a number of things and pay attention to place the right boundaries between your layers and tiers. Looking forward for the next EF...
Dino Esposito is one of the world's authorities on Web technology and software architecture. Dino published an array of books, most of which are considered state-of-the-art in their respective areas. His most recent books are “Microsoft ® .NET: Architecting Applications for the Enterprise” and “...
This author has published 54 articles on DotNetSlackers. View other articles or the complete profile here.
You might also be interested in the following related blog posts
Introducing Versatile DataSources
EF4: Lazy Loading on By Default but what about pre Beta 2 Models?
Silverlight, MVVM, Prism and More at VSLive Orlando
EF Table Splitting The Opposite of Entity Splitting
Checking out one of the new stored procedure features in EF4
System.Data.Linq.Binary is not XmlSerializable
VB Entity Framework Samples Now Available (Lisa Feigenbaum)
Customizing EDM Code Gen in EF4
Validation - Part 2 - Client-Side
You should NOT use ASP.NET MVC if. . .
Please login to rate or to leave a comment.