Jump to ratings and reviews
Rate this book

Software Design for Flexibility: How to Avoid Programming Yourself into a Corner

Rate this book
Strategies for building large systems that can be easily adapted for new situations with only minor programming modifications.

Time pressures encourage programmers to write code that works well for a narrow purpose, with no room to grow. But the best systems are evolvable; they can be adapted for new situations by adding code, rather than changing the existing code. The authors describe techniques they have found effective--over their combined 100-plus years of programming experience--that will help programmers avoid programming themselves into corners.

The authors explore ways to enhance flexibility

448 pages, Hardcover

Published March 9, 2021

136 people are currently reading
760 people want to read

About the author

Chris Hanson

17 books4 followers

Ratings & Reviews

What do you think?
Rate this book

Friends & Following

Create a free account to discover what your friends think of this book!

Community Reviews

5 stars
11 (22%)
4 stars
12 (25%)
3 stars
13 (27%)
2 stars
8 (16%)
1 star
4 (8%)
Displaying 1 - 7 of 7 reviews
Profile Image for Benjamin Scherrey.
12 reviews4 followers
November 26, 2023
My over-all rating for this is really 4 1/2 stars which I'll explain later. I just received it a few days ago, poured over the whole thing, and am now going back through it in detail but it's clearly destined to be yet another classic in the field of software systems design.

*If* you are a fan of SICP ( https://www.goodreads.com/book/show/2... ), however, then this is truly a 5 star book as it is SICP's worthy follow up volume that covers the core system design and architectural patterns that Sussman has identified and found compelling in all his years of teaching SICP at MIT. Here's a great video of Sussman that's not about the book but covers the core concepts that the book focuses on by Sussman. If you like this video then the book is a must-have and actually is what drove me to order it. https://youtu.be/cblhgNUoX9M

The half star is strictly because, if you're really going to work through the examples and fully grok the mechanics of the implementation of the concepts that Sussman and Hanson are describing, you do need to be a fairly capable schemer and the introduction to Scheme in Appendix B is not adequate to get you there. I think the biggest challenge for me (having not touched Scheme or Lisp in anger for over a decade) was not being clear as to what are built-in functions of Scheme versus something that you either need to code yourself or would get defined somewhere else in the code base. If you're not a Scheme programmer you can still generally follow the code fairly easily after reviewing Appendix B but a reference list/description of the built-in functions used in the code would REALLY aid in comprehension for non-experienced schemers. This is not an argument that they should have added more languages, however. It's really hard to point out a more suitable language that combines the terseness and expressability of Scheme for these techniques - perhaps Forth, but that's even more esoteric so challenging to make the case for. That said - you can definitely do these things in other languages so don't let this put you off of its higher purpose. It definitely supports the case that languages change our brains and make us think differently. Language is a lot more than syntax and grammar - it's the core foundation of culture.

Hopefully the non-schemers aren't scared off by now because otherwise this book is an outstanding tome on the art of software development and dealing with changes over a useful system's lifespan. Whereas Edsgar Dijkstra made the case for strict proofs of correctness in code, Sussman argues (and I agree) that such policies a) don't scale, and b) can't evolve and therefore are only usefully applied in the small intrinsics that larger programs are constructed from. The book makes the case and appeals to evolutionary biology that small coherent blocks of "stuff" that follow certain independent patterns or rules for how they interact and compose themselves result in emergent behavior that is more useful and evolveable. I'd even apply the term "anti-fragile" here. These are powerful concepts that anybody writing systems that need to last more than 18 months should really comprehend if we're going to improve the quality and capabilities of software development as we take on the inevitable increase in complexity that our industry demands.

Although the book doesn't discuss it directly, people who are familiar with cellular automatons might find some of these arguments particularly compelling. In this book's case, it is heavily Scheme flavored in the techniques used to demonstrate the ideas. That means it really doesn't address performance issues much but the argument here is that programmer time is far more costly than computer time and only continues to get further unbalanced. As a low level guy I find that I'm not necessarily in that demographic but I can agree for the general case.

The tools and techniques used in the books really speak to language designers like me. Central to the book are domain specific languages (DSLs) composed of combinators and wrappers. It builds from these core concepts to pattern matching, execution continuations, layering, and ultimately propagation which really pays off nicely. The examples are great and well developed in surprisingly little code (a wonderful feature of Scheme) starting with a useful board game abstraction that can flexibly support both checkers and chess (and any other set piece board game you might imagine) in just a few pages in the initial chapters. The code evolves and becomes more flexible as the book progresses so you can understand how the design evolves as requirements evolve. You don't start writing your system in a generalized manner from the get-go. You have to write the system more than once - and it's critical that the language and tricks you use encourage such evolution rather than deter it (which is the problem with most existing languages and code styles). This raises a lot of issues between strong and dynamic/inferred types and how to strike the right balance at the right time.

Ultimately, if you've been a developer for a while, you've likely encountered many of these techniques at one time or another in random contexts. But when to use one technique over another and how best to apply them is only something that comes from experience. I always say that an expert is not someone who, given a problem, knows what to do - rather an expert is someone who, given a problem, knows what NOT to do. This book gives some pretty clear guidance on what the architectural drivers are that would cause you to proceed one way versus another. Indeed the book reveals new options that you probably didn't even consider were possible before and I think that's ultimately what they're trying to build awareness of - which I think it succeeds quite well. Walking through the examples and doing the exercises will give you a lot of the experience to start becoming such an expert - hopefully without as much of the pain of failure that the rest of us had to go through.

I expect this to be one of those books I read through every year. Quite readable and comprehensible like a novel rather than a text book. Highly recommended.
Profile Image for Matt Diephouse.
92 reviews39 followers
May 19, 2021
I thought this book sounded very promising. I enjoyed SICP. I don't normally code in Lisp, but I've written some and think Clojure is a nice example of what can be done with it.

But this book was a huge disappointment.

The prose of the book reads like a poorly written academic paper, IMO. It does a very poor job of explaining. There are lots of code samples and lots of explanatory text about what the code does (which itself doesn't speak very highly of the code), but it's extremely lacking in detail about the important bits and the big ideas are.

Consider the beginning of section 4.2:

Term-rewriting systems are powerful tools for creating domain-specific languages for manipulating expression-like information. If we have a syntactic system of expressions, where we may need to replace some subexpressions with "equivalent" subexpressions, we can often use a rule-based term-rewriting system to describe those transformations. For example, many compiler optimizations can be expressed as local rewrites of program fragments in a larger context. The essential features of a term-rewriting system are the use of a pattern matcher to identify the information the be transformed, and a template system for instantiating the replacement. There has been extension research into the problem of constructing convergent term-rewriting systems from equational theories (systems of "equivalent" expressions), but we won't get into that here. Also, there is a superficial similarity between the patterns matched against and the templates for instantiation, which may suggest the possibility of making bidirectional rules; we won't look at that either. First we develop a simple unidirectional system, ni which patterns are used to recognize inputs and templates are used to make outputs.


The examples given are also extremely uncompelling: numerical analysis, checkerboard moves, etc. None of them are particularly relevant in the design of large scale systems.

The book is trying to argue for an embrace of dynamic programming (it doesn't get any more Scheme than that). But the ideas are hidden because of the writing.
Profile Image for Bugzmanov.
231 reviews97 followers
May 24, 2021
It was an instant buy and I'm a huge fan of Gerald Jay Sussman.
But the book did nothing for me. I gave up after slugging through 50% of it.
It felt like I've learned couple of scheme tricks and re-read about couple of Susssman's big ideas of design. But the book just doesn't help me to bridge these two islands.
And my proficiency with lisps is not at the level when I can appreciate the tricks I'm learning.
Profile Image for Denis Romanovsky.
215 reviews
May 13, 2021
Quite interesting theoretical and practical thoughts on flexibility in software development. Very intriguing comparisons with biological systems.

There was a bit of discomfort from the choice of the programming language for code samples.
Profile Image for mht.
22 reviews2 followers
Read
January 12, 2022
I liked it, but I think I'll have to read it again.
Profile Image for Brent Velthoen.
4 reviews2 followers
January 4, 2022
I give the authors kudos for recognizing that there is a huge gap in books targeted at professional programmers (or at least applied computer scientists) about advanced topics in academic research that can actually help with writing solid, maintainable code, code that not only gets the job done but that can survive months or years of modification at the hands of others. That being said, and I say this as a target reader who gleefully devoured the 400 pages or so, Scheme snippets and all, I'm not sure this is the book they intended to write. They seem to take for granted that the multiple techniques covered (DSLs, combinators, interpreters, pattern-matching, backtracking, layering/AOP, propagation networks) are superior to the normal way of writing programs (what that is, of course, they never really say). They don't actually provide any evidence for this claim. There is also no account of popular software libraries that are written in alternate styles yet have been maintained for many years without sacrificing adaptability or extensibility (i.e. Spring, Netty, Lucene, JUnit). Perhaps they think their elucidation of each technique using some real-life examples will prove the usefulness of the approach. The examples are the best part of the book. They present large snippets of Scheme code and work through stages of increased difficulty. The examples are tilted toward an academic audience, however: strategy games, numerical calculations, unit conversions. I would have liked to see more real-world examples from the domain of professional programming: ORM, UI composition and rendering, workflow state machine, control systems, robotics. They do present a novel method of datum layering used for data provenance that may prove useful in visualizing the results of automated reasoning programs (though how this would translate to ML is left out). Programmers will recognize techniques from the chapters on combinators, DSLs, interpreters, though they may not have encountered those techniques in practice, certainly not in Scheme. Java and JavaScript have popularized lambdas and higher-order functions. Pattern matching has become fairly well known outside of functional programming due to Scala and, more recently, Swift. The layering technique is based on AOP, though the authors present a novel dispatcher model based on CLOS. Propagation networks resemble recent graph processing frameworks such as Google's Pregel. The authors' presentation of all this material is surprisingly compact and highly readable, so programmers will benefit from having it all in one place and with such detailed examples (the complete source code can be downloaded as well). The most suggestive and unfinished part of the book is the authors' use of recent findings in evolutionary biology and genetics to suggest radically different approaches to programming. One concept they mention repeatedly is degeneracy, the capability of one failing mechanism to be replaced by another mechanism that may have evolved for alternate purposes. They attempt to show an example of how degeneracy can be put to use in calculations that depend on prior assumptions that can vary in accuracy, but the example doesn't really lead to any "ah-ha" moment. One gets the impression they are attempting to show their students an interesting topic for a future research project. Good fun, yes, but not part of a programmer's toolkit just yet.
Profile Image for LT.
414 reviews4 followers
Want to read
May 30, 2023
cs 139
Displaying 1 - 7 of 7 reviews

Can't find what you're looking for?

Get help and learn more about the design.