Traceability in layered architecture lets software architects to define, utilize, reuse and re-engineer existing, current and future application architecture in more structured way. This article provides a roadmap to trace multi-layer architectures easily.
Introduction
Multi layer architecture is one of the most popular and proven model in the current trend of software development. It lets software designers and developers to easily isolate user interface, business logic and data access logic.
In last few years I have worked on several projects done by other developers to be improved and/or enhanced. Also, I see lots of starter kits, sample projects are available in web, and where from a beginner to expert can improve their ideas regarding latest best practices in layered architecture.
However, while reviewing source codes of projects done by other developers, always I miss a simple document by which I can easily grab the core ideas of the layering, and can update any part along with my own point of view. No matter how big the application or how complex the application architecture is, having a traceability structure helps the future developers for a given project, quickly understand the existing layering model, and/or utilizing/updating existing structure with considering appropriate design and requirements context.
Traceability model considering the logical layers is a very basic document which addresses several common questions, answers and view points of any current or future application architecture.
This article explores some of the common question and explanation point which will help us to form our own traceability model.
Layered Architecture Design Factors: Business Entity
Business entities are the logical data containers which are passed across the logical layers. These can be a simple class which contains the data items commonly mapped from data columns from logical and/or physical data tables or can be complex classes with high end overhead.
What is the type of business entity?
For .NET application, business entities can be categorized as Custom Entity, Typed DataSet and Generic DataSet. Custom Entities are generally simple and faster than DataSet, where as it includes more involvement from developer end, as opposed to DataSet, which includes lots of built-in functionality, along with several trade-off in performance end. Choosing the right business entity is one of the basic parts in the software architecture, which fits accordingly in application requirements and development context.
To which context Business Entity classes are mapped?
For simple applications, mapping directly from physical table to logical business entities reduces lots of cost in programming, especially while using code generators. However, no matter in sample or complex applications, besides mapping physical tables, there are few areas which might not be suitable to be mapped directly from databases tables.
To map one-to-many relation from database to logical application model, some design creates a base container class for the business entities, which includes both parent and child business entities as data element. It facilitates complex data containers to be passed through layers simply.
Figure 1: A container class that holds two business entities with having one to many relationship.
Where and how the joined operation (fetched from multiple data tables) is placed in business entities?
When we need to retrieve result sets from multiple database tables via join operation a common practice is to use Generic DataSet to store the result. We can consider Custom Business Entity for the cases where the joining operation can be determined at the software design time, which provides faster execution time than Dataset.
Also in some cases joining operation is required to be implemented in application end, rather database end query, especially when multiple entities are required to be combined from database and/or web service source.
How do you map OOP concepts to relational database design?
Let’s consider a simple sample:
Contact db table: Contact ID (primary key), Contact Name, Contact Address
Employee db table: Employee ID (primary key), Employee Joining Date
Customer db table: Customer ID (primary key), Customer Birth Date
Now to utilize the object oriented inheritance concept in relational database model, we can create a one to one relation with Contact table with Employee and Customer table, where besides primary key, Employee ID and Customer ID will be used as the foreign key of Contact table, regarding the concept that all Employees and Customers are considered as a “Contact” object.
Figure 2: An inheritable model of three relational database tables.
Now if we wish to map this idea to real world OOP code, we will create a business entity named “Contact” which inherited sub classes will be “Employee” and “Customer” business entity. The corresponding BLL and/or DAL (Data Access Layer) class of “Employee” or “Customer” can also be inherited from BLL (Business Logic Layer) and/or DAL class of “Contact” to perform required operations in object oriented manner.
Are there any special considerations for “typed” entities?
There are few entities which data are not been changed very frequently, but one or two items are added over few months. For instance, user type, product category, order type, payment mode. For better database operations values of these fields are kept in database and been referred to other entities as foreign keys. But interestingly values of these “Type” entities are used very frequently in coding layer, where developers had to use the hard-coded primary key value or the string value of this type to perform any business logic or UI (User Interface) logic, which reduces ‘Readability” or “Maintainability” of code (what if we change the type name, in that case we need to search for the string or primary key value among the whole project!).
As .Net framework supports Enumeration type, where possible enumeration type can be implied upon those business entities. Where adding or changing to any of it’s values requires the developer only to concentrate on the code segment where the enumeration values are set.
Layered Architecture Design Factors: Logical Layers
How many layers will be considered? Why?
Here we will address few primary design considerations regarding logical layers. This is not mandatory that we need to build each and every system in popular “Three Layer” model. There might be a design context where single or two layer approaches can be a good design choice. Here we need to clarify the layered division and their responsibilities. Here we can also address some present and future possible considerations, supporting the current division of layers, such as, regarding multiple UI (Windows forms, Web Form), data source (SQL Server, XML, Oracle etc) platforms etc.
Do you use cache layer?
To improve the application performance, “Caching” is one of the popular techniques in current trend of best practices. In some design context supports to cache data in UI interface level, where built-in cache mechanism is available. Sometimes, putting the cache mechanism in a separate layer provides better isolation and control over application space. If so the cache isolation, expiration and coupling with other layers policy should be addressed properly.
How the layers communicate with next level layers?
For a three layered application model, in some cases, the UI interface layer can use the DAL directly, rather using it via the BLL (i.e. “immediate next layer”). This type of application model generally includes a small set of classes and methods in business logic layer, ignoring the mapping all functionalities from DAL to BLL. This design issue provides a sort of performance, by reducing the engagement of intermediate layer(s).
On the other hand, we can have a model, where a complete set of functionalities is needed to be present in BLL, is “tightly coupled”. In this context UI layers can’t use the functions of DAL directly.
Figure 3: A model where a layer has communicated only with the immediate next layer.
In this point, the software architect is needed to address this design issue clearly.
What are the mapping criteria for DAL classes and CRUD methods?
DAL classes can be defined with respect to physical or logical business entities, BLL classes, as vice versa. This mapping process can include one to one, one to many or many to many technique.
For example, we have two business entities (physical or logical), named “Order Summery” and “Order Items” for an e-commerce application. Having a one-to-one mapping relation to DAL will contain, two separate DAL classes, as “OrderSummeryDAL” and “OrderItemsDAL”.
What are the mapping criteria for BLL classes and CRUD methods?
BLL classes can be defined with respect to physical or logical business entities, DAL classes, as vice versa. This mapping process can include one to one, one to many or many to many technique.
For example, we have two business entities (physical or logical), named “Order Summery” and “Order Items” for an e-commerce application. Having a one-to-many mapping relation with BLL and DAL in class level can contain one separate BLL class, as “OrderBLL”, and two separate two separate DAL classes, as “OrderSummeryDAL” and “OrderItemsDAL”. The “CreateOrder” method of the “OrderBLL” class can call the “CreateOrderSummery” and “CreateOrderItem” method of “OrderSummeryDAL” and “OrderItemsDAL” respectively to complete the entire database create operation for a whole order, as shown in the figure below.
Figure 4: The class level one-to-many mapping process between DAL and BLL
Even having a one-to-one relation with BLL and DAL classes can include a one-to-many relation in method level. For example we have one BLL class “OrderBLL” and one DAL class “OrderDAL”. Having a one-to-many relation in method level, will include a “Create” method in OrderBLL which basically calls the “CreateOrderSummery” and “CreateOrderItem” methods, as shown in the figure below.
Figure 5: The method level one-to-many mapping process between DAL and BLL
The appropriate design issues needs to be defined at this point.
For CRUD operation in BLL, when we use the business entity and when do use parameters?
Business entities can be passed as method parameter in BLL, or all data elements can be passed separately in BLL methods as method parameter. Some design also may support the Business Entity class to include the corresponding CRUD methods, which basically doesn’t require any data element to be passed in the CRUD methods.
For CRUD operation in DAL, when we use the business entity and when do use parameters?
Business entities can be passed as method parameter in DAL, or all data elements can be passed separately in DAL methods as method parameter. Some design also may support the Business Entity class to include the corresponding CRUD methods, which basically doesn’t require any data element to be passed in the CRUD methods.
How do we generally handle one to many (database) relationships in logical layers?
One to many relation is one of the most core consideration in relational database design context. However while mapping the database tables to the logical layers, it needs to be defined clearly, how it has been handled. For instance, as design can include a container class that holds parent and child classes as property, or another design can include separate classes for all data entities regardless of parent/child relationship.
How do we generally handle many to many (database) relationships in logical layers?
Generally a many-to-many relation between two data tables forms a third table which contains the primary key of both tables. For instance, if there are two table or data entity, named “Person” and “Address”, and if there is a relation between these entities is “many to many”, there would be another table, which will keep this relation in the table, which could be named as “Person-Address”. Some logical model supports to create a separate logical entity in application layered components (DAL, BLL, BE etc) for the many-to-many table, and some application embeds the operations in the logical entity of any of the two primary tables.
Rather common model of BLL and DLL classes, what are special cases we need to consider?
The common model of the logical layers which can be fitted to maximum of the business entities can be implemented using code generator tools, which saves a lots of developer times. Besides the common model, there might have some cases which require special consideration. Specific and complex business logic can be an example of such special cases.
How the null values are handled?
Null values are one of the basic considerations, without taking care of which may raise lots of confusions and errors while the application is running in the live. Some application architecture supports a model which puts null values to the database while the user is providing empty data from the user interface end. For string/text type data some times are saved as empty string (i.e. string.empty). But it creates confusion where empty string itself considered as a value. Also, besides string/text type data, special care are required for other type of data (number, fraction, date time etc) with respect to null values to be saved and retrieved to and from the physical database tables. These considerations are required to be addressed in this point.
Where exceptions are thrown for invalid values?
In some cases invalid values are handled from the user interface level, by using validation controls. However we need to address the points, where and how we handle invalid values, which are not been validated from there user interface layer and/or required to be validated in coding level. These considerations are retired to be addressed in this point.
Which portion of the db utility classes are vendor specific?
To perform database operations from application, generally DAL uses some db utilities helps to write minimal lines of codes to perform data operations. In the data utility classes, some classes and methods might be specific to vendor (for instance, SQLHelper class will only work to perform operations on MS SQL Server) and some classes and methods might be used regardless of database vendors. These issues, along with the boundaries, should be addressed here.
Layered Architecture Design Factors: Physical Tiers
How the logical layers are connected?
Logical layers such as BLL, DAL, CL etc can be hosted in the same machine or can be distributed in separate machines specially where high end scalability are required. The relation and isolation among logical and physical tiers are required to be defined and explained with appropriate design goal.
While considering logical layers in distributed environment, there are several technologies are available. SOAP/HTTP based web service or .NET remoting can be considered, each of which has own merits and de-merits. These considerations are required to be addressed in this point.
Layered Architecture Design Factors: Some Basic Design Issues
Do we use transaction? If so, is it in DAL or SP layer? Why?
Transaction is a mechanism where a batch of operations can be rolled back for any failure at the mid point of the whole process or can be committed after successful completion of all the operation. Transaction can be used in both database level and/or application level.
Do we use cascading on CRUD operations? If so, is it in DAL or DB layer? Why?
Cascading is a technique that resides between the relations between two database tables. It enables the records of the child tables to be deleted/updates with respect to the corresponding records of the parent table records. Besides the database level, this operation can also be considered in the inter-mediate logical layer. Software designers are required to define the appropriate explanation regarding this consideration.
Where and why do we use inline SQL, LINQ queries, CLR stored procedure or built-in stored procedure to manipulate data?
To manipulate database objects there are several ways available to the developers, such as inline SQL, LINQ queries, CLR stored procedure or built-in stored procedure. Each of them has own benefits and trade-offs. These issues need to be addressed in this point.
What are the standard practices where we need high performance?
There are several best practices available in the developer community defined by the top experts. However while considering the best practices regarding performance of course there will be some trade-off (for instance security, usability etc). According to the application context these points should be adjusted properly.
What values are returned by the Create/Update/Delete methods (both in BLL/DAL) to the caller, notifying the success of data operation?
For example, Create methods may return the generated primary key of the new record, to the caller, so that it can be used if required. Returning a default value may be considered as the failure of the data operation. Also, since Update or Delete operations doesn’t usually need to return any value, these types to methods can only return Boolean values notifying success/failure status.
How do we consider naming convention to write a new business entity, BLL and DAL?
Following a naming convention on db objects, class names and methods makes coding and future modification easier. For example: the BLL CRUD methods for a given business entity, can be written as:
GetEmployeeById: that returns a single instance of employee business entity
Create Employee: that creates a new employee business entity.
What the scenario to be performed when there is an addition or modification on existing relation, entities and attributes?
This is one of the very important issues for traceability of software architecture. Some easy sample walk thru are required to be provided very clearly, for instance what steps needs to be performed while adding a new entity to the system, or adding a data element in the existing entity etc.
Conclusion
This article explored some common design considerations to be traced while developing multi-layer application architecture. However you can create your own traceable model by adding and/or removing issues provided here. Along with specific points to be defined in your traceable model will also help you creating your own design patterns, and thus enriching your design experience in more effective way.
Stay tuned with the latest updates along with blank templates @ code.msdn.
Appendix
DAL: Data Access Layer
BLL: Business Logic Layer
CRUD: Create Read Update Delete