What is Software Architecture?

What is software architecture? There have been many definitions. Here’s mine.
First let’s consider some of the earlier definitions. SEI has a huge collection of definitions on its website, including “classic” definitions, bibliographic definitions (stops in 1996?), “modern” definitions, and definitions submitted from the communityPerry and Wolf (1992) have perhaps the most classic definition, though it’s a little sketchy:

Architecture = {elements, form, rationale}

where elements are Processing, Data, or Connecting elements. Taylor et al. (2010) note that when people talk about software architecture in terms of Components and Connectors, that’s an over-simplification of Perry and Wolf’s definition – over-simplified because it doesn’t always work. For example in REST, Data elements are pre-eminent.
The ANSI/IEEE 1471-2000 definition expands on Perry and Wolf’s definition, and also slips environment into the scope of form (relationships).

Architecture is the fundamental organisation of a system, embodied in its components, their relationships to each other and the environment, and the principles governing its design and evolution.

Elements (components) and their form (relationships) are clearly key to understanding what software architecture is, but many people think that’s all it is! Instead, software architecture researchers have understood for a long time that rationale (design/evolution principles) is also a key part of what software architecture is.
But contrari-wise, software architecture is not just rationale. So although Taylor et al. (2010) is a great architecture textbook, their definition of software architecture isn’t so great:

A software system’s architecture is the set of principal design decisions made about the system.

I would instead say that design decisions are the means by which elements, form, and rationale are created. The design decisions are not the architecture per se.
Software architecture is commonly misunderstood to be an exclusively structural model. Perhaps that’s because UML class diagrams and deployment diagrams are often presented as iconic for software architecture. The definition from the Bass et al. (2008) classic textbook also encourages this view:

The software architecture of a program or computing system is the structure or structures of the system, which comprise software elements, the externally visible properties of those elements, and the relationships among them.

But there has been a shift in the software architecture research community to think about architecture more abstractly: in terms of rules or constraints or styles. So instead of “structures”, I prefer using the word “abstractions”, to more easily accommodate a rule-based architectural perspective. The abstractions here are not just of software, but also non-software elements in the system, including the environment. Fielding (2000) also talks about abstractions this way (though for some reason he limits software architecture to run-time, which I don’t agree with):

A software architecture is an abstraction of the run-time elements of a software system during some phase of its operation. A system may be composed of many levels of abstraction and many phases of operation, each with its own software architecture.

Apparently Clements et al. (2010) has another new definition:

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.

Here we have (ignoring “structures” for the moment) Perry and Wolf’s elements and form (relations) again, but now also with properties for each. Perry and Wolf’s rationale has not disappeared, but here appears as a qualifier (“needed to reason about”). I like this. I think the whole point of architecture is abstraction and analysis of a system for particular purposes. Here the “reasoning” objective implicitly encompasses those purposes and analyses.
I’d slightly prefer to say “communicate and reason” instead of “reason”, though perhaps you could say that understanding a communication is-or-requires reasoning. I’d also prefer to talk about “a” (not “the”) software architecture of a system (and similarly “a set” not “the set”), to more readily accommodate multiple views/perspectives of a single system.
So, in summary, my definition would be something like:

A software architecture of a system is a set of abstractions needed to communicate and reason about software in the system. A software architecture models elements of the system and its environment, relations among those elements, and properties of those elements and relations.