Thursday 29 November 2018

An annotated Philosophy of Software Design

We build our computer (systems) the way we build our cities:
over time, without a plan, on top of ruins
Ellen Ullman

After much hype I've read John Ousterhout's A Philosophy of Software Design which he uses to teach his course at Stanford and presents as a personal experience "opinion piece". Its basic goal seems to be to develop an awareness and intuition about how and when to manage complexity emerging out of proper problem decomposition in Software Design.

Undergraduate students thus seem to be the main audience, which explains why, despite the title, architecture or non-abstract large system design, distributed systems, developer workflow and design thinking are not covered much, and why a prosaic, almost aphorismic writing style were chosen. My assumption is this is  also why barely any references or annotations are given. It's supposed to be the beginning of an iterative journey, similar to language learning. I figured it might help to share mine, though, to go the next step in that journey (Github would feel too official, so blog):

Preface, Iterative process to this book. Exercises in Programming Style 2014Beautiful Code, 2008Software Craftsmanship 2001 (Craftsperson) and before that The Pragmatic Programmer 1999 and even Programming Pearls 1986 developed iterative, small-wisdom, later developed into Kata's, based learning of software design.




Page 2, Introduction. Modular Design: Also called Separation of concerns, coined by Edsger W. Dijkstra 1974, or Information Hiding (see page 19)

Page 2, Introduction. Agile Development: Agile Manifesto 2001, here sounds more like Evolutionary Design as increments were used earlier e.g. in the Rational Unified Process and Kanban as early as 1940ies

Page 3, Chapter 1, Introduction. Incremental works well: Some good proofs in Accelerate, Forsgren et al. 2018 and yearly Chaos Report.

Page 3, Chapter 1, Introduction. Continuous Redesign: Design Thinking as popularized e.g. by IDEO 1991 or Nielsen 1993, but already before that in Computer Art (Steenson 2018) or Kaizen in manufacturing (later called Lean, see Kanban above) and iterative design during World War II and the Space Age

Page 4, Chapter 1, Introduction. Red Flags: Also called Code Smells, coined by Kent Beck in the 1990ies, or Anti-Patterns, by Andrew Koenig 1995.

Page 4, Chapter 1, Introduction, Code Reviews. Atwood 2006 and many others have written about the need for reviews, also DevOps e.g. Humble 2010.

Page 5, omitted because there it lots of other definitions of Complexity and Complex Systems in Computing (Cyclomatic Complexity 1976, Highsmith 2000Wolfram 2002) all the way up to Emergence which, I agree, would be too much for the scope of this book.

Page 6, Chapter 2. Complexity: First, Design of Design came to mind but actually Fred Brooks mentioned it first in "No Silver Bullet" from 1986, coining the term "accidental complexity" based on McCabe 1976. Beyond, more generally, Herbert A. Simon, "The Architecture of Complexity" 1962 and Weinberg's "General Systems Thinking", which includes this excellent chart (in a version by Peter Van Roy from 2012) explaining which complexity domain programming fits in:

Page 6 at the end nicely speaks about to write for the reader. To be fair, Compassionate Code was only published this year and says it better than Uncle Bob, but Clean Code, 2008 did speak earlier about authoring the code itself with empathy for the reader in mind (see also page 149). Writing for a reader goes back as much as Kerningham's 1974 "Elements of Programming Style". Good book on reading code Spinellis 2003.

Page 7, Chapter 2, Cognitive Load: Herbert A. Simon developed the concept of bounded rationality, an early way to formulate limited rationality or bias outside of philosophy and a core idea on the way to bounded contexts in Domain-Driven Design (see page 22)

Page 7 further below, Brooks' Mythical Man Month, 1975 is the canonical reference why lines of code are not a useful metric. Also see Hofstadter's law

Page 8, Chapter 2, Unknown Unknowns: Refers to the Johari Window model as popularized by Donald Rumsfeld in 2002.

Page 9, Chapter 2, Obvious behaviour: The Field Guide to Understanding Human Error, 2006How Complex Systems Fail 1998, and Thinking fast, thinking slow, 2012 talk about biases and how to overcome them with techniques such as Choice Architecture in Nudge, 2008.

Page 9, Chapter 2, Causes: Network Protocol Dependencies are part of the old TCP/IP adage "Be conservative in what you do, be liberal in what you accept from others" coined Postel's Law 1980.

Page 11, Chapter 2, Incremental Complexity: Some references to Tech Debt, Software Rot in Martin Fowler and Beck's Refactoring 1999 could be given and how to tackle it e.g. the Scout Rule (Clean Code, 2008 or 97 Things, 2010), Fowler's Opportunistic Refactoring, 2011, or Design Stamina, 2007. Same on page 18.

Page 15, Chapter 3, Investment for Design: All references to Investment - See above on Design Stamina and (Tech) Debt but more generally Architecture, in particular Fowler 2003 "Who needs an architect", the BDUF discussion (Spolsky 2005 etc) how it relates to iterative development and "Just Enough Design" (Fairbanks 2010). Numbers on the success in Accelerate, Forsgren et al. 2018.

Page 16, Chapter 3, Spaghetti Code: Foote and Yoder, 1999, the seminal "Big Ball of Mud" begins with a picture of pasta.

Page 17, Chapter 3, Fun at Work: Chapter on Toil in the SRE Book, 2017, earlier in Chad Fowler's Passionate Programmer 2010, empathy is a topic of Clean Code as well as for Fred Brooks.

Page 19, Chapter 4,  SOLID paraphrased; Modules should be deep (one of the major design principles), Information Hiding, David Parnas in 1972 (actually mentioned in the video and in the Preface of the book)

Page 21, Chapter 4,  Technical Abstractions: Leaky Abstractions, Spolsky 2002. Could even go back to the SOLID principle of "Low Coupling, High Cohesion", coming from the 70ies or even 60ies structured programming, e.g. in Dijstra's references to Programming Style.  Referring here to OOP, Single Responsibility Principle, Wirfs-Brock 2002 and GRASP, Larman 2005.

Page 22, Chapter 4, Real-Life Abstractions: Most importantly in Domain-Driven Design, Evans 2003, but already in Code Complete, 1993, speaking about "Consistent Abstractions" and "Real-World Objects". System Metaphors, for instance when Steve McConnell talks about Metaphors in Code Complete, 1993, comparing the farming (or gardening) and the construction (or architecture) approach. Obligatory Borges reference.

Page 23, Chapter 4, Deep Modules: Could use a notion whether state or functionality (logic) is encapsulated. See Alan Kay 1972 on Object-Oriented Programming (OOP) with Messages or Henney 2010 "Encapsulate Behavior, Not Just State"

Page 24, Chapter 4, Classes should be small: Word "Micro" in Microservices, canonical reference Lewis 2014 although earlier e.g.  Hoff 2012

Page 30, Chapter 5, Information Leakage: Law of Demeter, 1987. Also see Leaky Abstraction, State and OOP above as in no Shared State and Shared-nothing architecture since the 70ies. Nice Temporal Decomposition anti-pattern is an interesting red flag leading to Event Sourcing / CQRS.

Page 35, Chapter 5, Example: Those methods use primitive types in their names (usually frowned upon e.g. in Code Complete, 1993 and, as this is Java, Effective Java, Bloch 2008 refer to Duck Typing) and exceptions for control flow (assertions), might benefit from an explanation why that is better. See page 106.

Page 36, Chapter 5, Default: Principles behind Convention over Configuration popularized by Ruby, 2007.

Page 38, Chapter 5, Conclusion: Domain-Driven Design, Evans 2003, especially for a ubiquitous language for naming.

Page 39, Chapter 6, Increments: Minimum Viable Product, 2001-2009, YAGNI 2001, Semantic Versioning 2010 and Chrome's' Evergreen concepts for incremental updates.

Page 40, Chapter 6, General Purpose: Composition over InheritanceRefactoring 1999 again (see also page 152)

Page 46, Chapter 7, Pass-Through Methods: Decomposition of pass through is one of the main concepts of the Unix Philosophy, McIlroy 1978, also Rule of Modularity, Raymond 2003.

Page 49. Chapter 7, Decorators: First time Design Patterns are mentioned, yet without explanation - only on page 156. Canonical is GoF (Gamma) 1994 which includes Decorator, Alexander 1977. As this is Java, Aspect-oriented programming (AOP), 2001, Metaprogramming, Erlang behaviours or function decorators in Python might be interesting.

Page 51-53, Chapter 7, Pass-Through Variables: See Pass-Through Methods above. Global State in Context came from Automata / Nondeterminism (Dijkstra 1976), badly done in J2EE introduced in 2003 typically now considered an anti-pattern (would be good to qualify "unlikely that would need multiple instances in production" and talk about distributed systems), better in Erlang as discussed in "Actor Model of Computation" 1974. Otherwise discuss State in UI Patterns e.g. MVC and contract with Unidirectional Flow in Flux, 2014 which is basically Data Flow / Reactive similar to Actors. Mentions "immutable" (12-Factor AppsFunctional Programming) only at the very end.

Page 57, Chapter 7, Configuration: See Convention over Configuration above but also consider Feature Toggles or Flags as a means to achieve Observability of application state run A/B Tests or Experiments, control Circuit Breakers etc. - see Nygard 2007 (on page 55 "System Administrator" is mentioned which suggests Immutable Infrastructure / Continuous Delivery are not considered).

Page 62, Chapter 9, Goto: Canonical reference Dijkstra 1968. Repetition / Duplication see DRY at least since Hunt and Thomas 1999, also Rule of three in Refactoring 1999. Not always bad e.g. a Distributed Monolith can be worse.

Page 64, Chapter 9, Layering: Think in Behaviour or Ports & Adapters, 2005, rather than Tiers. Obligatory Too many layers of Indirection reference.

Page 70, Chapter 9, Splitting and Joining: See page 24, Microservices, canonical reference Lewis 2014.

Page 71, Chapter 9, Do one thing: See page 30 Law of Demeter, 1987, page 46 Unix Philosophy, McIlroy 1978.

Page 76, Chapter 10.1, Transaction State and Rollback in Abort: See page 51ff on unbounded nondeterminism, should introduce concept of state. Transaction Monitoring and ACID principles at least since Haerder and Reuter 1982. Should mention development in Software Transactional Memory popularized by Akka 2009 and Persistent State in Streaming Systems, Lax 2018.

Page 78, Chapter 10.2, Exceptions: See page 35, Exceptions as control flow. Worthwhile mentioning other ways, e.g. Golang Error Types and Scala Try's (Läufer 1994) - Type safety and statefulness are part of the interface.

Page 82 (also page 80), Chapter 10.7, Exception aggregation: Error Hiding and Exception Chaining / Wrapping was introduced e.g. in Java 1.4, Bloch 2001, Scala and Golang support Exception pattern matching.

Page 85, Chapter 10.7 below: Ways of handling exceptions vs error for instance in Meyer 1998.

Page 86, Chapter 10.7 below: Recreating servers is part of Immutable Infrastructure (Containers, e.g. Menage 2007, Fowler 2013) popularized by Netflix' Chaos Engineering 2011.

Page 86, Chapter 10.8 Crashing: See page 78 for Golang approach, Erlang 1992 is famous for traditionally rather monitoring processes calling the "just crash" philosophy defensive programming .

Page 91, Chapter 11, Design twice: See page 57 on A/B Tests. Mention V-Model as historic idea to facilitate 4-eye principle. Nygard 2007 also covers Architectural Tradeoffs documented for instance in Architecture Decision Records. (nice comment on page 93 on Self-serving bias / Overconfidence Effect / Dunning-Kruger)

Page 95-96, Chapter 12, Comments: Discussion popularized in Clean Code, 2008 but earlier e.g.  Kerningham's 1974 and Reeves 1992 mentioned code as design / documentation instead of comments. Visual Programming, UML and MDA 1980ies as counter-examples, Lighttable 2012 as future direction.

Page 97, Chapter 12.1, Comments: May help to mention TDD, Behaviour-Driven-Development (BDD) DSL e.g. North 2009 for tests as specification and Traits / Aspects as a means to comment behaviour in code instead of "close to code" (page 137, may be omitted due to page 155).

Page 101, Chapter 13: see page 95-95, Kerningham's 1974 and Reeves 1992.

Page 101, Chapter 13, Interface comments: Generating interface / API balance between type safety, code readability and uniformity / consistency in various IDL's e.g. COBOL Copybooks 1968, C Header Files 1972CORBA 1991 , RDF 1997REST 2000Swagger 2010

Page 103, Chapter 13.2; See page 11, repetition of comments and page 95-96.

Page 105, Chapter 13.3, Abstraction via comment: Nice wording precision and intuition. See page 22 but also Bloch 2001 on abstraction levels for error messages.

Page 106 (and 110), Chapter 13.3, below: Unclear why variable names can't have units or invariants. Guards at least since Beck 1997 and earlier. Defect detection in Java since 2006. Example on heartbeat could be an enum to describe behaviour / attribute as advised in Code Complete, 1993. See page 35.

Page 116, Chapter 13.6, what and why: Instead of loop iterations mention documentation with recursion, higher-order functions and streams. Page 117 Comment to bug tracker may better be in blame layer (Atwood 2007).

Page 118, Chapter 13.7, Design Notes: See page 91 on why-decision. Markdown or Architecture as Code (e.g. Brown 2014) and Infrastructure as Code even with Service Meshes better than text.

Page 122-123, Chapter 14.2, vague naming. See Code Complete, 1993 how difficulty to name should raise doubts and metaphors (see page 22). Obligatory reference to Naming things is hard.

Page 125, Chapter 14.3, weak naming. Choosing names can also be bikeshedding (Parkinson 1957) and accelerate Conway's Law 1967 by having too tight bounded contexts resembling existing bias and assuming an ideal state rather than evolutionary processes (e.g. REST temporal quality, Fielding 2000).

Page 126, Chapter 14.4, consistency. Nice remark on consistency, already main principle in Kerningham 1974.

Page 129, Chapter 15, comments as design. See Literal Programming, Knuth 1984 popularized recently with the Wolfram Language and Jupyter Notebooks. Also User Stories, Cockburn 1998.

Page 131, Chapter 15, simplicity: See Wilson and Oram 2007, earlier Unix Philosophy, McIlroy 1978 and Beck 1999.

Page 135, Chapter 16, existing code: See Working with Legacy Code, Feathers 2004Refactoring 1999 and Event Interception since the 70ies.

Page 136, Chapter 16, below: See Evolutionary Architecture 2016 and lots of earlier examples on continuous improvement (page 3) and scout rule (page 11)

Page 138-19, Chapter 16.3, no comments in repo, findability: See page 95, Lighttable, page 116, use annotations instead of plain text, Dependency Injection (Inversion of Control since 1990ies) instead of direct dependency, Blame Layer and Google Code Search e.g. Sadowski 2015, Potvin 2016.

Page 143, Chapter 17.1, consistency: see page 126.

Page 148, Chapter 18.2, events: First time events are mentioned, move to front, discuss FP, Declarative and Reactive (Data Flow) e.g. Elliott 1998 (check out vvvv)

Page 153, Chapter 19.2, agile. Iterations are older than Agile e.g. Spiral, Rational, non-iterative Agile systems are e.g. Kanban and XP e.g. Reinertsen 2009 on product flow. See page 2.

Page 154,  Chapter 19.3, testing. Separate team is V-Model (see page 51), QA roles are orthogonal to Agile (Cunningham 2001), trend is more towards automation and validation (in the sense of Reliability, Meyers 1979) similar to Ops to SRE (Beyer 2016). Test-Driven-Development known from XP, Cunningham 1999, Behaviour-Driven-Development. Names for Test Stages canonical defined in Humble 2010 (may be omitted due to page 155)

Page 156, Chapter 19.5, Patterns. See page 49. Higher level patterns are Styles e.g. Shaw 1994

Page 159, Chapter 20, performance. Obligatory Knuth 1974 reference. Developing an awareness, Fermi Estimate, Numbers everyone should know Norvig 2001 (Animation)

Page 161, Chapter 20.2, measure first. See Page 159 Knuth, Observability Twitter 2013, SRE SLA's 2016, Impact Mapping 2012



No comments: