đź“–Just Enough Software Architecture: A Risk-Driven Approach

authors
Fairbanks, George
year
2010
url
https://www.amazon.com/Just-Enough-Software-Architecture-Risk-Driven/dp/0984618104
tags
§ Software Architecture
  • 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:

  • 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)

    • 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

  • 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