Architecture and Design 2:
– Intro to Software Architecture – Design Docs
Architecting
We always decompose large systems into smaller sub- systems/components to manage complexity: divide and conquer
Each component provides some set of related services.
An important part of software architecting is designing the global organization of the software system. We:
partition the system into components, decide how these will interact, determine their interfaces
All architecture is design and so our general design principles guide our architectural decisions.
The focus here is on the interfaces and not the internal designs of the components.
COMP3297: Software Engineering 2
Design Principles apply in obvious ways
Separation of Concerns
Divide the application into distinct areas of functionality with as little overlap as possible. Minimize the points of interaction between the areas. If separated on good boundaries, the result will be high cohesion and low coupling.
Single Responsibility Principle
Each component should be responsible for a single, specific logical area of functionality.
Information Hiding (Principle of Least Knowledge)
A component should not rely on internal details of other components. Rely on stable interfaces – coherent abstractions that change slowly
No Duplication (DRY)
Specific functionality should be implemented in only one logical module. May
duplicate the physical components for scalability, availability, etc.
COMP3297: Software Engineering 3
YAGNI and no BDUF (Big Design Up Front) ??
Does that mean we don’t do architectural design until some issue arises that requires it? What about documenting the design decisions when we’ve made them?
Agile Process limits planning and minimizes documentation, but it still recognizes they are valuable. You need to plan and describe the overall structure of the system and the decisions that led to it. And you need to do it early.
The whole team needs to understand the architecture and why that architecture was selected.
Rather than the traditional “single architect” approach, all developers should have input into the architecture. They all should understand the main drivers and trade- offs involved in the architectural decisions before implementing the product. The architecture needs to be described as a reference for implementation.
A Design Doc is a good place to describe the architecture
Architecting in Agile Process
COMP3297: Software Engineering 4
Design Docs
Get in the habit of writing a design doc for any major piece of work you plan to do. This includes your personal projects.
Most good software engineers write a design doc before designing and implementing a feature. Code monkeys tend not to.
At Google, pretty much every project or major feature has a design doc, even small or speculative projects. An approved design doc is usually required before a team starts work on any major project
The design doc outlines the problem and why it is worth solving. You lay out your plan for solving it: outline design alternatives, describe your solution, and explain why you chose that solution.
A design doc is like a combination of:
o a small-scale Vision document, and o a Technical Memo
COMP3297: Software Engineering 5
Technical Memos
6
Writing Technical Memos for smaller issues is also a good habit.
In all fields of engineering, it’s common to write Technical Memos to summarize technical decisions and to record why a particular solution was chosen.
(See sample on Moodle – in the Samples section.)
Quoting from the sample:
o They are particularly useful in agile development where there is no comprehensive design documentation.
o If the issues covered by Technical Memos are chosen well, then a small set of brief memos can stand in place of more extensive traditional documentation – they provide details where they are needed without the overhead of documenting everything.
o Agile development focuses on working code, but many important technical details cannot be discovered simply by reading code. For example, the code can’t tell us how particular design decisions were made, why one solution was chosen while others were discarded, what general approach is represented by the design of the solution, or what flexibility has been provided for future extension of the product.
That is the type of information we record in memos.
COMP3297: Software Engineering
Why are design docs popular
o They summarize your thinking and serve as an invitation for discussion and collaboration. A sort of “code review before the coding”.
o Certainly a way get feedback and resolve issues before committing to a design. Can be a way to get buy-in from colleagues. Ensures all concerns are covered.
o They can be updated with results, outcomes as development continues, and form a complete record of the history and success/failure of a project. It becomes the story of the project.
o Helps make a project visible and gets it launched faster.
o Can serve as documentation for another engineer to get up to speed with the project. It’s a permanent record of why things are the way they are – very useful if the author leaves.
o Forces you to think about project issues in detail before you start. Helps “solve the problem right”.
COMP3297: Software Engineering 7
Design doc format
o Often created with a tool like Google Docs to encourage collaboration.
o No standard format for the document. Company and individual style varies a lot.
o Take a look at Python Enhancement Proposals (PEPs). Quite similar to very focused design docs and can give an idea of a general layout for highly technical issues.
o See, for instance:
https://www.python.org/dev/peps/pep-0613/ (a short one) https://www.python.org/dev/peps/pep-0589/ (a long one)
COMP3297: Software Engineering 8
Design doc format
9
For more general cases, we’ll usually begin with:
o Overview of the document. (It’s the Abstract in PEPs)
o Summary of the problem in context/ Motivation
o Objectives (may include user goals) and success criteria o Proposed Solution/Technical Architecture
o Models and/or Prototypes to detail the solution
o Alternative Solutions and their pros and cons
o Expected Impact – costs, side-effects, vulnerabilities, …
And then keep it live by adding relevant details as development progresses.
COMP3297: Software Engineering
Architectural Drivers: Architectural Characteristics/ Non-functional Requirements/ Quality Attributes
All three names are commonly used and refer to the same type of property of a system.
Architecture has a fundamental influence on these properties
Since they are critical to the success of the system, they are critically important for the choice of architecture.
COMP3297: Software Engineering 10
Architectural Characteristics: (Examples we’ll use later)
Operational Characteristics
Performance Reliability Scalability
Elasticity
Fault tolerance …
Structural and Process-related
Modularity Modifiability Deployability
Characteristics
Simplicity Testability …
Cross-cutting Characteristics
Cost
…
COMP3297: Software Engineering 11
Availability Recoverability Safety Robustness Configurability Reusability Portability Accessibility Archivability Legality Privacy Security Usability
Everything in architecture is a trade-off.
Architectures can’t support all architectural characteristics. Impossible to optimize everything.
Characteristics impact each other. Examples:
Modularity vs. Performance
Security vs. Usability and Performance Availability vs. Cost
Decide on compromises to create a “good enough” solution. Build the “least bad” architecture.
COMP3297: Software Engineering 12
Example: Architectural Partitioning
Top-level partitioning for monoliths (a monolith has a single deployable unit containing all code). The top-level partitioning supported by an architecture has a big influence on the components identified by the architect who selects it:
code code
code code
Layer
Layer
code code
code code
Layer
code code
code code
Database
Layered Monolith
Database
Modular Monolith
COMP3297: Software Engineering
13
Which is better?
Technical Partitioning
Since everything is a trade-off, the answer is “it depends”.
First, need to know the approach to partitioning for each style.
The first style partitions around technical roles. Components are grouped by their technical role in the architecture.
Organizing principle is separation of technical concerns. Result is useful decoupling.
In the simple layered style, all persistence code is one layer, all business logic is in another, all presentation logic is in another, etc.
COMP3297: Software Engineering
14
Presentation
Business
Persistence
Database
Domain Partitioning
The second style partitions around decoupled domains or workflows within the overall problem domain.
Each major component may use technical layering internally, with its own persistence layer, business layer, etc., but the top-level partitioning is around domains.
Cart
Accounts
Orders
Inventory
Billing
Shipping
COMP3297: Software Engineering
15
Database
Technical vs. Domain Partitioning
Technical:
• Easy to understand, easy to find code related to each technical capability
• Easy for specialist teams to work in relative isolation on their layer
• But real workflows cut across capabilities – a feature change requires all teams to be involved and coordinated.
Domain:
• Easy to find code related to a particular feature.
• Partitioning better supports the kinds of changes that occur in real-world projects. More common to add or modify a feature than a technical layer.
• Easier to build cross-functional teams around domains.
• Easier to migrate from monolith to a distributed architecture.
COMP3297: Software Engineering 16
Monolithic or Distributed
For Domain Partitioning, the trend has been away from a Modular Monolith towards a Distributed Architecture.
Rather than a single deployable unit that includes all functionality, Distributed Architectures spread it over multiple deployment units, each running in its own environment and communicating through networking protocols.
COMP3297: Software Engineering 17
Trade-offs
Technical Partitioning or Domain Partitioning feature in two of the most popular architectural styles in general use.
Layered Architectures Microservices Architectures
Can get a better idea of architectural trade-offs, say between:
Monolithic vs. Distributed Architectures, and Domain vs. Technical Partitioning
by examining the two styles:
COMP3297: Software Engineering 18
Layered Architecture
19
Such a simple architecture and so well-known by all developers it is almost a default style. If a team just begins executing sprints without designing an architecture, but pays attention to design principles, they will often end up with a Layered Architecture.
Major components are coarse-grained packages arranged in a layered hierarchy. Lower layers provide low-level and general services. Upper layers are increasingly application specific.
Keep coupling low by allowing collaborations and dependencies only from higher layers to lower layers. No dependencies from lower layers onto higher layers.
Goal is to isolate layers from changes made in other layers as far as possible.
As we saw in the components of the Modular Monolith, layering is often
used to structure components in other architectural patterns.
COMP3297: Software Engineering
If they don’t pay attention? BBOM antipattern.
Shows information to the actor and interprets user requests.
Combined in small systems
Application/ Services
Domain/ Business
Exposes services the application provides. Manages business transactions. Delegates to and coordinates domain objects
Business concepts and information, business rules. The core functionality of the application
Sometimes called Resource Layer, Infrastructure Layer, or simply Data Source or Persistence Layer. Business Layer components access data through generic interfaces
What Layers?
Many variations. Enterprise architectures commonly feature these four layers. Any dependencies are on simple layer APIs:
Presentation
Data Services
COMP3297: Software Engineering 20
COMP3297: Software Engineering
21
Framework services that cut across layers are not considered part of the hierarchical layering
Physical Layering – Deployment
Layers may all be on the same physical tier (as a single deployment unit – all on a single server) or on separate tiers. Small applications may include the database layer in the deployment unit if it is embedded or in-memory.
Physically separating layers also comes with trade-offs. For example, it can improve scalability and resiliency, but adds latency.
COMP3297: Software Engineering 22
Layer Isolation Trade-offs
The layering is typically strict, where a layer can only call the next layer below. Access to other layers is closed.
This limits dependencies and, therefore, the effects of change. But there is unnecessary latency if many requests are simply passed onwards through tiers.
Layering may be relaxed, where a layer may call more than one layer below it. Bypassed layers are viewed as open.
This eases the latency problem, but now more difficult to modify safely because layer isolation is compromised and dependencies are less limited.
COMP3297: Software Engineering 23
Layered Architecture. Intended Benefits
Dependencies reduced such that changes don’t ripple through the entire system
Good separation of concerns – e.g. application logic is not bound up with presentation logic. Can use the application logic with a different UI or distribute it to another processing node
Infrastructure (data services) not tied up with application logic. Can reuse the services or replace them with a different implementation
Easy to work with any area in relative isolation.
Simple to test a layer independently, with dependencies provided by a mock layer.
COMP3297: Software Engineering 24
Support for Architectural Characteristics:
Basis for selecting a Layered Monolithic Architecture 1
Characteristic
Degree of Support
Performance
Low/Medium
Reliability
Medium
Scalability
Low
Elasticity
Low
Fault Tolerance
Low
COMP3297: Software Engineering 25
Closed layering introduced unnecessary indirection Poor support for processing in parallel
Low network involvement. But testing often incomplete and deployments are large and risky.
Limited by the monolithic structure and lack of fine scale modularity. The deployment unit is large.
Difficult to isolate failure – defect can cause entire application to crash. Recovery is typically slow (minutes) due to time required to restart the monolithic application..
Support for Architectural Characteristics:
Basis for selecting a Layered Monolithic Architecture 2
Characteristic
Degree of Support
Modularity
Low
Modifiability
Low
Deployability
Low
Simplicity
Good
Testability
Low/Medium
Low Cost
Good
COMP3297: Software Engineering 26
Only emphasised at the coarse scale of the layer.
In reality, changes tend to involve many layers. Coupling tends to spread within a layer which, in turn, limits flexibility. Difficulty in testing impacts ease of change..
Deployments are big efforts. Small changes require complete deployment. Typically bundled because of the effort, so risk of failure is high.
Can mock the layer dependency, which is good. But amount of testing required for even a simple change makes it impractical to test everything that should be tested.
Distributed Architectures
Distributed Architectures are a better match than Deployment Monoliths for current approaches to software development and deployment:
Agile development requires each increment to be potentially releasable. The trend is towards deploying every change directly into production when it is done.
The industry is steadily moving away from Software as a Product (SaaP) models to Software as a Service (SaaS) where the service runs on Internet- based servers, now mostly Cloud-based virtual servers, and is accessed by users through a browser.
Moving to the cloud increases the importance of various architectural characteristics that are not supported well by Monolithic Architectures:
• Scalability
• Elasticity
• Resilience (as earlier, a combination of characteristics that contribute to the ability of service to be maintained in the event of failures)
COMP3297: Software Engineering 27
Microservices Architectures
28
In Architecture, the most important decision is how to decompose a system into components such that the system will have the required architectural characteristics.
For Scalability, Elasticity and Resilience, components must be:
• easy to replicate,
• easily run in parallel, and
• easy to move between virtual servers.
Led to a rapid rise in popularity of decomposing into independent stateless software services that persist their own data locally.
Each service represents a single domain responsibility. The goal is for very low coupling such that replacing or replicating a service should not require changes in other services.
Each service runs in its own separate process and can be deployed independently, usually in its own container. Cloud and container technologies make it feasible for each service to have its own infrastructure without needing to share anything.
COMP3297: Software Engineering
Optional. Can provide the specific, perhaps coarser-grained, API that the client needs, rather than depending directly on the Microservices’ APIs. Also allows repartitioning of services without affecting clients..
Each Microservice provides a fine-grained API through which it exports its services.
Replication requires mechanisms to ensure data across replicas becomes “eventually consistent”.
COMP3297: Software Engineering APIs. But keep to a minimum..29
Microservices can access other services through their
How “Micro”?
There was a trend for some developers to make their microservices very small. But if the result is that the services need links to other services and many interservice calls to deliver something of value, then they are likely too small.
Guidelines:
• Each microservice should be functionally cohesive. “Common closure” – things that are likely to change together should be packaged in the same service.
• Try to avoid needing to build transactions across microservice boundaries.
• Don’t split cohesive services if they will then require a lot of inter-service
communication to execute a workflow.
• Each service manages its own data. Isolate data with the minimum of sharing. Where sharing is unavoidable, make it read-only wherever possible.
Typical scope of services for an online store:
Order Management
Service
Inventory Service
Product Catalog Service
COMP3297: Software Engineering 30
Delivery Service
…
Partitioning the Domain Model
Each Microservice encapsulates only the part of the system-wide Domain Model that makes sense for its service.
Fat, complex classes with many attributes in a universal model (Employee, Customer, Patient, Student, etc.) are split across Microservices which each deal only with attributes of interest and are not affected by change in others.
Customer
Bonus Program Num …
Order
Customer
Delivery address Alt. address
…
Delivery
Customer
Billing address …
Billing
COMP3297: Software Engineering
31
Refactoring to a Microservices Architecture
This architecture is a good choice if you are facing particular problems it solves. Otherwise, the added complication associated with building and maintaining a distributed solution can’t be justified.
Typically, the problems that the architecture solves won’t be present when first creating the system. Since the architecture is complicated, building microservices from the start will slow down initial development. YAGNI
A useful approach is to develop the system first as a monolith. Then, when you find that certain functionalities evolve at different rates or need to be scaled more frequently than others, refactor them into microservices.
This will enable those functionalities to be modified and deployed rapidly and frequently. Experience with the monolith will clarify the boundaries and dependencies of each microservice required.
COMP3297: Software Engineering 32
Benefits – in addition to those already highlighted
Good maintainability at the level of the service – services are small.
Easier to resist creating unnecessary dependencies – it is a carefully considered decision to depend on another service.
Easy to replace services.
Teams can work on services they are responsible for, independently of other teams.
Services are isolated from problems in other services which could bring down an entire monolith. Failure should not propagate.
Free choice of technology stack for each service. Easy to switch.
COMP3297: Software Engineering 33
Challenges
o Increased complexity in the system as a whole
o Calls to and between Microservices go via the network and suffer from
all associated issues.
o The system needs to be robust in the face of unreliable communication and partial failure.
o Client requests that involve multiple services can involve multiple teams and require careful coordination to implement.
o Possibly too much freedom in choice of technologies – refactoring within a Microservice is easy, refactoring across several Microservices and moving functionality can be difficult if they use different tech.
o Good decomposition is necessary for team independence with respect to requirements. And overall success depends on it. Need to get it right.
COMP3297: Software Engineering 34