đź“–Just Enough Software Architecture
- authors
- Fairbanks, George
- year
- 2010
- url
- https://www.amazon.com/Just-Enough-Software-Architecture-Risk-Driven/dp/0984618104
- tags
p.5 Architecture is a separate choice from functionality. When you build a system, you can choose an architecture that best suits your needs, then build the functionality on that architectural skeleton. (Functional requirements do not drive architecture)
p.6
Developers voluntarily impose constraints on the system in order to amplify their reasoning abilities.
p.18 In software architecture there is a chain of intentionality between a few high-level intentions through decisions that architecture makes to maybe some low-level details. (i.e., every architecture decision can be traced to high-level architecture requirement)
Constraints → Constraints as guide rails
Developers usually view constraints as something that restricts them. But it is impossible to design without constraints: constraints impose order on chaos.
Good constraints can embody judgment: new developers don’t have to know the system completely—constraints will protect them from making (stupid) mistakes.
Constraints provide consistency, reducing needless creativity of developers (so they can apply it where needed).
Consistency reduces complexity and makes system easier to understand and reason about.
Architecture is not always important. But it is important in case of:
hard to design any acceptable solution
high failure price (e.g., people lives)
new domain (to you)
product lines
Presumptive architecture is an mainstream architecture of a certain domain. → Presumptive architecture
In some domains, you justify why you do not use the default architecture.
Reference architecture is an architecture described by someone (e.g., frameworks, or real-time embedded systems)
Reference architectures are intended to become presumptive architectures but that might not happen.
Architecture hoisting is using architecture in such a way to ensure or guarantee a quality. It might set more constraints but would solve a requirement.
Laws to check:
Amdahl’s law
Brook’s law
Conway’s law → Conway’s law
Conferences and workshops
WICSA
ECSA
QoSA
SHARK
ICSE
SPLASH (form. OOPSLA)
Risk-driven model of software architecture concentrates on risks and techniques to address the risks.
It is important to use techniques to address risk they are designed to solve.
Risk prioritization
Risks need to be evaluated and prioritized: risk = perceived probability Ă— perceived impact
Risk prioritization is needed to optimize your time. You should evaluate what risks are better to spend time on.
you should not spend tons of time on low-priority risks
not all risks need to be addressed
Evolutionary design means that design of the system grows as the system is implemented (p.49)
Planned design: do not start implementation until design is complete
Minimal Planned Design (or Little Design Up Front): something in between. ~20% planed, 80% evolutionary
Backed-in risks (p.52–53) → Risk-biases in software development processes
Many processes bake-in risks they worry about and try to mitigate
e.g., scrum/agile bake-in time-to-market and user-acceptance risks
The baked-in risks might be appropriate for a project or not
Baked-in risks are like process biases—watch for them
For agile projects, risks can be added to the common backlog (spikes in scrum) and prioritized together with other features (pp.56–57) → Architecture risks can be added as spikes to backlog
If PO is not qualified to prioritize architectural risks, it might make sense to have 2 backlogs and team suggesting which risks are important.
Recasting design decisions in form of risks moves them into decisions on priorities/requirements. This helps to remove egos from the table (i.e., it’s now “testability vs. performance” instead of “yours vs mine solution”) (p.93)
Sign-offs encourage perfecting design instead of interleaving designing and prototyping. (p.94) → Sign-offs encourage Big Design Up Front
encourages Big Design Up Front / Design Until Perfect
Models help lift problem into abstract plane, solve it using the model, and then apply solution to real world (p.103-104)
When modeling, pick important details and ignore the rest. (p.106) → When modeling, pick important details and ignore the rest
Models can be used to amplify reasoning. (p.107-108) → Models can be used to amplify reasoning
“Question first and model second” → Question first and model second
know why you’re building the model to choose the correct one (p.108)
reading models → writing models → amplify reasoning (→ Levels of using models)
important when teaching modeling
Model is everything you know about the topic. View (projection) is an excerpt from model.
Master models (see p.122 for correspondence with other terminologies)
domain
design
code
Taylor, Medvidovic, Dashofy (2009) — the most comprehensive treatment of software architecture
4+1 architecture views
When doing domain modeling, beware of adding technical details as they blur line between what’s true in general and what is design. → For domain modeling, beware of adding technical details
Restrict yourself in usage of UML notation. That’ll help others (esp. non-devs) to understand the model (use simpler notation) → Use simple notations
Domain models → Domain model
Information model—what types exist in the domain, what is their relationship (pp.131-133)
+invariants—what’s always true, constraints
Snapshots (or instance diagrams)—show concrete instances of types (p.134)
Functionality scenarios (pp.135-136). describe how one snapshot transforms into another. (if a step does not involve a transformation of the snapshot, consider if the step is necessary)
(similar to use cases)
Design model → Design model
Boundary model
Use case diagram
Functionality scenarios (can refine scenarios from domain model with implementation details)
System context
Design decisions
Modules
Components
Deployment
Quality attribute scenarios
Trade-offs
Internals model
Component assembly—what components consist of (other components) / specific configuration of component instances
Two-level functionality scenarios—add details of how internal components interact
Responsibilities—what ports and components are responsible for (a table would do)
Constraints as guide rails → Constraints as guide rails
Architectural styles
(most of the diagrams for boundary model can be used for internal model)
Quality attributes tend to be emergent properties — there is no single place that is responsible for performance, modifiability, security, etc. (p.142) → Quality attributes are emergent properties
If you draw a component diagram, draw all ports and connectors. If you need to draw a simplified version, state that explicitly. (p.146)
If people don’t know about all components and communication channels, they can jump to the wrong conclusions
Write out quality attributes you care about and their priorities
Viewtype — a set of views that can be easily reconciled together
Module—seen at compile-time
Runtime—components and connectors
Allocation—deployment
+Spanning—views spanning other viewtypes
When explaining system, it’s good to show a representation view from each viewtype (so they get a wider picture)
Intentional vs extensional elements
Extensional elements are enumerable and map nicely from design to code
Intentional elements are rules, constraints, design decisions, and they are lost when translated to code
Architecturally-evident coding style: how to code to embed hints of architecture into code
OOP pattern “reification” means you create an object to represent a concept
e.g., event could be just a function call, but creating Event object makes it explicit
how to apply reification to real world?
Reify:
component types
connector types
port types
protocols
Dominant decomposition
what concern do you organize around
organize around functionality is just one of options
canonical “Library Problem” (Wing, 1988) p.212
component vs component instance
component instance only exists at runtime
Modules vs components:
module is just code
components communicate via connectors
components can be thought of as a special case of modules that are instantiated at runtime
component assembly diagrams
types:
context diagram
refinement diagram
show how component is implemented
“closed refinement semantics”: (p.221)
component should have the same ports as its refinement
adding new ports in refinement might surprise/anger the reader
or add a note that some parts are omitted
externally-visible constraints and behaviors are unchanged
component assembly using types can show when there can be multiple instances of component:
LibraryDesk[*]
,LibrarySystem[1]
(p.222-223)
Connectors
connectors are important
they can do work (translate protocols, broadcast messages)
they can pose constraints (client can call server but not vice versa)
sometime connectors are more important than components
connectors are usually underrepresented as they are usually just a line on a diagram (p.223)
diagrams don’t have enough space—describe connectors elsewhere (e.g., table)
p.224: common connector type
you can make connectors substitutable just like components (p.225)
re: Reification
p.231
Connectors should be treated as equals of components in software architecture.
Not all design decisions are important. Most are not, so be wary of wasting time documenting them. p.233-234 → Be wary of wasting time documenting design decisions
Functionality scenario vs. use case: use case describes how a user goal is accomplished. (p.234)
Quality attributes can be called “extra-functional” as they go beyond functional (not negate them). (p.246)
Books have to discuss tricky and corner cases so they might seem convoluted. You shouldn’t always use all techniques. Your code should be simple most of the time, but you know other techniques for when you need them. (p.253)
Relationships:
p.256 table of relationships
projection (view) p.256
can omit details but cannot add what does not exist
textual/tabular views are also powerful
views aid analysis
view can show only a relevant part
viewtype is a collection of views that cannot be reconciled (e.g., module/runtime/allocation viewtypes)
designation relationship §13.6 p.263
how two objects correspond
allow bridging domains
object in program ↔ object in real world
domain model ↔ design model
refinement
low-detail ↔ high-detail
open/closed semantics
- open
can add any new details
- closed
restricts what can be added. restrictions can be written out as text. a good approach: no new details at the same level as already shown on high-level diagram
Architectural styles
Architectural style is similar to architectural pattern but higher-level. You cannot use two architectural styles simultaneously. p.277
e.g., you cannot use both pipes-and-filters and client-server styles
“Big ball of mud” is a viable architectural style for some systems. (p.281)
Not every backyard storage shack needs marble columns. —Foote & Yoder, 2000
(how to apply architectural styles to programming language design?) → How to apply architectural knowledge to programming language design?
Model
sufficiently precise (cartoon vs. blueprint) p.298
(how to combine models with PL design?) → How to apply architectural knowledge to programming language design?
views anti-patterns:
favorite view
one view to rule them all
put legend on diagrams → Put legend on diagrams
avoid arrowhead on connectors (p.311) → Avoid arrowheads on connectors
there are many properties to depict
who initiates connection/makes first request
who sends most of data
readers tend to assume they know which property you represent but they can guess wrong
do instead:
use typographic differences on ports and connectors
list properties textually
Backlinks
- đź“ť Not every system needs an architecture
- đź“ť Avoid arrowheads on connectors
- đź“ť Be wary of wasting time documenting design decisions
- đź“– Software Architecture in Practice
- đź“ť Quality attributes are emergent properties
- đź“ť Use simple notations
- đź“ť For domain modeling, beware of adding technical details
- đź“ť Domain model
- đź“ť Levels of using models
- đź“ť When modeling, pick important details and ignore the rest
- đź“ť Models can be used to amplify reasoning
- đź“ť Question first and model second
- đź“ť Sign-offs encourage Big Design Up Front
- đź“ť Presumptive architecture
- đź“ť Architecture risks can be added as spikes to backlog
- đź“ť Risk-biases in software development processes
- 📝 § Software Architecture
- đź“ť Functional requirements do not drive architecture