Max Kanat Alexander understands software implicitly. He has spent his career not only working with it, but thinking about it too. But don’t think for a moment that Max is an armchair philosopher. His philosophy has real-world consequences for all programmers, offering a way to write better code and achieve incredible results while remaining happy and healthy in an industry that can be exhausting.
In his new book Understanding Software Max explores a wide range of issues that should matter to anyone working with software – we spoke to him about it, and discussed his thoughts on how thinking about software can help us all.
You’re currently working at Google. Could you tell us what that’s like and what you’re working on at the moment?
Max Kanat-Alexander: I can’t answer this question in a public setting without approval from Google PR. However, there is a public blog post that describes what I do and provides my title.
Why simplicity is so important in software
Your last book was called “Code Simplicity” – could you tell us exactly what that means and why you think it’s so important today?
MKA: One of the things that I go over in that book, and that I cover also in my new book, is that most of the problems of software fundamentally come from code complexity. Even when it doesn’t seem like they do, if you trace down most problems far enough, you’ll see that they never would have happened if there hadn’t been so much code complexity.
This isn’t obvious to everybody, though, so I wrote a book that provides a long reasoned argument that explains (a) the fundamental laws of software design and (b) hopefully brings the reader to understanding why simplicity (and maintaining that simplicity) is so important for software.
I figured that one of the primary causes of complexity was simply the lack of full and complete understanding by every programmer of what complexity really is, where it comes from, why it’s important, and what the simple steps are that you take to handle it.
And even now, when I go back to the book myself, I’m always surprised that there are so many answers to the problems I’m facing now. When you’ve discovered the fundamental laws of software development, it turns out that they do in fact resolve problems even long after their discovery.
Do you think you can approach code the same way whatever languages or software you’re using? Is there a philosophy you think any engineer can adopt? Or is flexibility key?
MKA: There are fundamental laws and principles that are true across any language. Fundamentally, a language is a way of representing a concept that the programmer has and wants to communicate to a computer. So there are ways of structuring concepts, and then there are ways of structuring things in a language. These both have rules, but the rules and principles of structuring concepts are the senior principles over the rules for structuring things in a language, because the rules for how you organize or handle a concept apply across any language, any computer, any set of tools, etc. Theoretically, there should be an ideal way to represent any particular set of concepts, but I’m not sure that any of our languages are there yet.
The philosophy I’ve expressed in Code Simplicity and now in Understanding Software is entirely a universal philosophy that applies to all software development. I don’t generally write about something if you can only use it in one language or with one framework. There is enough of that sort of writing out in the world, and while it’s really valuable, I don’t feel like it’s the most valuable contribution that I personally have to bring to the world of software development. Since I have a background in some types of philosophy as well as a lot of experience doing design (and extensive refactoring) across many languages on many large projects, there’s a universal viewpoint that I’ve tried to bring and that a lot of people have told me has helped them.
To answer your last question, when you say the word “flexibility,” you’re in dangerous territory, because a lot of people interpret that as meaning that you should write endless generic code up front even if that doesn’t address the immediate requirements of your system. This leads to a lot of code complexity, particularly in larger systems, so it’s not a good idea. But some people interpret the word “flexibility” that way. For a more nuanced view, you kind of have to read all of Code Simplicity and then see some of the newer content in Understanding Software, too.
Are there any languages where code simplicity is particularly important? Or any in which it is challenging to keep things simple?
MKA: More than for a particular language, I would say it’s important for the size and longevity of a project. Like, if I’m writing a one-off script that I’m only going to use for the next five minutes, I’ll take a lot of shortcuts. But if I’m working on a multi-million line codebase that is used by millions of people, simplicity is of paramount importance.
There are definitely languages in which it’s more challenging to keep things simple. I’ve made this statement before, and there are a lot of amazing developments in the Perl community since I first made it, but it was a lot of work to keep the Bugzilla Project’s Perl codebase healthy when I worked on it–more so than with other languages. Some of that had to do with the design of that particular codebase, but also that Perl allows you to accomplish the same thing in so many different ways. It led to a lot more thorough and time-consuming code reviews where we would frequently have to tell people to do things in the way that our codebase does them, or the particular way that we’d learned was the most maintainable through hard-earned experience. It did still result in a well-designed codebase, and you can write well-designed Perl, but it required more language experience and more attention in code review than I’ve experienced when writing in other languages. Bash is similar in some ways–I once maintained a several-thousand-line Bash program, and that was pretty challenging in terms of simplicity.
Languages aren’t equal–some are better than others for some types of tasks. There are tasks for which I love Perl and Bash, and others for which Java, Python, or Go are definitely more suitable. Some of this has to do with the suitability of a particular tool to a particular task, but more of it has to do with things like how much structure the language allows you to place around your code, how much consistency the language libraries have, etc.
What makes code bad?
What, in your opinion, makes code ‘bad’? And how can we (as engineers and developers) identify it?
MKA: It’s bad if it’s hard to read, understand, or modify. That’s the definition of “complex” for code. There’s a lot to elaborate on there, but that’s the basic idea.
What do you think the main causes of ‘bad code’ are?
- Lack of understanding on the part of the programmer working on the system.
- A failure of the programmer to take sufficient responsibility for enough of the system.
- A simple unawareness of the problem.
On your blog you talk a lot about how code is primarily ‘human’. Could you elaborate on that and what it means for anyone that works in software?
Sure. It’s people that write software, people that read it, and people that use it. The whole purpose of software is actually to help people, not to help computers or network cables. When you’re looking at solving the problems of software development, you have to look at it as a human discipline–something that people do, something that has to do with the mind or the being or the perceptions of individuals. Even though that might sound a bit wishy-washy, it’s absolutely true. If you think of it purely as being about the computer, you end up writing compilers and performance tools (which are great) but you don’t solve the actual problems that programmers have. Because it’s the programmers or the users who have problems–not the machines, for the most part. You have to talk to people, find out what’s going on with them.
Just as one example, one of the best ways to detect complexity is to ask people for negative emotional reactions to code. “What part of this codebase is the most frustrating?” “What part of this codebase are you the most afraid to touch because you think you’ll break something?” Questions like that. And those are basically questions about people, even though you’re getting data about code. Because when you come down to it, the whole reason you’re getting data about code has something to do with people. You can’t lose sight of the fact that the problem you’re resolving is code complexity, but at the same time, you also can’t forget the reason you’re resolving it, which is to help programmers.
How has your thinking around code changed over the years? Are there any experiences that stand out as important in shaping your philosophy today?
MKA: I’ve always been fairly meticulous in terms of how I want to approach code. However, it’s also important that that meticulousness delivers a product. There have been times, particularly in my early coding career, when I would go to clean up some codebase or improve something only to find that nobody actually wanted the end result. That is, you can work on a project for a long time that nobody actually ends up using or caring about. So one of the lessons that I learned, which is expressed in both Code Simplicity and Understanding Software, is that your software has to actually help somebody or you’re not going to actually end up being very happy with it, even if you enjoy the process of working on it.
Also, the more time I spend working with groups of engineers as opposed to working alone or in distributed teams, the more I learn about how to communicate the basic principles of software development to other engineers. I think that Code Simplicity did a pretty good job, but weirdly, sometimes you can be too simple for some people. That is, if you get too fundamental with your explanations, then sometimes people don’t see how to use the information or how it applies to their life. Sometimes you have to get a bit more complex than the fundamentals, explain a bit more about how to use the data or how it might apply in some specific situation, because some programmers are very focused on their specific problem in present time. That is, they don’t want to hear about how to solve all problems like the one they’re having – they can’t even listen to that or really digest it. So instead you have to frame your explanation in terms of how it applies to this specific problem, which–when you’re coming from the fundamental laws of software design all the way up to some extreme complexity that some programmer has boxed themselves into–can become quite difficult to fully communicate. It’s also tough because they often think they already know the fundamentals, even though the problem they’re having clearly indicates that they don’t. So you have to learn how to communicate around those barriers.
Working on the Bugzilla Project was a significant influence in how I think about software development, because I proved that you really can refactor a legacy codebase that’s gotten into a very bad or very complex state, and that that has significant effects on the product. I think that’s one of the things that’s been missing in other attempts or writings, is that there’s a lot of talk about how code quality is important, but I (and the people who worked with me on Bugzilla) actually went through the process of making significant impacts on products and users over a period of many years by focusing almost purely on code quality and applying the basic principles of software design.
There have been lots of other experiences that have been an influence. I think that I generally try to learn something from every encounter I have with programming or software engineers. It’s dangerous to think that you already know everything already–then you stop learning.
3 things to take away from Understanding Software
What are the three things you want people to take away from Understanding Software?
Well, I hope that they take at least as many things away from the book as there are chapters in the book. But in general, I’d like people to have some good ideas about how to handle problems that they run into in terms of code complexity. I’d also like them to understand more about the fundamental reasons that we handle code complexity, as well as the rules around it. I’d like people to see the basic philosophy of software development as something that they can think with themselves, not just something that somebody else has said, and I’d like them to be able to use that basic philosophy to resolve the problems of their software development environments. And of course, I’d like people to come away from the book being much better and faster programmers than they were before.
3 ways engineers can be more productive
What 3 tips can you give to developers and engineers who want to be more productive?
1. Understand as much as you can about software, the project you’re working on, etc. See the chapter “Why Programmers Suck” in Understanding Software for all the details on this and other things that you should learn about.
2. Try to take responsibility beyond the normal bounds of your code. That is, if you’re normally only responsible for one tiny part of the system, also start thinking about how you could improve the parts of the system that talk to your part. Think about the consumers of your code and work to refactor them as well, when necessary. Keep expanding your sphere of responsibility over your codebase over time, even to the point of helping out with the tools and languages that you use to develop software, eventually.
3. Stop thinking so much about your code and start coding more. Or do drawings, or take a walk, or talk to somebody, or something. See the chapter “Stop Thinking: The Secret of Fast Programming” in Understanding Software for the full details on this.