Functional Architecture
The goal of any business is to make a profit by producing goods or providing services. Therefore, any business needs software to track its money - accounting software, software to work with banks, and software to work with the tax authorities for tax purposes. Every business also needs HR management software. Companies that manufacture goods need software to track incoming ingredients to ensure proper production processes, and software to track sales of finished products. Service companies need software to track incoming goods and manage the services they provide.
To sum it all up, every business needs different types of software that work with different types of data. Data is the main subject of any business-related software. Data is collected, aggregated and analyzed. Data is the subject of buying and selling. In some cases, data is pure money.
Functional architecture, or business domain architecture, is about data, its creation through CRUD operations, and its use in daily routine operations, analysis, statistics, planning, etc.
The functional architecture is based on six pillars – physical separation of functional and non-functional architecture, data container, state handlers, metadata, transition handlers, and handler isolation. The following diagram gives a brief overview of these pillars:
Components belonging to the functional architecture must be placed in separate assemblies where there are no components belonging to the non-functional architecture. Conversely, components belonging to the non-functional architecture cannot be placed in any assembly belonging to the functional architecture.
Components belonging to a functional architecture cannot in any case have any knowledge about the existence of components of a non-functional architecture. Technically, assemblies belonging to a functional architecture cannot have any references to any assemblies belonging to a non-functional architecture.
On the other hand, in order for the non-functional architecture to serve the functionality of the functional architecture, assemblies belonging to the non-functional architecture can have references to assemblies belonging to the functional architecture. But despite this, components belonging to a non-functional architecture cannot have any knowledge of the existence of components of a functional architecture anyway. All they know is that they can service a set of specific requests coming from the functional architecture components. This is achieved by programming against interfaces and using events.
By moving in this direction, we will reach one of our fundamental goals – NFA-agnostic business domain.
A data container is a component that transfers data and metadata between functional and non-functional architecture components, as well as between logical layers of an application. The concept of a data container is taken from the ADO.Net Data Set component, which can transfer a set of data as a single unit between application components. Unlike the ADO.Net Data Set, a data container transfers strongly typed objects and is serialized into JSON format for transmission over the network.
As we have already learned in the chapter "State Logic", the application page represents the state of the business process or, in other words, it handles the state of the business process, responsible for all aspects of user interaction, including user clicks on clickable visual elements such as buttons or hyperlinks that trigger business process transitions. That is, the page is a state handler.
When a trigger starts a transition, the NFA provides a new data container to the state handler. If the state handler is part of a user interface, such as a visual page, the state handler collects all the necessary data from what the user has entered into the page and inserts it into the data container. In addition, the state handler adds metadata to the data container, which the NFA uses to route the data container to the correct transition handler. This metadata consists of five parts:
· Product code – a code that uniquely identifies a software product
· Use Case Name – the name of the use case that the state handler is a part of
· Software Logical Layer Name – the name of the layer to which the state handler belongs
· State Name – the name of the business process state that the state handler represents
· Transition Name – the name of the transition that was started
Continuing with the dental office information system example, we might have a page (state handler) that is part of the “Reception Desk” application, belongs to the “Patient Identification” use case, represents the “Initial” state of the use case, and has a "No Medical Record" button (trigger) that launches the “No Medical Record” transition. In this case, the following metadata will be inserted into the data container:
· Product code – “Receptionist Desk”
· Use Case Name – “Patient Identification”
· Software Logical Layer Name – “State Logic”
· State Name – “Initial”
· Transition Name – “No Health Card”
We have learned that there are some activities that need to be performed during the transition of a business process from one state to another. These actions are performed by transition handlers distributed across the logical layers of the application. Each transition handler can be uniquely identified by the following five metadata:
· Product code – a code that uniquely identifies a software product
· Use Case Name – the name of the use case that the transition handler is a part of
· Software Logical Layer Name – the name of the layer to which the transition handler belongs
· State Name – the name of the business process state from which the business process transition begins
· Transition Name – the name of the transition that the transition handler handles
Continuing with the dental office information system example, we might have a transition handler that is part of the “Receptionist Desk” application, belongs to the “Patient Identification” use case, resides at the business logic level, and handles the “No Health Card” transition that starts from the “Initial” state of the business process. In this case, the transition handler would have the following metadata:
· Product code – “Receptionist Desk”
· Use Case Name – “Patient Identification”
· Software Logical Layer Name – “Business Logic”
· State Name – “Initial”
· Transition Name – “No Health Card”
When the NFA receives a request in the form of a data container from the state handler, the first thing it does is increment the value of the software logic level in the data container, changing it, in our case, from "State Logic" to "Business Logic". Then it looks at the data container's metadata and tries to find a matching transition handler with the same metadata. If one is found, the NFA assigns it a data container and calls its "Process Request" method. In our case, the NFA finds a transition handler whose metadata matches the metadata in the data container and assigns the data container to the found transition handler to handle the request. If a transition handler is not found, the NFA redirects the request to the next logical level.
No handler can ever know about the existence of another handler. Technically, a handler is a class that cannot have references to other classes. All a handler can do is work with the data located inside its assigned data container. Handler isolation gives us the freedom to decide how the application can be deployed. We can easily deploy each logical layer on its own machine, transforming the application layers into layers:
Table of Content Software Architecture Previous: Layered Architecture Next: Non-functional Architecture