Philippe Kruchten, Grady Booch, Kurt Bittner, and Rich Reitman derived and refined a definition of architecture based on works by Mary Shaw and David Garlan (Shaw and Garlan 1996). Their definition is:
“Software architecture encompasses the set of important decisions about organizing a software system, including the choice of structural elements and their interfaces, of which the system is composed; behavior as specified in collaboration between these elements; composition of these structural and behavioral elements into larger subsystems and an architectural style, leading this organization. Software architecture also involves functionality, ease of use, robustness, performance, reuse, intelligibility, financial and technological constraints, compromises and aesthetic issues. “
In patterns by Enterprise Application Architecture, Martin Fowler outlines some common recurring themes when explaining architecture. I have identified these themes as:
“The highest-level division of a system into its parts; decisions that are difficult to change; there are multiple architectures in one system; what is architectural to whatever the important things are. “
Software application architecture is the process of defining and coming up with a solution that is well structured and meets all technical and operational requirements. The architecture must be able to take into account and enhance the common quality attributes such as performance, security and manageability.
The main focus of the software architecture is how the main elements and components of an application are used by or interact with other main elements and components of the application. The choice of data structures and algorithms or the implementation details of individual components are design problems, they are not an architectural matter, but sometimes design and architecture problems overlap.
Before you start software architecture, there are some basic questions that we should strive to get answers to. They are as follows:
How do users of the system interact with the system?
How is the application implemented in production and managed?
What are the different non-functional requirements of the application, such as security, performance, concurrency, internationalization and configuration?
How can the application be designed to be flexible and maintainable over time?
What are the architectural trends that may be affecting your application now or after it has been implemented?
Objectives of software architecture
Building the bridge between business requirements and technical requirements is the main goal of any software architecture. The goal of architecture is to identify the requirements that affect the basic structure of the application. Good architecture reduces the business risks associated with building a technical solution, while a good design is flexible enough to handle the changes that will occur over time in hardware and software technology, as well as in user scenarios and requirements. An architect must consider the overall impact of design decisions, the inherent trade-offs between quality attributes (such as performance and security), and the trade-offs required to meet user, system and business requirements.
Principles of software architecture
The basic assumption of any architecture should be the belief that the design will evolve over time and that one cannot know everything one needs to know from scratch. The design will generally have to evolve in the implementation stages of the application as you learn more and when testing the design against the requirements of the real world.
Keeping the above statements in mind, let us try to state some of the architectural principles:
The system needs to be built to change rather than build to last.
Model the architecture to analyze and reduce risk.
Use models and visualizations as a communication and collaboration tool.
The most important technical decisions must be identified and acted upon in advance.
Architects should consider using an incremental and iterative approach to refine their architecture. Start with baseline architecture to get the big picture right, and then develop candidate architectures as an iterative test and enhancement of one’s architecture. Do not try to get it right with first-time design as much as you can to start testing the design based on requirements and assumptions. Add iterative details to the design over multiple passes to make sure you make the big decisions first, then focus on the details. A common pitfall is to dive into the details too quickly and make the big decisions wrong by making the wrong assumptions or by not evaluating your architecture effectively.
When testing your architecture, consider the following:
What were the main assumptions made by the architect of the system?
What are the requirements both explicitly and implicitly this architecture is satisfying?
What are the main risks of this architectural approach?
What countermeasures are there to mitigate the key risks?
In what ways is this architecture an improvement over the baseline or the last candidate architecture?
When getting started with software design, keep in mind the proven principles and principles that adhere to minimize costs and maintenance requirements, and promote usability and extensibility. The main principles of any software design are:
Separation of concerns: The key factor to remember is the minimization of interaction points between independent feature sets to achieve high cohesion and low coupling.
Single responsibility principle: Each component or module must be independent in its own right and only responsible for a specific function or functionality.
Principle of Least Knowledge: A component or object should not know about internal details about other components or objects.
Do Not Repeat Yourself (DRY): The intent or implementation of a feature or functionality should be done only one place. It should never be repeated in another component or module
Minimize design in advance: This principle is also sometimes called YAGNI (“You Don’t Need It”). Design only what is needed. Especially for smooth development, great design can be avoided in advance (BDUF). If the application requirements are unclear, or if there is a possibility that the design will evolve over time, one should avoid making a major design effort too soon.
Keep design patterns uniform in each layer.
Do not copy the functionality of an application.
Prefer composition rather than inheritance. If possible, use composition rather than inheritance when reusing functionality because inheritance increases dependency between parent and child classes, thereby limiting the reuse of child classes. This also reduces inheritance hierarchies, which can become very difficult to manage.
Create a coding style and naming convention for development.
Maintain system quality using automated QA techniques in development. Use device testing and other automated quality analysis techniques, such as dependency analysis and static code analysis, in development
Not only development, also consider the operation of your application. Determine the metrics and operational data required by the IT infrastructure to ensure effective implementation and operation of your application.
Application Layers: While archiving and designing the system, carefully consider the different layers into which the application should be divided. There are some important considerations to keep in mind as you do so:
Separate the areas of concern. Divide your application into different features that overlap in functionality as little as possible. The main advantage of this approach is that a feature or functionality can be optimized independently of other features or functionality
Be explicit about how layers communicate with each other.
Abstraction should be used to implement loose coupling between the layers.
Do not mix different types of components in the same logical layer. For example, the UI layer should not contain business processing components, but instead contain components used to handle user input and process user requests.
Keep the data format consistent within a layer or component.
Components, Modules and Features: Key Considerations
In the previous sections, we talked about important considerations to keep in mind while archiving or designing an application. We also touched on what to remember when dividing our application into different layers. In this section let’s look at some key considerations for designing component, modules and functions.
A component or object should not rely on internal details about other components or objects.
Never overload the functionality of a component. For example, a UI processing component should not contain data access code or attempt to provide additional functionality.
Explain explicitly how the components communicate with each other. This requires an understanding of the installation scenarios that your application must support. You need to decide whether all components are running within the same process, or whether cross-physical or process communication needs to be supported – perhaps by implementing message-based interfaces.
Keep intersectional code (such as logging and performance) abstracted from the application’s business logic as far as possible.
Present a clear contract for components. Components, modules and functions must define a contract or interface specification that clearly describes their use and behavior.