In the realm of software engineering, the journey from system architecture to software architecture is a critical phase that lays the foundation for the development of robust and scalable systems. This journey involves the meticulous design and integration of hardware and software components to fulfill the system’s requirements while adhering to nonfunctional characteristics and architectural patterns. In this article, we delve into the intricacies of system and software architecture, exploring their key components, nonfunctional characteristics, and prevalent architectural patterns and models.
All systems are designed to achieve some human purpose. Whether it’s a web application like Facebook connecting people in a social network or an aircraft transporting passengers long distances, every system serves a specific function. A Boeing spokesman once humorously remarked, “We view a 777 airliner as a collection of parts flying in close proximity.” This illustrates the complexity of modern systems and the importance of managing their design to ensure they fulfill their intended purpose without causing harm.
The role of a systems architect is crucial in overseeing the design of complex systems and systems of systems, such as the Boeing 777, to ensure they meet their assigned purpose and operate safely. System design involves defining the hardware and software architecture, components, modules, interfaces, and data to satisfy specified requirements. Simply put, system design is the process, and system architecture is one of the results of system design.
System Architecture:
System architecture is a conceptual model that describes the structure and behavior of multiple components and subsystems within a system, including software applications, network devices, hardware, and machinery. It serves as a blueprint for understanding how these components interact and collaborate to achieve the system’s objectives.
Architectural descriptions handle complexity by decomposing systems into design entities like sub-systems and components. These descriptions outline the physical and logical structures, interfaces, and communication mechanisms of the system. Architectural blueprints provide a roadmap for understanding how different components fit together and interact both internally and externally.
- Hardware Components: Processors, memory, storage devices, and other physical elements that form the building blocks of the system.
- Software Elements: Operating systems, applications, and middleware that provide the system’s functionality.
- Network Infrastructure: Communication channels that enable data exchange between different parts of the system.
- Interfaces: Defined communication protocols that govern how hardware and software components interact.
System architecture encompasses the high-level structure and organization of hardware and software components within a system. At this stage, architects focus on defining the system’s overall functionality, interfaces, and interactions between subsystems.
Hardware architecture
Hardware architecture delineates the physical components of the system, including processors, memory modules, input/output devices, and communication interfaces. Hardware architecture focuses on identifying a system’s physical components and their interrelationships. This description enables hardware designers to understand how their components fit into the system and provides essential information for software development and integration. Clear definition of a hardware architecture allows the various traditional engineering disciplines (e.g., electrical and mechanical engineering) to work more effectively together to develop and manufacture new machines, devices and components
Software Architecture
Software architecture, on the other hand, outlines the software components, modules, and their interrelationships, paving the way for the development of scalable and maintainable software systems.
There are many parallels between software architecture and traditional architecture, such as building buildings. Architects, regardless of the field, act as the interface between the customer’s requirements and the contractors responsible for implementing the design. Good architectural design is essential, as it cannot always be salvaged by good construction.
A software architect considers:
- Modules and Components: Functional building blocks of the software, each with a specific responsibility.
- Data Flow: How data is exchanged and processed between different modules.
- Communication Mechanisms: Methods used for modules to interact with each other, such as function calls or message passing.
- Technologies and Frameworks: Programming languages, libraries, and frameworks used to implement the software.
Software requirements are categorized into functional and nonfunctional requirements. Functional requirements define what the software should do, while nonfunctional requirements specify qualities like scalability, availability, reliability, and security. Describing an architecture involves formalizing the system’s structure, interfaces, and behaviors to support reasoning and development.
Partitioning large systems into smaller, independent components is crucial for scalability, maintainability, and ease of integration. Each component should have standalone business value and be seamlessly integrated with other components. This approach facilitates parallelization and allows different teams to work on individual components simultaneously.
Nonfunctional Characteristics:
Nonfunctional characteristics, also known as quality attributes or system qualities, are essential considerations in system and software architecture. These characteristics define the system’s behavior and performance attributes, such as reliability, scalability, security, performance, and maintainability.
These include:
- Performance: How fast and responsive the system is under various loads.
- Scalability: The ability of the system to handle increasing demands or data volumes.
- Security: The system’s ability to protect data and resist unauthorized access.
- Reliability: The system’s consistency in delivering expected results and minimizing downtime.
- Maintainability: Ease of making changes and fixing issues within the system.
Architects must carefully analyze and prioritize these characteristics based on the system’s requirements and user expectations. For example, in safety-critical systems like autonomous vehicles, reliability and fault tolerance take precedence, whereas in high-traffic web applications, scalability and performance are paramount.
In software engineering, software architecture involves creating a high-level structure of a software system. It encompasses scalability, security, reusability, and other characteristics into structured solutions to meet business requirements. Software architecture defines the interaction between externally visible components and emphasizes modular design principles.
System architecture and software architecture are not isolated concepts; they work hand-in-hand. The system architecture defines the overall framework, and the software architecture details how the software components will fit within that framework. A well-defined system architecture guides the development of a sound software architecture, ensuring all software elements work together seamlessly to achieve the system’s goals.
Describing an Architecture
An architecture description is a formal description and representation of a system, organized in a way that supports reasoning about the structures and behaviors of the system. A system architecture can consist of system components and the sub-systems developed, that will work together to implement the overall system.
Architectural structures are described in terms of:
The physical arrangement of components
Logical arrangement of components usually with a layered architecture model. At the next level of detail, assuming an object-oriented approach, this arrangement may be fleshed out with object models such as class diagrams, communication diagrams, and sequence diagrams.
Physical arrangement of code. For software-intensive systems, the architecture maps the various code units onto the physical processors that execute them and describes the high-level structure of the code.
System Interface. A system architecture primarily concentrates on the internal interfaces among the system’s components or subsystems, and on the interface(s) between the system and its external environment, especially the user. In the specific case of computer systems, this latter, special, interface is known as the human-computer interface, or HCI; formerly called the man-machine interface.
Component interfaces. Interactions between components including, communications protocols, message structures, control structures and synchronisation. The scope of interfaces also includes the modes of interaction with human operators and the associated human factors.
System behaviour. The dynamic response of the system to events. System behaviours are typically described with use cases that illustrate how various components of the architecture interact to achieve some required result.
Design styles. Selection of appropriate architectural styles and design patterns. For example, client/server model, supervisory control, direct digital control, pipe and filter architectural style, layered architecture, model-view-controller architecture. The rationales for design decisions are also recorded.
Allocation of system requirements to components. Detailed mapping of all system requirements to system components.
There have been efforts to formalize languages to describe system architecture, collectively these are called architecture description languages (ADLs). A system architecture can be broadly categorize into centralized and decentralized architectural organizations.
Software Architectural Patterns and Models:
Architectural patterns and models provide reusable solutions to common design problems in software development. These patterns, such as layered architecture, client-server architecture, and microservices architecture, offer guidance for organizing and structuring software components effectively. Each architectural style has its advantages and is suitable for different types of systems and applications.
Multiple high-level architecture patterns and principles are followed during defining architecture of a system. It mainly focuses more on externally visible components of the system and their interaction with each other.
Software architectural patterns and models provide reusable solutions to common design problems encountered in software development. These patterns offer a blueprint for organizing and structuring software components to address specific functional and nonfunctional requirements. Some prevalent architectural patterns include:
Pipe and Filter Architecture
Pipe and Filter is another architectural pattern, which has independent entities called filters (components) which perform transformations on data and process the input they receive, and pipes, which serve as connectors for the stream of data being transformed, each connected to the next component in the pipeline.
One scenario where the pipe and filter architecture is especially suitable is in the field of video processing, such as in the media-handling library, GStreamer. In video processing, a unprocessed video undergoes a series of transformations to become a processed video that can serve a more useful purpose. One example of this is in the real-time object detection from a live cameras.
In the example use case illustrated above, the image frames from the live video recorded serve as the input data and are sent into the application via the data source. Once in the pipeline, the data is transported via pipes between each component.
From the data source, the data goes through a series of filters sequentially, each processing the data to make it more useful for the next filter order to achieve the eventual goal of object detection. Eventually, the processed data, which in this case is the input image frame with bounding boxes drawn around objects of interest, is served as the application’s output in the data sink.
This Pipe-and-Filter architecture is particularly useful in those cases where we may want to expand, parallelize, or reuse components across large systems like this. So that’s one focus in architectural style that can be applied to something like this. And you see that, for example, in compilers. Compilers, for example, will have things like logical analysis, pair parsing, semantic analysis, and code generation. Those should all have essentially the same types of input and output so they can be reused.
Layered Architecture:
Layered architectures provide a structured approach to organizing system components, with each layer dedicated to specific tasks and responsibilities. Components within a layered architecture are arranged in a hierarchical fashion, with higher layers making downcalls to lower layers, while lower layers may respond with upcalls to higher layers.
This architectural approach is widely adopted due to its versatility and effectiveness, particularly in scenarios where systems need to manage complex data processing tasks. In many business applications, the layered architecture revolves around a central database, leveraging its capabilities for storing and retrieving information.
Consider a familiar example like Google Drive or Google Docs, which exemplifies the layered architecture:
- Interface Layer: This is the entry point for user interaction. Users request actions like viewing the latest document from their drive through the interface layer.
- Processing Layer: Once a request is received, the processing layer handles it, orchestrating the necessary actions and interactions. It communicates with the data layer to retrieve relevant information.
- Data Layer: At the lowest level is the data layer, responsible for storing and managing persistent data such as files. It provides access to higher-level layers by retrieving requested data and facilitating data manipulation.
In this architecture, each layer performs distinct functions, ensuring a clear separation of concerns. This separation offers several benefits:
- Maintainability: With distinct layers, it’s easier to maintain and update specific components without affecting others. Developers can focus on individual layers, streamlining maintenance efforts.
- Testability: Layered architectures facilitate testing by isolating components. Each layer can be tested independently, allowing for comprehensive testing of system functionality.
- Role Assignment: By assigning specific roles to each layer, the responsibilities of components are well-defined. This enhances clarity and simplifies development and troubleshooting processes.
- Modularity: Layers can be updated or enhanced separately, promoting modularity and flexibility in system design. Changes in one layer are less likely to impact others, fostering agility and adaptability.
The Model-View-Controller (MVC) structure, prevalent in many web frameworks, exemplifies a layered architecture. In MVC, the model layer encapsulates business logic and data management, the view layer handles user interface rendering, and the controller layer manages user interactions and orchestrates communication between the model and view layers.
Overall, the layered architecture’s emphasis on separation of concerns makes it a preferred choice for developing scalable, maintainable, and robust software systems. Its clear organization and modularity contribute to efficient development workflows and long-term system sustainability.
In layered architecture, the system is organized into horizontal layers, with each layer encapsulating a specific set of responsibilities. This pattern promotes modularity, separation of concerns, and ease of maintenance. Common layers include presentation, business logic, and data access layers.
Event-driven architecture
Event-driven architecture (EDA) revolutionizes how software systems handle dynamic events and user interactions, catering to the asynchronous nature of computing environments. In essence, many programs spend a significant portion of their runtime waiting for specific events to occur, whether it’s user input or data arrival over a network.
EDA addresses this challenge by establishing a central unit that acts as a hub for incoming events. When an event occurs, this central unit delegates it to designated modules capable of handling that particular type of event. This process of event delegation forms the backbone of event-driven systems, where events serve as triggers for executing specific actions.
A quintessential example of EDA in action is programming web pages with JavaScript. Here, developers write small modules that react to various events like mouse clicks or keystrokes. The browser plays a pivotal role in orchestrating these events, ensuring that only the relevant code responds to the corresponding events. This selective event handling contrasts with traditional layered architectures, where data typically flows through all layers irrespective of relevance.
Event-driven architectures offer several advantages:
- Adaptability: EDA excels in dynamic and chaotic environments, easily accommodating diverse event streams and changing requirements.
- Scalability: Asynchronous event processing enables seamless scalability, allowing systems to handle increased event loads without sacrificing performance.
- Extensibility: EDA systems readily adapt to evolving event types, facilitating the integration of new functionalities and features.
However, EDA also presents unique challenges:
- Testing Complexity: Testing event-driven systems can be intricate, particularly when modules interact with each other. Comprehensive testing requires evaluating the system as a whole, including interactions between modules.
- Error Handling: Structuring error handling mechanisms in event-driven systems can be challenging, especially when multiple modules must handle the same events. Ensuring consistent error handling across the system is crucial for robustness and reliability.
- Fault Tolerance: In the event of module failures, the central unit must implement backup plans to maintain system integrity and functionality.
- Messaging Overhead: Processing speed may be impacted by messaging overhead, especially during peak event loads when the central unit must buffer incoming messages. Efficient message handling strategies are essential to mitigate performance bottlenecks.
Despite these challenges, event-driven architectures offer unparalleled flexibility and responsiveness, making them indispensable for modern software systems. By embracing the asynchronous nature of events, EDA empowers developers to build resilient, adaptable, and highly scalable applications capable of thriving in dynamic environments.
Object-Oriented, Service-Oriented Architectures, Microservices, and Mesh Architectures
Object-Oriented (OO), Service-Oriented Architectures (SOA), Microservices, and Mesh Architectures represent a spectrum of architectural paradigms, each offering unique approaches to organizing and deploying software systems. While distinct in their implementations, these architectures share a common evolutionary lineage, with each iteration building upon the principles of its predecessors.
Object-Based Architectural Styles
Object-oriented programming (OOP) serves as the foundation for encapsulating functionality within logical components known as objects. Traditionally associated with monolithic applications, OOP enables the organization of complex systems into manageable units. Within a monolith, objects are interconnected, forming a cohesive yet intricate structure. Each object maintains its encapsulated data set, known as its state, along with methods that define operations performed on this data. Objects communicate through procedure calls, invoking specific requests to interact with one another.
Service-Oriented Architecture (SOA)
SOA extends the principles of OOP by encapsulating services as independent units. Services, akin to objects in OOP, are self-contained entities that interact with each other over a network via messages. This architecture promotes modularity and reusability, allowing for flexible integration of services across distributed environments. SOA emphasizes loose coupling between services, facilitating interoperability and scalability.
Microservices
Microservices represent a refinement of SOA principles, advocating for smaller, more lightweight services. Unlike traditional SOA, microservices are designed to be highly decoupled and independently deployable. Developers have the freedom to choose the programming languages and technologies best suited for each service, enabling rapid development and deployment. By breaking down applications into smaller, self-contained components, microservices offer improved agility, scalability, and fault isolation.
Mesh Architectures
Mesh architectures introduce a decentralized approach to service deployment, where services or processes operate on nodes without centralized control. These architectures embrace the distributed nature of modern computing environments, enabling services to establish temporary peer-to-peer connections. Mesh architectures facilitate uniformity among interacting services, with an emphasis on distributed communication and fault tolerance. Services communicate over multiple hops, traversing the network to reach their destination, even in unstable environments.
While these architectural paradigms represent evolutionary advancements, they do not render previous methodologies obsolete. Object-oriented principles continue to underpin modern architectures, with microservices often composed of encapsulated objects. Each architectural style offers distinct advantages and trade-offs, catering to diverse application requirements and development contexts. As software systems evolve to meet the demands of an ever-changing landscape, architects must carefully evaluate and adapt these architectural patterns to ensure the resilience, scalability, and maintainability of their designs.
Client-Server Architecture: Client-server architecture distributes the system’s functionality between client and server components, facilitating scalability, resource sharing, and centralized management. Clients interact with servers to request and receive services, while servers handle data processing and storage.
Microservices Architecture: Microservices architecture decomposes the system into small, independent services that communicate via lightweight protocols such as HTTP or messaging queues. This pattern enables flexibility, scalability, and rapid deployment, making it well-suited for cloud-native and distributed systems.
Event-Driven Architecture: In event-driven architecture, components communicate asynchronously through events and event handlers. This pattern promotes loose coupling, scalability, and responsiveness, allowing systems to react to changes and events in real-time.
Model-View-Controller (MVC): MVC is a software architectural pattern that separates the application’s data, presentation, and user interaction into three distinct components: the model, view, and controller. This pattern enhances maintainability, extensibility, and testability by decoupling user interface logic from business logic.
Conclusion
In conclusion, transitioning from system architecture to software architecture involves meticulous planning, design, and integration of hardware and software components to meet the system’s requirements. By prioritizing nonfunctional characteristics and leveraging architectural patterns and models, architects can create scalable, reliable, and maintainable software systems that meet the evolving needs of users and stakeholders.
References and Resources also include:
http://www.chambers.com.au/glossary/architecture.php
https://thenewstack.io/primer-distributed-systems-and-cloud-native-computing/