#begin

 

And, that’s it folks; We’ve discussed the entirety of the book called The Pragmatic Programmer by Andrew Hunt and David Thomas. Oh boy, this was a blast and really interesting. This book remains one of the best books about engineering practices I’ve read so far. The great part of it is that everything still applies to modern day engineering even though the book was written almost 25 years ago. I think that’s a major indicator about how good the content of the book really is. Many books about software are outdated within the first few months. Because technology evolves really quickly or engineering practices go our of date or simply get nullified. I mean, look at what DevOps did to the way infrastructure is done. I believe many books written about infrastructure management really don’t apply anymore. Of course, the fundamentals do, but the details have changes drastically.

Before we wrap things up for good; let’s recap what I think were the most interesting topics in the book.

 

Chapter 1 – A Pragmatic Philosophy

I think that one important concept to understand about software is that entropy exists. Overtime, when left unattended, even software degrades. Even when you are not changing any of the source code the external environment will be changing. And it changes quickly. This creates entropy just as much as dirty code.

Another really great piece of advice is the fact that maintaining your portfolio is very important. Especially in the instable job market we are today. If you’re currently looking for a job in game-dev, you better have a solid portfolio because without it you will probably not make it very far. Its a sad reality.

 

Chapter 2 – A Pragmatic Approach

Chapter two is what I think the most fundamental chapter of the book. It’s about the pragmatic approach. So even if you don’t want to spend time reading the entire book, read through chapter 2 at least. Chapter two lists all the major practices that make up a pragmatic programmer. It explains the DRY principle. We should not have duplicated code, within the same bounded context. And comments that explain the implementation qualify as duplicated code as well! I really love this!

We also get introduced to the concept of orthogonality in this chapter. Orthogonality is another word for decoupling. We want individual systems in our games to be decoupled so we can add a thin integration layer between them. That makes systems testable, replaceable and maintainable. You don’t want your character controller somewhat dependent on the database queries, to let’s say get information about walking speed on your equipped boots. That’s a nonorthogonal design!

Another fundamental concept is tracer bullets. Remember them? They are production ready code used for exploratory purposes. Think of tracer bullet code as prototype code that complies with production ready practices and design. Tracer bullet code is not throwaway code, it could remain there for the duration of the project. In most cases I think tracer bullet code will at some point be replaced by more integrated code. Especially when the software evolves and the architecture needs to be adapted. But still, you have to expect that the tracer bullet code will exist for the remainder of the project.

Chapter two also presented the, let’s say, opposite of tracer bullet code; prototypes. Prototypes are often throwaway code. But before you roll with this expectation please make sure you communicate that with stakeholders. Don’t just expect it’s throwaway code because you will shoot yourself in the foot when you have to evolve the bolognese souse dripping ball of spaghetti. Trust me, I’ve been in such a situation, even worse, a colleague of mine wrote the prototype and then I got put on the project to continue. But they expected me to take the prototype and evolve it into the final product. It had all kind of assumptions which were definitely not ready for production. So, always make sure you communicate the intend of the prototype with stakeholders; if they are unwilling to throw away the prototype when the phase is done, you will probably be better off with a tracer bullet appraoch

David and Andrew also mentioned domain languages in this chapter. These relate a little bit to what Eric Evans calls Ubiquitous language in Domain Driven Design. David and Andrew were a bit early to this party and I think Eric Evans articulated the concept in far more detail. But the basics are all in this book. David and Andrew also talk about Domain Specific Languages (DSL). They said we need to program close to the domain and for example also throw exceptions that match the domain. So instead of throwing a NullReferenceException, throw a WeaponPrefabNullException or something.

The last important topic in the chapter was about estimating; Estimating is notoriously hard in software. We just don’t now what weird situations we will encounter. Uncle Bob also talks a lot about estimating and his advice closely matches the advice in the Pragmatic Programmer. He says its always best to give a datetime range instead of a specific datetime. If you give a specific datetime, you are probably lying. Not on purpose, but there’s just too many unknowns most of the time. I think I have mentioned this before, but it’s best to investigate the Pert method for estimating. I’ll leave a link in the shownotes.

 

Chapter 3 – The Basic Tools

Chapter three was all about the basic tools. This mostly boils down to learning the terminal, using API’s instead of GUI’s and selecting your favorite tool and learning it very vert well. To the point that the tool gets trained into your muscle memory. I think the advice to find your way through the terminal is great as well. The terminal is such a powerful tool and it will open up so many doors when you get accustomed to it. Using the terminal will allow you to circumvent GUI’s and call API;s directly so you can design your own workflows instead of following the ones that UX designed. This will make for some very flexible workflows. We discussed the ultimate power of plain text. Plain text rules the configuration world. It drives the unity engine, cloud infrastructure and documentation. David and Andrew also mention source code control but and that you should use it. In my opinion there’s not a single valid argument to not use source code control systems. They are free to use and very easy to set up. If you’re not using any, shame on you, and get you ass an account on github, gitlab or any other source code control provider.

 

Chapter 4 – Pragmatic Paranoia

The next chapter was about pragmatic paranoia. I think this chapter boils down to not being dogmatic, even about the pragmatic practices. We cannot write perfect software, period. What we can do however, is out our best effort towards writing perfect software. We can use practices suggested in the book like designing by contract and assertive programming. We can use exceptions properly and make sure we use our available resources in a good way. David and Andrew also mention that when a failure is detected, let it crash early. We don’t want errors to be propagating through the code and showing up totally somewhere else. I bet you’ve probably seen that happening in your career. We must have a balanced approach of throwing exceptions. We don’t want to be throwing them left and right. Remember Prof. Ousterhout’s principle of defining errors out of existence. Design your API’s so they can work around errors.

 

Chapter 5 – Bend or Break

Chapter five was called Bend or Break. We’ve talked about the Law of Demeter, again and again and again. This law is so prevalent it also showed up in the previous chapter about pragmatic teams. We should be able to design software by only talking to our neighbors and not to strangers. What Andrew and David made explicit in this book is the fact that the Law of Demeter also applies to methods, not just data. Don’t start calling methods on objects that aren’t directly referenced by the caller. We also discussed another very, very important concept in the chapter, especially in the context of game development and that is temporal coupling. Temporal coupling is a type of coupling where the software is bound to time. This means, if you cannot control time in let’s say your tests, you are doomed to resort to manual testing or maybe some very elaborate visual testing. We want to be able to control time as much as we can. So if you have some system in your game that relies on the update loop in unity; abstract that update look and only bind to it at runtime. This way you can control it during tests and manually progress, or even revert time. Another big concept that was introduced here was the concept of “It’s just a view”. In lot’s of cases the presentation layer really is… just a view. Try to decouple business code from the views as much as possible. This is also a mantra from Uncle Bob and what Clean Architecture is all about. But Clean Architecture doesn’t just decouple the UI, but any low level layers from the business code. We’ve talked extensively about this topic in previous episodes to go have a listen. David and Andrew also dive deep into the concept of metadata. Nowadays we would call the concept they are describing, data oriented programming. We want to be able to adjust our systems, at runtime, by just using data and configuration files. But then again, remember Prof. Ousterhout’s advice to pull complexity downwards and not expose overly complex config files. Because you are just displacing complexity from you, as an engineer, to the user of the system. And he or she will probably not be very happy about it. But data oriented programming is a really cool concept. If you have done any projects or experiments with Unity Dots or entity component system you have done exactly that.

 

Chapter 6 – While you are coding

Next was chapter 6 called “While you are coding” and this was also some stellar content. We’ve discussed the idea of programming by coincidence. We should always be knowing what we are coding and how our own code works and how the API’s we integrate work. We don’t need to know all the low level details, but we should know the semantics of the API’s to be able to integrate properly. Chapter 6 also refreshed our knowledge about the O() notation. This will most likely come up in future tech interview questions so better try to understand it. Its generally a good idea to know about O() notation and the algorithm speed you are dealing with. Remember, there is a great chart in the book where they make common notations visual. Good stuff! Then we talked about refactoring. This is an integral part of your job. You should refactor continuously or your software will degrade over time. Even when you are writing really tiny micro-services and throwing the entire thing away and starting over is faster, I would still count that as refactoring. You’re still changing structure, without changing function. Andrew and David also reconfirm that writing testable code is just a really great idea. For any long lasting system, tests will save your ass and make refactoring and evolving the software easier. The last topic of the 6th chapter was about Evil Wizards. When we are using any kind of code generators, from classical generators to modern AI generators; if you don’t understand the code it generates you will get yourself into trouble. So make sure to read it thoroughly and if you are dealing with AI generated code, just ask it to explain it to you when you don’t understand. You could potentially just copy code from copilot and paste it into chatgpt or vice versa and see what the AI overlord comes up with for an explanation.

 

Chapter 7 – Before the Project

The next chapter, was of course, chapter 7 which was called Before the Project. This chapter dealt with all the things we need to keep in mind before or at the start of a project. Like requirements engineering. David and Andrew mention that requirements engineering is not so much as just simply gathering requirements from relevant stakeholders. You really need to dig for them sometimes. You need to educate your stakeholders about the impact of what they are asking. And often you will need to extract software requirements both functional and architecture characteristics from vague statements. A simple example might be that you are dealing with a startup with some very ambitious plans. They specifically mention that, if the game becomes a success they will expand and try to acquire other studios. This indicates they need a flexible architecture that allows for integration points and hooks to latch on to. Think maybe some game company trying to create a meta-verse. Even though the idea of a meta-verse is pretty dead if you ask me. Well, there is this Omniverse thing by Nvidia and the OpenUSD standard which sounds pretty cool but let’s see where that goes in the upcoming years. Unity even has support for OpenUSD by the way. But, David and Andrew also mention that some stakeholders will provide you with impossible puzzles. They say you should try and change your approach, design it twice as Prof. Ousterhout would say. David and Andrew also say that to break procrastination you can as well just start prototyping. When you notice you get bored quickly, it means you are ready to start production code, if not you were correct about prototyping first. Maybe move into a tracer bullet approach next. The next part of the chapter was about diagramming techniques. Remember David and Andrew’s law; don’t be a slave to any formal method. Formal methods can lock you into specific patterns and this way you might not be able to express the concepts you want. They specifically mention the part where, in their opinion UML is not well suited to express dynamic systems driven by metadata. So, choose your documentation and diagramming methods lightly and make sure you are able to express the intend of the software in a clear way.

 

Chapter 8 – Pragmatic Projects

And last but not least was chapter 8 which made an effort to raise everything we’ve learned in previous chapters to the team level. I think this is a great addition for the book because this is often overlooked. Some people still think that software development is some asocial, individual nerdy effort. But once you are 1 day into your software engineering or gamedev career you will know; this is a team sport. Chapter 8 also reassured the fact that we should automate as much as we can. Luckily we have the modern DevOPS movement to back us up. CI/CD has become second nature to many developers, even to the point that some developers might not even know how it was before DevOPS. Now I don’t want to sound old but I remember the days of manually running tests, compiling, downloading cache into a local directory, creating an installer wizard and including that cache and then code signing it. Uploading it to some website or shared disk or even dropping it on some thumb-drive for shipping. It feels like savages living in caves haha. Pragmatic teams also are ruthless with their testing approach. We want to cover as much as meaningly possible with automated tests. You’ll not reach that 100%, especially when dealing with the code that integrates with the game engine, or shaders, but everything else, you should be able to write tests for. David and Andrew are also very serious about writing. Writing is a big part of our job, and it’s not just about writing code. We also need to write documentation, presentations and of course day to day written communication. They mention that we should apply the same pragmatic approaches to these kinds of writing as well. Most importantly, automation, the DRY principle and the fact that any kind of writing is just a view. So when we can, we should use markup languages to style our already written information into a new format. I think this is a cool idea, but in practice might be a bit difficult to achieve, unless you generate a lot of what is written, right? If you have any great idea’s about this, let me know. David and Andrew also talk about expectations. We should be well aware of what is expected of us, and we must also make sure the stakeholders know what they should be expecting. We should not try to “manage expectations” into something we as developers want. David and Andrew say that managing expectations is somewhat elitist, and I agree. It’s like we are forcing our will onto the stakeholder, which is in the end paying our salaries, right. We should work tightly together with our stakeholders and gain a common understanding about the options to make clear what everyone can expect. And the last topic in the book is called Pride and Prejudice. We as pragmatic programmers should take pride in our work. I think this is less of a problem in gamedev than it is in regular software development. I mean, how many times have you seen posts on linked in by gamedevs where they post a screenshot of the end credits of a video game that shows their name. I’ve seen that many times. On the other hand, can you refer to any post ever where someone refers to some commercial software being proud to be a part of it. Well maybe people put up some post when they are about to leave a company for a new job. But, we as pragmatic programmers ARE proud of our work. We are craftsmen and women, we are true engineers who tackle hard problems based on our intuition as well as a scientific approach. I think the best software devs combine the practices of craftsmanship and engineering into one to create a clean and repeatable way of working.

 

Conclusion

And that my friends, was the entirety of the Pragmatic Programmer. I think this was a wonderful book. To this day, the 1999 version is just flat out amazing. I can’t recommend this book enough, its truly a classic and should be read by any software engineer who’s serious about his or her career. I give this book a big 5/5 stars review.

 

#end

01010010 01110101 01100010 01100101 01101110

Hey, sorry to bother you but you can subscribe to my blog here.

Never miss a blog post!

You have Successfully Subscribed!