Software Architecture

Rainer Stropek | rainer@software-architects.at

Introduction

Role of Software Architects has changed

  • Previously: Only technical aspects of architecture
  • Today: Intersection with many other aspects
    • Integration patterns
    • Engineering practices (e.g. Scrum, XP, Kanban)
    • DevOps
    • CI/CD
    • Cloud computing
    • Artificial intelligence
    • Team organization
    • Soft skills
    • ...

Role of Software Architects has changed

  • The only constant is change!
  • Rapidly evolving software development ecosystem
    • New/improved languages
    • New/improved frameworks
    • New/improved data storage systems
    • Low code movement
    • Generative AI
  • Software architects must evolve
  • Patterns and habits must regularly be questioned

What is Software Architecture?

  • Description of a system's structure
    • Architecture style (e.g. Microkernel, Microservices, Layered, etc.)
  • Description of a system's characteristics ("-ilities")
    • E.g. Availability, Reliability, Testability, Scalability, etc.
  • Description of a system's architecture decisions
    • How should the system be built?
    • Constraints that guide the development teams
  • Description of a system's design principles
    • Guidelines for development teams
    • Example đź”—

Software Architects' Tasks

  • The exact responsibilities of software architects vary depending on
    • the organization (e.g. structure, culture)
    • the project's nature (e.g. scope, complexity)
    • the project's requirement (e.g. business domain)
    • regulatory requirements
    • resource availability
    • team skills and dynamics
    • outsourcing strategy

Software Architects' Tasks

  • Establish Architectural Foundations:
    • Define and make critical decisions on software structure and design to fulfill business requirements and objectives.
  • Conduct Architecture Analysis:
    • Regularly evaluate and reassess the architecture to ensure it meets the project’s evolving needs and identifies any areas of improvement or refinement.
  • Stay Abreast of Industry Trends:
    • Keep informed about the latest technological advancements, methodologies, and best practices in software development and architecture.
  • Maintain Architectural Integrity:
    • Uphold and enforce compliance with the established architectural decisions and standards throughout the development process.

Software Architects' Tasks

  • Cultivate Diverse Skills and Experience:
    • Develop and maintain a wide range of technical skills and experiences across different platforms, technologies, and domains.
  • Develop Business Acumen:
    • Acquire extensive knowledge of the business domain to ensure that the software solutions are aligned with business goals and values.
  • Foster Effective Communication:
    • Utilize strong interpersonal and communication skills to convey complex technical concepts and facilitate collaboration among team members.
  • Navigate Organizational Dynamics:
    • Understand and maneuver through the political landscape of the organization to advocate for architectural goals and mitigate any conflicting interests.

Software Architects' Tasks

  • Lead and Mentor:
    • Provide leadership and mentorship to development teams, fostering an environment of learning and continuous improvement.
  • Risk Management:
    • Identify and assess potential risks related to architectural decisions and propose mitigation strategies to manage them effectively.
  • Define Non-Functional Requirements:
    • Establish requirements related to usability, scalability, performance, and security to ensure the creation of robust and reliable software solutions.
  • Vendor Interaction and Evaluation:
    • Interact with vendors, assess their products and services, and make recommendations based on the project’s needs and constraints.

Software Architects' Tasks

  • Integrate Solutions:
    • Design systems that facilitate the seamless integration of various components, services, and technologies.
  • Stakeholder Communication:
    • Engage with stakeholders to gather requirements, communicate architectural decisions, and ensure alignment between technical and business objectives.
  • Innovation and Research:
    • Research new technologies, methodologies, and tools, and innovate to improve the architecture and development processes.
  • Quality Assurance:
    • Work closely with quality assurance teams to define testing strategies and ensure the delivery of high-quality software.

Software Architects' Tasks

  • Budgeting and Cost Management:
    • Assess and plan for the financial aspects of the project, managing resources efficiently to stay within budget.
  • Sustainability and Environmental Impact:
    • Consider the environmental implications of architectural decisions and aim for sustainability in design and implementation.

What makes a good architect/architecture?

Adaptable

  • Nothing remains static
  • Architecture must survive
    • implementation
    • changing requirements
    • change of software ecosystem
  • Driven by requirements and additional concerns
    • E.g. Performance, Security, Scalability
    • Aka non-functional requirements
  • "Fitness functions" used to assess the integrity of the architecture
    • E.g. tests, telemetry, chaos engineering, etc.

Everything in software architecture is a trade-off

If you think you found a solution that isn't a trade-off, you have missed something

"Why" is more important
than "how"

Hard to Google,

AIs can be of help

Modularity

  • Software architects talk a lot about modularity
    • Splitting up a large system into modules or components
    • Goals: Reuse of code, keep related code in one place
  • Modules do not need to be physically separated
    • Can also be a logical separation (e.g. namespaces)

Coding Architect

  • Waterfall is an anti-pattern
    • Architect creates architecture
    • Hands it over to developers
    • Organizational boundary between them
  • Understands business drivers
  • Architects should have broad knowledge đź”—
    • Not an expert in one particular area
  • Architects can code
    • Maybe not as hands-on as developers
    • Beware of "bottleneck trap"!

Architectural Characteristics

  • Operational
    • Availability
    • Continuity
    • Performance
    • Recoverability
    • Reliability/safety
    • Robustness
    • Scalability
  • Structural
    • Configurability
    • Extensibility
    • Installability
    • Reusability
    • Localization
    • Maintainability
    • Portability
    • Supportability
    • Upgradeability
  • Cross-Cutting
    • Accessibility
    • Archivability
    • Auth
    • Legal
    • Privacy
    • Security
    • Usability

Microkernel Architecture

Case Study

Microkernel Architecture refers to a software design pattern that emphasizes separating a minimal functional core from extended functionalities and features.

It's often used to create highly modular and extensible applications.

Characteristics

  • Minimal Core
    • A small, isolated core containing the essential functionalities
  • Plug-in Modules
    • Additional components that extend the core functionality, acting like plugins
  • Loose Coupling
    • The core and the plugins are independently deployable and can evolve separately
  • High Cohesion
    • Related functionalities are kept together in plugins.

Components

  • Core System
    • The central component managing the primary functionalities and coordinating the plugins
  • Plugins
    • Modules that add specific functionalities and features to the core system
  • Communication Mechanism
    • Allows interaction between the core system and the plugins.

Structuring the Microkernel 

  • Layered Approach, example:
    • Interface Layer - Exposes APIs or contracts for plugins to interact with the core
    • Business Logic Layer - Contains the core functionality and business rules of the application
    • Data Access Layer - Manages interactions with data storage and retrieval mechanisms
  • Bounded Context Approach

    • Core Context - The central domain, containing the essential business logic
    • Supporting Contexts - Surrounding domains (e.g. notification, reporting etc.), usually implemented as plugins, supporting the core context with additional functionalities and features

Benefits

  • Flexibility
    • Facilitates modifications and extensions without affecting the core system
  • Maintainability
    • Easier to maintain due to the modular design and separation of concerns
  • Scalability
    • Supports the addition of more plugins to meet growing needs
  • Resilience
    • The failure in one module does not necessarily bring down the entire system

Challenges

  • Complexity
    • Management of plugins and their interactions can get complex
  • Performance Overhead
    • Additional layers can introduce latency and affect performance
  • Dependency Management
    • Proper handling of dependencies between plugins is crucial

Testability - Plugins

  • Unit Testing
    • Tests individual components/functions within the plugin
    • Validates that the plugin meets its specified requirements
  • Integration Testing
    • Ensures that the plugin integrates well with the core system and other plugins
    • Ensures that interactions between plugins and the core system adhere to their defined contracts.
  • Plugin Isolation
    • Mocking Core System - Use mocks to simulate the core system behavior during plugin testing
    • State Isolation - Test each plugin in isolation to ensure it does not rely on global/shared state
    • Data Isolation - Provide each plugin with its own test data to avoid conflicts and dependencies

Testability - Good Practices

  • Design for Testability
    • Structure plugins with testing in mind from the beginning
  • Keep it Simple
    • Simple, well-structured, and cohesive code is easier to test
  • Maintain Documentation
    • Well-documented contracts and behaviors aid in the formulation of test cases
  • Regular Refactoring
    • Continuously improve the codebase to maintain high levels of testability

Microservices Architecture

Case Study

What is the Microservices Architecture Style?

  • Distributed architecture
  • Inspired by DDD
    • Concept of the Bounded Context
  • Tight coupling within the bounded context
    • Shared classes, common database, etc.
    • A change in one module usually forces a ripple effect of changes in other modules
  • Loose coupling between bounded contexts
    • Components have little or no knowledge of the definitions of other components
    • Each Microservice includes all necessary parts (incl. data isolation)
    • Microservices operate independently, can be scaled independently, are isolated from each other, etc.

Bounded Context

What are Microservices?

  • Small, autonomous services working together
    • Single responsibility principle applied to SOA
    • See also concept of Bounded Context
  • Best used with DevOps and continuous deployment
    • Enhance cohesion, decrease coupling, enable incremental evolvement
  • How small are Microservices?
    • It depends (e.g. team structure, DevOps maturity, etc.)
    • “… one agile team can build and run it”, “… can be rebuilt by a small team in two weeks”
    • Find an individual balance
  • Autonomous = deploy changes without affecting others
    • Technology- and platform-agnostic APIs

How to identify Microservices?

  • Common purpose
    • One implementation team for one business team
  • Transaction boundaries
    • Data isolation
  • Communication pattern
    • Two components that need extensive communication might be better in a single Microservices
    • Prevent performance and stability problems

Distributed System

  • Each service runs in a separate process
    • Managed service runtimes in public clouds
    • Containers
  • Sidecars/libraries for cross-cutting concerns
    • E.g. logging, circuit breaker, authorization, etc.
  • ⚠️ Drawbacks
    • The network isn't safe or stable
    • Performance implications
    • Implications for testing and troubleshooting
  • Communication patterns
    • Between Microservices, to UI, to outside world
    • Synchronous (e.g. REST API), asynchronous (e.g. queues)

User Interface

  • Monolithic approach
    • Single user interface
    • Calls Microservices via APIs (synchronous, asynchronous)
    • API Gateways
    • All advantages and disadvantages of monoliths
  • Microfrontends
    • UI part of bounded context
    • Owned by Microservice team
    • Technically challenging (quite hard outside of browser)

Why Microservices?

  • Work well in heterogeneous environments

    • Right tool for the job

    • Available skills of team members

    • Grown environment (e.g. M&A, changing policies, changing overall designs)

  • Easier to test/adopt new technologies

    • Reduce risk and cost of failure

    • New platforms (e.g. Node.js instead of .NET), new versions (e.g. .NET Core)

  • Resilience

    • Reduce single point of failures

    • Support different SLAs for difference modules (costs, agility)

    • Separation of services add complexity (e.g. network) -> criticism of Micrservices

Why Microservices?

  • Let people take responsibility

    • Teams “own” their services

    • You build it, you run it

  • Scaling

    • Fine-grained scaling is possible

  • Simplify deployment of services

    • Overall, deployment of many Microservices might be more complex
      -> criticism

  • Composability

  • Ability to replace system components

    • Outdated technology

    • Changed business requirements

Why Not?

  • Harder to debug and troubleshoot

    • Distributed system

    • Possible mitigation: Mature logging and telemetry system

  • Performance penalty

    • Network calls are relatively slow

    • Possible mitigation: Remote calls for larger units of work instead of chatty protocols

  • No strong consistency

Why Not?

  • Harder to manage

    • You have to manage lots of services which are redeployed regularly
      Possible mitigation: DevOps, Automation

  • System is too small

    • For small systems, monolithic approach is often more productive

    • Cannot manage a monolith (e.g. deployment)? You will have troubles with Microservices!

  • Environment with lots of restrictions

    • Microservices need a high level of autonomy

Organization

  • Organizational hurdles for Microservices

    • Tightly-coupled organizations

    • Geographically distributed teams

    • Missing tools (e.g.  self-service cloud infrastructure, CI/CD tools)

    • Unstable or immature service that frequently changes

    • Missing culture of taking ownership (need someone to blame)

    • Problems copeing with many different and new technologies

Any organization that designs a system will inevitably produce a design whose structure is a copy of the organization’s communication structure

Source: Conway, How Do Committees Invent, Datamation magazine, April 1968

Organizational Helpers

  • Co-locate teams

    • One team responsible for a single service should be co-located

  • Embrace open source development style

    • Works internally, too

  • Internal consultants, custodians and trusted committers

    • Quality gateways

    • Servant leaders

  • Step-by-step approach

  • Be clear in communication

    • E.g. responsibilities, long-term goals, changing roles

CQRS, Redux

Case Study

CQRS

  • Command Query Responsibility Segregation
  • Uses a different model to update information than the model you use to read information

Traditional CRUD model

CQRS

CQRS

  • Works very well with
    • Event-based programming
    • Event sourcing đź”—
  • What to consider
    • ⚠️ Eventual consistency
    • Added complexity

Redux

  • Central app state
    • Immutable
  • To change the app, dispatch an action
  • Actions are processed by reducers
    • Apply the action on the app state
    • Returns the new app state

Layered Architecture

Case Study

Introduction

  • Simple, frequently used
  • Horizontal layers
    • Each layer has a specific role in the application
    • Partitioning based on technical aspects, not domain-specific ones
    • Number of layers differ
    • Examples for layers: Presentation Layer, Business Logic Layer, Persistence Layer, Database Layer
  • Separation of concerns
    • Each layer knows as little as possible about other layers

Closed or Open Approach

  • Closed or open approach
    • Closed: Each layer can only interact with the layer directly below
    • Open: Layers can interact with multiple layers depending on the use-case (e.g. no business logic necessary for simple query)
  • Services layer
    • An open layer that all other layers can access
    • Can contain commonly used business objects and logic

Sinkhole Antipattern

  • Requests are passed on from layer to layer unchanged
  • Disadvantages
    • Unnecessary glue code (e.g. DTOs, APIs)
    • Inefficient (runtime, memory management)

Things to read/watch Recommendations

Books

Video Trainings

Software Architecture Introduction

By Rainer Stropek

Software Architecture Introduction

  • 383