Planning on starting a greenfield software project? Then selecting the right architectural pattern will play a crucial role to the outcome of the project. Selecting the most popular or the latest technology in the market won’t always mean that it would bring the best results. However, selecting the most appropriate will provide proven solutions to prevailing and recurring issues.
There is a famous saying in the field of software engineering that says “take decisions to your resume”. What does this mean? IT professionals like to decorate their resumes with the latest and greatest technologies which would help in their next interview, but would not actually be beneficial for a project. For example, if your project is to build a regular data capturing form (with no more than 10 fields) for a survey which will be used only once by less than 100 users, using highly complex architecture patterns like Microservices would be an utter disaster. It would be like building a fighter jet just to visit the grocery store at the end of your street.
Thorough planning must be done when selecting an architecture pattern and the following features must be taken into account.
Cost
Time to Market
Number of users (current and future)
Level of isolation (ie: integration with other systems/platforms)
What happens if we develop a system without any architecture pattern? It will eventually end up a ‘big ball of mud’ where every class connects to all other classes.
So whenever you change the behaviour or structure of one class, a ripple effect would follow where multiple other classes would break. Is your software like this? The best way to find out is by using a software design reverse engineering tool like hex-ray that analyzes your component/class structures. If you end up with something like the above picture, then its time to rethink and do some alterations to your software design.
To help you, we will skim through the fundamentals of main software architectural patterns along with the pros and cons of each pattern. Then we will elaborate what architecture pattern would be the best fit for a given scenario. But we need to keep one thing in mind. When it comes to software architecture, there is no black and white answer; no correct or wrong architectures exist. It is very subjective and depends on a multitude of factors as mentioned before.
This blog goes as a series and we will be covering the following topics as the main chapters of the series.
The discipline of creating the fundamental structures of a software system is referred to as software architecture. Software structures are made up of software elements and their relations which function as a blueprint, laying out the pattern of tasks to be executed. Software design teams greatly depend on these software architectural patterns. It should be noted that software architecture must be chosen wisely because once implemented it is not easy to change.
Software architectural patterns are important as they are examples of the best solutions that have been built and tested successfully in architecture design. Experienced developers use their knowledge and familiarity to include these patterns rather than creating patterns artificially or randomly when designing. Furthermore, by using these patterns and highlighting them, they can share their knowledge and teach new developers key design strategies as well.
Patterns help in the identification and specification of abstractions which are found above the level of single objects, classes, and components. It is difficult for a single application to address a complex problem by itself. Patterns introduce different roles which have multiple application components thus helping in providing solutions. They define the constituent components along with their responsibilities and relationships on how they collaborate.
Additionally, these solutions portray the relationship between the roles which are introduced. For example, the Observer pattern comprises of two leading roles which are the subject and observer. The two roles cooperate via a push-based change propagation mechanism which ensures that the components can hold their state consistent with each other.
Patterns offer a common language and a shared understanding of design concepts. This helps ease the re-use of architectural knowledge and artefacts even though the reuse of certain algorithms, interfaces, implementations, and detailed designs may not always be possible. For instance, when developers have an understanding of the Observer pattern, discussions on how to manage two cooperating components consistent in their system is not required.
Patterns help in documenting software architectures. Through an in-depth evaluation of the consequences and implementation trade-offs, patterns make it possible to trace the reasons why specific design choices are selected over others. The software development path, practice, and maintenance can be smoothed by keeping a record of the intent, behaviour, and structure of the software in terms of the patterns which are found within it. Product-line architectures use patterns that are beneficial thus developers should be aware of it. If not, they would struggle to use it correctly without any understanding of the fundamental structure, mechanisms and control flow. Pattern based documentation of architecture helps in resolving conflict by helping developers focus on main design decisions.
Patterns are useful in the construction of software which have well-defined processes. Some patterns make a sketch of particular behaviour. This paves the way to meet certain functional requirements for the applications in a certain domain. For instance, patterns have been recorded for accounting systems and corporate finance and in improving the capacity of reactive systems.
Patterns also help in capturing experience in a form that can be independent of specific project details and constraints, implementation paradigm and often even programming language. When understanding coding principles and addressing design challenges in new projects, it is possible for developers to implement solutions that are error-prone, inefficient or unable to be maintained. Patterns help developers select suitable software architectures without falling into potential pitfalls in a domain.
Patterns help software developers coming from different programming language cultures share design insights that are of mutual interest while also preventing ‘language wars’. The transfer of knowledge among different generations of developers who are familiar with it helps balance and enable members of various communities to communicate and refocus on the concerns of a particular language community. While the coding could be dissimilar, similar patterns could be present which underpin the old and the new.
It must be noted that patterns cannot be deemed as coding guidelines. Coding guidelines can be put together either partly or from patterns that are focused on code style. However, the converse is not true. Though there are many coding guidelines that are idiomatic, this does not automatically make them design patterns. For instance, the specification for Sun Microsystem’s JavaBeans had consistently used get and set prefixes for property accessors as ‘design patterns’. However, though most of these prefixes are patterns, they do not help solve design issues for general designs even within Java code.
It is always important to understand the pattern vocabulary clearly as applying the wrong pattern can lead to a lot of problems. An experienced developer would have a sound judgement which would help him understand when a pattern is not appropriate in a particular situation. When there is misapplication, it can yield inappropriate designs and implementations.
Having superficial knowledge of a pattern can give developers the impression that they are well versed in it even though there may be a better solution for it. A good example is when knowing the structure and participants in complex patterns like Proactor and Reflection. This knowledge is only a single aspect thus is not enough. For effective pattern application, it is important that the essence of the pattern is reflected in its context and not just the structure.
Stay tuned to this blog series as we will be discussing how to apply most common software architecture patterns. The next post of this series will discuss the Layered Architecture pattern.
If you have any queries/concerns, then you can drop me an email or send me a message on LinkedIn or Twitter. I’m just a message away :)
Thanks for reading!
Welcome back to the Software Architecture Patterns blog series. This is the 2nd chapter of the series and we’ll be talking about Layered Architecture Pattern. Hopefully, by the end of this post, you’ll have an understanding of this particular architecture pattern and how it can benefit you. So let’s get to it!
This blog goes as a series and we will be covering the following topics as the main chapters of the series.
Layered architecture patterns are n-tiered patterns where the components are organized in horizontal layers. This is the traditional method for designing most software and is meant to be self-independent. This means that all the components are interconnected but do not depend on each other.
There are four layers in this architecture where each layer has a connection between modularity and component within them. From top to bottom, they are:
The presentation layer : It contains all categories related to the presentation layer.
The business layer : It contains business logic.
The persistence layer : It’s used for handling functions like object-relational mapping
The database layer : This is where all the data is stored.
In this instance the layers are closed, meaning a request must go through all layers from top to bottom. There are two reasons for this, one being that all ‘similar’ components are together and the other reason is that it provides layers of isolation.
To elaborate, having ‘similar’ components together means that everything relevant to a certain layer, stays in that single layer. This allows for a clean separation between types of components and also helps gather similar programming code together in one location. By isolating the layers, they become independent from one another. Thus if, for example, we want to change the database from an Oracle server to a SQL server, this will cause a big impact on the database layer but that won’t impact any other layers. Likewise, suppose that you have a custom written business layer and want to change it for a business rules engine. The change won’t affect other layers if we have a well-defined layered architecture.
The layered architecture pattern can be modified to have additional layers aside from the ones mentioned. This is known as hybrid layered architecture. For example, there can be a service layer between the business layer and the persistence layer. However, this is not an ideal scenario as now the business layer must go through the service layer to get to the persistence layer. This request doesn’t gain any value by going through the service layer. We call this an architecture sinkhole anti-pattern. Requests pass through layers with little or no logic performed in each layer.
The only way this can be solved is by making the optional layer an open layer. This means that if the optional layer adds any value to the request being sent, then the request goes through it. If not, then it will simply bypass this layer and go to the relevant layer after. This can be seen in the above diagram where the request bypasses the service layer and moves through from the business layer to the persistence layer.
Note however that by having open layers, we take away the benefits of having isolated layers. If we wanted to swap out the persistence layer, we would have to consider the open service layer as well as the business layer. Both these layers are now coupled to the persistence layer. Thus while it is very easy to add open layers to a system, it should not be allowed to happen. We must try to solve problems without compromising the architecture.
The layered architecture is the simplest form of software architectural pattern. If you are going to design a rudimentary application where the user count is very low ( < 100–200 ) and you are sure that there won’t be too much requirement changes after you go live, this is the best software architecture pattern to use. The implementation cost for this architecture pattern is very minimum compared to other patterns.
The following is a pros — cons analysis of layered architecture pattern.
It is easy to test as components belong to specific layers. As such, they can be tested separately.
It is simple and easy to implement because naturally, most applications work in layers.
Although changes can be done to a particular layer, it is not easy because the application is a singular unit. Also, the coupling between layers tends to make it harder. This also makes it difficult to scale.
It must be deployed as a singular unit thus a change to a particular layer means the whole system must be redeployed.
The larger is it, the more resources it requires for requests to go through multiple layers and thus will cause performance issues.
Stay tuned to this blog series as we will be discussing how to apply most common software architecture patterns. The next post of this series will discuss the Microkernel Architecture pattern.
If you have any queries/concerns, then you can drop me an email or send me a message on LinkedIn or Twitter. I’m just a message away :)