Introduction to Software Architecture (Part 1)

Amine Bellamkaddem
Geek Culture
Published in
11 min readJul 6, 2021

Software Architecture (SA) has often been mistakenly thought of as a bunch of line-and-box diagrams generated using ad-hoc techniques, experience, and intuition. By chance, this might work, especially in the first days of production, but as time goes by, the situation would most likely become a nightmare.

In fact, SA is an engineering discipline whose artifacts should be designed, analyzed, evaluated, documented and then implemented. Missing one or more of these steps should be considered as a serious warning to the involved stakeholders.

In this series, we’ll formally define software architecture, understand its role in software development, and discuss the main challenges of its application. We’ll learn how to design, analyze, evaluate, and document software architectures as well as how to balance tradeoffs and generate alternative architectures. We’ll also talk about major architectural styles, patterns, tactics, and more.

This first article is the starting point that introduces the foundations that we’ll be using throughout this series. It starts by formally defining and showing the importance of SA in the project lifecycle, then it covers topics such as architectural drivers, structures and perspectives, and it concludes by discussing the challenges facing the application of SA as an engineering discipline.

Future articles of this series will focus on particular topics, such as quality attributes and tactics associated with them, documentation and SA deliverables, styles and patterns, and more.

Defining Software Architecture

What is Software Architecture ?

Software systems are designed to address abstract business goals. These goals are listed as requirements (aka specifications). Requirements should be implemented in order to deliver the solution to the client. But there is something missing here: how can we get from requirements, which are often specified at a very high level of abstraction, to concrete operations and instructions that can be implemented. There should be something in between to glue them together as shown in Figure 1.

Software Architecture
Figure 1

The gray cloud in Figure 1 is where SA comes into play. It is a bridge linking the high-level business goals and the solution.

Definition of Software Architecture

Informally, software architecture is an abstraction that captures certain parts of the system at hand and omits others. The selected parts are the key elements needed to reason about the system, while the omitted ones are details that are not needed for high-level reasoning.

Dozens of definitions can be found on the Software Engineering Institute’s (SEI) website and more definitions exist on the internet, but the one that best summarizes these definitions is: “The software architecture of a system is the set of structures needed to reason about the system, which comprise software elements, relations among them, and properties of both.” [1]

In other words, software architecture consists of decomposing a system into a set of elements, or “structures”, often at a higher level of abstraction, defining how those elements are communicating with each other, which we call “relations”, and then defining properties of both structures and relations. This decomposition often follows a style (or pattern) that we’ll cover in more detail in a future article.

Why do we need Software Architecture

Let’s consider the following requirements and constraints:

  1. Currently, our website has 10,000 visitors a day. The website should operate exactly with the same levels of performance and availability, if we reach 1,000,000 visitors a day.
  2. As a user, when I trigger operation “A”, it should complete and return its output in less than 0.5 seconds, since operation “B” will search for the output of “A” in exactly 0.5 seconds after “A” has been started.
  3. A “critical” bug should be fixed in no more than 0.5 person/day.
  4. A new module should be “easily” integrated into the project after it has been developed.

How can we meet these kinds of constraints ? What does “critical” mean in requirement 3 ? What does “easily” mean in requirement 4 ?

Well, this is where the magic of SA happens. Software Architecture’s decisions and tactics allow us to promote quality attributes of interest and inhibit ones that are less important for the system at hand.

For example, if we care about modifiability, we need to carefully decompose the system into sub-parts and then assign responsibilities so that future updates do not propagate into other parts of the system.

If we care about performance, we need to take, to some extent, the opposite direction of modifiability. We also need to pay attention to the usage of shared resources, just to name a few tactics. More details about quality attributes will be the subject of part 2 of this series.

Software Architecture also allows us to predict the system’s behavior at the design stage instead of waiting until the implementation phase to check whether or not requirements and constraints have been met. This is primarily done by promoting or inhibiting candidate quality attributes, selecting the appropriate architectural style/pattern that will likely lead to the desired results, calibrating and selecting optimal tradeoffs among competing quality attributes, and also by conducting experiments and then evaluating candidate architectures.

Moreover, SA helps us deal with ambiguity in the requirements such as the “critical” and “easily” qualifiers mentioned in the requirements above. The architecture team should convert these ambiguities into quantitative data (numbers, durations, acceptance criteria, etc) . Other ambiguity examples might be:

  • The system should “quickly” respond to users’ requests.
  • The user interface should be “easy” to use.

Because SA is an abstraction that links high-level business goals and the solution, it drastically enhances communication among different stakeholders. It bridges the gap between technical and non-technical people, which is critical for resolving requirements’ ambiguities, relaxing complex parts, and negotiating conflicting requirements, and more.

Architectural Drivers

Design decisions are influenced by multiple factors. The architect should capture key requirements and constraints that will shape design decisions, called architectural drivers, and abstract away unimportant details. Architectural drivers are the most important and influential requirements and constraints.

There are four types of architectural drivers as shown in figure 2: functional requirements, quality attributes (QA) requirements, technical constraints, and business constraints.

Software Architecture
Figure 2

High-level functional requirements: these are high-level general descriptions of functional features and capabilities that the system must perform. For example, an online eCommerce platform should allow clients to create their account, create their virtual shopping cart, pay online, etc. Use cases can be used to explore, analyse, and document functional requirements. Remember that, at this stage, details are abstracted away, and we only focus on high-level and influential requirements.

Another example is an infusion pump system where the user can switch on or off the pump, the pump shall automatically switch to the battery mode if the AC adapter fails during operation, the pump produces an audio alarm when something goes wrong, such as fluid delivery has stopped, the batteries are low while the pump is running on battery mode, etc.

Quality attributes requirements: sometimes referred to as “non-functional requirements”. They are properties such as performance, testability, security, reliability, maintainability, usability, etc. Sometimes, quality attributes requirements are explicitly stated by stakeholders, but in most cases they should be inferred, which makes them difficult to capture in an exhaustive way.

Back to our examples. The online eCommerce platform is primarily concerned with security since it deals with users’ personal information and online payment, usability to ease the experience of existing users and to attract new ones, as well as availability. Regarding the Infusion pump system, safety and reliability might be good candidates.

Important QAs, strategies and tactics associated with them (and more) will be the subject of part 2 of this series.

Technical constraints: Imposed technical constraints that architects should take into account when designing the system. Technical constraints could be a type of hardware, operating system, databases, programming languages, software programs and tools, etc.

The worst possible case is when these constraints prevent the realization of some functional or quality attributes requirements. For example, using a particular infusion pump brand, which does not support audio alarms.

Business constraints: These Indirectly impact architectural decisions because they don’t directly impose technical choices, but they do so implicitly. Limited budget, deadlines and reuse of existing tools are some examples of business constraints.

Now, let’s ask a question: which architectural driver/s has/ve the most influence on design decisions ? Take a minute, think about it and try to answer. If needed, you can reread the section just above.

Ok! Imagine you are an expert in Java programming language and you want to implement the eCommerce platform using Java. Ultimately you will bundle your solution into classes using Java’s elegant style. But wait, the client requires using the C programming language. This means, you cannot use the Java build-in object-oriented support and other out-of-the-box Java capabilities. Instead, you have to use the structured programming paradigm. At the end of the day and regardless of which programming language and which pattern you use, the system shall have the requested feature, which is the functional requirement. But the design will be strongly impacted by the imposed technical constraint (programming language in this case).

Another example. We like elegant programming trends and try to apply them such as the single-responsibility principle (SRP) so that we can guarantee low coupling and maybe also high cohesion, which will result in a well-structured solution. But after taking a deeper look into specifications, we realize that we have some hard-deadline constraints (performance). Therefore, we have to increase the coupling of some parts of the system to bring them close to each other, so that we reduce the “distance” (abstraction layers) between them. Again, we are guaranteed to have the requested feature, which is the functional requirement, regardless of where we are placing different parts of the system. But to meet a given performance requirement we have to reshape our design.

Do you get it ? Quality attributes requirements and constraints can have even more impact on design decisions than functional requirements.

Structures, Perspectives, and Views

As we’ve seen, the architect needs to decompose the system into a set of structures, capture relations among them, and then, find out their properties. But first, we need to know what a structure is and how we can reason about it.

Let’s take an example of a car engine, which is our structure in this case. How can we analyze a car engine ? Well, let’s begin by opening the hood and taking a deeper look at the engine, inspecting its different metallic parts and objects such as the timing chain. Is this “static” analysis enough ? clearly no. We need to start the engine and see how it behaves “dynamically” in runtime. We also need to see how it fits in its world and interacts with its “physical” environment. Figure 3 illustrates the 3 perspectives we have just described of the structure at hand: static, dynamic and physical.

Software Architecture — Perspective
Figure 3

The perspective is a logical reasoning about a structure that should be done at the design stage. This logical reasoning is critical for producing effective and appropriate architectural documentation. A view is a documentation of a particular perspective.

Back to software architecture. Structures are complex elements that should be viewed from different perspectives. Looking only at modules and code-related elements will not be enough to capture all properties of the system at hand. All systems have three perspectives: static, dynamic, and physical:

Software Architecture
Figure 4

The Static perspective is critical for reasoning about modifiability, maintainability, scalability as well as the cost of change. It focuses on code-oriented elements such as packages, modules, classes, functions, files, data structures, etc. Relations among static elements includes: uses, inherits, and depends.

The dynamic perspective focuses on runtime components of a structure, such as objects, processes, threads, etc. Common relations include: calls, returns, triggers, and interrupts. This perspective should be used to reason about concerns such as: concurrency, memory and CPU utilization, performance, load testing, and availability.

The physical perspective is critical for system integration and testing. It focuses on physical components such as servers, sensors, routers, chips, etc. Relations among physical elements includes wire cable, cable adapter, wireless etc.

As mentioned above, views are used to document perspectives. A view is a representation of a structure from a given perspective. Sometimes a single view might be enough, but in practice, we generally need multiple views to capture all details of a given perspective.

Figure 5 depicts a high-level picture of a structure, its perspectives, its views, and relations among them.

Software Architecture — Structures, perspectives, views
Figure 5

Challenges of Applying SA as an Engineering Discipline

The application of SA as an engineering discipline faces several challenges. The main obvious barrier is the lack of qualified resources. Companies tend to use ad-hoc software applications relying on experience and intuition. While hands-on experience might be enough for some types of projects, it may not be sufficient for more demanding ones. The lack of financial resources to hire qualified architects as well as a lack of understanding of the criticality of software architecture in a project lifecycle might be the main reasons leading to this barrier.

The time and cost associated with the adequate use of SA early in the project lifecycle might also be a barrier. IT companies tend to emphasize time-to-market constraints and adopt agile-like processes resulting in quick and regular updates. This, to some extent, breaks the architecture-centric approach. Companies working on embedded projects, on the other hand, tend to adopt more stable software engineering processes which are, generally, more suitable for an architecture-centric approach. This remains a hotly debated topic between Agile processes lovers and software architects which is out of scope of this post, but it is worth mentioning that there is a trade-off to calibrate between the agility and the architecture-centric approach.

Wrapping up

That’s all for this part. We started by defining software architecture and discussing why it is important for the project lifecycle. We talked about architectural drivers, then we defined structures, perspectives and views. Finally, we discussed some of the barriers facing the application of SA as an engineering discipline. We’ll be using these definitions and concepts in subsequent posts when we’ll discuss quality attributes and tactics associated with them, styles and patterns, documentation and SA deliverables, and more.

References
[1] Bass, Clements, & Kazman. Software Architecture in Practice, 3nd Edition, 2013
[2] Clements et al. Documenting Software Architecture: Views and Beyond, 2nd Ed, 2011
[3] J.Lattanze. Architecting Software Intensive Systems — A practitioner’s Guide, 2017
[4] David E. Arney, Raoul Jetley, et al. University of Pennsylvania. In Generic Infusion Pump Hazard Analysis and Safety Requirements Version 1.0, 2009

--

--