You need to sign in or sign up before continuing.

5.0

A very resourceful book that has earned its status as a classic. It's an all-encompassing brew of topics, including personal philosophy, team psychology, coaching in how to think as a developer, but also techniques and practices to utilize as a developer. Without assuming knowledge in any particular language or framework of thought, this book steams you ready to be resilient for whatever the future may bring.

The first few chapters were a little dry for a technical person like myself, but there were some very important facts that my experienced self needed to be reminded of. In the topic "Software Entropy", one of my dearest values is emphasized: if you leave something small broken, this will lead to more disaster in a snowballing effect. I value quality of code very highly, and in a competitive (albeit friendly) working environment it can be hard sometimes to assert yourself. It's nice to be reinforced in my beliefs and convictions by a classic book written by world famous revolutionaries.

Some other tip I highly appreciate are to keep a journal of your technical challenges. It's hard to start doing it, but it is a great way to learn, and not forget about your lesson.

At the heart of this book however, is the "ETC" principle: make your code easier to change. There's many acronyms and ways to achieve this, but ultimately that's what matters, especially in the highly dynamic and evolving world of today. It connects perfectly to the agile mindset they preach, and that many teams these days use: start small and iterate soon and often. We have learned that is to be expected that the requirements are incomplete, faulty or changing, and the same goes for the code. It is subject to change all the time, for all sorts of reason, and if it's easy to change, then you have combatted one of the biggest problems in the trade.

The nuanced differentiation between prototypes and what they have dubbed tracer bullets is very useful as well. Prototyping is intended to explore, or to prove a concept, and it should then be dismissed. If your prototype doesn't feel like it can be trashed easily, you probably put to much effort and detail into it.

Only when your prototype has proven that the concept works, or that the client is happy with the set goal, only then do you proceed to build the actual code. This, you also do incrementally of course, and the suggestion they make is fantastic. Instead of starting to build one component after another (or simultaneously in the case of several people), they suggest to start with writing some feature that hits every part of the program. This is what they call a "tracer bullet", since it gives you a sense of where you're going. Imagine having some feature that hits the database, backend logic and frontend logic (for example). You have the benefit of having their co-operation implemented and therefore proven, which allows for iterations of improvement and expansion in a way that's more operational and therefore testable at a more conceptual level. It is easier to fail fast, and re-iterate.

Again, the first few chapters are especially useful for beginning developers, but starting from chapter 4 there's a good chance you'll learn something new as an experienced developer. I was only vaguely familiar with the idea of "Assertive Programming", and was happy to see examples of "Design By Contract" in other languages such as Clojure.

As far as the more technical chapters go, I believe chapter 5 is the most challenging, packed and important chapter. It's here where they lay out the "Tell, Don't Ask" principle which is crucial for a well-encapsulated component/system. By telling what you need (give me the users who used a discount in the last month) instead of asking for it (can I have the users please, oh, and now I'd like to get all the orders they made, filtered by those who had a discount, ...) you minimize how much the consumer of a provider (a module, API, etc.) is supposed to know about the internal implementation of that provider. This looses coupling, and improves maintainability.

In chapter 5, important lessons about the caveats with inheritance ("Inheritance Tax") are discussed, as well as a completely different mindset (the one used in Functional Programming) to approach your application as a series of data transformations ("Transformative Programming"). Lastly, they explain Finite State Machines as a tool to build applications in a more declarative way. They expand on this with the Observer Pattern, which is expanded upon further in chapter 6 ("Concurrency").

I love how many different methodologies and techniques the book knows to bundle into a relatively small book. One surprising example that I think is (sadly) quite niche is that of "Property-Based Testing", a technique that allows the generation of test data based on the declaration in properties (invariants and post-conditions). This is an incredibly useful technique for certain types of applications, and it's great they expose many people to it in this book.

There's so much more to say, but I'll conclude by praising the authors with their incredible book. They understand how learning works, how psychology works, and no less importantly, what the software development trade is about. They managed to write a book that's a perfect mix of a reference and a (superficial) teaching textbook, making it suitable for reading from start to finish, as well as for referencing tips/parts at some other time.

They approach pragmatism and agility from first principles, without the buzzwords and fake layer. The topic of superficial and fake agility is even treated in the book as a problem, which I greatly appreciate.

If you want to learn some fundamental principles to become a professional, resilient and future-proof developer, be sure to pick this great classic up!