Software architecture is specifically the fundamental organization of a system, embodied in its components and their relationships.

Quote

Senior engineers think in systems.

Primary dimensions here include:

  • The structure of components, subsystems, modules, their communication as well as any non-functional requirements.

Levels of abstraction are a good thing in software architecture. They allow us to identify commonalities and de-duplicate.

Monoliths Vs Microservices

Monoliths contain one software project that contains functionality. There is a module structure and some amount or organization in the system but it is one deployable unit. Communication between different parts of the monolith are just in-memory or use an internal API.

A microservices architecture is one where deployable units work together via network communication.

In general, start with a monolith and break things off into microservices if this proves valuable.

Pitfalls of Over Engineering

  1. Excessive network calls:
    1. networking is slow and has unpredictable delays since each network call has fixed overhead.
    2. many small calls are often slower than one larger call, even with parallelism and async
    3. payload size matters too
  2. Bottlenecks
    1. This can occur if your architecture has you repeatedly accessing the same data or system.
  3. Over-taking Responsibility
    1. Have a clear separation of ownership so that work is evenly distributed across your system. For example, the backend doing work that should be done on the frontend
    2. Sometimes this is an organizational result
    3. This could cause tech-debt that people don’t want to touch
  4. Too much waiting
    1. Moving to an async model is valuable in reducing perceived waits
    2. It is better to return partial results and fill them in, then everything all at once if that takes longer

N+1 Query Problem

One query to fetch a list, N queries to fetch related data. This makes the query count explore and latency compounds. This is usually a design bug.

ORMs and GraphQL can silently introduce this.

Always inspect generated SQL and query count profilers.