As many companies and their software systems have continued to grow and develop over the years, the code base behind their systems have grown and mutated quite a bit. In many instances it has done so without anyone in the organization first taking time to reflect how to best scale the system or how best to reutilize aspects of the code that could function equally well in multiple areas. The state of these systems, in most instances, would most commonly be referred to as a monoliths. While this can have some benefits, the software industry has largely started trumpeting a more componentized approach to building software. In order to more easily and malleably support the future growth of these software systems, the decision is often made to navigate to a different architectural approach that favors smaller chunks of deployable code. This is often referred to as Service Oriented Architecture (SOA). This document is intended as an overview into how I generally think about and apply some of those architectural paradigms to compose our software systems.
From a very generic perspective, the main breakdown of the components we would like to utilize to create applications would be in line with the following diagram.
Each of the above layers will be composed of many smaller components, but the idea is to keep the above three responsibilities distinctly separate and to create "contracts" that specify and enforce the means and modes of interaction between the various layers(represented by the area overlapping from one region to another). Also, as demonstrated in the graphic, no interactions should skip over any layers. For instance, the UI should never talk directly to the DAL and the DAL should never dictate anything that appears in the UI. Common examples of violating this principle would be to have input coming from the UI being directly added to the text of any SQL that is getting executed in the database. Storing HTML elements in the database and passing them through to the UI for rendering would be another example.
These distinctions provide a meaningful way to reason about and segregate different responsibilities of applications. It can allow for a significant amount of flexibility and agility over a monolithic type of system. As long as the contracts are clearly stated and adhered to, this approach can lead to quicker development of applications as the different layers can easily be developed in parallel. When the contracts are maintained, any layer of the application can change drastically in its implementation without the knowledge of or effect to the layers above or below it. Looking to the future growth of Peineary Development as well, this approach can provide much greater means of scalability as it will be easier to identify bottlenecks in the system and to provide more resources to specific areas to alleviate the bottlenecks.
USER INTERFACE/INTERACTION LAYER (UI)
While this term usually denotes the aspect of the application that humans interact with, we define this a little bit more broadly as the layer of a business application that interacts with externally initiated interactions with the system. Application components that would fall into this category would be components that allow human interactions with the system through a graphical or command line interface as well as external file drops that initiate an import process of data into our systems. This layer utilizes the contracts exposed by the BLL to make those interactions meaningful and in most cases stateful.
There are three main UI areas in which we develop regularly.
- Web/Desktop applications
- Data feeds
- Exportable reports
BUSINESS LOGIC LAYER (BLL)
This layer contains the fundamental logic, rules and defined interactions that are allowed to take place in the system. The BLL is responsible for enforcing that only valid data enters into the system. If the data passed to it is invalid it is also responsible for providing meaningful feedback to the UI in order for the external interactor to decide which further actions it should take. It exposes contracts that define these interactions. The BLL also has knowledge of the DAL contracts and utilizes those to either persist data permanently or to retrieve data that has already been persisted.
This layer is built of many modular units that each encapsulates a certain business component. This allows for a consistent exposure of and interaction with those business components. Along with this consistency, it creates smaller more manageable chunks of code for any given developer to reason about. These business components can be tested, versioned and deployed independently from all other areas of the code base. The intent is to create a homogeneous set of methods that each business component should expose, allowing for business applications to be developed more rapidly and consistently.
DATA ACCESS LAYER (DAL)
This stratum of the application is responsible for interacting with a data store. Most meaningful applications have a need to persist data past a current interaction and retrieve that data at a later state to provide additional depth to further interactions. The DAL exposes contracts that define those interactions. The DAL is responsible for encapsulating the interactions that need to happen with the data store to persist and retrieve its data.
In the current design, the DAL for a given business component is tightly coupled to the BLL of the component only by virtue of the fact that they share a Visual Studio solution file. Each BLL should be loosely coupled to the DAL by virtue of the fact that its only interaction with the DAL occurs through the DAL’s exposed interfaces and contracts. This allows the actual implementation of the data persistence to be easily replaced without the need for changing anything outside of the DAL. One DAL could utilize a relational data model initially and through further investigation, could determine that a document data store would be more appropriate. The interaction with the data store as well as the data store itself could be replaced without requiring changes to any other layers of the software system. This flexibility allows the developers to choose the most appropriate data store for the data that is to be stored.