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
-
We are going to miss transactions!
-
Possible mitigation: Idempotent retries
-
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
Image source: https://martinfowler.com/bliki/CQRS.html
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
Further readings: https://redux.js.org/introduction/core-concepts
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
- Fundamentals of Software Architecture: An Engineering Approach
-
Software Architecture: The Hard Parts
-
Building Evolutionary Architectures
Video Trainings
- Software Architecture video training series
Software Architecture Introduction
By Rainer Stropek
Software Architecture Introduction
- 383