I was familiar with Tom Griffiths's academic research (particularly his work on concept learning, and also, his 2006 paper "Contextual Dependencies inI was familiar with Tom Griffiths's academic research (particularly his work on concept learning, and also, his 2006 paper "Contextual Dependencies in Unsupervised Word Segmentation" was a seminal paper in Bayesian NLP), and so I was really excited to see that he'd written a pop science book.
I was expecting this to be a pop science book about computational cognitive science, but instead it was a pop computer science book. I don't think I'd ever encountered a pop computer science book before, at least not like this one. I mean, obviously, I have seen all the pop AI books on the shelves, talking about the singularity and its implications, or the resemblance of a neural network to a human brain, or whatever. But this is the first pop sci book I've encountered that talks about core computer science topics. Like, I suspect that a lot of non-experts really have no idea what computer science is about. They probably think it's about programming, or fixing broken computers, or whatever. They've probably heard of algorithms, but don't really know what they are. I think that, if such people read this book, they'd get a much better understanding of what algorithms are, and how integral they are to computer science. This book talks as if algorithms are what computer science is really about; it introduces readers to the concept of efficiency and the importance of finding efficient algorithms; and it also emphasizes the importance of proofs and mathematical results in computer science research. This fits very well with my own understanding of the discipline, and I'm glad to see it being conveyed to a popular audience.
Each chapter of the book covered a different computer science problem (searching/sorting, caching, networking, etc.). In each chapter, the authors explained the problem in very concrete terms, relating it to challenges in everyday life; they then explained some of the computer science results relating to that problem. The book was remarkably well-written; it took these very abstract and mathematical concepts and made them extremely accessible to a lay audience. Obviously, they don't go into the full mathematical details (though the notes in the back of the book are extremely rich and do provide some mathematical explanations and a lot of pointers into the literature). Rather, they give a really good conceptual overview of what these problems are all about. I was continually impressed at how good of a job they did describing these core CS problems in layman's terms. (Since I am a computer scientist, I was familiar with most of the problems already. But in the couple cases where I really didn't know anything about the topic (networking and algorithmic game theory), I felt like I learned a lot.)
Probably the main thing this book does is introduce non-experts to some of the core concepts used by computer scientists, and how they apply to daily life. Like, as a computer scientist, I don't just use CS concepts when solving CS problems; I also use them all the time when reasoning about everyday life. When I'm hanging out with fellow computer scientists, I notice that we reference CS concepts all the time. Like, about a week before I started reading this book, I was out getting lunch with two friends who are also computer scientists. One of them explicitly commented on the exploration/exploitation tradeoff when choosing what to order off the menu. When you study a topic in enough depth, its concepts start to permeate everyday life; the field of study gives you an entire conceptual toolkit for reasoning about ordinary things. This book takes that toolkit and makes it accessible to non-computer-scientists. It provides non-computer-scientists with this set of conceptual frames for viewing the world. I would therefore recommend this book to all my non-CS friends who want to know what all of us computer scientists are talking about all the time. :)
If I had to name a main theme of this book, it would be the importance of tradeoffs, and the fact that rationality doesn't mean perfection. The authors repeatedly mention that people tend to have this conception that computers always get perfect answers; that they go off, exhaustively examine every solution, and then return with the best one. But they explain that in actuality, sometimes the constraints of the problem mean you actually *can't* get a perfect solution. For instance, in the secretary problem, the setup is that you literally can't search the entire space of possible secretaries and then choose the best one; you are forced to make a tradeoff between gaining more information and risking missing the best candidate. In that case, computer science tells you what the optimal tradeoff is; in other cases, the tradeoff will depend on your particular use case. For instance, the authors talk about the tradeoff between searching and sorting (since all sorting is really just done to make future searches more efficient); how carefully you should sort something will depend on how often you expect to be searching it. Sometimes it's more rational (that is, more efficient) to sort something part-way than to sort it absolutely perfectly. (I am not sure if the authors actually used the phrase "tradeoff between efficiency and accuracy", but they definitely conveyed the concept in several chapters.) They also explain that, with some problems, even if you want to find the absolute perfect solution, you can't, because the problem is intractable. (Interestingly, they introduce the concept of "intractable" but never mention the words "NP-complete" or "NP-hard", even those that's something a lot of laypeople have heard of; I'm curious why they made that decision.)
Anyway, this was a very well-written book. (If we could give star ratings to different aspects of the book I would absolutely give this book 5 stars on writing style. However, as it is, I reserve the 5-star rating for books that were really important to my life in some way. And because I'm already a computer scientist, I didn't really learn that much from reading this book. So it gets 4 stars. But it was really a very high-quality book.)
The book's conclusion introduced the very interesting idea of "computational kindness" -- the idea that one of the ways you can be kind to people is by reducing their computational load. For instance, when planning to meet up with someone, you can suggest a few concrete times that work for you, instead of asking them when they're free and making them search their whole calendar for something that satisfies the constraints. This was a cool and very sensible idea....more
[Note: This is a reference book; I didn't actually read it cover to cover. I did read the first two chapters in full though.]
For the last couple years[Note: This is a reference book; I didn't actually read it cover to cover. I did read the first two chapters in full though.]
For the last couple years, I've been working as a software engineer, and I've found myself getting very confused by a lot of our Java code. Why do we use dependency injection? What's a factory and why do we need them? It felt like everyone else on my team had gotten some memo that I didn't receive.
It turns out that everyone else on my team *did* get some memo that I didn't receive, and that memo was this book.
This book describes the concept of design patterns, which are broad overarching ways of structuring your code. Design patterns are not about ensuring syntactic or algorithmic correctness; rather, they're about writing your code in a way that makes it easily extensible, restructurable, and maintainable. A design pattern is not something like "use for-loops for iteration"; that's just a specification of the syntactic structure of the language. And, as far as I understand, "test your code using unit tests" is not a design pattern (since it's not really about code structure), just a good testing practice.
An example of a design pattern is something like using a factory to make new instances of an object. Suppose you have some interface Foo, and an implementation of it called FooImpl. And suppose you frequently need to create new instances of this. You could pepper your code with "Foo foo = new FooImpl()", but then suppose you wrote a new, better implementation of the Foo interface called FooImplImproved or something. You would have to find each instance of "new FooImpl()" and replace it with "new FooImplImproved()". This is a pain. So instead, you could create an object called FooFactory which returns instances of Foo. Then you could do something like "Foo foo = FooFactory.create()". This create() method would then just contain "return new FooImpl()". Then, when you wanted to change FooImpl to FooImplImproved, you would only have to change it in one place: in the FooFactory.create() method.
I think I would have benefited from encountering this book in college, before I ever worked as a professional software engineer. But I wouldn't have fully understood or appreciated it then. I still don't fully understand it, but now that I've worked in industry, I have a much better understanding of the need for maintainable code.
This book definitely changed how I think of programming / software engineering. And, if I'm understanding correctly, back when this book came out, it changed how *everyone* thought about software engineering. As far as I know, this book introduced the concept of a design pattern. The book tells you about all sorts of different design patterns, but I think the main impact of the book was not teaching people individual design patterns, but introducing them to the concept of a design pattern altogether. Once you have that concept, you can identify and use new design patterns more more easily. The specific design patterns presented are certainly useful, but the concept itself is more important.
Also, in the spirit of "reading the history of philosophy backwards", this book taught me a lot about what was known about software engineering back in the early 90s, just based on what it felt like it needed to explain to its audience. One thing that surprised me was that it went out of its way to explain the separation into interface-based inheritance and implementation-based inheritance. I'd always taken that distinction for granted, because it's built into Java, which was my first language. But I realized, after reading this book, that the distinction between implementing an interface and inheriting an implementation was not always obvious. And in C++, that distinction is not a syntactic feature, but merely a design pattern. (Which makes me wonder what it would look like if OO languages incorporated more of these design patterns into their syntax.) Anyway, "program to the interface, not the implementation" was something I had only learned since starting at this job; it's not something that was covered during my undergrad education. So I was glad this book went out of its way to emphasize its importance.
Anyway, this book absolutely gets 5 stars, for introducing me (and also the rest of the software engineering world) to a new conceptual framework that allows software engineers to do a much better job. I expect that I will return to this book very often and will always view it as a useful resource....more