Qualities of Highly Effective Architects

Maneesh Chaturvedi
7 min readApr 27, 2021

What is Software Architecture

Before defining the qualities of an effective architect, we need to understand what an architect is and does. The terms architect and architecture are highly overloaded terms in the software industry. In his famous whitepaper Who Needs an Architect, even Martin Fowler famously refused to try and define it, instead falling back to the quote,” Architecture is about the important stuff, whatever that is — Ralph Johnson.”

What makes an attempt difficult is that the role of a software architect embodies a massive amount of responsibility that continues to expand. Quantifying and qualifying a constantly moving target is not an easy task. However, certain fundamental concepts are helpful when thinking about architecture.

  • Architectural Structure — This is captured by the architectural style like microservices, layered, microkernel, space-based, etc.
  • Architectural Capabilities — These are the various -ilities(reliability, testability, availability, security, scalability) that define the success criteria for the system. These capabilities are generally orthogonal to the functionality desired from the system and hence are also called non-functional requirements.
  • Architectural Decisions — These define the rules of how the architect should construct a system. These constraints direct the development teams on what is allowed and not allowed. Examples could be build vs. buy decisions, utilizing a managed service of a cloud provider, or the use of open-source vs. commercial offerings.
  • Design Principles — Design principles constrain the allowed design choices. For example, using synchronous vs. asynchronous calls, or the use of communication protocols like REST or gRPC, etc.

All of the above concepts need to be specified to define and understand architecture. It is not enough to state, “It’s a microservices architecture” since that captures only the structural aspect of the architecture.

Expectations of An Architect

It’s not sufficient to state that an architect does architecture. To be an effective architect, we need to understand the actual expectations. The list below is not exhaustive; however, it captures the most significant expectations.

  • Make architectural decisions.
  • Continually evaluate architectures and analyze architectural risks.
  • Communicate and present architectures
  • Make teams effective
  • Possess domain knowledge
  • Negotiation and Leadership skills
  • Diverse Knowledge and Experience

As is evident from the expectations stated above, being an effective architect requires more than technical skills. Highly skilled and effective architects possess an aggregation of technical, domain, soft skills, and leadership skills. However, covering all of these aspects would not be feasible in one post. Hence, we will limit ourselves to the technical skills required to be an effective architect.

Make Architecture Decisions

The most fundamental technical skill expected from an architect is making architectural decisions. So what are these decisions, and how do good architects make them.

Fundamentally, the focus of an architect is on the following architecturally significant decisions.

Define the architectural structure

One of the fundamental activities involved in developing an architecture is to figure out the architectural style. Often, architects tend to follow the most prevalent architectural style of that period. In the late 90s and the early 2000s, Client-Server was the predominant style of architecture; around the mid-2000s, it was SOA, and in more recent times, it is the Microservices style. However, making decisions based on popularity or recency can often lead to costly architectures, which come with significant costs in terms of development, maintainability, testability, and evolvability. Maxims like monolithic systems are inherently wrong, commonly heard in the industry, have minimal grounding in reality. Most architectural decisions involve trade-offs. Architectural thinking requires looking at the benefits and analyzing the trade-offs associated with the solution.

With the evolution of distributed computing, the focus has shifted away from analyzing architectures in the small. These are architectures within individual components, for instance — a single microservice.

Skilled architects generally have in-depth knowledge of various architectural styles, both for architectures in the small and distributed architectures. Some of the most common architectural styles are listed below.

Extract Architectural Capabilities aka Non-functional Requirements

An architectural capability identifies a constraint on the system. It must fulfill the following criteria.

  • Specifies a non-domain design consideration
  • Influences some structural aspect of the design
  • It is critical/essential for application success

Architectural capabilities can be sub-categorized (For reference: not a comprehensive list.)

  • Operational: Availability, Continuity, Performace, Recoverabilility, Reliability, Resilience, Fault Tolerance, Scalability, Elasticity.
  • Structural: Configurability, Extensibility, Maintainability, Portability, Supportability, Evolvability.
  • Cross-Cutting: Accessibility, Security, Authentication and Authorization, Compliance, Privacy, Usability.

When defining architectural capabilities, an architect should limit the supported list to as small as possible. A common anti-pattern is to try and keep all of the architectural capabilities, leading to a generic architecture. Each architectural capability adds complexity to the architecture; hence the more the number of capabilities supported, the higher is the complexity you add to the overall architecture. Also, many of these capabilities are orthogonal; for example, improving security adversely affects performance.

System Decomposition/Component Identification

The essence of the architecture of a system is the breakdown of the whole into its constituent components. The act of identifying these components is called system decomposition. Proper decomposition is critical. A wrong decomposition means a bad architecture which can lead to a lot of pain in the future, potentially leading to a complete rewrite.

One of the most common ways of decomposing systems is functional decomposition. However, unless care is exercised, this form of decomposition can lead to many issues.

As an example, consider a system that performs three functions of invoicing, billing, and shipping. Functional decomposition will lead to three services, Invoicing, Billing, and Shipping.

Some of the issues with improper functional decomposition can lead to the following.

  • Precludes Reuse — If there is temporal coupling between the services, that is, billing needs to be called before invoicing, and only after that can shipping be called; we cannot reuse invoicing in any other context where the notion of this temporal call chain does not exist.
  • Too Few or Too Many — Since a decently complex system can have hundreds of functionality, there are chances of having too many fine-grained services, one for each function. At the other extreme, there could be a case where many functionalities are combined, which leads to God Monoliths and Big ball of mud implementations.
  • Client Bloat –With functional decomposition, each discrete unit performs a single function. Hence there needs to be something that combines these functionalities into required behavior. Often, this something is the client who performs this orchestration. The client is intimately aware of how to call the services, handle error cases, and compensate for errors with the call flow, etc. Besides, there are multiple entry points now, one for each service, for things like authentication, authorization, scalability, transaction propagation, identities, etc.
  • Service bloat — The same arguments as above apply when the client is not orchestrating the required behavior, but there is a call flow with each service calling the next in sequence.

In principle, when performing system decomposition, it is best to look at areas of volatility and isolate those. Combining things that change together ensures that ripple effects do not percolate throughout the invocation chain.

Architecture Analysis

By continually evaluating architectures, an architect can identify deficiencies within the architecture and take corrective actions to mitigate them. These deficiencies can be qualified as

  • Deficiencies in Software Artifacts — Things like code coverage, technical debt, complexity analysis, SUT metrics, etc.
  • Non-Functional Risks — Risks involving non-functional requirements like data integrity, availability, scalability, security, etc.

Software artifact-based deficiencies are well-studied. However, with distributed systems becoming a norm and the criticality of non-functional requirements, we will focus on the latter.

The standard mechanism of performing architecture risk analysis is to quantify the risk from both an impact and a likelihood perspective.

The overall risk is calculated as the cross-product of the impact and the likelihood. The overall risk can then be quantified as a range.

As an example, consider the case of a database becoming unavailable. This would have a high impact on the application. However, since the database runs on highly available servers in a clustered configuration, the likelihood of it happening is low. Hence, in this case, it would be deemed as low risk(3*1=3). Similarly, the architect can create a risk matrix for the different components within an architecture.

Diverse Knowledge

A large part of the value of an architect is a broad understanding of technology and having the ability to apply that to solve particular problems. An architect is expected to be aware of multiple ways of solving a problem, rather than being aware of just one specific way. Hence for architects, breadth is more important than depth. However, at the same time, she is also expected to have depth in certain areas. The way to incorporate knowledge as one progresses from a developer to an architect is to have T-shaped learning. There are certain pockets of excellence coupled with a wide breadth of knowledge to draw upon when solving problems.

It isn’t easy to outline a sundry list of things to know. However, here are a few that highly skilled architects possess as part of their arsenal.

  • Fallacies of distributed computing
  • The 12-factor app
  • CAP theorem/FLP Proof/ 2 General Problem
  • Atomic Broadcast/Consensus algorithms — RAFT/Paxos/ZAB
  • Consistency Models — Strong(Linearizable), Eventual, Consistent Prefix, Read Your Writes, Monotonic Reads
  • Queueing Theory and the Universal Scalability Law
  • Promise Theory — its main contribution to a microservices architecture is the ability to move away from the concept of the obligation of communication, where both sender and receiver are dependent on each other and must be active during communication, towards the idea of promises. Promises concept postulates autonomy and independence of the systems and services collaborating as part of a distributed system.
  • Unix Philosophy — The core idea of UNIX Philosophy is that every program should do one thing well and collaborate with other programs through well-defined interfaces.

--

--

Maneesh Chaturvedi

Seasoned Software Professional, Author, Learner for Life