
Book Review: A Philosophy of Software Design - dailymorn
http://www.pathsensitive.com/2018/10/book-review-philosophy-of-software.html
======
quaunaut
This book has been my own personal technical revolution over the past few
months. I've been programming professionally for 7 years now, so while I'm not
the most experienced I'm certainly no one new either. Some takeaways from how
it changed my flow:

1\. It gave me specific goals in terms of my own improvement, and the chapter
titles did a good job of being a stand-in for challenging my own intuition.

2\. In mentoring other developers, those I shared some of the lessons in the
book with saw huge improvement literally week over week. I saw, personally,
one of my mentees go from producing code that was hard for me to step through
without bringing up half a dozen issues, to producing code where my largest
criticisms were ecosystem dependent.

3\. It created common language for discussing with teammates why certain code
felt wrong.

4\. It significantly reduced time spent refactoring later. The subtleties in
some of the points make a re-read valuable as well. One of the better examples
of this, was "Make code just a little generic"\- often, we attempt to code
things as generic as possible, and end up making what is effectively code soup
that doesn't help accomplish the problem. Instead, building specifically for
this problem, but trying to spot places it can be made just a little bit more
generic, has altogether eliminated times I know I would've had to refactor
again later if I hadn't been thinking of it.

5\. The book knows what it isn't. He even says right in the forward and on the
related Google Talk[1], that this first version is probably not the most value
it can produce, but that hopefully by version 3 it'll be there.

For my time and energy, it's been more influential on how I develop software
than anything else I've read. Furthermore, despite coding in primarily
functional and/or dynamic languages, the examples used never made that a
problem despite always being based on C. I recommend it highly.

1\.
[https://www.youtube.com/watch?v=bmSAYlu0NcY](https://www.youtube.com/watch?v=bmSAYlu0NcY)

~~~
barbs
> _4\. It significantly reduced time spent refactoring later. The subtleties
> in some of the points make a re-read valuable as well. One of the better
> examples of this, was "Make code just a little generic"\- often, we attempt
> to code things as generic as possible, and end up making what is effectively
> code soup that doesn't help accomplish the problem. Instead, building
> specifically for this problem, but trying to spot places it can be made just
> a little bit more generic, has altogether eliminated times I know I would've
> had to refactor again later if I hadn't been thinking of it._

Wow, I've often felt this during my time coding. Unnecessary abstractions
often just make things more convoluted and increases boilerplate when adding
new things. Great to see this being addressed.

~~~
MaxBarraclough
This principle is well known: 'YAGNI'.

~~~
gitgud
You Ain't Gonna Need It is a great principle, but I think this is slightly
different, as it implies it's useful to abstract it a little... So maybe JAIL?

Just Abstract It a Little

~~~
TeMPOraL
Agreed. JAIL is YAGNI/KISS with a little bit of sanity sprinkled on top of it.
You generally want to keep code simple and straightforward, but that doesn't
mean avoiding the most obvious and most probably useful generalizations.

------
tabtab
I always wanted to write a "Philosophy of Software Design", except I wouldn't
dictate HOW to write software. Instead I'd focus on what questions to ask and
what trade-offs to expect. It would be Yoda-ish: Yoda teaches you how to ask
questions and how to find answers, not the answers themselves.

In the end: there is NO right way, only trade-offs. At least know what the
tradeoffs are. My book would be a trade-off recognition training guide.

I would state my experience, though. Such as "In my experience, typical shops
are more comfortable with pattern X over pattern Y. I have no idea why: it's a
psychology question I don't have the funds to answer."

And there'd be a chapter on how to recognize and scrutinize fads.

~~~
chrisweekly
Write it! Start with a blog post series if "a book" is too great a hill to
climb!

~~~
justaguyhere
Seconded. Start with a series of blog posts to gauge interest, level of effort
etc.

------
arximboldi
I haven't finished the book and I am not sure I will. I was quite disappointed
because from the title and description I was expecting something deep, that
presented more questions than answers, navigated constraints, attempted to
discuss the nuances of defining the problem of designing itself. On the
contrary, it is a collection of superfluous recommendations for Object
Oriented programmers presented without much justification.

The writer uses a very narrow perspective and just "assumes" all this can be
generalized. One of the most recurring topics in the book is "complexity", but
it is just introduced with a narrow one sentence tautological definition
without offering any interesting discussion. All kinds of assumptions are
taken for granted and not discussed.

So overall, the book reads so far like a bland collection of "do this, don't
do that blog-posts". Papers like "Out of the tarpit", speakers like Rich
Hickey, etc. offer much more interesting discussions on the topic of design
and complexity, and are definitely more argumentative and "philosophical".

I even feel bad for writing something in such a negative vibe about a book.
But really its pretentious title lead to such disappointment...

~~~
jpittis
I've read his book cover to cover and have enjoyed and learnt from a number of
the concepts he discusses.

That being said, after recently reading "Out of the tarpit" and being a long
time Rich Hickey fan, I completely agree that the model of complexity
presented by the book feels simplistic.

I can't quite put my finger on why though. Maybe cause complexity in software
has a lot more to do with understanding the problem domain rather than just
the structure of the code. IMO it was worth the read, but I was slightly
disappointed and it was without a doubt not a be all end all reference. (And
it would be unfair to expect it to be.)

------
nostrademons
I feel like this review is making an important point, but the point it's
making is talking past the point Ousterhout is making, and so this isn't much
of a rebuttal at all.

The idea behind "deep modules" could be expressed as _learning an interface
should save you work, not cost you work_. There's a couple of deep insights in
that. One is that every new interface you create imposes a cost on the
programmer who is reading the code, and so you should be sparing in them. New
functions and new classes are not free; each time you add one, it makes it
that much harder for the maintenance programmer or library user to grok the
API as a whole.

The other big insight is in _embedding complexity in the code_. This was a
perspective shift I learned from talking with Ben Gomes (my boss's boss at the
time, and now head of Search at Google) while complaining about how messy some
of Google's code was. His argument was that the code is complex because the
problem is complex. By embedding the complexity into the code, you let the
computer deal with it on every search request instead of letting the user deal
with it on every search request. The number of times a programmer will look at
the messy code probably numbers in the single digits, while the number of
searches that code gets per day numbers in the billions, so by making things
_a little_ better for the user at the cost of it being _much worse_ for the
programmer, you are saving millions of hours in mental tax for humanity.

As programmers, we all have a drive toward simplicity, but it's worth
remembering that we exist within an economic reality too. If you want people
to use your product, your product has to _do something they don 't want to do
themselves_, and if it's easy for them to whip up a quick tool that solves
their problem, your product is doomed in the marketplace.

The point the review is making seems to much more about _protocols_ , and the
ability for interfaces to serve as a firewall that lets different
implementations interoperate. If you don't specify that interface precisely,
you get abstraction leakage, where an interface that seems simple at first
actually can become very complicated.

This is a valid and interesting point too, but it's worth remembering that the
vast majority of interfaces have only a single implementation. It's not
necessary to specify that interface in precise detail as long as the user of
that code has a reasonably intuitive view of it. They can always go look up
the details as necessary, when the strange behavior occurs, while the "deep
module" saves them a significant amount of work as long as they stick to the
happy path.

~~~
TeMPOraL
> _The number of times a programmer will look at the messy code probably
> numbers in the single digits, while the number of searches that code gets
> per day numbers in the billions, so by making things a little better for the
> user at the cost of it being much worse for the programmer, you are saving
> millions of hours in mental tax for humanity._

Thank you. I'm going to quote it, and keep quoting it, at the "developer time
is more important than machine time" crowd - the one that then goes and
externalizes all this "machine time", making it "user's time (and
electricity)".

~~~
carlmr
I think it's great but it shouldn't be quoted without the part about the
complexity of the problem. Because often you have simple problems solved in a
complex manner that also lead to slow/buggy code that angers the user.

------
wokwokwok
By far the most interesting part of this is the contention:

interfaces should be simpler than their implementations

Which the author then goes to some lengths to absolutely reject.

I find this very interesting, because 1) this is the view I’ve always held and
2) I’m having trouble accepting the authors proposition than an interface and
a _formal specification_ are equivalent.

...if they are, certainly, the non-code ‘level 3 artifacts’ that define code
behaviour but are not code, will be much more than the implementation in some
cases.

However, I dispute more strongly that the principal is wrong.

Surely not every implementation is longer than its interface, but _in general_
striving to avoid bloated hideous interfaces is ideal.

Certainly it’s a sliding scale... and the idea of ‘too simple’ an interface
that is superficially simple seeming, but actually very complex (eg. the file
I/O example) is food for thought.

...but I feel too much is made of rejecting the point that all interfaces
should be simpler than their implementation _absolutely_.

Did the book really claim that?

Hm.

I want to actually read it myself now.

~~~
bwy
I agree with you that the review seems to have misunderstood the author on
this point. I wrote a comment on the blog to explain more. I think the review
mixes up the words abstraction and specification, especially once I dug a
little bit into the correspondence on the draft he posted for the book
author's feedback.

------
ilaksh
The reviewer seems to say that he has a higher level of programming mastery
than the author of the book.

Thats where I could not listen to him anymore. I would entertain the idea that
theoretically programming languages that have features like contracts or
specifications could be more robust or effective in some ways or for some
applications. And actually I am interested in seeing examples of feature rich
applications written in languages with these types of features.

But I am not convinced of the practicality of these languages or the
superiority of the reviewer. The proof is in the pudding. I would challenge
the reviewer who has clearly placed their knowledge and skills above the
creator of Tcl/Tk and RAMCloud to show the useful projects he has created that
prove this superiority.

~~~
quickthrower2
I like to be open minded but he does seem to have spent most of his time in
academia, and not a lot of time spent on commercial software. So I wonder if
its genius or hubris it can be hard to tell the difference.

------
bch
JO (John Ousterhout) is so thoughtful and lucid.

My experience with him is firstly through Tcl, which I like more than he does
now (time for a TIP: "-jo" switch to [unset] which removes complaint to unset
non-existent variables)[0], and his book on it[1], and various papers. His
work is at once both powerful and humble. Note in [0] how he without much
emotion he suggests how Tcl came to be less prominent, and how even at Tcl's
height, he explained without ego why it was there, and how it would leave[2].
His papers on threads[3] and comments on performance and testing[4] are also
lovely reads. I encourage any developer or architect to read or re-read them.

[0]
[https://www.youtube.com/watch?v=bmSAYlu0NcY](https://www.youtube.com/watch?v=bmSAYlu0NcY)
(thx `quaunaut)

[1] [https://www.amazon.ca/Tcl-Tk-Toolkit-John-
Ousterhout/dp/0201...](https://www.amazon.ca/Tcl-Tk-Toolkit-John-
Ousterhout/dp/020163337X)

[2]
[https://vanderburg.org/old_pages/Tcl/war/0009.html](https://vanderburg.org/old_pages/Tcl/war/0009.html)
(This is The Law, and it is good.)

[3] [https://web.stanford.edu/~ouster/cgi-
bin/papers/threads.pdf](https://web.stanford.edu/~ouster/cgi-
bin/papers/threads.pdf)

[4] [https://web.stanford.edu/~ouster/cgi-
bin/sayings.php](https://web.stanford.edu/~ouster/cgi-bin/sayings.php)

------
mcguire
I'm going to disagree witha lot of this review. Here's an example:

" _In other words, take a conditional out of the spec for the function. But in
Section 10.5, he tells us that we should add a conditional to the spec of a
function, namely in making Java’s substring method defined for out-of-bounds
indices. I’m not completely sure he’s wrong (as I discuss in my Strange Loop
talk, it comes down to: is there a clean way to describe this behavior?), but
I find his claims that this makes the code “simpler” only slightly more
credible than his claims about the Unix file API._ "

Ousterhout contrasts that with the similar operation in Python. Substring
throws exceptions if the indices are out of range, Python returns the part of
the string that is in-range. For example, calling it witha start, end pair
where start > end results in an empty string, not an exception; it's much
easier to use in my experience. And I doubt the formal specification is any
larger, to address the author's point.

The formal does of Unix I/O is a horror show, sure, but what does the spec of
it plus all of the filesystem that can back it look like?

~~~
tabtab
This sounds like the "limp versus die" design decision:
[http://wiki.c2.com/?LimpVersusDie](http://wiki.c2.com/?LimpVersusDie)

The "right" answer depends on the domain. For a web startup, you may want to
live with occasional errors being ignored in order to get your product up
quickly and grow market share. Early Amazon.com used to fudge up my orders,
but such didn't end the company.

But a bank probably doesn't want the software to "guess" if there is a
potential numerical problem. It would rather have the batch process "crash".
Otherwise, it could generate thousands of bad transactions and get sued to
Pluto.

People used to debate this with MySql's default "truncation" setting. MySql
was popular with start-ups because you could get it up and change the tables
quickly without dealing with persnickity details, living with stuff
occasionally falling thru the cracks.

~~~
mcguire
The difference is between total and partial functions. A total function can
have well-defined results (thus, no guessing) and is much easier to use than a
function that unnecessarily fails.

------
blub
The greatest thing about this book is that it develops an antidote to the work
of the gang of three (Martin, Fowler, Beck), which would have everybody write
only 3 line functions TDD style if they could.

This can be seen for example in the intro chapter to Fowler's 2nd edition of
Refactoring, where he pulverizes some code into submission.

~~~
_pmf_
That has been exactly my sentiment after reading the book (although I'm only
anti-Uncle Bob, not against Fowler).

------
jasim
I'm enjoying Ousterhaut's "A Philosophy of Software Design", but it is
striking how much it is shaped and limited by the languages that are
implicitly considered (mostly, imperative OO languages).

One oddity is the view of the class as the only real scope at which one can
build abstractions. The idea that one can use little abstractions to build big
abstractions, without cluttering the final abstraction to be presented to the
user, is nowhere in sight.

Most shockingly to me, I've found no reference to types as a design tool.
Sure, precise names help you avoid confusing physical block ids and logical
ones. But wouldn't a type-based distinction be way better?

\-
[https://twitter.com/yminsky/status/1005066579929911296](https://twitter.com/yminsky/status/1005066579929911296)

~~~
johnousterhout
Good point about using types. I should have mentioned that as a way to
eliminate the block number problem in Section 14.1; I'll fix that in a future
revision of the book.

~~~
jasim
That'll be a great addition to the book.

Can I also recommend Yaron Minsky's talk on OCaml, specifically the part where
he talks about "making invalid states impossible":
[https://youtu.be/-J8YyfrSwTk?t=1079](https://youtu.be/-J8YyfrSwTk?t=1079)

I've found this to be the single most valuable programming technique I've
learnt.

Richard Feldman dives deeper into the topic with a lot more examples in
[https://youtu.be/IcgmSRJHu_8?t=73](https://youtu.be/IcgmSRJHu_8?t=73)

------
emmanueloga_
Meta 1: I enjoyed his review. It got me interested in learning more about all
these concepts I've never heard about: "Level 3 Software? What's that?". It is
not clear to me if a lot of this terminology is of his creation or if it comes
from literature.

Meta 2: What better way to establish yourself as an expert than disagreeing
with a currently recognized one? Not saying he did not back up his claims. In
fact, I want to read more of his materials now to check that up.

Meta 3: This reading also gets me excited about investigating model driven
development more. In this post, he talks a bit about the value of strict types
related to such modeling, but lately I've been reading and writing some
Clojure code and I'm slightly swinging back to more dynamic typing as a more
flexible way of writing modular systems.

~~~
saisundar
Level 1, level 2 and level 3 are the authors conceptions. Another post of his
details what he means... [http://www.pathsensitive.com/2018/01/the-three-
levels-of-sof...](http://www.pathsensitive.com/2018/01/the-three-levels-of-
software-why-code.html?m=1)

------
aqibgatoo
What are some of the best design books you people would recommend for a junior
developer?

~~~
blub
This one. I also read Code Complete (2nd ed) when I was a junior and found it
very helpful, but I don't know how well it has aged.

Object Design by Wirfs-Brock is a practical OOP book.

I would avoid anything with clean code in its name, they're generally dogmatic
and obsessive about TDD.

------
thr0w__4w4y
> Thanks John Ousterhout for his extensive comments on this review

That's a bit meta, eh? The author of the book being reviewed reviewed a review
of his book.

------
mrcoder111
I'm a recent college grad from a good CS program. How do I get better at
bugfixing and diagnosing code? To give a specific example: I was recently
working with a Tensorflow code base for image recognition, and Tensorflow kept
hanging (no error, just hanging) or giving me shape errors. I felt stuck.
First, the lack of error made it hard to diagnose, and when I did get the
shape error, I didn't understand why quickly. I find myself too dependent on
stackoverflow for bugfixing and if someone hasn't solved it, I feel helpless.
I've tried reading through the Tensorflow source but it's pretty verbose and
hard to understand. Are there any books that give you concrete methods to
really understand other people's code well and fix bugs?

~~~
lmilcin
In my understanding, to begin learning diagnosing issues in code you need to
understand your stack very well. Try to invest time explicitly learning bits
and pieces of how your platform works, in detail.

Once you learn few different platforms and spend some time diagnosing problems
you will start recognizing recurring patterns in problems. Hopefully this will
gradually become your ability to diagnose difficult issues on unfamiliar
platforms.

------
pacuna
I've been wanting to read this book but there's not a digital version yet. I
wonder if it's to avoid pirate copies everywhere.

