#89 - Code That Fits in Your Head - Mark Seemann
“The goal of software is often to sustain an organization. An organization invests in software in order to achieve some goal and hopefully to sustain itself in helping it achieve that goal.”
Mark Seemann is an acclaimed author, international speaker, and a highly experienced developer. In this episode, Mark shared some insights from his latest book, “Code That Fits in Your Head”, on how to write sustainable software and manage software complexity. Mark first started by sharing why he wrote this book and explained why software development is hard. He also pointed out the difference between software engineering and other physical engineering disciplines, especially on the set of constraints. Mark then explained the importance of writing sustainable software and shared the perspective that code is a liability instead of an asset. Towards the end, Mark shared about the Rule of 7 as a guideline to manage code complexity and a few practices we can use to build sustainable software, such as checklist, vertical slice, x-driven development, and command query separation.
Listen out for:
- Career Journey - [00:06:26]
- Code That Fits in Your Head - [00:07:49]
- Software Development is Hard - [00:10:55]
- Software Engineering vs Physical Engineering - [00:15:01]
- Sustainable Software - [00:17:58]
- Code is a Liability - [00:19:55]
- Rule of 7 - [00:22:43]
- Checklist - [00:31:23]
- Vertical Slice - [00:35:52]
- X-Driven Development - [00:39:47]
- Command Query Separation - [00:45:07]
- 3 Tech Lead Wisdom - [00:49:38]
_____
Mark Seemann’s Bio
Mark Seemann is a bad economist who’s found a second career as a programmer, and he has worked as a web and enterprise developer since the late 1990s. As a young man, Mark wanted to become a rockstar, but unfortunately had neither the talent nor the looks – later, however, he became a Certified Rockstar Developer. He has also written a Jolt Award-winning book about Dependency Injection, given more than a 100 international conference talks, and authored video courses for both Pluralsight and Clean Coders. He has regularly published blog posts since 2006. He lives in Copenhagen with his wife and two children.
Follow Mark:
- Website – https://blog.ploeh.dk
- Twitter – @ploeh
- LinkedIn – https://www.linkedin.com/in/ploeh
Mentions & Links:
- 📚 Code That Fits in Your Head: Heuristics for Software Engineering – https://amzn.to/3MF9xJ8
- 📚 Dependency Injection in .NET Core – https://amzn.to/3lvXd1H
- 📚 The Checklist Manifesto: How to Get Things Right – https://amzn.to/3wyG25Z
- 📚 Growing Object-Oriented Software, Guided by Tests – https://amzn.to/3yRhh6K
- 📚 Accelerate: The Science of Lean Software and DevOps: Building and Scaling High Performing Technology Organizations – https://amzn.to/3G7VXLH
- The Magical Number Seven Plus Minus Two – https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two
- Cyclomatic complexity – https://en.wikipedia.org/wiki/Cyclomatic_complexity
- Command query separation – https://en.wikipedia.org/wiki/Command%E2%80%93query_separation
- Pluralsight – https://www.pluralsight.com/
- Clean Coders – https://cleancoders.com/
- George Miller – https://en.wikipedia.org/wiki/George_Armitage_Miller
- Atul Gawande – https://en.wikipedia.org/wiki/Atul_Gawande
- Nat Pryce and Steve Freeman – http://www.growing-object-oriented-software.com/authors.html
- Bertrand Meyer – https://en.wikipedia.org/wiki/Bertrand_Meyer
- Nicole Forsgren, Gene Kim, and Jez Humble – https://itrevolution.com/accelerate-book/
- Haskell – https://www.haskell.org/
- Eiffel – https://www.eiffel.org/doc/eiffel/Learning_Eiffel
- F# – https://fsharp.org/
Skills Matter is an easier way for technologists to grow their careers by connecting you and your peers with the best-in-class tech industry experts and communities. You get on-demand access to their latest content, thought leadership insights as well as the exciting schedule of tech events running across all time zones.
Head on over to skillsmatter.com to become part of the tech community that matters most to you - it’s free to join and easy to keep up with the latest tech trends.
Tech Lead Journal now offers you some swags that you can purchase online. These swags are printed on-demand based on your preference, and will be delivered safely to you all over the world where shipping is available.
Check out all the cool swags available by visiting techleadjournal.dev/shop. And don't forget to brag yourself once you receive any of those swags.
Code That Fits in Your Head
-
The book actually started out more as a catalog of software development, software engineering heuristics, because I spend a lot of time coaching various different software development teams over the last decade or more. I discovered that there were certain explanation and certain rules of thumb that people kept asking me the same questions, and I kept giving them the same answer.
-
As Martin Fowler says, “Any fool can write code that a computer can understand. Good programmers write code that people can understand”. That’s from his book, “Refactoring”.
-
I think what makes software development hard is sometimes writing the code is difficult, but it’s more the fact that you have to go back and read what was already written and try to understand what was the purpose of it and why was it written in that way? What’s it actually doing and where can I insert some new behavior into the existing code? So we spend much more time reading code than we actually spend writing code.
-
And I have this thesis that runs through the book that one of the reasons why we are having trouble reading code is that the human brain has certain cognitive constraints. There’s just so much working memory that the brain actually has and it’s quite limited. On the other hand, a computer has a completely different way that its memory works.
-
A computer can easily juggle 10,000 things at the same time, and the human brain can juggle maybe six or seven things. So the guiding principle then becomes to see if you can write code that takes into account not the memory limit of the computer, but the memory limit of the reader.
Software Development is Hard
-
I think complexity grows exponentially with software. So, writing something like, “Hello World” is not difficult. You know, most people can do that. Getting started with things that are a little bit more complicated than that is something that most people can learn. That’s one thing that might influence the way that people from the outside look at the industry.
-
And you see this very often in projects, development software that starts from scratch from greenfields. The first couple of months, things actually go pretty well, and developers move at a good pace. And then as time goes by, things starts to be slower and slower.
-
One problem with the other stakeholders is that often they discover that velocity decreases. They discover that too late. And then they start to complain about why is everything going so slow.
-
I think there’s a problem from the outside is that, first of all, you have this sort of exponential growth of complexity as time goes by, if you don’t do anything to manage that complexity.
-
And I think another thing is that there’s a disconnect between how easy it is to formulate a problem and then how difficult it actually is to implement in code. So there are things that are difficult to write.
-
We have this disconnect as well, where people who don’t have the technical insight, they often get completely surprised by how difficult or hard things are. We even get surprised by that ourselves.
-
Software development, copying things is free. We do new things every time because we never do the same thing. In industry, you may build a thousand copies of the same car because there’s actually a cost associated with creating a copy. But there’s no cost associated with creating a copy in software. So we never actually spent much time creating copies.
-
Everything we do is always producing new things. When we’re producing new things, it also means we do things we’ve never done before. So we are constantly engaged in doing things that we have never done before. Sometimes it looks like something we’ve done before. We have some experience. But we’re always doing new things because if we weren’t, we could just have copied what we already have created early on.
Software Engineering vs Physical Engineering
-
Engineering is always about producing an outcome, a desired outcome within a set of constraints.
-
The very common metaphor of software development is like building a house. That’s a metaphor. I don’t believe in that metaphor, but it’s very common. And one of the problems is that the set of constraints is completely different because when you build a house, you have some constraints that are imposed upon you basically by the real world. You have gravity. You have strength of materials. You have a lot of logistics you need to take care of.
-
Whereas you also have a set of constraints in the case of software development, but the constraints are quite different. Often there’s no implied order to things. So the example that I just gave, the way you can’t start with the roof. There is an implied order to things. You have to sort of start from the bottom and go up if you’re building a house. The constraints imply or they enforce that order on the way you have to do things in a certain order.
-
That’s not so much the case when you do software development, because you can basically start wherever you’d like to start. If you want to start with the user interface, you can do that. If you want to start with a database, you can do that. So that’s much more flexible.
-
But then you have another set of constraints and people are often not really aware of those. First constraint is the software needs to actually execute correctly on the computer. That’s sort of like the bottom line. That’s not the end goal. That’s sort of like the bare minimum.
-
In order to be able to keep on developing on the software, developers will have to read the existing code in order to understand how to move next.
-
I think it’s a little bit comparable in the area of software engineering, in the sense that the logistics are more related to how can you enable people to keep on working on adding more stuff to the software six months from now, a year from now and two years from now? And the logistics that are involved in that is also the hygiene that is involved because you have to make sure that the code is understandable to those people who come after you or just your future self. So that’s also a set of constraint.
Sustainable Software
-
A lot of people talk about maintainable software and I did that for many years as well. And then I thought, well what if I’d start to call it sustainable software instead of maintainable? Because I think using a word like maintainable, you’re talking about that characteristic of the software from the developer’s perspective.
-
The goal of software is often to sustain an organization in some way. It doesn’t have to be a private enterprise. It might also be a government organization or an NGO or things like that. But the software rarely exists just for its own sake. It always exists to fulfill some other goal that an organization has.
-
An organization invests in software in order to achieve the goal and hopefully also to sustain itself in helping it achieve that goal. So software is there to sustain the organization.
Code is a Liability
-
The observation that code is a liability, not an asset. That’s not mine. I think I have it from Tim Ottinger, who claims to have it from someone else. Basically, the idea is that if we want to talk about assets versus liabilities, the code itself is really not worth anything.
-
You can make this thought experiment. If you imagine that you’d written the perfect software for the purpose of whatever it is that you’re trying to do, and by some magical way, you know that there are no bugs in the software. It does exactly what it’s supposed to do, and there will be no change requirements.
-
Why would you need to keep the code around? The code just created the software. A set of EXE files or DLLs or whatever it is, you can always just copy them. You don’t need to be able to compile them ever again. I’m assuming here a compiled language and not in an interpreted one. So I would argue that the code is, at best, worth nothing in that scenario. There’s no reason to keep it around.
-
The reason why we keep code around is not because it has an inherent worth in itself. We keep it around in order to be able to make changes to the software. In the real world, it’s not. It will have bugs, and even if it has no bugs, it will need new features because there will be changed requirements and so on. So we keep the code around in order to be able to produce the outcome that we actually desire.
-
That’s just like any other liability in the sense that you can keep spare parts around in your factory in order to be able to create new cars, whatever it is that you produce. All the parts you keep on stock is a liability and the same thing goes with code.
-
That also means that in terms of being productive, you have to manage the liability. That means minimizing the cost of owning that liability. So, again, we come back to this thing where, you know, if you make it as readable as possible, the cost of owning or having that on stock, the cost goes down.
Rule of 7
-
One of the conclusions of this paper is that we have short-term memory, and it can hold about seven things in our short-term memory, plus minus two. So that means that if we try to remember random numbers, names or colors or variables that we read in code, we can juggle around seven things in our short-term memory before we start to forget some of that stuff again.
-
That’s a very interesting insight in terms of what it means to read code because what we do when we read code is that we do our best to sort of interpret the code as we go. So it’s almost like we’re running a little interpreter, a little compiler or a little emulator in our brain that sort of tries to understand. And that means we need to keep track of state.
-
We can’t make those interpretations of code unless we are able to maintain states in our head. Again, you know, I think we can keep track of, as the paper says, maybe seven things. But if there’s more state that we need to keep track of than those seven things, then the code becomes really much harder to understand.
-
I went a little bit with the number seven for a couple of reasons. First of all, I wanted something simple and easy to remember. There’s also this thing where in lots of cultures, seven is sort of like a magical number anyway, because you know it from fairytales and so on.
-
There could be lots of different things. I like to look at cyclomatic complexity. So that’s one thing where you might say you’d like to have some sort of threshold in your code.
-
I think it’s very important to have some thresholds you can agree on as a team to say, and measurement like cyclomatic complexities should in general not exceed a particular threshold. That threshold might be seven, might be something else.
-
The reason why I think thresholds are important is that if no one looks after when are things getting near towards something that is problematic, if no one pays attention to that, your code will grow in complexity in lots of different dimensions, and you’re not really going to notice until it actually really hurts. At that time, it’s very late. It’s difficult, and it’s expensive to fix.
-
So that’s just one quantification mechanism. I’m looking for those quantifications, various different quantifications in order to be able to monitor thresholds. Cyclomatic complexity is one.
-
You also mentioned just counting objects. Basically, counting variables is a very unsophisticated way of introducing your metric. the thing I want to do with metrics, I don’t want the metrics to be something that only the machine can do for you. I want metrics to be something where you can just do it if you’re discussing with a colleague, if you’re doing pair programing, or if you’re doing a code review.
-
Basically, the measurements that I tend to look for are cyclomatic complexity, object activation, number of variables, lines of code, inner method and the width of the code. That’s pretty much what I’m looking for.
-
We should really come up with a better name for it because the name sounds really scary, but it’s a super simple concept. The idea is basically just to count the number of distinct pathways through the code. So if you imagine you have a method where there’s a single if branch, either code can go through the ‘if’ branch if the boolean expression turns out to be true, or it can fall through the ‘if’ branch if the boolean expression turns out to be false. In this very simple example, you have two distinct pathways through the code. We count looping as a distinct pathway as well. Because in most cases, if you loop over a collection and the collection is empty, all the code that’s within the loop is not going to be executed.
-
Basically, you just start by one. Because there’s always going to be one distinct pathway through the simplest line of code. And then every time you see a branching instruction or looping instruction, you just increment the counter by one. This is something you don’t need a tool to do that. You can do that in your brain while you’re just looking at the code. The name is horrible, but it’s just counting distinct pathways through the code. And it tells you a little bit about the load on your short-term memory as well.
Checklist
-
[Atul Gawande] has this wonderful phrase that one of the people who partook in his experiment said that the checklists increase the outcome without any increase in skill. So you can use exactly the same skill level as you already have, but then by using a very simple aid to memory, which is a checklist, you can improve the overall outcome of a process by making sure that you do things in the right order.
-
I know that a checklist is something that, to most people, sounds a little bit oppressive or at least boring. What we need to understand, first of all, the origins are from a military aviation. You can imagine pilots going through checklists before they take off, and before they go into landing and so on.
-
A checklist is an aid to memory. It’s basically just to make sure that you always remember to do things in a certain order. If you’re already good at it, you can just run through the checklist and say, okay, did I remember to do this? Because if you actually do that as a process, you will be surprised how many small things you forget. It’s human nature that we forget all of those things.
-
And, again, I think we have this very limited capacity in our short-term memory. So everything we can offload and say, well, sometimes, we can remember things by putting them in long-term memory. But if we can somehow automate things away in various different ways by, for example, following a checklist, that means we don’t have to spend limited brain power of making sure that we remember to do all the things correctly. We just go through a checklist.
-
I want to be very explicit here that a checklist is not a control mechanism. It’s not something that your managers should be able to leverage in order to keep an eye on you. It’s there to improve the process.
-
I would think twice before I started turning a checklist into something that produced reports. You can automate the checklist. You know most languages and most development environment come with all sorts of extra tools that can make suggestions about your code. So in some languages you should call them linters and in .NET we call them static code analysis.
-
I think it’s very important when we talk about checklist to say, it’s for your benefit, it’s not for your manager’s benefit. It’s just there to make sure that you remember to do things in the right order. And while it seems stupid, it’s probably a good idea.
Vertical Slice
-
This idea of a vertical slice is to say, try to implement a feature of the software all the way through as narrowly as possible. Because I’ve seen lots of teams that get hung up on all sorts of side quests where they say, “Well, yeah, but before we can implement that feature, we need to have the locking system in place.”
-
The idea with a vertical slice is to say, figure out a simple way to get all the way through. You don’t have to have layered application architecture, but basically just say, well, implement a feature so that it actually works.
-
The reason why it’s called vertical slice, by the way, is that I think it’s named like that in opposition to the traditional horizontally layered architecture where you typically write an architecture with a set of layers where the bottom layer is going to be a data access layer. And then you’ll have maybe a business logic in the middle and you have UI on the top and maybe some more layers in between. So the idea of the vertical slice is just to say, well, instead of thinking about those horizontal layers, you then create a vertical little section through that layer cake.
X-Driven Development
-
This idea about using some sort of driver in order to inform you of “What’s a good idea? What should I be doing next?” - I think that’s an important thing to do because, again, the human brain is actually not very good at thinking formally.
-
Before, I talked about the limitations of our short-term memory. But also if you just look at our ability to do a formal analysis of things. We’re not very good at that, actually. And that’s one of the reasons why, despite our best intentions, we always create defects in the code because we write code that we think behaves in one way, and then our brains just weren’t really up to the task. And then we created an off by one error or whatever it is that we do, and that happens all the time.
-
I think for that reason, it’s always a good idea to say, okay, can we institute some processes that will help us verify that what it is that we are doing is actually appropriate? So that’s the idea behind test-driven development is you write a test, and the idea of the test is that it’s a stimulus. Our response is to write a code that can pass the test. We get the verification that we’ve done the right thing by first we see the test fail, and then we write a simple implementation and then we see the test pass. So that’s one way where you can use an external driver in order to make sure that you’re doing the appropriate thing. You’re not just editing code and thinking it works. You’re actually getting some verification of that.
-
Another thing that I talk about is if you’re working in a language that is statically compiled and has static typing, you can use the type system to tell you whether or not you had done the right thing. Because if the code doesn’t compile, it certainly doesn’t work either. And that doesn’t mean that if the code does compile that it works. But, again, you can design things in certain ways so that if your code compiles, it’s more or less likely to actually compile.
-
That’s a concept from lean manufacturing called Poka-Yoke, and I’m probably not pronouncing it correctly, but it’s Japanese and it means something like mistake proof. But basically the idea is that you can write an API so that if the API call compiles, it probably also works the way it’s intended to work because it’s designed in such a way that you can’t really call it in the wrong way. So that’s another way where you can sort of use the static type system as a driver for changes.
-
I also talk about how to use things like static code analysis, or other languages would call that linters and use that for drivers of changes.
Command Query Separation
-
He thought it would be a good idea to distinguish between two types of operations. He called one of them commands and he called the other one queries. Command is something that changes the state of basically the observable universe. All of those things we call side effects. Bertrand Meyer thought that if you have a side effect, the API and operational methods should then be about side effects.
-
On the other hand, if you want to have some data, then you should have another kind of operation that can go and read data from somewhere and return data. It might also just be hard-coded data or a calculation like adding numbers together.
-
If you want data, that’s a different operation, and he called that query. So it doesn’t have to be a database query. It could be any sort of thing that produces data. It’s not a good idea to mix those two things together. If you want to produce data, then produce data. Don’t mix them. So that’s the command query separation.
-
The reason why this is beneficial is that, again, particularly if you’re looking at things that have a static type system, if you have an operation that is a command only, you know, it’s all about the side effects, and it’s not allowed to produce any sort of output. It’s very recognizable because you can always tell by the method signature that it has a void. It has no return value. So that means whenever you encounter something that is void, that has no return value, you know it’s going to be about the side effects.
-
If you know that a particular code base is designed according to the command query separation principle, then you know that whenever you run into something that does produce an output, it will have no side effects.
-
Being able to just at a glance which of those two buckets a particular method falls, that just saves you so much time because now you don’t have to go and read the implementation in order to understand, is it one or the other?
-
So there’s just fewer surprises in a code base like that. When we go back and talk about reading time, that just frees up reading time. That cuts down on the number of different files you have to go and visit in order to understand what’s going on. I’m not saying that it completely eliminates the need to go and read other things, but it saves you some time there.
3 Tech Lead Wisdom
-
Take breaks
-
I regularly take breaks. I run the Pomodoro timer.
-
I also, during the day, often take longer breaks where I go grocery shopping, or go and do the dishes, other things like that. The reason for that is, again, this has something to do with how the brain works.
-
I get all my insights when I’m away from the computer. I can sit and look at code or problem definitions for a long time and not really go anywhere. And then I go grocery shopping. While I’m in the supermarket, I’ll go, “Oh, now I know what I need to do.”
-
If at all possible, take breaks during the day. That’s really going to help your brain to come up with good ideas.
-
-
If at all possible, see if you can get to Continuous Delivery.
- It seems like the single most important thing in order to determine whether or not your organization works effectively is can you do Continuous Delivery? Because so many other things will sort of come as a byproduct in that journey towards Continuous Delivery.
-
Learn functional programming
- I have an argument in the book that sort of takes this idea we talked about command query separation a little bit further and say, well, if we add another constraint and other idea to this idea about queries and say, not only must they be side effect free, they must also be deterministic. You have something called a pure function.
[00:01:26] Episode Introduction
Henry Suryawirawan: Hello again, my friends and listeners. Welcome to the Tech Lead Journal podcast, the show where you can learn about technical leadership and excellence from my conversations with great thought leaders. And this is episode number 89. Thank you for tuning in today listening to this episode.
If this is your first time listening to Tech Lead Journal, subscribe and follow the show on your podcast app and social media on LinkedIn, Twitter, and Instagram. If you enjoy listening to the podcast and would like to contribute for future episodes, support me and this podcast by subscribing as a patron at techleadjournal.dev/patron.
As a developer, many of you would have seen it in your project or when working with legacy software, a code base that is very complex, hard to trace and understand, and is super difficult to make changes to it. This kind of code is a code that doesn’t fit in our head, and it’s one of the main reasons that software deteriorates and rots over the time, and thus becomes unmaintainable. So how can we avoid this problem in our code base?
My guest for today’s episode is Mark Seemann. Mark is an acclaimed author, international speaker, a highly experienced developer and has published a number of books and courses. In this episode, Mark shared some insights from his latest book, “Code That Fits in Your Head”, on how we can write sustainable software and manage software complexity. Mark first started by sharing the reasons why he wrote this book and explained why software development is actually very hard. He pointed out the difference between software engineering and other physical engineering disciplines, especially the difference on the set of constraints. Mark then explained the importance of writing sustainable software, and shared a unique perspective that code is actually a liability instead of an asset. Towards the end, Mark shared about the Rule of 7 that he advocates a lot in the book as a guideline to manage code complexity, and a few other practices that we can use to build sustainable software such as using checklists, building vertical slices, X-driven development, and implementing command query separation pattern.
I really enjoyed my conversation with Mark, learning from him about human brain, short-term memory, and how to write code that could fit in our head easier. I also love some of the practices that Mark shared in this episode, which are very practical and is something that we can start applying straightaway. If you also enjoy this episode and find it useful, share it with your friends and colleagues who may also benefit from listening to this episode. Leave a rating and review on your podcast app and share some comments or feedback about this episode on social media. It is my ultimate mission to make this podcast available to more people, and I need your help to support me towards fulfilling my mission. Before we continue to the conversation, let’s hear some words from our sponsor.
[00:05:45] Introduction
Henry Suryawirawan: Hello, everyone. Welcome back to another episode of the Tech Lead Journal podcast. Today I have with me a guest named Mark Seemann. He’s based in Denmark, Copenhagen. Mark is actually a well-known author and also publisher of few videos, courses on Pluralsight and also Clean Coders. He recently published a book with a title “Code That Fits in Your Head”. So today we are going to discuss a lot about what he means by code that fits in your head. Previously, Mark also authored a book which is very popular. It won the Jolt award, which is titled “Dependency Injection”. So, Mark, it’s really good to meet you today. Thank you for spending your time and looking forward to have a chat more about your recent book.
Mark Seemann: Well, thank you for having me.
[00:06:26] Career Journey
Henry Suryawirawan: So maybe in the beginning, if you can tell us more about your background and maybe turning points or highlights in your career.
Mark Seemann: Alright. Okay. So I was born in 1970 and grew up without computers. I’m not your typical software developer who actually grew up with the early computers. I didn’t. So I actually didn’t think that I was going to have anything to do with computers. I have a degree in economics from the University of Copenhagen. Started out actually in a career in Government, and then figured out that that was really not my cup of tea. So I thought that I wanted to do something else, and I had bought a computer in order to write some of my master’s thesis and stuff like that, and I thought that was much more interesting. So I tried to get a job in IT and this is back in the mid 1990. So basically, if you could spell HTML back then, you could get a job in IT, which was what happened.
I actually started out being just your normal IT professional. And then because I could spell HTML, I actually had written a little bit of HTML. I actually got the job of being the company’s first web master because no one else knew how to do that. It started out really as a niche thing back then, and then I discovered I don’t really want to be an IT pro. I thought software development was much more interesting. I had written a little bit of code before that. So, I got myself another job as a software developer, and then I basically never looked back since then.
Henry Suryawirawan: Thank you for sharing your story. I think it’s kind of like interesting, right? You started from the government. You figure out HTML. Quite a few of us probably started as a web developer and then moving on to as a software developer in general.
[00:07:49] Code That Fits in Your Head
Henry Suryawirawan: So you recently published a book titled “Code That Fits in Your Head”. I assume that code that we wrote is sometimes too big, too complex. Is that something that you’re trying to suggest by writing this book? Or is there any kind of problem that you see that you try to tackle by writing this book?
Mark Seemann: Well, so the book actually started out more as a catalog of software development, software engineering heuristics, because I spend a lot of time coaching various different software development teams over the last decade or more. I discovered that there were certain explanation and certain rules of thumb that people kept asking me the same questions basically, and I kept giving them the same answer. So I thought, well, okay. There’s actually a catalog of things here, ideas. Some of them I’ve learned from other sources and some of them I sort of figured out by myself. So I thought it’s probably worthwhile to connect all of those things, but we also need a little bit of a backbone, a thesis to put a lot of those things together, and particularly with the things that I’ve tried to figure out by myself.
I’ve been thinking now for quite a few years that one of the things that makes software development difficult is that one thing is writing the code, but as Martin Fowler says, “Any fool can write code that a computer can understand. Good programmers write code that people can understand”. That’s from his book, “Refactoring”. And that interested me quite a bit, because I think what makes software development hard is sometimes writing the code is difficult, but it’s more the fact that you have to go back and read what was already written and try to understand what was the purpose of it and why was it written in that way? What’s it actually doing and where can I insert some new behavior into the existing code? So we spend much more time reading code than we actually spend writing code.
And I have this thesis that runs through the book that one of the reasons why we are having trouble reading code is that the human brain has certain cognitive constraints. There’s just so much working memory that the brain actually has and it’s quite limited. On the other hand, computer has a completely different way that its memory works. So if you only take into account the computer’s memory, computer can juggle 10,000 global variables if you wanted to. There’s a famous case with Toyota. If you look up something called the unintended acceleration bug, they figured out that maybe they actually had about 10,000 global variables in the code that ran the car. Well. Okay. So I’m digressing here. But basically, a computer can easily juggle 10,000 things at the same time, and the human brain can juggle maybe six or seven things. So the guiding principle then becomes to see if you can write code that takes into account not the memory limit of the computer, but the memory limit of the reader. So that’s basically the idea, and that’s why the book is called “Code That Fits in Your Head”.
Henry Suryawirawan: I’m sure that almost all developers here, the listeners, me, myself included, we have seen code that probably cannot fit in our head. First, it’s like it’s too big. It’s either too many lines of code in one class, for example, one function, or just too many variables or too many things in one go. And then also at the same time, sometimes you have to jump into multiple files in order to get the full picture of certain things. I think we all have been there and I can see this as a real problem. And when you mentioned about human memory limit, I think that speaks why that sometimes we struggle to read the code.
[00:10:55] Software Development is Hard
Henry Suryawirawan: You mentioned that software development is hard. Most people, predominantly from the business side or the product side, they will think that writing software is easy. For software engineers, sometimes we think it’s not. Really, not that easy. Why do you think there’s this mismatch? Like when you say software is hard. Can you explain a little bit more why is it really difficult?
Mark Seemann: I think complexity grows exponentially with software. So, writing something like, “Hello World” is not difficult. You know, most people can do that. Getting started with things that are a little bit more complicated than that is, again, something that most people can learn. That’s one thing that might influence the way that people from the outside look at the industry. They say, “Well, it’s easy to get started. So, why is it so hard?” And you see this very often in projects, development software that starts from scratch from greenfields. The first couple of months, things actually go pretty well, and developers move at a good pace. And then as time goes by, things starts to be slower and slower. One problem with the other stakeholders is that often they discover that velocity decreases. They discover that too late. And then they start to complain about why is everything going so slow? All the developers must be lazy or something like that. You often get that sort of response. So I think there’s a problem from the outside is that, first of all, you have this sort of exponential growth of complexity as time goes by. If you don’t do anything to manage that complexity, that’s one thing.
And I think another thing is that there’s a disconnect between how easy it is to formulate a problem and then how difficult it actually is to implement in code. So there are things that are difficult to write. There’s still a frontier where people are trying to figure out how do we do all sorts of advanced artificial intelligence, whatever people call it these days. There’s still things that are hard to do. There’s this famous XKCD comic where they say something like, someone comes by and starts giving the software developer a set of requirements. The person said that’s the stakeholder. The stakeholder says, “We need our application to be able to identify if a photo was taken in a national park.” And then the developer says, “Oh, that’s easy. We just look at the coordinates of the metadata on the phone or the photo and correlate that with the national park. That’s easy.” And then, “tag it if the picture contains bird.” And then the programmer says, “Okay, I’m going to need a research grant and 10 developers and 10 years.” Because that is as easy to say, but it’s an order of magnitude more difficult to actually implement a feature like that. So we have this disconnect as well, where people who don’t have the technical insight, they often get completely surprised by how difficult or hard things are. We even get surprised by that ourselves. Sometimes we get a requirement and we say, “Oh yeah, I can do that. I can do that in a week.” And then when you start diving into it, you figure out, “Oh, this is actually really difficult. I have no idea. I thought it was going to be easy. I don’t know. It’s going to be really hard.”
So that happens a lot in software development as well. So I’m paraphrasing, and I apologize that I can’t remember what the source was. But someone said something like, you know, software development, copying things is free. We do new things every time because we never do the same thing. In industry, you may build thousand copies of the same car because there’s actually a cost associated with creating a copy. But there’s no cost associated with creating a copy in software. So we never actually spent much time creating copies. Everything we do is always producing new things. When we’re producing new things, it also means we do things we’ve never done before. So we are constantly engaged with doing things that we have never done before. Sometimes it looks like something we’ve done before. We have some experience. But we’re always doing new things because if we weren’t, we could just have copied what we already have created early on.
Some development organizations call that development part, they call it R&D, Research and Development. And I think that’s actually not too far from the truth. We should probably recognize more than most software development organizations are actually research departments. That might actually go a bit of a way towards setting expectations a little bit better. That last part is something that just occurred to me right now. So I haven’t really thought that through whether that’s a good idea or not. But you know, that’s at least worth thinking about it, I think.
[00:15:01] Software Engineering vs Physical Engineering
Henry Suryawirawan: In your book, the first few chapters you are talking about the metaphors of software engineering versus the physical or mechanical engineering, which have been around for quite some time. And you mentioned that software engineering can not be treated similar to building a house. Can you explain a little bit why software engineering is different than the other types of engineering?
Mark Seemann: Yeah. Okay. So engineering is always about producing an outcome, desired outcome within a set of constraints. I think in the sense that we can talk about software engineering, that’s true as well. But let’s talk about the other things first. You asked about the very common metaphor of software development is like building a house. That’s a metaphor. I don’t believe in that metaphor, but it’s very common. And one of the problems is that the set of constraints is completely different because when you build a house, you have some constraints that are imposed upon you basically by the real world. You have gravity. You have strength of materials. You have a lot of logistics you need to take care of. For example, you can’t just start by building the roof, and then later on say, “Well, yeah, I don’t like the roof. Let’s try to build another roof.” And then later on, once you’re done with the roof, you say, “Okay. Let’s now do the foundations.” That’s not gonna work with the building because the set of constraints is based in the real world.
Whereas you also have a set of constraints in the case of software development, but the constraints are quite different. Often there’s no implied order to things. So the example that I just gave, the way you can’t start with the roof. There is an implied order to things. You have to sort of start from the bottom and go up if you’re building a house. The constraints imply or they enforce that order on the way you have to do things in a certain order. That’s not so much the case when you do software development, because you can basically start wherever you’d like to start. If you want to start with the user interface, you can do that. If you want to start with a database, you can do that. So that’s much more flexible.
But then you have another set of constraints and people are often not really aware of those. First constraint is the software needs to actually execute correctly on the computer. That’s sort of like the bottom line. That’s not the end goal. That’s sort of like the bare minimum. But then you’ll have all these other problems where you say, well, okay. So in order to be able to keep on developing on the software, developers will have to read the existing code in order to understand how to move next. So it’s a little bit comparable to logistics in the sense that you can’t build a house if you can’t get materials onsite and if you excavate a foundation, you need to move all the dirt away from the building side. So there’s some logistics in the real world. And I think it’s a little bit comparable in the area of software engineering, in the sense that the logistics are more related to, you know, how can you enable people to keep on working on adding more stuff to the software six months from now, a year from now and two years from now? And the logistics that are involved in that is also the hygiene that is involved because you have to make sure that the code is understandable to those people who come after you or just your future self. So that’s also a set of constraint. So that’s why I think that we can still talk about engineering, but it’s just very different from physical, structural engineering.
[00:17:58] Sustainable Software
Henry Suryawirawan: I think it’s a good segue as well. Because of the topic that you just described is actually sustainability, right? Which is, I think, one of the main theme of the book. You want the code that fits in your head because you want to aim for sustainable software. You have this lovely quote, which I will read. “The goal is not to write code fast. The goal is sustainable software.” So can you explain a little bit further what do you mean by sustainable software? And why we should aim for sustainable software instead of just rapidly churning out code?
Mark Seemann: Okay. So a lot of people talk about maintainable software and I did that for many years as well. And then I thought, well what if I’d start to call it sustainable software instead of maintainable? Because I think using a word like maintainable, you’re talking about that characteristic of the software from the developer’s perspective. Other developers are probably going to understand what it is that you mean by it, but it doesn’t sound sexy. It doesn’t sound like something that other stakeholders would actually be interested in.
So I thought, what other words could we look for one? I thought, well, the goal of software is often to sustain an organization in some way. It doesn’t have to be a private enterprise. It might also be a government organization or an NGO or things like that. But the software rarely exists just for its own sake. It always exists to fulfill some other goal that an organization has. An organization invests in software in order to achieve the goal and hopefully also to sustain itself in helping it achieve that goal. So software is there to sustain the organization, basically. And that’s why I chose that word, sustainable code rather than maintainable code. Because I thought the outlook is a little bit wider. You can sort of include other stakeholders when you’re talking about sustainable software instead of maintainable software.
Henry Suryawirawan: Yeah. Because sometimes this can be tricky, right? So for software engineers, sometimes we think writing software is easy. We just add few lines of code, doing some debugging or just compile and build and see the output. And that’s it. But actually, if you want to see sustainable or maintainable software, it’s like, you have to look at the bigger picture, probably. Is there a place where maybe there are duplicates or maybe they are better designs and you have to do refactoring and things like that?
[00:19:55] Code is a Liability
Henry Suryawirawan: And you mentioned at the beginning that code is mostly read. It’s not written, mostly. So there are many legacies or maybe lines of code that are already written that probably you just need to build and improve from there on. Optimize for readability is one thing that you suggest in your book, right? Because adding more code in your view is not actually an asset. It’s actually a liability. Maybe you can explain a little bit more about this aspect of readability, adding code as a liability instead of asset.
Mark Seemann: Okay. So first of all, again, the observation that code is a liability, not an asset. That’s not mine. I think I have it from Tim Ottinger, who claims to have it from someone else. That’s how it always goes. So that’s not my idea at all, but basically, the idea is that if we want to talk about assets versus liabilities, the code itself is really not worth anything.
You can make this thought experiment. If you imagine that you’d written the perfect software for the purpose of whatever it is that you’re trying to do, and by some magical way, you know that there are no bugs in the software. It does exactly what it’s supposed to do, and there will be no change requirements. This is a hypothetical thought experiment. That’s never going to happen in the real world. But, you know, if you imagine that. You have the perfect software. It’s done. Why would you need to keep the code around? The code just created the software. A set of EXE files or DLLs or whatever it is, you can always just copy them. You don’t need to be able to compile them ever again. I’m assuming here a compiled language and not in an interpreted one. Let’s make that assumption. So I would argue that the code is, at best, worth nothing in that scenario. There’s no reason to keep it around.
So the reason why we keep code around is not because it has an inherent worth in itself. We keep it around in order to be able to make changes to the software. Because in the thought experiment, the software was perfect, but in the real world, it’s not. It will have bugs, and even if it has no bugs, it will need new features because there will be changed requirements and so on. So we keep the code around in order to be able to produce the outcome that we actually desire.
So that’s just like any other liability in the sense that you can keep spare parts around in your factory in order to be able to create new cars, whatever it is that you produce. All the parts you keep on stock is a liability and the same thing goes with code. So that’s the reason for that. So that also means that in terms of being productive, you have to manage the liability. That means minimizing the cost of owning that liability. So, again, we come back to this thing where, you know, if you make it as readable as possible, the cost of owning or having that on stock, the cost goes down.
Henry Suryawirawan: Thanks for explaining this. Sometimes it’s counterintuitive, right? Because people think we write the code, it is an asset. It keeps producing values that we wanted to do. So thanks for sharing that perspective. It’s also something that I learned.
[00:22:43] Rule of 7
Henry Suryawirawan: You mentioned about optimizing for readability, and also you quoted Martin Fowler in the beginning saying, “any fool can write a software that a computer understands, but not everyone can actually write a software that people can understand.” I think, again, it’s true. We all have seen it in our real life, and that code that is quite complex and big and doesn’t fit in our head. And you have this rule of thumb, or maybe just guidelines for people in your book over and over again, which is the rule of seven. Can you explain what is rule of seven? Why is it seven? Not five, not ten?
Mark Seemann: Yeah. So this is a little bit of a cheat, again, in the sense that it doesn’t have to be seven. But the reason why I picked seven, there’s a couple of reasons for that. But there’s a very famous paper in experimental psychology called “The Magical Number Seven Plus Minus Two”. This was based on some experiments done by an experimental psychologist called George Miller and the paper is from 1956. So it’s actually quite a robust resource. One of the conclusions of this paper is that we have short-term memory, and it can hold about seven things in our short-term memory, plus minus two. So that means that if we try to remember random numbers, names or colors or variables that we read in code, we can juggle around seven things in our short-term memory before we start to forgetting some of that stuff again.
So I think that’s a very interesting insight in terms of what it means to read code because what we do when we read code is that we do our best to sort of interpret the code as we go. So it’s almost like we’re running a little interpreter, a little compiler or a little emulator in our brain that sort of tries to understand. Okay. So if the input here is that, you know it’s going to branch and this one. So we’re sort of running an interpreter in our brain. And that means we need to keep track of state because if we encounter an if statement, for example, we need to be able to say to ourselves, okay. So if the input was that, that if statement is going to be false, so we’re going to fall through into the else statement. All of these things. We can’t make those interpretations of code unless we are able to maintain states in our head. Again, you know, I think we can keep track of, as the paper says, maybe seven things. But if there’s more state that we need to keep track of than those seven things, then the code becomes really much harder to understand.
So I went a little bit with the number seven for a couple of reasons. First of all, I wanted something simple and easy to remember. So instead of keep on saying five to nine, plus minus, I’m just using this because it’s easy to remember. There’s also this thing where in lots of cultures, seven is sort of like a magical number anyway, because you know it from fairytales and so on. So it’s easy to remember. So I never call it the rule of seven in the book. I don’t think I ever do that. But you did that and I’ve heard other people do that now. So that’s actually quite great that it turns out that the idea is catchy enough that you begin to put it in your own words. Which means that it’s somehow must be working. Which I’m very happy about. As you can tell, sometimes I’m being a little bit deliberate with the way that I choose words or the way that I put things. I don’t think that I’m cheating. I think it’s very much on target in terms of what I’ve read about what this human short-term memory can do. But I also think it’s quite important to present things in a way that they’re memorable. And that’s why I’m sometimes picking one number instead of a range. That’s the story, basically.
Henry Suryawirawan: So to make it more practical, right? So when we look at code, do we count the number of variables? Do we count the number of lines? Do we count the number of what? In your book, you mentioned about cyclomatic complexity. But what exactly seven here refers to?
Mark Seemann: So there could be lots of different things. I like to look at cyclomatic complexity. So that’s one thing where you might say you’d like to have some sort of threshold in your code. In the book, I also talked about thresholds. Because I think it’s very important to have some thresholds you can agree on as a team to say, and measurement like cyclomatic complexities should in general not exceed a particular threshold. That threshold might be seven, might be something else. And the reason why I think thresholds are important is that if no one looks after when are things getting near towards something that is problematic, if no one pays attention to that, your code will grow in complexity in lots of different dimensions, and you’re not really going to notice until it actually really hurts. At that time, it’s very late. It’s difficult, and it’s expensive to fix.
So it’s better to sort of nip things in the bud, if you will, by having some thresholds where, for example, with cyclomatic complexity, you could say, “We should set an aggressive threshold.” I just picked number seven again just because I do that all the way through the book. I’ve written the code that goes with the book that demonstrates that’s possible to do. Most of the code that I write actually it doesn’t have even cyclomatic complexity of seven. It’s more like three or four, typically. So that’s definitely possible. So that’s just one quantification mechanism. I’m looking for those quantifications, various different quantifications in order to be able to monitor thresholds. Cyclomatic complexity is one.
You also mentioned just counting objects. Basically, counting variables is a very unsophisticated way of introducing your metric. But the thing I want to do with metrics, I don’t want the metrics to be something that only the machine can do for you. I want metrics to be something where you can just do it if you’re discussing with a colleague, if you’re doing pair programing, or if you’re doing a code review. You should be able to just do that in your head and say, well, that’s just too many variables here. You can just count them. So simple stuff like that. So those two things like object activation and cyclomatic complexity, I just picked seven because I think that’s actually quite a reasonable threshold for those, anyway.
You also mentioned, I talk about lines of code and also with the number of characters you can use on a horizontal line. That’s not seven by seven. I’m not suggesting that people should write code in the seven by seven box because that’s not really going to be useful. So I have some other numbers there. It’s not seven all the way, but it’s seven in a lot of ways, in lots of places. But that’s basically the measurements that I tend to look for, you know, cyclomatic complexity, object activation, number of variables, lines of code, inner method and the width of the code. That’s pretty much what I’m looking for.
Henry Suryawirawan: So maybe for people who are not familiar yet with the cyclomatic complexity, if you can take a few minutes to explain what is exactly cyclomatic complexity? How do we count it?
Mark Seemann: Yeah. We should really come up with a better name for it because the name sounds really scary, but it’s a super simple concept. The idea is basically just to count the number of distinct pathways through the code. So if you imagine you have a method where there’s a single if branch. Either the code can go through the if branch. If the boolean expression turns out to be true, or it can fall through the if branch if the boolean expression turns out to be false. So in this very simple example, you have two distinct pathways through the code. We count looping as a distinct pathway as well. Because in most cases, if you loop over a collection and the collection is empty, all the code that’s within the loop is not going to be executed. So that’s a little bit like a branching instruction as well.
So basically, you just start by one. Because there’s always going to be one distinct pathway through the simplest line of code. “Hello World” has cyclomatic complexity of one because there’s just one thing you can do. So you just start by one and then every time you see a branching instruction or looping instruction, you just increment the counter by one. So it’s super simple. And again, this is something you don’t need a tool to do that. You can do that in your brain while you’re just looking at the code. The name is horrible, but it’s just counting distinct pathways through the code. And it tells you a little bit about the load on your short-term memory as well, because it’s almost like those distinct pathways. They’re sort of like parallel dimensions. A method that can take three different ways. You’re looking at something that can behave in one of mutually exclusive ways. So sort of like you’re looking at a thing that exists in three dimensions at once.
So again, I think if you’re looking at something with a cyclomatic complexity of seven, for example, it’s sort of like you’re looking at a thing that is one of seven things at the same time, and that’s probably going to tax your short-term memory as well. And, again, I think the threshold of seven actually makes a lot of sense to me. But if you look at the older literature about cyclomatic complexity, most other sources would say that cyclomatic complexity of 20 or 30 is actually considered to be quite acceptable. So if I have anything new to say, if this book brings anything new to the table, it’s more that it really dramatically lowers what I think the threshold ought to be.
Henry Suryawirawan: Thanks for explaining that. So, again, for people who may not be familiar, so you just count by the number of paths that the code could possibly execute. So if you have if statements, there’s probably two pathways created there. If you have more and more if statements, basically you keep adding the cyclomatic complexity. And I think one of the quote in the book, I think it’s from Kent Beck or someone else, “The goal of software design is to create chunks or slices that fit into a human mind.” So you mentioned here about the cognitive load in your brain short-term memories. So when you reach a certain threshold, maybe it’s seven, maybe something else, keep splitting, maybe the chunks of code into smaller compartments, right? So that you don’t have this cognitive load and your software does become more sustainable, which is again the theme of the book, the code that fits in your head. So thanks for sharing all this.
[00:31:23] Checklist
Henry Suryawirawan: So you mentioned a number of practices in the book. Maybe when we have time, we cover some of them. The first one sounds very simple, but actually it’s quite powerful, which is checklist. I think we sometimes also hear it from medical or maybe we look at the book as well, “The Checklist Manifesto”. Can you explain to us what is this checklist and how we should use it in our day to day?
Mark Seemann: Yeah. So, again, I actually just also took a lot of inspiration from The Checklist Manifesto. You just mentioned that, which is written by Atul Gawande who is a surgeon. He has this wonderful phrase that one of the people who partook in his experiment said that the checklists increase the outcome without any increase in skill. So you can use exactly the same skill level as you already have, but then by using a very simple aid to memory, which is a checklist, you can improve the overall outcome of a process by making sure that you do things in the right order.
And I know that a checklist is something that to most people sounds a little bit oppressive or at least boring. What we need to understand, first of all, the origins are from a military aviation. You can imagine pilots going through checklists before they take off, and before they go into landing and so on. So you have to imagine those sorts of situations, instead of imagining filling out boring forms on paper because that’s actually not really what you’re supposed to do. So a checklist is an aid to memory. It’s basically just to make sure that you always remember to do things in a certain order. If you’re already good at it, you can just run through the checklist and say, okay, did I remember to do this? Oh yeah, actually did. Did I remember to do that? Oh, I also actually did remember to do that. Because if you actually do that as a process, you will be surprised how many small things you forget. It’s human nature that we forget all of those things. And, again, I think we have this very limited capacity in our short-term memory. So everything we can offload and say, well, sometimes, we can remember things by putting them in long-term memory. But if we can somehow automate things away in various different ways by, for example, following a checklist, that means we don’t have to spend limited brain power of making sure that we remember to do all the things correctly. We just go through a checklist.
So I want to be very explicit here that a checklist is not a control mechanism. It’s not something that your managers should be able to leverage in order to keep an eye on you. Ideally, it’s just something, for example, with the surgeon, some of the experiments that Atul Gawande did in the hospital he worked on. He put the checklist. He created posters of the checklist. There were questions like, did you remember to wash your hands before you went into surgery? Are you sure you’re operating on the right patient? Things like that. You’d actually be surprised how often these things go wrong if you don’t explicitly deal with them. The point is, it’s a poster on a wall, so it leaves no audit trace. There’s nothing where some manager can come by afterwards and try to extract information about how you work or how efficiently you work or whatever. It’s there to improve the process. It’s not there to keep an eye on you. And I think that’s very important.
I would think twice before I started turning checklist into something that produced reports. You can automate the checklist. I talk about that in the book as well. You know most languages and most development environment come with all sorts of extra tools that can make suggestions about your code. So in some languages you should call them linters and in .NET we call them static code analysis. But the idea is basically the same. It’s sort of like a checklist where it says, “Oh, you’re using that overload of the method, but that’s not really supposed to do that because it might be deprecated in the future. You should use that one instead.” That’s sort of like an automated checklist. I’m all for that. But as far as I know also, the static code analysis that comes with .NET, for example, doesn’t create a report. And I would be very concerned if it started doing that. So I think it’s very important when we talk about checklist to say, it’s for your benefit, it’s not for your manager’s benefit. It’s just there to make sure that you remember to do things in the right order. And while it seems stupid, it’s probably a good idea.
Henry Suryawirawan: So actually, from my personal experience, checklist is also powerful. Imagine, for example, I’ve been producing this podcast 80 plus episodes. So I use checklists as well. Because sometimes depends on stress, depends on mood, depends on complexity of the episode, sometimes you tend to miss certain parts of the process, which even though you assume you know, but you sometimes miss it. And actually, you also mentioned in the book that sometimes just following a checklist doesn’t mean that you will produce the successful outcome. But it increases the chances that you will get successful outcome. Do keep in mind, maybe in your day-to-day process, if there’s something that you want to increase in terms of success rate, maybe you should use a checklist. So thanks again for explaining.
[00:35:52] Vertical Slice
Henry Suryawirawan: The second practice that you mentioned is about vertical slice. So maybe explain a little bit why we should aim for this vertical slice?
Mark Seemann: Yeah, okay. So, again, another idea that’s not mine. I basically stole that from Nat Pryce and Steve Freeman. They have this wonderful book called “Growing Object-Oriented Software Guided by Tests”. So that’s an entire book about basically that idea. But I just thought I wanted to include it. When I coach teams, I’m trying to teach them to do some test-driven development, but then they sort of can’t really figure out where to start. So I’m not saying we should always do this vertical slice, but I think it’s a very good idea. If you don’t have better ideas, then do that as a default, if you will. So that might also be a checklist. Where to start? Do you have a good idea for where to start? If yes, go there, follow your good idea. If no, stop with the vertical slice.
So basically this idea of a vertical slice is to say, try to implement a feature of the software all the way through as narrowly as possible. Because I’ve seen lots of teams that get hung up on all sorts of side quests, if you will, where they say, “Well, yeah, but before we can implement that feature, we need to have the locking system in place.” “Oh, that means we need to pick a locking framework and then we need to create our own framework on top of the other logging frameworks.” Weeks go by and nothing actually gets produced. And once you actually start creating features, it turns out that the locking framework they created or the database framework they created doesn’t really actually solve the problem they need to solve, and then they have to go back and retrofit it. So that just wastes a lot of time.
So instead, basically the idea with a vertical slice is to say, figure out a simple way to get all the way through. You don’t have to have layered application architecture, but basically just say, well, implement a feature so that it actually works. The book has one running example that goes all the way through, which is an online restaurant reservation system. And the first one I start doing is to enable you to post a reservation. This is a REST API, so you should be able to post a reservation in a little JSON document. I considered the feature complete when that reservation is persisted in the data store. So that’s the first vertical slice. I start by writing a test, an automated test that posts that JSON document to a self hosted REST API.
The first thing is just to ensure that the API response with some 200 response code. At that point, it is not persisting anything, but just making sure that the end point is there. And then you can sort of flesh it out from there. This bit takes a lot of time. It takes almost half the book just getting to the point where it actually saves into the database. But then, you know, I introduce all sorts of different engineering techniques using that idea for vertical slice. So that’s just a very thin slice through the application. But now you actually have something that has real behavior. So at this point you could say, we could actually take and deploy this code to production, and conceivably, someone could start using it. Because it actually is useful. It’s not very useful, but it actually does what it’s supposed to do.
So the reason why it’s called vertical slice, by the way, is that I think it’s named like that in opposition to the traditional horizontally layered architecture where you typically write an architecture with a set of layers where the bottom layer is going to be a data access layer. And then you’ll have maybe a business logic in the middle and you have UI on the top and maybe some more layers in between. So the idea of the vertical slice is just to say, well, instead of thinking about those horizontal layers, you then create a vertical little section through that layer cake, if you will. So that’s the reason for the name.
Henry Suryawirawan: I like your metaphor “side quest”. Sometimes we engineers, when we work on something, we like to go into a certain different quest. We dig our rabbit hole and then it goes nowhere. You mentioned that when we come up with the vertical slice as narrow as possible, and then we ship it, actually, there’s a value in that, right? When you ship this code into production instead of just building code over time and actually don’t deploy to production. I think that also doesn’t give any value to anyone, including stakeholders. And you mentioned after we come up with this vertical slice, you’ve tried to find a certain factor to keep on improving from there.
[00:39:47] X-Driven Development
Henry Suryawirawan: The next practice that we want to talk about is about X-driven development. You mentioned that to make a change to the code, you should find a motivation to do that. These days, we have so many X-driven developments, like test-driven development, maybe domain-driven development, or maybe behavior-driven development. Maybe you can explain a little bit more about this concept X-driven development and our motivations to change code.
Mark Seemann: Yeah. So you already mentioned test-driven development, which I think is probably the most well known of those X-driven development things. I just noticed that once test-driven development gains popularity, lots of other similar techniques came by where people started to name things in the same way. So you have behavior-driven development and property-based testing is also sometimes called property-driven development. And then you mentioned domain-driven development. So you have various things like that.
But this idea about using some sort of driver in order to inform you of what’s a good idea? What should I be doing next? I think that’s an important thing to do because, again, the human brain is actually not very good at thinking formally. So before I talked about the limitations of our short-term memory. But also if you just look at our ability to do a formal analysis of things. We’re not very good at that, actually. And that’s one of the reasons why, despite our best intentions, we always create defects in the code because we write code that we think behaves in one way, and then our brains just weren’t really up to the task. And then we created an off by one error or whatever it is that we do, and that happens all the time.
So I think for that reason, it’s always a good idea to say, okay, can we institute some processes that will help us verify that what it is that we are doing is actually appropriate? So that’s the idea behind test-driven development is you write a test, and the idea of the test is that it’s a stimulus. Our response is to write a code that can pass the test. We get the verification that we’ve done the right thing by first we see the test fail, and then we write a simple implementation and then we see the test pass. So that’s one way where you can use an external driver in order to make sure that you’re doing the appropriate thing. You’re not just editing code and thinking it works. You’re actually getting some verification of that. So that’s one thing.
Another thing that I talk about is if you’re working in a language that is statically compiled and has static typing, you can use the type system to tell you whether or not you had done the right thing. Because if the code doesn’t compile, it certainly doesn’t work either. And that doesn’t mean that if the code does comply, that it works. But, again, you can design things in certain ways so that if your code compiles, it’s more or less likely to actually compile.
So, I’ve been spending a lot of research time with a programming language called Haskell, which most people probably have heard about. And there’s this phrase going around about Haskell that if it compiles, it works. It does often take you a couple of hours actually getting your Haskell code to compile because it’s a language where the compiler has a lot to say. But there’s some truth in it. You can also write bugs into Haskell code. That’s absolutely possible. A language like Haskell definitely leans in that direction where, if it compiles, there’s a pretty good chance that it probably works. But once you understand what it is that makes Haskell work like that, you can actually take some of those ideas and port back into languages, like, I work in C#, the book is written in C#. So if you deliberately start designing in ways where you emulate some of the things that gives Haskell that characteristic, you can also pull your code in that direction yourself where you can say, “I’ve designed this API over here so that it’s really difficult to use wrongly.” That’s a concept from lean manufacturing called Poka-Yoke, and I’m probably not pronouncing it correctly, but it’s Japanese and it means something like mistake proof. But basically the idea is that you can write an API so that if the API call compiles, it probably also works the way it’s intended to work because it’s designed in such a way that you can’t really call it in the wrong way. I have some examples of that in the book as well. So that’s another way where you can sort of use the static type system as a driver for changes.
I also talk about how to use things like static code analysis, or other languages would call that linters and use that for drivers of changes. So, for example, in my code, I have quite a few places where there’s a guard clause against null values and null input. There’s no unit test that provoked me to write that guard clause. Because there’s a static analysis tool that provokes me to write that guard clause. That means if I remove that guard clause, the code doesn’t compile because then the analysis tool kicks in and says, well, you haven’t checked for null here and you should do that. I also turned all warnings into errors, so it’s simply not going to compile in that case. And that means I don’t have to write a test for it because I have another thing that drives that particular change. So I take whatever I can get from all sorts of different shelves and combine that into something where I try very much to always have some sort of external thing that pushes me to write code in a certain way, because then I also have a degree of confidence that the code does what it’s supposed to do.
Henry Suryawirawan: Thanks for sharing this powerful concept. I think it’s really powerful because sometimes we change code out of our curiosity or maybe side quests that you mentioned in the beginning. But I think the lessons here is that find the appropriate drivers, and then use that as the motivation to change the code, instead of just changing for the sake of changing it. And you mentioned about Poke-Yoke, I don’t know how to pronounce it. And you compare that with the Swiss army kind of behavior where you have simply everything. You can do anything. But I think foolproof, maybe API design contract, whatever that is very simple for people to understand, right? Again, that fits in your head, probably. Rather than having to understand the context, how to use the thing.
[00:45:07] Command Query Separation
Henry Suryawirawan: There’s another powerful practice that you mentioned for API design, which is this pattern called command query separation. I think this is also worth to explain for people so that they can improve their API design. Maybe you can explain. What is command query separation?
Mark Seemann: Yeah. So that’s an idea from Bertrand Meyer, which goes back to the middle of the 1980s. Bertrand Meyer invented this language called Eiffel, and he was a pioneer in object-oriented programming. He thought it would be a good idea to distinguish between two types of operations. He called one of them commands and he called the other one queries. If I should explain this as succinctly as possible, command is something that changes the state of basically the observable universe. So that might be something like, if your software sends an email that changes the state of the universe, if it adds a row to the database, that’s also changing the state of the application, at least. If it repaints the screen, changes the pixels on your screen, that also changes the state of things. So, all of those things we call side effects. Bertrand Meyer thought that if you have a side effect, the API and operational methods should then be about side effects.
On the other hand, if you want to have some data, then you should have another kind of operation that can go and read data from somewhere and return data. It might also just be hard-coded data or a calculation like adding numbers together. But, you know, if you want data, that’s a different operation and he called that queries. So it doesn’t have to be a database query. It could be any sort of thing that produces data based on my asset. It’s not a good idea to mix those two things together. If you want to produce data, then produce data. Don’t mix them. So that’s command query separation. Separate those two things. He still thought about them as belonging to the same class. So you can have a class of objects and then some of the methods would be changing the state of the object, and then other methods would be methods that produce data, maybe about the contents of the object. So his idea was you could definitely mix them on the same object. But each method viewed in isolation should be doing one of those things, and not both. That’s the general idea.
Henry Suryawirawan: Yep. I think this pattern really is powerful because I once worked with a code that has no separation of this. Like you produce side effects, you change something, and also you return maybe the result of that, or maybe some other extra computation afterwards. So it makes it slightly more difficult to trace and also understand what is actually happening. I think this pattern is really worth to implement in your code.
Mark Seemann: Yeah. I actually didn’t explain why it’s beneficial. So I think the reason why this is beneficial is that, again, particularly if you’re looking at things that have a static type system, if you have an operation that is a command only, you know, it’s all about the side effects, and it’s not allowed to produce any sort of output. It’s very recognizable because you can always tell by the method signature that it has void. It has no return value. So that means whenever you encounter something that is void, that has no return value, you know it’s going to be about the side effects. So this is a big if. But then if you know that a particular code base is designed according to the command query separation principle, then you know that whenever you run into something that does produce an output, it will have no side effects.
Again, this is a big conditional thing here saying, well, you have to be able to trust that this code follows the principle. I’ve worked with code bases that followed this principle in a systematically. And it just makes things so much easier because that means whenever you’re looking at an API and maybe, it’s not something you’re familiar with, or you forgot, even if you wrote it you forgotten how you did it, you don’t have to go and read the actual implementation code. You just look at the API and say, “Oh, this one has void. It’s got to produce some sort of side effects. Oh, this returns data. I know that it’s safe to call it. Because even if I call it too many times, the only thing that’s going to happen here is that it might use some extra CPU cycles, but it’s not going to change the state of the system.” And being able to just at a glance which of those two buckets a particular method falls, that just saves you so much time because now you don’t have to go and read the implementation in order to understand, is it one or the other?
So there’s just fewer surprises in a code base like that. When we go back and talk about reading time, that just frees up reading time. That cuts down on the number of different files you have to go and visit in order to understand what’s going on. I’m not saying that it completely eliminates the need to go and read other things, but it saves you some time there.
Henry Suryawirawan: It definitely will save our brain cycle, not to be able to read multiple files. Again, following the principles strictly, I think, that’s still the keyword and also maybe the naming of the API design itself, the methods or the functioning or whatever API. So that is also must be self explanatory. Otherwise, again, you will have this cognitive load to guess, okay, what is this function about?
[00:49:38] 3 Tech Lead Wisdom
Henry Suryawirawan: So Mark, I think there are plenty more practices that you have in the book, right? So I really highly suggest the listeners here to read the book because in preparation of this recording, I actually took a look. There are so many gist and insights there. I think this book is really great. Thanks for writing this. If you haven’t checked it out, please do check and I’ll put it in the show notes how you can get the book as well. Unfortunately, due to time, we have to end this conversation. So before I let you go, normally I have this one last question that I asked to all my guests, which is for you to share your three technical leadership wisdom. So think of it like an advice that you want to give to the listeners here so that they can follow or maybe do your best practice.
Mark Seemann: Okay. So the first one doesn’t sound like a technical advice, but I think it’s very useful for technical people, take breaks. I regularly take breaks. I run the Pomodoro timer, so I worked for twenty-five minutes and then I take a five-minute break. So that’s one thing. But I also, during the day often take longer breaks where I go grocery shopping, or go and do the dishes, other things like that. The reason for that is, again, this has something to do with how the brain works. I’m not sure I completely understand what’s going on here, but I get all my insights when I’m away from the computer. I can sit and look at code or problem definitions for a long time and not really go anywhere. And then I go grocery shopping. While I’m in the supermarket, I’ll go, “Oh, now I know what I need to do.” And then I could go back and actually do something useful. So, if at all possible, take breaks during the day. That’s really going to help your brain to come up with good ideas.
The second tip or advice, I would say, is that if at all possible, see if you can get to Continuous Delivery. I’m basing this advice on this book called “Accelerate” by Nicole Forsgren and Gene Kim, and Jez Humble. You can discuss whether you want to call it research. I think research is a fair enough word to use. So It’s based on a lot of surveys. It’s like 50,000 people answered the survey. It seems like the single most important thing in order to determine whether or not your organization works effectively or not, is can you do Continuous Delivery? Because so many other things will sort of come as a byproduct in that journey towards Continuous Delivery. And it’s a big journey if you’re not already doing it, but it’s really worthwhile to go in that direction. That would definitely be something that I would look into.
The last thing I want to say is if you’re interested in code the fits in your head, learn functional programming. I have an argument in the book, again, that sort of takes this idea we talked about command query separation a little bit further and say, well, if we add another constraint and other idea to this idea about queries and say, not only must they be side effect free, they must also be deterministic. You have something called a pure function. There are various reasons why I argue in the book, why that actually fits in your brain very well. So definitely, I encourage people to learn some functional programming. The best language to really understand functional program with is Haskell. But it’s also really difficult to learn. If you’re up to the challenge, if you’re curious, then I would recommend that.
Henry Suryawirawan: So in my previous episode, I had a chance to talk to Scott Wlaschin. So he advocates F#.
Mark Seemann: F# is a wonderful language as well. I write quite a bit of F# as well. For me, it was a great stepping stone. So I came from C# and then I learned F# and then from F# I learned Haskell, and that was actually great. I don’t know if I could have learned Haskell straight from C#. That might not actually have been the case. But spending some years with F# enabled me to then learn Haskell later on. If you ask me which language would I pick from all the languages that I know for an important project, I would probably pick F#. Because while I really like Haskell, I’m not so convinced that the ecosystem is actually something that you would bet a real enterprise on. Whereas I know that F# is running on the .NET framework, and I know that I can trust that pretty well.
Henry Suryawirawan: He mentioned about this as well. So thanks for this wisdom, Mark. It’s been a pleasant to talk to you and discuss about this idea, code that fits in your head. So for people who want to follow you or find out more from the book, where can they find it online?
Mark Seemann: To find me, that’s probably the easiest thing. I have this blog called blog.ploeh.dk, that’s the address. From there, you can find links to the book and to my Twitter profile and anything else. But otherwise, just using your favorite web search engine and searching for “code that fits in your head” is probably going to work pretty well as well.
Henry Suryawirawan: Thanks again for your time today, Mark. It’s been a pleasant learning from you. So, thanks again.
Mark Seemann: Yeah, it was a pleasure. Thank you for having me.
– End –