What is Software Architecture?

--

All characters and events described in this post are entirely fictitious. Any similarity to actual events or persons, living or dead, is purely coincidental.

If someone asks you this question — “What is software architecture?” — what would you answer? Why can’t you just sit down and start writing code to implement your idea? Or can you? Why would anyone invest the time, money, and effort into creating a bunch of diagrams and documents?

You might be thinking that I am asking rhetorical questions. Hardly so. One day, just for curiosity’s sake, I asked the engineers on my team:

“Hey guys,” I said after we wrapped up one of the meetings. “If I ask you to define the term software architecture for me, how would you do this?”

Tom — one of the engineers — said quickly:

“Architecture is a process of creating a structure for a software project”. Tom looked around the room as if he just earned a free lunch.

Tom’s definition was almost straight from Wikipedia… here is how it has it: Software architecture refers to the fundamental structures of a software system and the discipline of creating such structures and systems. The definition is hard to argue with, but it isn’t really explaining much.

“Well…” I cleared my throat, “Why do you need to create a structure for your project?”

That got him thinking.

“I guess to create a plan, break down the project into tasks…” Tom was no longer certain about that free lunch.

“To review the plan and ensure it is solid,” Jerry — another engineer — suggested.

“To ensure flexibility of the solution,” another suggestion came up.

I pressed on:

“Why do you need a plan? What are the tasks for? Why review the plan? Why is flexibility important?”

It took another 15 minutes of digging until we got somewhere:

“To improve velocity of development”

“To reduce costs”

“To make software maintainable”

What do you think? What is software architecture, and what is its purpose?

Software architecture is a series of decisions intended to reduce the cost of building and changing your software.

Think about it. When you are building a software solution, it is usually intended to address a business need. The more time you spend building it, the higher your engineering costs are. The longer your time-to-market, the higher the business risks and the cost of lost opportunities. Once your solution is built and deployed, your business is likely to face a need to extend or change the software further, to optimize your sales funnels, to expand the addressable market segment, to continue innovating, and to adjust for ever-changing market and legal conditions. Such changes go far beyond the original plan for the system and are impossible to predict. Eventually, you will be facing the challenge of changing your system in ways you never anticipated. But despite the unknowns, there are certain principles of software construction which help reduce the cost of the planned software development, as well as minimize the negative impact of the future changes. Such principles, once applied to a particular application, are usually referred to as software architecture.

Let’s be clear: most architectures stink to high heaven. Just learn to read between the lines. When a company rolls out version 2.0 of their software, and announce that this new version “was rebuilt from the ground up”, it actually means “well, we failed getting it right on the first try”. When the same happens with 3.0, it means “oops we did it again”. And again. And again.

This is not to say the companies don’t know their business. They know very well which functionality must be delivered to their customers. If they don’t, then there will be no version 2.0 — but most are fully capable of defining their functional spec, and of building the software software implementation for it. All engineering teams know the importance of architecture, and they take time to create and document their approach to implementing the functional spec. Then they follow the plan and roll out the version 1.0. A year later, they rewrite everything, or bear an unreasonably high cost of maintaining their original creation. If the original system is not rewritten in the first 3 years, the new hires start calling it “legacy system”. If the legacy system remains in place for more than 5 years, it is unlikely to be ever replaced, because very few companies have the budget to re-invest 5 years of coding. Unless the legacy system represents an existential threat to the business, it stays.

All of this is happening because engineering teams diligently build against the functional spec, but more often than not ignore the non-functional requirements.

In order to explain this, let’s take a detour, leave the all-familiar software engineering domain, and consider how automakers build their cars.

A car must meet the drivability requirements, such as maximum speed, fuel consumption, handling, acceleration, safety, etc. But this is only a tip of the iceberg, as the engineering work for cars goes much further. First, the car should be maintainable by third parties, such as independent mechanics and dealerships. Second, it should be easy to swap replacement parts by independent body shops. Third, the car should be quick and inexpensive to assemble, which is achieved through proper architecture of the assembly line. Fourth, the assembly line must ensure consistent quality, largely achieved by the processes and equipment which eliminate or limit human errors and make the errors easily detectable before the car leaves the factory. Fifth, the assembly lines are designed to quickly switch from one car model to another, allowing an automaker to quickly respond to changing market demands.

No surprises there, right? Then why aren’t we thinking the same way about software? For some reason, many of us think that collecting the functional requirements for a software product or service and building a system around those requirements is all it takes. But then — drawing a parallel with an automaker — we build a car that is drivable, but the kind of car that is tedious and expensive to produce, impossible to fix, and which next-generation model would have to be redesigned from scratch. Then we suffer for years, seeing how our ability to innovate and adapt slows down to a crawl. Teams and managers change, and finally someone proposes a radical fix — a “rewrite”. A few more years, and the new management makes a daring decision to put an end to the pain and suffering and approves the “rewrite” budget (it has to be new management, by the way, for the obvious reasons). The engineers get all excited at the opportunity to fix everything that went wrong, and they take off on the crusade of re-architecting everything… only to make the same mistakes all over again. They create a new, expanded functional spec, and they leave the non-functional requirements out. The vicious circle continuous… unless the business dies and puts an end to everyone’s misery.

This cycle is so commonplace that I met scores of young developers who never saw anything but this wasteful and reckless way of building technology, which makes it the new norm.

I hope I convinced you that architecting against a functional spec for the final sellable product or service isn’t nearly enough. It doesn’t address the main purpose of the software architecture in the first place. It does quite the opposite — instead of reducing the cost of future changes, an architecture that is based purely on a functional spec (or the lack of thereof) frequently necessitates future changes.

Over the years, I compiled a laundry list of non-functional topics which must be considered as a part of software architecture, in addition to the functional requirements specific to your business. The list is hardly exhaustive, and I encourage you to expand it (and post your thoughts as comments). Here it is:

  • Programming languages, their features, readability, and interoperation
  • Code reuse across platforms (server vs web vs mobile)
  • Early error detection (compile-time vs runtime error detection, breadth of validation)
  • Availability and cost of hiring the right talent; learning curve for new hires
  • Readability and refactorability of code
  • Approach to code composition, embracing the change
  • Datastore and general approach to data modeling
  • Application-specific data model, and the blast radius from changing it
  • Performance and latency in all tiers and platforms
  • Scalability and redundancy
  • Spiky traffic patterns, autoscaling, capacity planning
  • Error recovery
  • Logging, telemetry, and other instrumentation
  • Reducing complexity
  • User interfaces and their maintainability
  • External APIs
  • User identity and security
  • Hardware and human costs of the infrastructure and its maintenance
  • Enabling multiple concurrent development workstreams
  • Enabling testability
  • Fast-tracking development by adopting third-party frameworks

By considering every item on the list early, we have a chance to make fundamentally correct choices for our future architecture. Ideally, your engineering team should have an answer to every item on that list before a single line of code is written.

Clearly, many answers come with experience. Good architects are not born, they are made by decades of relentless work, by gaining hands-on experience in various industries, and by continuously staying on the bleeding edge of technology. If you have an aspiration to become a great architect, but have no patience to wait until your hair turn silver, grab my new book Become an Awesome Software Architect. It is a highly practical guide to building modern architectures, packed with actionable advice. The book will save you tons of time, and will spare your business a lot of risks — while saving $$ upfront and in the future.

I’d love to hear your thoughts; looking forward to reading your comments!

--

--

Anatoly Volkhover
Become an Awesome Software Architect

Serial entrepreneur, dynamic engineering leader, software architect extraordinaire, marketer, and writer. https://www.linkedin.com/in/anatolyvolkhover