Book Review – The Pragmatic Programmer

This book is a classic. It doesn’t cover any particular language or technology, instead it provides general advice to the aspiring software developer. This advice is organised as seventy separate aphorism. Each of these numbered tips gives a general recommendation to improve your work. There is a lot of good advice in this book, and I can’t really cover it all in a single post. So I’m just going to try and cover some of the main themes and the parts that I did not agree with.

Modularity is a theme that comes up again and again. The authors advocate for code that is cleanly divided into orthogonal modules with clear APIs. This is, of course, very good advice. Another mantra they return to repeatedly is “DRY – Don’t repeat yourself”. Again, this is broadly good advice, you should definitely avoid unnecessary duplication. But in reality you are going to have to repeat yourself. In fact repeating yourself is often the best option. Another major theme is to avoid programming by coincidence. Again this is broadly good advice. You should not just randomly permute things until they work. However, sometimes this is the only way to find out how things do in fact work.

The authors also advocate for fixing issues whenever you see them. Sure this is a good idea. But the reality of a large complex system is that it just isn’t really possible. In a large evolving legacy code base, you will see a lot of awful code. If you fixed every issue you came across you would never get any work done. Also this kind of tinkering can be pretty dangerous.

The authors strongly recommend making your code highly configurable. They advocate for a model of software where you can completely change the behaviour of your binary with a change to a config file. In my opinion this is an anti-pattern. It makes code execution unpredictable. It makes reading and reasoning about code hard. Having to carefully trace how config values percolate through the code base can be a nightmare. Also, it leads to a lot of dead code, if no one is sure what code is actually used, old code will just be left to rot.

I think that the biggest overall issue with this book is that it is old: it was published in 1999. So a lot of the advice is out of date. I don’t mean that it has since proven to be wrong, but that it is now so widely accepted that you won’t need to read the pragmatic programmer to find it, it will just be part of any normal software development job. For example there is an entire section about how you should use source control. They also recommend using nightly tagged builds as well as integrating testing into your build process. There is even advice on how to use email!

Another problem with this book is that there are very few concrete examples given. This does help to keep the book relatively light and readable. But it makes it hard to relate the general tips to real world programming.

On the whole, this is a good book. It can be quite vague and dated, but there is definitely useful advice in there. I should say that a new edition of this book was published while I was reading it. I assume that it has been updated appropriately, however I didn’t read it so I really can’t say.

Book Review – Functional Programming in C#

I read Enrico Buonanno’s Functional Programming in C# directly after Jon Skeet’s C# in depth. Unlike Skeet’s book, this is not a book about C#, it is a book about functional programming which uses C# is the medium of instruction.

What makes this particularly interesting is that C# isn’t really a functional language. Usually functional programming is discussed in terms of niche explicitly functional languages like Haskell. By using C#, Buonanno makes the principles and practices of functional programming a lot more accessible to the average programmer. He does advocate mixing the more traditional object oriented style of C# with functional programming, but this is not something that really comes through in the code samples.

This book covers the basic concepts of functional programming really well. He explains how and why to avoid state mutation, the concept of functions as first class citizens and higher order functions, function purity and side effects, Partial application and currying and lazy computation. One thing that interested me particularly is the good case the author makes that pure functions should not throw exceptions.

He does not spend a long time justifying functional programming. The two main benefits he repeatedly highlights are easier testing and better support for concurrency. It is clear that a functional approach is more suited to concurrent programming. However the claim that functional code is easier to test seems somewhat dubious to me, and is not really backed up with credible examples. He also claims that functional programming leads to cleaner code. Again, I am somewhat skeptical.

I really enjoyed the discussion of user defined types. In particular the pattern of creating new types that wrap low level types and add some semantic meaning. A great example he uses is an age type. This has only one member, an integer. It’s constructor will only accept valid values for human ages. This means that we have added an extra layer of static type checking to this type: when we want an age, we use the age class, and not just an integer. It also means we don’t have to perform extra checks when using an age type, as we know it’s value was checked when it was initialised.

The material on LINQ was also quite good. LINQ is strongly functional in style, it emphasizes data flow over mutation, composability of functions and pureness. This is all well explained, the author even shows how to integrate user defined monads into LINQ. However LINQ is not dealt with in a single place in a systematic way, which is disappointing. Another gripe I have is that the author uses LINQ query syntax. I do not like query syntax. Not only is it ugly, it is usually incomprehensible.

Buonanno uses Map, Bind and Apply to introduce functors, monads and applicatives in a very practical way. He also goes into detail explaining how and why to use the classic monads Option and Either. We even see variations on the Either monad that can be used for error handling and validation. Both the applicative and monadic versions of Traverse appear near the end of the book as well. In my opinion, Monad stacking is one of the worst anti-patterns of functional programming. So it is disappointing that it only gets very limited coverage. I would also have liked if he had used his excellent examples as a jumping off point to dig deeper into category theory. Perhaps however, that would have been too abstract for what is quite a practical book.

Handling state in a functional way is covered well, but it feels a bit academic. It is hard to imagine applying the patterns he covers in a real world code base. Sometimes you just have to use state! The final few chapters cover IObservables, the agent model and the actor model. These sections were quite interesting but felt a little out of place. They really merit a much deeper dive.

When I finished this book I had a much greater appreciation for functional programming. In particular it gave me lots of ideas of how I could practically apply it in my real life work. The code samples were all very good, occasionally though they were a little convoluted. Indeed they sometimes seemed like evidence against a functional style. But, as someone relatively new to functional programming I appreciated how grounded it was in real world examples. Overall, this book is an excellent resource for C# programmers who want to add a little functional flourish to their code. I highly recommend it.

C# In Depth – Book Review

Jon Skeet is a bit of a legend. He has the highest reputation score on Stack overflow. He got there because of his consistently patient, helpful and correct answers. He is probably the most prominent C# developer there is. So, when I started a new job as a C# developer, I decided to read Skeet’s book, C# in Depth.

It’s a very good book. There is one big problem however, the structure. This book is divided into five parts, each dealing with a successive major numbered release of C#. This chronological structure is quite strange. The overriding assumption of the author is that the reader is familiar with C# 1. Given that C# 2 was released 13 years ago, this is a pretty strange angle. It’s hard to imagine there are many programmers today who are familiar with C# 1 but need a detailed walk through of the new additions to the language in C# version 2 to 5. The book ends up a sort of mix between a history of C# and an intermediate user’s guide.

One example of the problem with this structure is how delegates are covered. They are first introduced briefly in chapter 1. Improvements to the delegate syntax in C# 2 are then covered in detail in chapter 5. In neither of these chapters is there a clear explanation of what delegates actually are or why they are part of C#. Indeed when we reach chapter 10 Skeet covers lambda expressions, which, in reality, make delegates redundant for most use cases.

Another victim of the unorthodox structure is the coverage of class properties. Modern C# syntax allows us to define properties in a very quick intuitive manner. In this book, first we learn about properties as they originally appeared in C# 1. Then, in chapter 7, we see how C# 2 allowed a mix of public getters with private setters. Finally in chapter 8 we see how properties are actually implemented in modern C#.

There is of course a benefit to covering older versions of the language in detail. C# is a language designed for enterprise development. So, if you code in it, you are likely to be working with a large legacy code base. This means that understanding what the language looked like in it’s various iterations is useful. However, these topics would be a lot better served if they were covered all at once, rather than being split over multiple chapters.

Skeet spends a lot of time covering Linq, which is great. Linq is a really cool feature of C#, and he covers cool details, like how to use extension methods and iterators to integrate your own code into LINQ. He also covers the query expression Linq syntax. This is the syntax that lets your write a linq expression in the style of a SQL query. Frankly I think Linq expression syntax is a monstrosity and should never be used, but it is probably useful to cover it, and explain how it works (it’s really just syntactic sugar for the normal linq syntax). There is also a useful section on async code, that gets into a lot of really useful detail.

Overall, Skeet has an ability to make some quite obscure topics interesting and accessible. He always presents new ideas with realistic and useful code snippets. Most important of all, he writes in a fun conversational style, that makes reading his book a lot more fun than a typical intermediate language guide.