Requirements engineering and analysis describe the problem; system design chooses a solution. This companion follows that move: setting design goals from the non-functional requirements, decomposing the system into cohesive, loosely coupled subsystems, and selecting an architectural style whose known shape and trade-offs match those goals. It develops in full the architectural styles and the 4+1 view model that the Chapter 4 companion only previews, and it builds one worked example from design goals through to a justified architecture.
Requirements engineering and analysis answer what the system must do; system design answers how it will be built. The two work on different domains: analysis models the problem, design models the solution.
Between analysis and implementation. Design takes the analysis model (use cases, domain classes, the requirements) as input and produces the subsystem decomposition and architecture that implementation then follows.
Analysis stays in the problem domain: it describes the world the system serves, in the vocabulary of the user. Design moves to the solution domain: it describes the software and hardware that will be built, in the vocabulary of the developer. The same noun can live in both, but it means different things; a Patient in analysis is a domain concept, while a Patient in design is a class with a chosen persistence strategy, an interface, and a home in some subsystem.
| Analysis | Design | |
|---|---|---|
| Question | What must the system do? | How will it be structured to do it? |
| Domain | Problem domain: the world the system serves. | Solution domain: the software and hardware to be built. |
| Output | Requirements, use cases, analysis (domain) classes. | Design goals, subsystem decomposition, architecture, design classes. |
| Vocabulary | Of the user and the domain. | Of the developer: components, layers, interfaces, nodes. |
A design is never judged on functionality alone. The same set of functions can be realised by many structures, and the structures differ in qualities the user never sees directly but always feels: response time, security, the cost of the next change, the effort to test. Design is therefore a multi-perspective activity that weighs these qualities against one another. The non-functional requirements are where most of them originate, which is why design begins by turning those requirements into explicit, prioritised design goals.
System design proceeds in a structured way rather than by jumping to code. The skeleton of the process is short:
The next sections take these in order: first the goals and the two principles that govern every decomposition (cohesion and coupling), then the decomposition itself, then the architectural styles that give a decomposition its recognised shape.
System design is the set of decisions that turn an analysis model into an implementable structure. It is worth naming those decisions, because a design is incomplete until each has an answer.
The two that dominate, and that the rest of this companion develops, are the design goals and the subsystem decomposition (which carries the choice of architectural style and the cohesion and coupling of the parts). The full set of issues a complete system design resolves is:
| Issue | The question it answers |
|---|---|
| Design goals | Which qualities matter most for this system, and in what priority when they conflict? |
| Subsystem decomposition | Into what cohesive, loosely coupled subsystems is the system divided, and in what architectural style are they arranged? |
| Hardware / software mapping | Which subsystems run on which nodes, and how do the nodes communicate? |
| Data management | What data is persistent, and is it held in files, a relational database, or another store? |
| Access control and security | Who may access which data and operations, and how is that enforced? |
| Global control flow | Is control procedure-driven, event-driven, or thread-based across the system? |
| Boundary conditions | How does the system start up, shut down, and handle failure? |
The hardware/software mapping is exactly what the deployment diagram records, and the subsystem structure is what the component diagram records: the two structural diagrams from Chapter 4 are the notation for two of these issues. This chapter concentrates on the first two, where the architectural choices are made.
A design goal is a quality the design must optimise, drawn from the non-functional requirements and from general engineering principles. Goals are made explicit precisely because they conflict, and a design is a defensible set of trade-offs between them.
Three terms are easy to blur, and keeping them apart is what lets a design be checked. A goal is a general, often imprecise and non-verifiable statement of intent, usually about a quality: “the system should be secure”, “it should be fast”. A non-functional requirement sharpens that same quality into something precise and verifiable: “an unauthenticated request must never reach a patient record”, “95% of searches return in under 200 ms”. A design goal is that quality carried into design as a property the structure must optimise. So the chain runs goal (intent) → non-functional requirement (precise, verifiable) → design goal (what the architecture optimises). This is also why a bare goal is not yet checkable and a good design goal usually is.
Design goals arise from two places, and a complete design weighs both:
Cohesion and coupling are therefore not a separate topic from design goals: they are the general design goals, the ones you pursue on every project, while the system-specific goals come from the non-functional requirements of the system in front of you.
The goals are not shared equally. Different stakeholders press for different, often opposing, qualities, and the designer's first job is to surface the conflict rather than pretend it away:
| Stakeholder | The design goals they tend to prioritise |
|---|---|
| End user (who operates) | Functionality, usability, user-friendliness, ease of learning, ease of use, ease of remembering, runtime efficiency (performance), reliability, fault tolerance, robustness. |
| Customer / client (who pays) | Low cost and cost-effectiveness, delivery on schedule and rapid development, increased productivity, functionality, flexibility, portability, backward compatibility, traceability of requirements, good documentation. |
| Developer / maintainer (who builds and maintains) | Minimum number of errors, maintainability (modifiability), readability, understandability, reusability and reuse of components, adaptability, well-defined interfaces, reliability, portability, minimal complexity. |
That is the full catalogue of design goals worth knowing, sorted by the stakeholder who cares most. Several goals (reliability, portability, functionality) matter to more than one stakeholder, which is exactly why they collide. A design lists the ones that matter for this system, attributes each to a stakeholder, and prioritises them; the next two tables show why prioritising is unavoidable.
Because resources are finite, raising one quality usually lowers another. Recognising these trade-offs, and deciding which way to resolve each one for this system, is the substance of design. The pairings below are indicative, not one-to-one: a quality is rarely bought at the cost of exactly one other. Robustness, for instance, is paid for in efficiency and in cost and in complexity at once.
| Raising this… | …tends to cost this | Why, with a concrete example |
|---|---|---|
| Robustness | Efficiency, cost, complexity | The redundancy, extra validation and fault-tolerance that make a system robust are paid for on three fronts at once: more work per request (efficiency), more hardware and licences to run the spares (cost), and more moving parts to get right (complexity). Example: a payment service that re-validates every request, retries failed calls and keeps a hot standby survives a crashed node, but each payment does more work, it needs roughly twice the hardware, and the failover logic is one more thing that can be wrong, against a single-instance, trust-the-input design that is faster and simpler but falls over on the first fault. |
| Functionality | Usability and simplicity | Every feature adds a control, a mode, a path to test. Example: a camera app that also edits video, manages files and posts to social media buries the one-tap shutter under menus; the stripped-down camera is easier to use precisely because it does less. |
| Performance (efficiency) | Portability and readability | Speed often means code tied to one machine and hard to follow. Example: rewriting an image filter in hand-tuned CPU-specific SIMD assembly can double throughput, but it no longer compiles elsewhere and few on the team can safely change it. |
| Security | Usability and performance | Every check is a step for the user and a cost per call. Example: two-factor login plus an authorisation check on every request keeps intruders out, but adds a login step for the user and a permission lookup on each call. |
| Low cost / fast delivery | Robustness and maintainability | Shortcuts ship sooner and cheaper, then charge interest. Example: dropping the test suite and staging server to hit a demo date works once, but the first production outage, and every feature slowed by the shortcut schema afterwards, costs more than they would have. |
A goal is only worth stating if there is a structural move that serves it. The architecture is where most non-functional goals are won or lost, so each one points to a recognised technique:
| Design goal | How to achieve it (architecturally) | What that looks like in practice |
|---|---|---|
| Performance | Localise critical operations and minimise communication between components; use large rather than fine-grain components. | Group the ten steps of checkout into one coarse CheckoutService so a purchase is a single in-process call, instead of ten chatty calls hopping across the network, each paying latency. |
| Security | Use a layered architecture with the critical assets in the inner layers. | Put patient records in the innermost layer, so every request has to pass through the authentication and authorisation layers above before it can reach them; there is no shortcut to the data. |
| Safety | Localise the safety-critical features in a small number of subsystems. | Confine an infusion pump's dosage-calculation logic to one small, heavily reviewed subsystem, rather than scattering it, so the safety case only has to certify that one part. |
| Availability (and robustness) | Include redundant components and mechanisms for fault tolerance. | Run two web servers behind a load balancer with a replicated database, so one node failing does not take the service down (this is the backup node in the deployment diagram). |
| Maintainability | Use fine-grain, replaceable components. | Keep each tax rule in its own small, replaceable component, so a rate change touches one component and its tests, not a tangled monolith. |
Notice these techniques pull against each other, which is the whole point of prioritising. Performance wants large components and few calls; maintainability wants fine-grain replaceable ones. You cannot maximise both, so the design commits: the CheckoutService that makes a purchase fast is the very coarseness that makes it harder to change one step of it later. Naming which goal wins for this system is the decision the architecture records.
A design goal is only useful if it can be attributed to a stakeholder and, ideally, measured. "The system should be secure" is not yet a goal; "an unauthenticated request must never reach the patient record, enforced at a single gateway" is one a design can be checked against.
These two are the general design goals promised in the previous section, the ones pursued on every project regardless of its non-functional requirements. Every decomposition is judged by them: cohesion looks inside a subsystem, coupling looks between subsystems. A good design maximises the first and minimises the second, and doing so is what reduces overall complexity while keeping the system open to change.
Cohesion measures the strength of functional relatedness among the classes inside one subsystem. High cohesion means the classes perform similar or related tasks and clearly belong together. Low cohesion means unrelated classes have been grouped with no clear theme, usually a sign that the subsystem is really several subsystems in disguise.
Coupling measures the degree of interdependence between subsystems. High coupling means a change to one subsystem forces changes in others. Low coupling means a change in one has minimal or no effect on the rest. Low coupling is what lets a subsystem be understood, tested, replaced, or reused on its own.
High cohesion is achieved when most of the interaction is kept within a subsystem rather than across its boundary: gather the classes that talk to each other constantly into the same subsystem, and you raise cohesion and lower coupling at the same time.
Low coupling is achieved by making subsystems self-contained and having them depend on each other's interfaces, not their internals. A calling subsystem should know what another offers (its public operations) and nothing about how it works (its attributes and representation). This is the principle of information hiding.
Information hiding, the foundation of modular programming, says a subsystem should hide its internal data and representation behind a stable set of public operations. Callers depend only on those operations, defined as an interface. The benefit is direct: the internals can be rewritten, optimised, or replaced without touching any caller, because nothing outside ever depended on them. Coupling drops to the width of the interface, and the interface is the one thing the design keeps stable.
A subsystem is a replaceable part of the system that provides a coherent service through a well-defined interface. Decomposition is the act of dividing the system into such parts, guided by the two measures of the previous section.
A subsystem is a group of cohesive classes (or components) that together provide a service: a related set of operations offered to other subsystems. The service is exposed as the subsystem's interface: the set of public operations other subsystems may call. Other subsystems depend on the interface, never on the classes behind it; that is information hiding applied at the architectural scale.
There are two ways to relate subsystems, and most architectures use both:
Decomposition has a concrete consequence at build time. If subsystem A uses subsystem B, then B must be compiled and available before A can be built. The "uses" relationships therefore form a build-dependency graph, and building the system means processing that graph in dependency order. This is exactly what build tools (make, ant, maven, gradle) compute: a topological sort of the dependency graph.
Architectural design decides how the system is organised as a set of communicating subsystems and how responsibility is allocated across them. It is the critical link between requirements engineering and design: the earliest decisions, and the most expensive to reverse.
The first design activity. It sits directly after analysis and before detailed design, and it sets the frame every later decision works inside. Get it wrong and no amount of detailed design recovers the lost quality.
The output of architectural design is an architectural model: a description of how the system is organised as a set of components and how those components relate. In UML that model is carried by the structural diagrams from Chapter 4, the component and deployment diagrams, plus the chosen style. The model is an abstraction; it deliberately omits internal detail so the overall structure can be discussed and reasoned about as a whole.
Architectural design is a creative process, so it cannot be reduced to a fixed procedure; but a small set of questions recurs across every design process, and the answers are the architectural decisions that shape the system's non-functional behaviour. Sommerville frames them as eight:
Every one of these answers affects the non-functional characteristics, which is why architectural design is where most design goals are won or lost. (Source: Sommerville, 9th ed.)
The two words are often used loosely, but the distinction is the same one a class diagram draws between a class and its objects.
A style is chosen because its known trade-off matches the system's prioritised design goals. The point of cataloguing styles is that the matching can then be done by recognition rather than from scratch: once the goals are clear, the field of sensible structures narrows to a few named candidates. The catalogue below is that field.
The common styles, developed one by one in the next section: layered, client-server, peer-to-peer, three-tier / four-tier, model-view-controller (MVC), repository, pipe-and-filter, and service-oriented (SOA).
Each style below is a recurring arrangement of subsystems with a known shape, the roles its parts play, and the design goals it serves and sacrifices. Hover any glyph in a diagram for what it is.
A layer is a subsystem that offers a service to the layer above it and uses the service of the layer below. Stacking layers produces an architecture where dependencies point in one direction, downward, so each layer can be understood and replaced given only the interface of the one beneath it. A generic four-layer arrangement separates the interface, its presentation logic, the application, and the platform underneath:
| Name | Layered architecture |
|---|---|
| Description | Organises the system into layers with related functionality associated with each layer. A layer provides services to the layer above it, so the lowest-level layers represent core services that are likely to be used throughout the system. |
| When used | When building new facilities on top of existing systems; when the development is spread across several teams with each team responsible for a layer of functionality; when there is a requirement for multi-level security. |
| Advantages | Allows replacement of entire layers so long as the interface is maintained. Redundant facilities (e.g. authentication) can be provided in each layer to increase the dependability of the system. |
| Disadvantages | In practice, providing a clean separation between layers is often difficult, and a high-level layer may have to interact directly with lower-level layers rather than through the one immediately below it. Performance can be a problem because of the multiple levels of interpretation of a service request as it is processed at each layer. |
The pattern table above is Sommerville's standard form (name, description, when used, advantages, disadvantages); the same form is given for each of the styles below, so the whole catalogue reads consistently.
A layered architecture comes in two variants that differ only in which lower layers a layer is allowed to call. The choice is a direct trade between coupling and runtime efficiency, and it is tied to different design goals.
Two different relationships connect layers, and UML draws them with different lines, a point worth getting exactly right:
A single pair of subsystems can have both relationships at once: A may both depend on B at build time and call B at run time, drawn as a solid and a dashed line between the same two boxes.
Client-server is a special case of the layered style in which the layers are split across machines. One or more servers provide a service; many clients call on it. The server owns the shared data and the logic that protects it; each client owns its own user interface and calls the server when it needs the service.
| Name | Client-server |
|---|---|
| Description | The functionality of the system is organised into services, with each service delivered from a separate server. Clients are users of these services and access servers to make use of them. |
| When used | When data in a shared database has to be accessed from a range of locations. Because servers can be replicated, it may also be used when the load on a system is variable. |
| Advantages | Servers can be distributed across a network. General functionality (e.g. a printing service) can be available to all clients and need not be implemented by all services. |
| Disadvantages | Each service is a single point of failure, so susceptible to denial-of-service attacks or server failure. Performance may be unpredictable because it depends on the network as well as the system. There may be management problems if servers are owned by different organisations. |
Read against the design goals, the client-server style scores as follows (the deck's feature assessment):
| Design feature | Level | Why |
|---|---|---|
| Service portability | High | The server runs on many operating systems and networking environments. |
| Location transparency | Reasonable | The server might itself be distributed, but presents a single "logical" service to the user. |
| Performance | Reasonable | The client is optimised for interactive, display-intensive tasks; the server for CPU-intensive operations. |
| Scalability | High | One server can handle a large number of clients. |
| Client portability | Reasonable | The client interface can support a variety of end devices (phone, laptop, wearable). |
| Reliability | Reasonable | The server survives some client and communication failures; one client crashing does not bring the system down. |
In UML the relationship is drawn as an association between Client (role requester) and Server (role provider), with the server exposing its public operations service1()…serviceN(). The client knows the server's interface; the server does not need to know the client's.
Peer-to-peer generalises client-server by collapsing the two roles into one. A peer is both client and server: it requests services from other peers and provides services to them. There is no central authority, so there is no single bottleneck and no single point of failure, and peers can communicate directly.
Modelling "a peer can be a client as well as a server". Two inheritance models are proposed, and only one is correct. Model 1 makes Peer the parent and has Client and Server inherit from it: this reads "a peer is either a client or a server", which is not what peer-to-peer means. Model 2 (correct) makes Peer inherit from both Client and Server: this reads "a peer is a client as well as a server", which is the definition. The right model is the one whose inheritance, read aloud, states the requirement.
| Name | Peer-to-peer (P2P) |
|---|---|
| Description | The system is organised as a set of equal nodes (peers), each acting as both client and server, that communicate directly with one another rather than through a central server. Any peer may initiate a request to any other. |
| When used | When there is no natural central authority, or a central server is to be avoided, and the data or load is spread across many equal participants: file sharing, blockchains, and some messaging and collaboration systems. |
| Advantages | No single point of failure and no central bottleneck; the system scales with the number of peers; storage and compute are pooled across the nodes. |
| Disadvantages | Security, consistency and peer discovery are all harder with no central point to enforce them; the overall behaviour is harder to reason about; every node must implement both roles. |
A layer is a logical type: a subsystem at one level of abstraction. A tier is a physical allocation: the node a layer is deployed on. The two are often used interchangeably, but the distinction is exact. A three-layered style becomes a three-tier architecture only when its three layers are placed on three separate nodes:
| Name | Three-tier (and four-tier) |
|---|---|
| Description | A layered architecture whose layers are allocated to separate hardware nodes (tiers): presentation on the client, application and business logic on a middle server, and data on a database server. A four-tier variant inserts a further node, typically a web or security/gateway tier, in front of the application tier. |
| When used | For distributed, usually web-based, systems where presentation, logic and data must run on separate machines for scale, security or manageability, and many clients are served at once. |
| Advantages | Each tier can be scaled, secured and replaced on its own; the presentation tier never reaches the database directly (an opaque, layered path); supports large numbers of concurrent clients. |
| Disadvantages | More infrastructure to deploy and operate; every request crosses tier boundaries, adding latency; the middle tier can become a bottleneck and must be sized for the load. |
The problem. In an interactive system the presentation (the boundary objects: screens, forms, reports) and the data (the entity objects) tend to become tightly coupled. Change the data and you are forced to change every screen that shows it; change a screen and you reach into the data objects. The user interface cannot be re-implemented without touching the data representation, and the data cannot be reorganised without touching the interface. That coupling is exactly what makes such systems expensive to change.
The solution: decouple. MVC separates presentation and interaction from the system data by splitting an interactive application into three logical components, so that data can change independently of its representation and the same data can be shown in several ways at once. It is the dominant style for user interfaces.
How a view stays current: subscribe and notify. The Model does not call the views; that would couple it back to the presentation it is meant to be independent of. Instead each View subscribes to the Model. When the Model's data changes, it notifies its subscribers, and each notified View re-reads the Model and redraws itself. This is the observer mechanism, and it is what lets several views of one model (a table, a chart, a summary) all refresh from a single change without the Model knowing any of them by name. It is also why the relationship is drawn as a triangle rather than a stack: the View is updated directly from the Model, not through the Controller.
| Name | Model-View-Controller (MVC) |
|---|---|
| Description | Separates presentation and interaction from the system data. The system is structured into three logical components that interact with each other. The Model component manages the system data and associated operations on that data. The View component defines and manages how the data is presented to the user. The Controller component manages user interaction (keystrokes, mouse clicks, etc.) and passes these interactions to the View and the Model. |
| When used | Used when there are multiple ways to view and interact with the same data. Also used when the future requirements for interaction and presentation of the data are not known. |
| Advantages | Allows the data to change independently of its representation and vice versa. Supports presentation of the same data in different ways, with a change made in one representation shown in all of them. |
| Disadvantages | Can involve additional code and code complexity when the data model and the interactions are simple. |
Which design goal does MVC buy? Modifiability: by decoupling the entity objects from the boundary objects it removes the coupling that makes interactive systems expensive to change, at the price of extra structure (the disadvantage above) when the interface is trivial. That is the trade-off the design-goals table calls out: you spend simplicity to buy independent change.
In the repository style, all shared data is held in one central store, and the subsystems interact only through it; none calls another directly. The subsystems are therefore loosely coupled to each other (they are coupled only to the repository's schema), and the repository is the single source of truth.
| Name | Repository |
|---|---|
| Description | All data in a system is managed in a central repository that is accessible to all system components. Components do not interact directly, only through the repository. |
| When used | When you have a system in which large volumes of information are generated that has to be stored for a long time. Also used in data-driven systems where the inclusion of data in the repository triggers an action or tool. |
| Advantages | Components can be independent: they need not know of the existence of other components. Changes made by one component can be propagated to all components. All data can be managed consistently (e.g. backups done at the same time) as it is all in one place. |
| Disadvantages | The repository is a single point of failure, so problems in it affect the whole system. There may be inefficiencies in organising all communication through the repository. Distributing the repository across several computers may be difficult. |
In the pipe-and-filter style, data flows through a chain of independent filters, each transforming its input and passing the result down a pipe to the next. Filters share nothing but the stream between them, so each can be developed, replaced, or reordered on its own.
| Name | Pipe and filter |
|---|---|
| Description | The processing of the data is organised so that each processing component (filter) is discrete and carries out one type of data transformation. The data flows (as in a pipe) from one component to another for processing. |
| When used | Commonly used in data-processing applications (both batch- and transaction-based) where inputs are processed in separate stages to generate related outputs. |
| Advantages | Easy to understand and supports transformation reuse. The workflow style matches the structure of many business processes. Evolution by adding transformations is straightforward. Can be implemented as a sequential or a concurrent system. |
| Disadvantages | The data-transfer format has to be agreed between communicating transformations. Each transformation must parse its input and unparse its output to the agreed form, which increases overhead and may make it impossible to reuse transformations that use incompatible data structures. |
Two canonical examples: the Unix shell command ls -a | cat, where ls and cat are filters and the | is the pipe; and an invoice/payments system, where "read issued invoices" feeds "identify payments", which forks to "issue receipts" and to "find payments due → issue payment reminder".
In a service-oriented architecture the system is built from independent services, each owning a slice of functionality and communicating over the network through published interfaces. Microservices are the modern, fine-grained form. Because each service is deployed and scaled on its own, the style buys independent evolution and elastic scale; the price is operational complexity and the distributed-system problems (partial failure, latency, eventual consistency) that a single-process design never has. It is best read as client-server generalised to many small, independently deployable servers.
| Name | Service-oriented architecture (SOA) / microservices |
|---|---|
| Description | The system is decomposed into independent services, each owning one capability and exposing it through a published, network-accessible interface. Services are composed to deliver the application and may be developed, deployed and scaled independently; microservices are the fine-grained modern form. |
| When used | For large systems that must evolve and scale part by part, be built and owned by several independent teams, or reuse capabilities across more than one application. |
| Advantages | Each service can be developed, deployed, scaled and replaced on its own; teams work independently; services may use different technologies and be reused across systems. |
| Disadvantages | Full distributed-system complexity: partial failure, network latency and eventual consistency; harder to test and monitor end to end; the operational overhead of many independently deployed units. |
A style is chosen because its known trade-off serves the system's prioritised design goals. The choice is a matching exercise: read the top one or two goals, and the field narrows to a few candidates.
| If the leading design goal is… | Candidate style(s) | Why it fits |
|---|---|---|
| Maintainability and replaceability | Layered | One-way dependencies; a layer can be replaced behind its interface without disturbing the rest. |
| Shared data reached from many places | Client-server, Repository | A single store owns the data and the rules that protect it. |
| Independent scaling of parts | Three-tier, SOA / microservices | Tiers or services sit on separate nodes and scale on their own. |
| Resilience, no single point of failure | Peer-to-peer | No central authority to fail or bottleneck. |
| Decoupling presentation from data | Model-View-Controller | Three roles let the UI and the data change independently. |
| Sequential data transformation | Pipe-and-filter | Independent filters chained by a shared stream; easy to reorder and extend. |
| Tools sharing a large, evolving model | Repository | One source of truth that every tool reads and writes. |
| Independent deployment and team autonomy | SOA / microservices | Each service is owned, deployed, and scaled separately. |
Real architectures almost always blend styles rather than pick one. A typical web system is layered overall, with MVC inside its presentation layer, a repository (relational database) at its data layer, and the whole deployed three-tier. The styles compose because each governs a different concern; the skill is naming which style is doing which job, and why.
No single diagram captures an architecture. Kruchten's 4+1 view model (1995) describes it from several viewpoints at once, each addressing a different stakeholder concern, and each maps onto a UML diagram from Chapter 4.
| View | The concern it answers | UML diagram |
|---|---|---|
| Logical | What functionality does the system provide? | class and object diagrams |
| Process | How does it behave and coordinate at run time? | activity and sequence diagrams |
| Development | How is the software organised for building? | component (and package) diagrams |
| Physical | How does the software map onto hardware? | deployment diagrams |
| + Scenarios | Do the four views actually work together? | use case diagrams |
The "+1" is the set of scenarios (use cases) that animate the other four and check they agree: a scenario is walked through the logical, process, development, and physical views to confirm the architecture actually supports it. This is the same idea as Sommerville's four perspectives (context, interaction, structural, behavioural): a system is understood only by looking at it from more than one direction at once, and the views are kept honest by the scenarios that cut across them.
The pieces in order, on one system: read the goals, decompose, choose styles whose trade-offs serve the goals, and justify each choice. The realised structure is the seminar-registration architecture drawn in the Chapter 4 companion.
The system holds student records, serves many concurrent users at registration time, and must outlive several rounds of interface change. Turning those non-functional requirements into prioritised design goals gives: security of student data; maintainability (the interface will change often); independent scaling of the web front under load; and reuse of the university's existing authentication and database. These are the goals every later decision is justified against.
Group classes for high cohesion and low coupling: a <<UI>> presentation subsystem; three business-domain subsystems (Seminar, Schedule, Student), each cohesive around one concept; and shared <<infrastructure>> subsystems (Security, Persistence). Each business component reaches data only through the Persistence interface and security only through AccessControl, so coupling is held to the width of those interfaces.
DataAccess interface (repository style, one shared University DB); Security is the cross-cutting infrastructure component. This is the structural view; the reasoning for why it takes this shape is the table below.| Decision | Style | Goal it serves |
|---|---|---|
| Three layers overall (presentation, business, data) | Layered | Maintainability: the interface layer can be rebuilt behind a stable interface without touching business logic. |
| Presentation layer split into model, view, controller | MVC | Maintainability: decouples the changing interface from the stable domain model. |
| Data held in one shared university database | Repository | Reuse and a single source of truth for student records. |
| Layers deployed on separate client, application, and database nodes | Three-tier | Independent scaling of the web front; security, since the database sits behind the application tier and is never exposed to the client. |
| Authentication delegated to a shared Security component | infrastructure subsystem | Reuse of the university identity service; one enforcement point for access control. |
The three layers are allocated to three separate nodes: presentation on the client, the business logic on an application server, and the data on a database server. That allocation is what makes the layered design a three-tier architecture, and it is drawn as a deployment diagram.
seminar.war, and the database server holds university.db. The client reaches the application server over <<HTTPS>> and never touches the database directly, that opaque path is the security the third tier buys.Three tiers add two network hops and two more nodes to operate, accepted for the scaling and security they buy. Layering adds a call through the middle layer on every data access, accepted for the maintainability. Naming the trade-off, rather than hiding it, is what makes the design defensible: the goals in Stage 1 are the standard each of these costs is judged against.
Questions across the main points of system design, from precise definitions to distinguishing concepts to reasoning about a scenario. Work each one fully before opening the answer; the answers are deliberately tight, in the form a strong solution takes.
Cohesion measures the strength of functional relatedness among the classes within one subsystem; a good design seeks it high, because a subsystem that does one related thing is easier to understand, maintain, and reuse. Coupling measures the degree of interdependence between subsystems; a good design seeks it low, because then a change to one subsystem has minimal or no effect on the others, so each can be understood, tested, and replaced on its own. High cohesion tends to produce low coupling, because gathering related work into one subsystem keeps most interaction internal.
A layer is a subsystem that provides a service to the layer above and uses the service of the layer below; layers divide the system vertically, by level of abstraction, and a layer depends only on lower layers and has no knowledge of higher ones. A partition divides one layer horizontally into several independent, same-level subsystems (weakly coupled peers) that provide services to one another; partitions divide by area of responsibility, not level of abstraction.
Closed (opaque) layering uses direct addressing: a layer may call operations only from the layer directly below it. It is more portable and gives low coupling, serving maintainability and flexibility. Open (transparent) layering uses indirect addressing: a layer may call operations from any layer below it. It is more efficient but increases coupling, serving runtime efficiency.
"Depends on" is a compile-time dependency: the depended-on subsystem must be built first (the relationship a build tool such as make or maven orders). UML draws it with a solid line. "Calls" is a runtime dependency: at execution one subsystem invokes another (a browser calls a web server). UML draws it with a dashed line. The same pair may have both at once.
Subsystem decomposition is the identification of subsystems, services, and their relationships. An architectural style is a pattern for a subsystem decomposition (layered, client-server, repository, etc.). A software architecture is an instance of an architectural style applied to one specific system. Style is to architecture as class is to object.
Performance: localise critical operations, minimise inter-component communication, and use large (coarse-grain) components. Security: use a layered architecture with the critical assets in the inner layers. Availability: include redundant components and fault-tolerance mechanisms. Maintainability: use fine-grain, replaceable components. Performance and maintainability conflict directly: performance wants large components and few calls, maintainability wants fine-grain replaceable ones, so the two goals must be prioritised rather than both maximised.
Client-server provides no peer-to-peer communication: calls are triggered only by a client, never by the server, so the server cannot, for example, notify a client when shared data changes. Peer-to-peer removes this by making every node both client and server. The correct model has Peer inherit from both Client and Server ("a peer is a client as well as a server"). The wrong model makes Peer the parent of Client and Server, which reads "a peer is either a client or a server", not what peer-to-peer means.
A layer is a logical type (a subsystem at one level of abstraction); a tier is its physical allocation (the hardware node it runs on). A three-layered style (user interface, middleware, database) becomes a three-tier architecture only when its three layers are deployed on three separate hardware nodes. A four-tier architecture inserts a further node, typically an application server for session management and dynamic content between the web server and the database.
MVC is non-hierarchical (triangular): the View sends user actions to the Controller, the Controller updates the Model, and the View is updated directly from the Model. Three-tier is hierarchical (linear): the presentation layer never communicates directly with the data layer; all communication passes through the middle (middleware) layer. So in MVC the view reads the model directly; in three-tier the presentation tier must go through the middle tier to reach data.
The repository style: all the tools read and write a single central project repository and never call each other directly, so they are loosely coupled and a change one tool makes is immediately available to the others, exactly what is needed when components share a large, evolving body of data. Its main risk is that the repository is a single point of failure and a potential bottleneck, and every tool is coupled to its schema, so the schema becomes hard to change.
Choose the one best answer for each, then check the answers below. (More than one answer marked is wrong.)
1 (b) a dashed line marks a runtime call; a solid line marks a compile-time “depends on”. 2 (b) closed layering is direct addressing, the layer directly below only. 3 (c) MVC is triangular, the view reads the model directly; three-tier is linear. 4 (b) a single central store with no direct calls is the repository. 5 (c) coarse-grain components and fewer calls serve performance (and pull against maintainability). 6 (b) layers are logical; a tier is a layer allocated to its own hardware node.
Bruegge and Dutoit's system-design framework and Sommerville's chapter on architectural design anchor this material; the works below are those directly referenced, alongside the standard practitioner references.