My Architectural Philosophy

- - posted in architecture, philosophy, requirements, scale, startup

I was recently putting together a presentation to discuss the architecture of a system, and I found myself wanting to elaborate on the foundational principles that drove my decisions about technologies, deployment topology, domain modeling, service definition, APIs, and so on. The need to focus the discussion on concrete issues ultimately led me to cut those sections, but now I am compelled to write this blog post.

What is architecture in the context of software?

The architecture of software systems is difficult to define pithily. My favored definition comes from a classic paper that introduces the Perry-Wolf Architectural Model Foundations for the Study of Software Architecture.

Software Architecture = {Elements, Form, Rationale}

“Elements are either processing, data, or connecting elements. Form is defined in terms of the properties of, and the relationships among, the elements - that is, the constraints on the elements. The rationale provides the underlying basis for the architecture in terms of the system constraints, which most often derive from the system requirements.”

So much context is required to comprehend this definition that, beyond telling you to go read the paper, this becomes a jumping off point for a lengthy discussion.

It may be simpler to begin with what architecture is not. We do not typically talk about the architecture of functions or methods. So we can agree that architecture does not apply to programming in the small. It should however be noted that architecture is sometimes quite concerned with decisions made in the implementation of specific methods - such as when an algorithmic or data structure choice has an impact on system performance.

This leads back to the first part of the Perry-Wolf definition: the elements in an architecture may be data, processing, or connecting. That sounds like data structures, algorithms, and interfaces (whether they be simple method calls or API endpoints). The elements are where architecture and construction meet. Ultimately we must be able to implement architectural ideas lest we become what Joel Spolsky derisively calls architecture astronauts. There is no doubt there is a danger of attempting to solve a problem that is too abstract and too far removed from actual domain requirements, and I will address the goodness of architecture in the next section.

The form of an architecture is concerned with how elements are organized. My preferred approach to system architecture is to first focus exclusively on the problem domain and produce a Domain Architecture that defines a set of elements without regard to technology. Those elements represent the business domain and have names that the business stakeholders would use when discussing the problems we are attempting to solve. As we add the technology concerns, the organization of the domain objects into components, subsystems, services, etc. produce a form of connected elements to satisfy both the domain requirements and the technical nonfunctional requirements.

The need to balance constraints using judgment based on experience leads to different architects producing different solutions. That is, the elements and form will vary based on an architect’s biases. Two different architectures can both be good, but it is critical that an architect provide the rationale behind the set of decisions leading to a given solution. This is essential to engage the business stakeholders as partners in making the various trade-offs that must be balanced in an efficiently designed system.

What makes an architecture good?

The short answer is that a good architecture balances all of the key system constraints. These include the functional requirements, but also the nonfunctional requirements including budget, availability, scalability, maintainability, and security. Additionally, the need to satisfy regulatory or industry rules can promote some requirements from nonfunctional into functional, as noncompliance can mean significant penalties for the business!

For modern internet-facing web services a typical set of nonfunctional requirements would include ensuring high availability by the use of redundant web/app-tier servers with a replicated database tier. For an early stage startup still looking for product-market fit, this is probably sufficient to ensure 99.99% availability. That may mean triple the cost of a single-node deployment, however, so this is a good example of a business trade-off that needs to be discussed. Is the extra 0.09% availability worth the impact to the burn rate? My bias is toward the additional availability. For most deployments on Amazon AWS today, the triple cost amounts to $200 - $300 additional per month. Hopefully that is a negligible sum for a properly capitalized startup!

Here too we must recognize that the goodness of the architecture may only be defined in the business context. If the business will happily accept minutes or hours of downtime as a new server is spun up to replace a failed one, then the extra cost of the highly available configuration represents resources that may be better spent elsewhere.

To my thinking this is a contrived example, as there are other important factors to be considered - such as the fact that the highly available cluster may be scaled out to many web nodes in minutes. A single node configuration would be much more troublesome at responding to a traffic spike scenario.

Rationale

But the central point is valid. Ultimately the architect’s job is to communicate trade-offs with all of the stakeholders and design a system that balances all of the requirements. Communicating those whys is an essential part of creating a shared metaphor for what the system should be from the technical and domain perspectives. This is especially critical on agile teams where user stories represent thin slices of functionality developed in isolation. That shared metaphor is what fills in the gaps as the team works through the backlog to combine those slices into an effective solution.