TL;DR – There was a lot in the book that I didn’t know about and/or that was helpful. Equally there was a lot of topics I was aware of but that the authors reminded me of or expanded my understanding. Worth buying and reading 👍
For those of you who don’t know, this book is a collection of short “essays” or “blog posts” about Java programming and programming in general, written by a whole load of different authors.
I won’t review the book chapter by chapter because it would take ages, but I’ll reference some of the chapters I think are great and finish with a few criticisms to, uh, balance things out.
For context: I’ve been writing Java professionally for 6 years at one company.
Chapters I Liked
I liked Edson Yanaga‘s coherent explanation of why immutability helps solve the problem of state management.
Michael Hungor‘s chapter on JMH was so practical that I nearly added some benchmarking at work the day after I read about it, but then I realised it wasn’t appropriate for the problem I was trying to solve. Regardless: a great chapter, exactly what I was hoping would be in the book.
ArchUnit is something I had not come across before, but seemed really useful, and Daniel Bryant‘s chapter was really practical (read: contains code). Unfortunately I’ve not been convinced of the benefits of a stricter class architecture yet so I’ve not put this into practice either. If I was building libraries for other teams or for public consumption then this is something I’d revisit.
I’ve been reflecting on a project I’ve worked on for the last few years and one of the things that stood out to me with hindsight is how much technical debt we introduced to ship the product and provide value to customers. I appreciated Abraham Marin-Perez‘s mature take on “code restorers” slowly improving codebases over time instead of throwing legacy code away or reimplementing it in one fell swoop.
Christin Gorman pointed out a very useful part of the ZonedDateTime class which lets you control what should happen in the “duplicate” hours that occur when daylight savings time changes. I had not considered this “edge-case” before 😬
I totally agree with Steve Freeman about making variables final. Yes!
Michael Hunger listing tools to create flame graphs including IntelliJ was so helpful I sent a late night Slack message to a colleague for them to pick up in the morning and by the time I checked in with them they’d generated one in IntelliJ and were analysing it!
Jessica Kerr did a great job of reframing my perspective on our abundance of feature flags and production migration paths with some extra tips for making those observable. I’d highly recommend this chapter on “designing change, not code” as it conveys more accurately what software engineering looks like on
legacy established products.
Maciej Walkowiak does a really nice job articulating the benefits of being engineers who are willing to (and therefore actually do) solve problems in any language and more importantly at any layer in your software stack: frontend, backend, infrastructure. Teams are arguably more productive when members of the team aren’t siloed into a single area of the codebase. However, there is a challenge in ensuring that your codebases can be picked up relatively easily by newcomers, but I think this can be solved by using common/popular tech and creating useful onboarding for anything more esoteric that the team has introduced.
Carlos Obregón was preaching to the choir with his chapter on avoiding null.
Jeanne Boyarsky‘s chapter “It’s Done, But…” hit a little close to home, calling out the fallacy of referring to incomplete work as complete. I think the team I’ve been working in recently has perhaps been over-optimising moving our Jira tickets to the “Done” column at the cost of testing and actually tracking all of the work that needs doing to complete non-trivial tasks.
I don’t have any official certifications from Oracle or AWS, and tend not to think of them as being worth pursuing, but Mala Gupta reminded me of their benefits.
Ben Evan‘s chapter on “Unspeakable Types” was fascinating to me, learning that I can define inline objects with functionality but not referenceable type. I’m not sure if this is actually a useful solution for any particular problem and if so, if its a wise choice, but its fascinating nonetheless. Edit: I actually used this the other day in some tests to validate what happens if some object is not serializable by Jackson.
Mike Dunn‘s brief intro to Kotlin was useful and practical. I work on a mixed Java and Groovy codebase, so its good to know that Kotlin could also be introduced gradually, although I’d be keen to learn more about the limitations and gotchas of introducing and switching over to Kotlin before starting to embrace it.
Uberto Barbini‘s chapter on loving legacy code was helpful in expressing ways to approach older codebases to those who are new to them and have that kneejerk “this is awful” reaction.
There’s a load of useful advice from Mario Fusco about designing APIs.
Ken Kousen‘s chapter on Groovy was quite entertaining.
Jenn Strater‘s advice on how to move beyond “this works by magic” and really get to grips with tools and technology was helpful. When I realised I had started practicing that skill it felt like a big turning point in my abilities as a software engineer.
During the last year or so I’ve struggled with “proper functional programming” ie monads, semigroups, functors, currying for its own sake, and so I appreciated Nicolai Parlog‘s pragmatic take on why Java’s Optional API isn’t “a proper monad”. I think a lot of my frustration with more advanced FP has been that it feels like its getting in my way, rather than helping me.
I’d long wondered what the practical applications of package-private classes and methods were, and Marco Beelen‘s chapter on the default access modifier answered that subconscious query. I feel a refactor coming on…
It was refreshing to read Heinz M Kabutz pointing out flaws with common “clean” or “readable” code expectations by highlighting some OpenJDK source code. As I will mention later, I feel like there’s a common but naïve rhetoric regarding aspects of code readability and cleanliness that often go unquestioned.
“Boolean blindness” was a condition I only became aware of in 2020, so it was interesting to me to then read Peter Hilton‘s chapter about it. I’m pleased to say that it has actually changed how I write code!
Although I’ve attended several Devoxx presentations about Java’s module system, I am still none the wiser on how I should be using that instead of the classpath for the applications (not libraries) that I build. Given that I’d just finally completed an upgrade to Java 11, Nicolai Parlog’s chapter just reinforced that position. Maybe I’m not
Googling DuckDuckGoing for the right thing…
Brian Vermeer‘s chapter on dependencies was a bit of a pointed reminder to take vulnerability scanning seriously. It’s really not that hard to automate and deal with in a timely manner. No excuses here.
I find applying “separation of concerns” hard work, but Dave Farley gives a load of great reasons why its worth spending more time (re)designing your software to fit this “pattern”.
Recently I was struggling to use Ratpack’s compute/IO thread model correctly and Dawn and David Griffiths’ chapter on coroutines reminded me of that. I’d like to find some time to explore Kotlin more.
In the same vein, I was really struck by the late Russel Winder‘s chapter on how we haven’t abstracted threads away in the same manner as other things like the call stack or heap memory management.
I really liked Jannah Patchay’s thoughts on what makes really, really good developers (spoiler alert its not their ability to write code). I my opinion, software engineering is a communications role. So having great communication and relational skills are extremely valuable.
Having recently been working on a codebase full of Eithers to represent failure values Kevlin Henney‘s chapter on unchecked exceptions was a great read. It shines a light on why checked exceptions kind of failed in Java.
Nat Pryce‘s chapter on fuzz testing I could have used yesterday when I was implementing tests for some new logging related business logic. Maybe I should revisit that next week…
When I started writing Java professionally, the customer I was building software for had a requirement in our contract that we provide something like 80% test coverage. Although we definitely wrote tests that increased our coverage but didn’t increase our testing, I found it a really helpful discipline. Everytime I spend a decent amount of time writing tests I always find a load of bugs (and no I don’t practise TDD), so I really liked Emily Bache‘s idea to make test coverage a part of code reviews.
Like Mala Gupta, Colin Vipurs chapter on certifications was a helpful reminder that the official ones do have value and can be useful after all. Maybe I should try and obtain one.
Java’s memory model is still a bit of a mystery to me, and I’m aware that its changed since Java 7 so Maria Arias de Reyna‘s chapter was a helpful refresher although I woud like to read more about it and how its changed.
Code examples that are not actual real world code (or simplified real world code) are lazy and less helpful than real world code IMO.
I’ve come to a point where I believe that a lot of the popular narrative on code quality/readability/cleanness is naïve or oversimplified. I’m not sure I’d want my colleagues to be writing code as if their non-software-engineering grandparents were the target audience. I’m intending to write more about this in the future.
Honestly? The book was too long. As you might have picked up by now, I was bookmarking every
other third chapter (37 out of 97) in my Kindle app which is why it took so long to write this review. In reality it’ll take me years to begin to apply half of the improvements, tools or techniques outlined above. The flip side of this? There’s quite possibly something for everyone in there, you just have to find it 🙂