The Pragmatic Engineer - The Philosophy of Software Design – with John Ousterhout
Episode Date: April 9, 2025Supported by Our Partners• CodeRabbit — Cut code review time and bugs in half. Use the code PRAGMATIC to get one month free.• Modal — The cloud platform for building AI applicat...ions.—How will AI tools change software engineering? Tools like Cursor, Windsurf and Copilot are getting better at autocomplete, generating tests and documentation. But what is changing, when it comes to software design?Stanford professor John Ousterhout thinks not much. In fact, he believes that great software design is becoming even more important as AI tools become more capable in generating code. In this episode of The Pragmatic Engineer, John joins me to talk about why design still matters and how most teams struggle to get it right. We dive into his book A Philosophy of Software Design, unpack the difference between top-down and bottom-up approaches, and explore why some popular advice, like writing short methods or relying heavily on TDD, does not hold up, according to John.We also explore: • The differences between working in industry vs. academia • Why John believes software design will become more important as AI capabilities expand• The top-down and bottoms-up design approaches – and why you should use both• John’s “design it twice” principle• Why deep modules are essential for good software design • Best practices for special cases and exceptions• The undervalued trait of empathy in design thinking• Why John advocates for doing some design upfront• John’s criticisms of the single-responsibility principle, TDD, and why he’s a fan of well-written comments • And much more!As a fun fact: when we recorded this podcast, John was busy contributing to the Linux kernel: adding support to the Homa Transport Protocol – a protocol invented by one of his PhD students. John wanted to make this protocol available more widely, and is putting in the work to do so. What a legend! (We previously covered how Linux is built and how to contribute to the Linux kernel)—Timestamps(00:00) Intro (02:00) Why John transitioned back to academia(03:47) Working in academia vs. industry (07:20) Tactical tornadoes vs. 10x engineers(11:59) Long-term impact of AI-assisted coding(14:24) An overview of software design(15:28) Why TDD and Design Patterns are less popular now (17:04) Two general approaches to designing software (18:56) Two ways to deal with complexity (19:56) A case for not going with your first idea (23:24) How Uber used design docs(26:44) Deep modules vs. shallow modules(28:25) Best practices for error handling(33:31) The role of empathy in the design process(36:15) How John uses design reviews (38:10) The value of in-person planning and using old-school whiteboards (39:50) Leading a planning argument session and the places it works best(42:20) The value of doing some design upfront (46:12) Why John wrote A Philosophy of Software of Design (48:40) An overview of John’s class at Stanford(52:20) A tough learning from early in Gergely’s career (55:48) Why John disagrees with Robert Martin on short methods(1:10:40) John’s current coding project in the Linux Kernel (1:14:13) Updates to A Philosophy of Software Design in the second edition(1:19:12) Rapid fire round(1:01:08) John’s criticisms of TDD and what he favors instead (1:05:30) Why John supports the use of comments and how to use them correctly(1:09:20) How John uses ChatGPT to help explain code in the Linux Kernel—The Pragmatic Engineer deepdives relevant for this episode:• Engineering Planning with RFCs, Design Documents and ADRs• Paying down tech debt• Software architect archetypes• Building Bluesky: a distributed social network—See the transcript and other references from the episode at https://newsletter.pragmaticengineer.com/podcast—Production and marketing by https://penname.co/. For inquiries about sponsoring the podcast, email podcast@pragmaticengineer.com. Get full access to The Pragmatic Engineer at newsletter.pragmaticengineer.com/subscribe
Transcript
Discussion (0)
Right now, there is a huge explosion of AI and LLM tools.
How might this change software engineering?
There's things that seem relatively clear and things that seem less clear.
I think on the relatively clear side is that the AI tools will make it easier to churn out low-level code.
As you call it, autocomplete.
Auto-complete will get better and better.
It could actually be reasonably high-quality code that gets turned out.
So it seems like that will probably happen.
And the big question is, to what degree can the AI tools actually replace the higher-level design tasks?
I don't know the answer to that.
So far, I don't see anything in the current tools that makes me think they're going to do that.
But what's interesting about this, I think, is that by handling more and more of the low-level programming tasks,
what software designers do is going to be more and more design.
I think software design is going to become more and more important.
That'll be a larger and larger fraction of where developers spend their time,
which makes it even more sad that we don't really teach software design in our universities at all.
John Alls-Sor-Howell is the author of a philosophy of software design,
and currently a professor of computer science at Stanford.
John Kohl found a two-tech companies, worked at some microsystems,
created a T-Scripting language, and invented the Rath-consensus algorithm
that is used across databases and systems like MongoDB, CockrooosDB, Kafka, and others.
In our characterization, we cover the impact of AI and software engineering
and why software design could become more important than before.
The concept of deep and shallow modules,
and why deep modules are so important to deal with complexity and software.
John's advice on error handling, commenting, and why he suggests avoiding test driven development, and many more topics.
If you're interested in practical software design tactics and strategies and want to take a step back from tactical coding, this episode is for you.
If you enjoy the show, please subscribe to the podcast on any podcast platform and on YouTube.
Welcome to the podcast.
Thank you. I'm excited to be here.
You have been working in academia at Stanford for quite a while, but you were in the industry beforehand.
What made you change from working at tech companies, from founding your own companies to academia?
And, you know, why did you do it?
I've always wanted to do both academia and industry.
When I got my PhD, I debated what to do because I love the creative freedom of academia and I love teaching also.
But I also love building real software.
Coding is one of the passions that I live for in my life.
And so I always kind of figured I'd probably do both.
over my career. When I got my PhD, the advice I was given was, if you're going to do both,
it's always better to do academia first because it's easier to switch from academia to industry than
the other way around. So I went to Berkeley, had a fabulous 14 years there, but over time,
this nagging feel for wanting to build commercial software had built up. And so I finally decided
to take the plunge. I gave up my position at Berkeley, moved to Silicon Valley, worked at Sun for a few
years, started a couple of only moderately successful companies, and had a great time doing that.
just learned a ton of stuff doing startups.
But over time, the nagging of the call of industry kind of built up in me.
And I gradually realized, although I liked doing startups, that I think being a professor
is my real sort of true passion in life.
So after doing startups for 14 years, I was fortunate enough to get a position at Stanford.
And I've had another 14 or 15 years back at Stanford where I've been really happy.
So it's been really fun, really fun getting to see both sides.
And honestly, I think, you know, doing both has actually made me better at both.
What you see, I talk with a lot of people, obviously, who are only in the industry and maybe they're thinking of at one day doing academia.
I at some point thought of this myself.
My dad is a university teacher or was a university teacher.
And obviously, there's people in academia.
Having them both, what are big differences between, you know, as we call the tech world, which is industry and an academia?
Well, first, it wasn't as different as I thought it was going to be when I went to industry.
Really?
Really?
In both cases, you're, well, particularly doing startups.
In both cases, you're working with a relatively small team.
You're trying to do something relatively new, you know, trying to build software that really works.
So even when I was in academia, we tried to build stuff that really works, not just throwaway research prototypes.
So in many ways, it wasn't that different.
But in other ways it was, and that you deal with a much broader spectrum of people, you know,
salespeople and marketing people and finances and venture capitalists.
That was one of the fun things about it as seeing a much greater diversity of people.
I would say the difference that contributed to my going back to academia,
I would say one of the downsides of industry,
is that there's tremendous pressure in startups, particularly to make yourself look bigger and better than you are.
You know, you're trying to survive and get funding.
And so there's a lot of pressure to spin your company and exaggerate and market yourself.
I mean, everybody does it to some degrees.
Some people do it in ways so stream it's illegal.
They get in trouble.
But that kind of bothered me.
And within my companies, of course, we had to market ourselves externally, but internally,
we try to be very honest.
I don't want to hear lies and spinning internally because that puts our company at risk if you do that.
But nonetheless, the thing I like about academia is you do a project.
Some of them work.
Some of them don't.
If a project doesn't work, you just say, oops, okay, that wasn't a good idea.
Here's why.
And you go on to the next thing.
In a company, if it's not working, you can't really say, oops, that didn't work.
Sorry, everybody, we're shutting down tomorrow.
You try and somehow figure some way around it.
So I think that was the one thing about industry that I liked least.
This episode was brought to by CodeRabit, the AI Code Review platform,
transforming how engineering teams shift faster without sacrificing code quality.
Code reviews are critical, but time-consuming.
CodeRabbit acts as your AI copilot, providing instant code review comments and potential impacts
of every poll request.
Beyond just flagging issues, CodeRabit provides one-click fixed solutions and lets you define
custom code quality rules using ASD grab patterns, catching subtle issues that traditional static
analysis tools might miss.
CodeRabit has so far reviewed more than 5 million.
and pull requests, is installed on 1 million repositories, and is used by 50,000 open source
projects.
Try CodeRabbit free for one month at codrabbit.AI using the code pragmatic.
That is coderabit.aI and use the code pragmatic.
This episode is brought to by Modal, the cloud platform that makes AI development simple.
Need GPUs without a headache.
With Modal, just add one line of code to any Python function and boom.
It's running in the cloud on your choice of CPU.
or GPU.
And the best part,
you only pay for what you use.
With sub-second container starts
and instant scaling to thousands of GPUs,
it's no wonder companies like Suno,
ramp and substack already trust Modal
for their AI applications.
Getting an H-100 is just a pip install away.
Go to modal.com slash pragmatit
to get $30 in free credits every month.
That is modal.com slash pragmatic.
Now, you know, thanks to you having worked in academia as well
and you taught a course, which we'll later talk about,
but which you wrote this book,
the philosophy of software design,
and a lot of people in the tech world,
who I talk with,
point to this book as one of the best books that gives them specific,
actionable things,
ways to think about software design.
I just want to go into some of the things into the book.
People who've read it will find it's refreshing,
and people who haven't,
minefied is new ideas.
In the very beginning of the book,
in chapter, I think two or three,
in the first 10 or 15 pages,
you write about something called tactical tornadoes.
And let me just quote a little bit from this.
You wrote a tactical tornado is a prolific programmer
who pumps out, quote, faster than others works,
but does it in totally tactical fashion.
When it comes to implementing a quick feature,
nobody gets it done faster than a tactical tornado.
In some organizations,
management trees tactical tornadoes as heroes.
However, tactical tornadoes leave a wave of destruction behind
and typically other engineers must clean up the messes left by this tactical tornado.
So I wanted to ask you, first of all, how did you come across your first tactical tornado?
And why do you think these types of folks are still around in most companies?
Because I had an aha moment when I was like, oh, yeah, I know the tactical tornadoes as well.
I can't point to a specific incident or person, and I wouldn't want to identify them anyway.
But I've encountered them over my career.
I bet everybody who has significant software development experiences
that counter these people over your career
and just kind of observing them and the frustration with that.
I think it's just a particular personality type.
There are people who are very detailed focused and sort of closers
want to get absolutely everything right and they finish everything.
And there's people who are, they love getting started on projects
and doing the first 80 or 90 percent, but that last 10 or 20 percent.
doesn't matter to them so much, and they're not, you know, there's just like there's,
needer people, and there's sloppier people in the world. So the technical tornadoes are just
sort of sloppy. They don't care about, you know, leaving Cruff behind. It doesn't really bother them
at all. It's just a personality type. So I suspect they'll always be there, particularly
because some organizations value speed above all else.
Especially startups, right? Yeah, yeah, a lot of, right, right. There are startups that are
probably completely staffed by tactical tornadoes.
You call them tactical tornadoes, but like some of the synonyms that came into my mind as
I was thinking of people, sometimes they use a 10x engineer, especially when management sees,
oh, they just get things faster.
Sometimes it's a hacky way of doing things or someone who just hacks quickly or at some
point maybe a decade ago, people call it a hacker, but in a way of working fast, but I don't
think we have that anymore.
But there are a lot of cases, it is a positive thing.
indeed.
Well, I was distinguished.
When I think of 10x engineers in the way Google defined it, I don't think of these
as tactical alternatives.
I think of these are people who come up with the really clean designs that can be implemented
in very small amounts of code.
And so they might actually write less code per day than other people, but the functionality
that they implement is way higher.
And it comes with higher stability and evolvability and so on.
So to me, at least, that's the 10x engineer.
I agree with you.
I'll just add the note that I think the 10x engineer is so ambiguous that it means different for every person.
And especially so when I've seen it was mostly less technical CEOs refer to my 10x engineer who was a tactical tornado because what they saw is, oh, I'm getting output.
They're not saying no.
They're building it.
But of course, they had trouble understanding the tech depth that is going into there, how it's slowing others down.
And, you know, some of the people that you talked about in this environment might have not been perceived as a TNX engineer by this person who didn't really, who is not that close to the code.
And I totally agree with you, by the way.
But this is probably a good reminder of, you know, like everything is relative, right?
Like everything is based on your vantage point.
If you are close to the code, you're technical, you will value other things.
You should value other things.
You know, I think a lot of this comes down to strategic versus tactical.
Again, there are people who value all the short-term stuff and they're people who place more emphasis on the long-term stuff.
And my view of design is all about the long-term stuff.
But as you've said, there are many people who think of it all in terms of short-term stuff.
And so I can see how they would have a different idea of what a 10-X engineer is.
And speaking of long-term versus short-term, one thing that came to my mind, rereading this tactical tornado part is right now there's a huge explosion of AI and LLM tools, which are, as,
as you're probably seeing it,
they are really good at generating code rapidly,
a little bit like the tactical tornado, to be honest.
You can prompt them, they can do short,
they can do long, they can do auto-complete,
they can do all skeletons.
I was wondering, so far what you've observed,
what do you think the long-term impact of these tools?
If we assume that this is how they're going to stay,
let's just assume that.
Every engineer will have tactical tornadoes at their fingertips
and who do not say no,
and they will turn out code.
How might this change?
software engineering?
That's a really interesting question.
And I wish I knew the answer.
I don't.
I can only guess.
I think we're going to see big changes over the next five to ten years, and it's
really hard to predict what direction are going to go.
There's things that seem relatively clear and things that seem less clear.
I think on the relatively clear side is that the AI tools will make it easier to churn out
low-level code, as you call it, autocomplete.
Auto-complete will get better and better.
And I think it won't necessarily be sort of tactical tornado stuff.
It could actually be reasonably high-quality code that gets turned out.
So it seems like that will probably happen.
And the big question is, to what degree can the AI tools actually replace the higher-level design tasks?
And, you know, I don't know the answer to that.
So far, I don't see anything in the current tools that makes me think they're going to do that.
But never underestimate what could happen to this.
But what's interesting about this, I think, is that by handling more and more of the low-level programming tasks,
what software designers do is going to be more and more design.
So I think software design is going to become more and more important.
That'll be a larger and larger fraction of where developers spend their time,
which makes it even more sad that we don't really teach software design.
our universities at all. So the skills we're teaching students may actually be the skills
that are going to be replaced by the AI tools. Can we just double click on software design?
How do you see software design? What is it and why is it important? And the reason I'm asking
the question, it might seem like a naive question. But these days, you really can get started
building an application by, you know, taking a template, using it, you know, you will soon be
able to prompt an AI tool that will generate things for you. How do you think about software
design? It's abstract, right, by nature?
So, well, I think of it as it's a decomposition problem. It's how do you take a large,
complicated system and divide it up into smaller units that you can implement
relatively independently. And by the way, to me, when I give talks, I often ask people,
what do you think is the most important idea at all of computer science? Ask the audience.
To me, I think decomposition. That's the key thing that threads through everything we do in
computer science. How do you take large, complicated problems and break them up? And that's design.
And then implementation is when you go about the individual pieces. But again, you may do more
design of those to break them up into still smaller pieces. But that's the way I think about
software design. Now, an interesting thing that I've noticed over the past few decades is about 20 years
or so, maybe a little bit more. There was a lot of focus on architectural practices that felt
closer to software design, things like TDD test-driven development, architecture approaches,
like architecture patterns, I think they were called design patterns, a gang of four, different
like factory, et cetera patterns. However, the focus seems to be moving away, at least at least at
at least in the industry, there's fewer people referencing these models, these ideas.
From your observation, both in academia and industry, like, why do you think this might have been?
Why did we have such a big focus on architecture, design topics 10 or 20 years ago?
And maybe just we're talking about it less, or maybe even thinking about it less.
Well, you know, of course, there's always fads that everybody gets excited about it and they gradually fade away.
So maybe that's part of it.
Now, to me, the things you mentioned, TDD and patterns, I don't think of those as design, certainly not TDD.
In fact, I would argue if you want to get into a TD discussion, we could have that, but I don't argue it actually works against design.
Design patterns, that's an alternative to design.
That is, rather than designing something, you pull something off the shelf.
And I think where it works, it works.
Certainly there's areas where, of course, if a pattern works, you should just use it.
But to me, that only addresses a tiny, tiny fraction of what I think of a software design.
There's so much more to design than just picking one of a half a dozen patterns.
When you're starting to, when you're building new software and you're saying, okay, I'm going to start to design.
Like, how do you start designing?
Is it a sitting down pen and paper?
And if we can talk about something specific, I think that could be even useful if there was a project that you did.
Because I'm just really curious about your, you know, thinking.
I can't give a recipe for design. I wish I could. Can you know, follow these steps in this order and you'll get a great design? I wish I could. But, you know, there's two general approaches, each of which has its pitfalls is the top-down approach or the bottom-up approach. I think what people tend to use, particularly less experienced engineers or people who are in a domain that they're not familiar with is you do bottom-up. You just say, okay, I'm going to need this functionality in this system. I have no
idea what the overall system can look like, but I need this piece. I'll just build this piece.
And then you pick another piece and you build it. Then you start trying to put the pieces
together and you gradually layer in your design. That's the bottom up approach. The top-down approach is
you start at the top and you try and break the system up into what you think are relatively independent
components and then decompose those until you eventually get something that you can design.
My personal, and by the way, in the 1970s, back when I was in graduate school, there was a big
discussion about should you do design top down or bottom up and people argued about it.
My personal opinion is that it's hard to do either one pure, that the actual process of design is
some combination where you think about big pieces and then you start thinking about some
little pieces and you build some stuff and you discover it actually didn't work very well,
so you throw it away and you build some more stuff.
And it's this iterative kind of back and forth process.
And it's interesting that you mentioned the two ways because in the book, the book itself,
starts with you're writing how design is all about managing complexity, and then you bring
these two approaches.
What were the two approaches to complexity?
So one is that there are certain things you can do design that simply eliminate complexity
completely, eliminating, working on special cases and things like that.
So those are the best, most powerful approaches.
But you can't eliminate all complexity.
So then the second approach is where you use modular design, where you basically try and
hide the complexity. That is, you take things that are relatively complicated and put them off
to the side where somebody can solve this problem and deal with this complexity, and nobody
else in the system has to be aware of that complexity. So those were the two overall ways
of dealing with complexity. Yeah. And good software designed will help us deal, like,
wrangle complexity. Do I sense that? That's one of the... It will do with both of those.
It will both give you ideas for how to eliminate it.
and also for how to, again, modularize it so most people don't have to be aware of most of the complexity.
What interesting idea that it resonated with in the book is you wrote about how it's worth designing things twice.
In fact, this is a whole chapter in the book, Chapter 11.
It's called Designing It Twice.
And you wrote, I'll quote from you, unfortunately, I often see smart people who insist implementing the first idea that comes to mind.
And this causes them to underperform their true potential.
it also makes them frustrating to work with.
How did you come across this observation?
And one more thing that you added is it doesn't take more time to design twice than what most people think.
Yeah.
So first, the way I came across this is because I've been a professor of both Stanford and Berkeley,
which are two of the top universities in the world.
And both places get brilliant graduate students.
and I've noticed it's common for students at both places to have bad work habits.
And the reason is, all their lives, everything's always been easy for them.
They've always been the best at everything they did.
In high school, they were smarter than their teachers and college, perhaps as smart as their professors, top of their class.
Their first ideas, just the first thing they come off their mind was always good enough to get great grades.
And so there's never been any real incentive for them to think twice.
And I think they start kind of latching on of the idea that whatever comes to my mind is going to be good.
But, you know, as you get into harder and harder problems, that characteristic goes away.
And particularly when we're doing research at top universities, honestly, we're working on really hard problems.
Nobody's first idea is going to be the best idea.
And so I often have to work with students to force them to think about things.
And so, for example, a common technique I will use is I will say,
suppose I told you that you may not implement this thing you just suggested.
And if you try and do it, I'm going to stop funding you and have you thrown out as a grad student.
What would be your second approach?
Would you come up with something or would you say, okay, I better look for a new advisor?
And the interesting thing is, by the way, I say this typically when I think there's a better way of doing it.
And when I force them and they go away and come back, the second idea is always better.
It's better.
And I've seen this myself.
The best example I could think of over my whole career was when I was designing the TK toolkit, which is a part of the Tickle TK system.
And I was trying to figure out what should be the API for programming graphical widgets.
And I spent actually, I think it was mostly a long airplane ride.
And I basically did two designs for this.
I did kind of the first idea that came to mind.
And then I said, okay, suppose I'm going to throw that out.
what would be something that's really different that I could do? I did a second one.
And after comparing them, I ended up choosing the second idea. And honestly, that was one of
the best ideas I've had in my professional career. The one of the things that may tickle TK
popular was the API for TK was just a very sweet, simple, powerful API. And it was my second
choice. It was the second thing that came to my mind. So I have that example. That always motivates me.
And when I'm doing new things, I usually try and
forced myself to think of two ways.
Even if I think one of them is really bad,
even come up with what you think is a bad alternative
and compare it to what you did, you'll learn something from that.
And you may discover the bad thing wasn't as bad as you thought was.
I'm actually starting to realize when I worked at Uber,
we had this concept of design docs, RFCs,
where you were expected to just write down why you're doing something,
how you're doing it, et cetera.
And after a while, we started to start
start to add a thing called trade-offs or alternatives considered.
And we were asking people, like, write down at least one, ideally multiple arts alternatives
considered.
And we did it because we just like we got better, you know, designs, ideas, plans, et cetera,
and better discussions as well because it was clear why you wouldn't do it.
And now I'm just reflecting on what you said on like, yeah, well, we were kind of doing
a little bit of what you were saying, forcing people to not stop, either or not get their first
idea or put down others as well and compare them. What would you say, oftentimes it will be people
just doing, you know, okay, here's some things that will surely not work. And usually fair enough,
it doesn't work. But then sometimes they're like, oh, actually, that's a simple thing. We could
just use that instead. Or maybe we combine these two things together. Yeah. And you know,
you asked about, does this take a lot of time and slow down the process? Well, it will take some extra
time, of course. Nothing is free. But honestly, the design of this level is a very high level design.
This is not, it's not like we're completely building a second alternative.
It's, I kind of think at the high level.
So with Tickle and TK, this TK design, I might have spent maybe a few days on the design,
thinking about these two alternatives and comparing them, but then it took a year to implement TK or more than that.
So we're talking something on the order of one or two percent of the total time to build a system.
It's just, it's not that big of a deal.
And if it gives you a better design, you get back way more than 1 or 2%.
Yeah, I feel this is a lesson that people, teams, engineers learn again and again.
You know, first, there's always a point where you jump into coding.
I'm faster.
And then when it's complex enough, you learn, oh, we probably should have planned a little bit better.
I would have saved myself time.
And then after a while, the cycle goes into like too much planning or people feels too much planning.
And then it starts again.
So I feel there's a little bit of never-ending cycle.
There, people still talk about waterfall, which used to be a thing like 20 or 30 years ago.
It's not really a thing.
But like there is some disdain, especially for fast moving teams in planning too much because it's seen as, you know, too much talking, not enough doing.
Well, and I get that too.
So, you know, the, I think the fundamental thing about design is it always involves tradeoffs.
And if you take any one idea and you push it too far, you're probably going to end up in a bad place.
So this idea about doing multiple designs, you could certainly take that too far also.
And I think one of the things that separates the really good designers from the not as good ones is they kind of know how to make those tradeoffs and how to combine these different ideas and different phases and balance them off.
And that's the kind of thing.
Probably you just have to learn from experience.
You know, you try both approaches and see the bad problems with them.
And then you eventually get a gut feel for what the tradeoffs are.
Now, in the book, one idea that stuck with me is this concept of deep modules and shallow modules.
And you introduce this concept that a deep module is something, a piece of code or functionality or, well, a module that has a pretty simple interface, but it has a lot of depth to it.
It has a lot of functionality, complexity.
And then a shallow module is something that has a wide interface, but it doesn't do too much.
So it kind of, it almost, it might be even transparent in some point that it doesn't do much.
hiding. And in the book, you emphasize how deep modules are important for good software design.
Why is this so? And how did you, again, like, come across this realization?
Well, it all comes back to complexity. And everything in the book really derives from this idea
about how do we eliminate or manage complexity. And so a deep module is what gives us leverage
against complexity.
And the way it does that is it provides this very simple interface.
So people using the module have almost no cognitive load, very easy to learn.
But inside the module, there's a tremendous amount of functionality and complexity that
is hidden from everybody else.
And so that's, in the deep notion, I was trying to capture the tradeoffs.
And basically, it's this tradeoff between two things, the complexity of the interface and
how much functionality you have in the module.
And so what you want to do is have, get the most functionality you can for the simplest
possible interface on top.
In the book, you have a chapter title defining errors out of existence.
And in this one, you talk about error handling.
What is your take on error handling and how to design for sensible error handling?
Right.
So again, this comes back to the complexity issue.
And anybody who's built a lot of software knows that error handling is a huge.
huge source of complexity. Basically, it's, you know, it's all the special cases, all these weird
special cases you have to deal with. And so it's easy for the, for error handling to impose
tremendous complexity on software. So then the question I'm constantly asking myself is, how can we
reduce the impact? I mean, we do have some situations we have to deal with. There's some, you know,
there's many exceptions you simply can't be avoided. They're fundamental to the systems. You
have to deal with them, other cases where they're not so important. So in that chapter,
what I was trying to argue is that exceptions, having more exceptions is not better. It is
sometimes necessary. But I sometimes think that designers think that the more exceptions I throw
from a class, the better programmer I'm being, I'm being a more cautious, careful programmer.
And I would know the problem is every exception you throw is imposing complexity on the users of
your class. And so if you can, if you can reduce the number of exceptions you throw, the number
of special cases you generate, that will reduce system complexity. And I gave a bunch of examples
in that chapter where, in fact, by just a slight change in the design of the system, whole
classes of errors simply disappear. They can't happen. There is no error to deal with. But I will
say, this is something that this happens occasionally, but you have to be very careful about this.
And in the class I teach on software design, students have, virtually every class, there are people
that misunderstand this. And in the first project, they have essentially zero exception handling.
The building a distributed server where machines can crash, and they don't even check for errors in the
network. And I say, you have no error checks here. What happens if a system crashes? And they say,
oh, we just defined those errors out of existence.
And I say, well, no, the errors are still there.
You're just ignoring them.
You can't do that.
So anyhow, I think this is a chapter I have to warn people about.
It's really easy to take this one in bad directions.
It's kind of like a spice, you know, they use tiny amounts of it in your cooking and you get a good result.
But if you use very much, you end up with a mess.
Yeah, but I feel errors, exceptions.
things going wrong.
One of the things that are,
we don't really talk to enough about it
when we think about design.
When I look at outages,
I remember a lot of outages that we had,
specifically at Uber,
but even at other companies,
a lot of the times when we looked into what caused it,
it was,
you know,
like a mishandling of an error.
It came from one system.
We mapped it incorrectly as a success.
And there was a lot of these edge cases,
which were we misunderstood either errors
or unexpected responses.
You know, they're all the same thing.
It was something with errors.
And I think we struggled to put a finger on it.
You know, we looked at ways that were like, okay, let's map responses, better.
Let's have white lists.
Let's have blacklists.
But during the planning phase, I don't really remember.
I feel for planning, people tend to be optimistic of here's how it works.
Here's how these things will communicate.
And I rarely recall planning sessions where we thought, okay, what could go bad?
how will we catch it how will we will recover so it's just i think you make a good point in
that i i think people don't they i don't think exception handling is top of people's mind when
they're doing the overall system design it just kind of it just sort of happens tactically
was people discover potential problems yes this this is i think you're putting what i'm trying to
to put as this observation, it's just a very interesting one.
So the one general piece of advice I have for people is that when you're building a module
and thinking about what kinds of special cases and exceptions you're going to export through your
interface, you think about how you think the callers are going to deal with these and try and
put yourself in the mindset of the user as you're thinking through these.
and see, rather than having 10 different exceptions,
kind of is it actually,
there's only really two different ways people are going to handle this,
and so I can boil it all down into two kinds of exceptions,
rather than 10 kinds of exceptions, for example.
So I think the key thing is to think about it from the callers standpoint.
By the way, that brings me to what I think is one of the most important attributes
of a really good designer, which is,
What is it?
They can change their mindset and think about things from very different point of views.
So when I'm designing a module, I'm thinking about all of the details of that module.
But then I can change my mindset to think about the user of this module and realize I don't want to have any awareness of those details.
And in particular, when I'm using a module, I don't want to take advantage of things I might know about the inside of that module.
I only wanted to use things in the interface.
And so being able to shift your mindset and think about things at one point, but then completely put those out of your mind and take a totally different view some other time.
That's really powerful.
That's how you come up with good designs, I think.
Again, when you're designing something, you can also think about it from the standpoint of somebody that's going to be using it.
Interesting.
So are you saying that having empathy and having being able to put yourself in this, you know, put yourself in this.
shoes of another role, may that be a customer, another developer, you know, another developer
who will be working on this, that could make us a better software engineer? I was about to say
the word empathy. Yes. What I was going to say is, I think this skill set has tremendous value
in social context as well as an engineering context, the ability to think about things from some
other person's viewpoint. By the way, one of the things I love about computer science, people
People think of us as these sort of geeky, nerdy people, but many of the ideas that we use in computer systems actually have interesting analogies in social systems as well.
Yeah, it's just interesting because when I, you know, I'll sort of like you on this offering journey, you know, start to learn to code, go to college, get my first job, et cetera.
And initially, I thought the hard part is the coding.
and every developer I talk to or every engineer I talk to above a certain years,
we always have this discussion that the hardest part in software engineering, computers, and programming,
it's the people.
You know, when we think back of after your first few years, once you get the syntax and you learn how to debug in those things,
you think about what was the hardest project I was, what was the biggest problem,
what caused me the most headache and it's oftentimes miscommunication.
You know, like we misunderstood each other, the spec was off, et cetera.
Of course, there's outages as well, but usually the root cause is we did not expect this to happen.
We didn't have the empathy for the user.
And yeah, it's usually, and the biggest one is conflicts with teammates, with people that you work with.
It's all human things.
So it's interesting.
You know, there's this joke that the hardest thing in computer science are, I think, caching and naming things.
But I will add people as well.
Yeah, that sounds interesting.
one thing that in your book you don't touch on of course you know that the book cannot touch on anything
but it's a practice that a lot of teams and tech companies use is these things called design reviews
and discussions the idea is that someone before building a system will write down a plan
and people will either have a meeting amazon famously has this writing culture where people
get into a room and they read the plan and then they discuss in other places it's done with
Google Docs and even some others like Figma, they use your own tools to kind of like draw visuals
and comment on it. What is your take of before building a system explaining a plan,
either whiteboarding or otherwise, and kind of criticizing each other's plans? Have you either
done this to some of the things that you do? Do you encourage students in your class on design
classes to do this? Oh yeah. We do this certainly all the projects I work on. And
Certainly when I was doing startups, we would do design reviews.
They were relatively informal.
We didn't have, you know, lengthy written documents.
But we'd get together and talk about ideas.
And this is where, again, you get the multiple designs and you talk about the tradeoffs.
And, you know, it's just if you can get multiple minds to think about a topic, it's pretty clear you're going to come up with better ideas than if just one person doesn't.
Again, this is how, this is an area where smart people sometimes have to get past their history.
because they've been for much of their life in environments where they couldn't expect to get a lot of useful input from other people.
But when you're working at the very highest level with very, very smart people, you know, two minds are better than one, clearly.
So I'm all for it.
Again, you know, it's you don't want to get caught in analysis paralysis.
And so trying to figure out what's the right place to do, at how much time to spend on it.
There's a certain art to getting just the right level.
But I'm all for that.
And I think this might have changed in the last few years because of remote work.
You know, we've had an explosion of remote work and now it's a bit of a contraction.
But I remember before 2020, some of the most innovative companies, when you went into
their thing or startups who are gaining momentum, what they had is whiteboards and these
erascible whiteboards everywhere.
And what would happen in these places actually, I even had one of my older teams where we
actually requested a whiteboard is people, you know, you're just doing your thing.
someone says something, you're like, hold on, and then you go to the whiteboard, you start
whiteboarding and you can erase it. Sometimes you leave it there, sometimes you photograph it.
Basically, it's just like on demand when there's a, it could be any trigger. It can be just
mishearing. It can be doing, you just have people come together, do their ideas. And there's
something special about, they have and startups have to try to replicate this digitally, but there's
something special about in person, just, you know, like doing, just getting your ideas out there,
especially when we're talking about something like software where you do, you know, boxes and arrows do help.
I totally agree. I love whiteboards. And I like having meetings that are in person.
I've also over my career developed a technique for using whiteboards to resolve complex issues,
which may or may not even be technical, other kinds of management issues in a company.
And what I found is that oftentimes people get in meetings and they just kind of talk past each other,
repeat the same account arguments and counter arguments. And it just goes round and round and round and
it never reaches a conclusion. So what I do in these situations is I stand at the whiteboard. And
basically I list, typically we're arguing for or against something, just list all the arguments
for and are the arguments against. And the rule of the discussion is you can make any argument
you think is reasonable. No one is allowed to tell you your argument has to be removed. It's a bad
argument. Every argument goes on the board, but you are not allowed to repeat an argument that
is already on the board. And this is really important. So having the arguments up so everybody
can see, everybody's argument is valid, you know, everyone's allowed to contribute. No one can stop you
from putting your argument on the board. So everybody's arguments goes up. And then the discussion
just naturally reaches a point where nobody has anything more to say. And so this shortens the
discussion. And then what I do after that is I take a straw pole. And
And what's amazing to me that you should try this sometime because it's really, it's quite
shocking, is that people will be arguing violently on both sides and you'll think there's total
disagreement.
And then at the end, and then we just draw uphole, you tell everybody you get to weight these
arguments in any way that you think is appropriate.
You decide which ones you value, which ones you don't value, should we do A or B?
We almost always end up with a really, really strong consensus.
It's shocking.
Like I said, I'll be in these meetings where I think.
think we have total disagreement here. And then we do the vote and poop, it's unanimous.
Well, it sounds, I have not done it. So it's, you know, it sounds one of those things where I don't
believe, I wouldn't believe you. I'm sorry. I do believe you. But yeah, as, as you said, I think,
you know, I'm going to try to try this out. It's a point. It's all about that whiteboard, I think.
Yeah. And I think anyone listening or watching just like this is, this is why I love these
discussions. It's just like getting a tactic that you can try out. And now that more and more companies
are doing at least a few days in the offices, you get a whiteboard. Try it out. By the way,
this works best in environments where people are, first, generally, pretty smart and reasonable
and goal aligned. Like, you know, in a startup, for example, or an engineering team, you're typically
goal aligned. You all want to achieve the same result. You know, with this work in Congress,
with opposing political parties, no, no, not in political environments. Yeah. Fortunately, we don't
operate mostly in those environments. Well, yeah, and I think, you know, one nice thing about how the tech
industry seems to be able. And from my perspective is it's more and more common and accepted,
even at large companies that you do want teams to have clear goals, like have those goals,
because you don't have it, you know, everyone's going to go in different directions. So I think
it's becoming more common. Also, companies don't do it. They, they fizzle out pretty quickly.
So similar question on design. There's two schools of thoughts when it comes to design. One is,
let's design up front. And the other ones, let's not design a front. Let's just do prototyping or just
you know, build something and let the code decide.
Do you subscribe to either of these approaches, you know,
taking time upfront or just dropping into and prototyping?
Or, you know, have you seen times or types of projects where one just works better than the other?
My personal belief is that design permeates the entire development process.
You do it up front.
You do it while you're coding.
You do it while you're testing.
You do it while you're fixing bugs that you should constantly be thinking about design.
I think you should always do at least a little bit of design up front.
Again, you know, not waterfall method.
It's important to realize that our software systems are so complicated that we are not able to predict the consequences of our design decisions.
We simply can't.
But I think it's really important to do some design and to have some hypotheses to work from.
And then you start implementing.
And, of course, you know, once you get in the back,
all your plans kind of fall apart and you'll discover lots of problems with it. And so you
have to be prepared to revise as soon as you discover problems. But if you don't do any design
up front, I think you're wasting your time on code that is just very unlikely to be useful.
The only time I'd argue for coding without design is if you're so young and inexperienced that
you really have no clue how to do design. Then, you know, you may just have to write some code
and start learning from it. But in any case, absolutely be prepared to redesign, you know, as you
discover problems. Yeah, like I had one of my colleagues a long time ago, many years ago,
he said something super interesting because we were talking about why software is hard. And we were
experienced engineers at this part. Like, why do some projects take a lot longer, even if we do
proper planning up front? Why are some projects actually, you know, they're pretty easy? And he says
something interesting. It's like software, like building software is a little bit like, like, we're in
a terrain, you know, like, and we need to march to that location. We, we see. We, we see.
that we see the target, but the terrain is unknown.
And sometimes you just walk there and it's exactly how you'd expect.
Other times you're walking and, oh, suddenly there's a big kind of boulder appears out of nowhere
and you kind of climb over it, then another one comes.
Sometimes you walk and like a mine explodes right in front of you and suddenly you have this
massive hole and you didn't know this was a minefield.
And he said, and this analogy kind of resonated with me because I realize a lot of it is about
like how how much unknowns are unknowns.
And the approach is just very different, right?
Like if you're building a tech stack or product that you've done before versus something
that is completely new, if are using new technology, are using a beta version of a framework
that could have issues, but maybe it'll work and so on.
Yeah, I think a lot of it has to do whether you're in a domain you've been in before or not.
It's not that you got lucky and there was a flat field.
I think it's more that, oh, I've actually walked through this mountain.
range before and so I know the right paths.
And so, you know, if you're building your, if you're building a driver for a new device and
you've built drivers for five devices before that, you kind of know what the main problems are
and the process is much more predictable and smooth.
If you're in a new environment, well, I don't know, maybe I'm just unlucky, but I don't
think I've ever had a smooth experience when I'm in a new environment.
It's just too hard to predict.
Neither have.
Like the only kind of new environment, well, it's not really a new environment.
like a new version of the framework and it's not a big change or, you know, the, a new language
release, which is backwards compatible with all the importance of that you're not using
new features, that kind of stuff. But it's kind of fake, right? Like, it's kind of the same
as before. One thing I'd like to get into is the writing of this book. Because again, like,
this book, it feels to me, it has just a lot of really kind of practical insights. Now, first of all,
I haven't seen many books written about software design or software architecture specifically.
How did you get the idea to even start writing a book about this?
You know, like pretty hard to tangle domain.
It's kind of a long process, but the path leads through the course I taught at Stanford.
So the background for this is, as I mentioned earlier, I love coding.
I'm one of few professors that still writes large amounts of code.
You know, I try to write five or 10,000 lines of code a year, at least,
been significant fraction of my time coding. And I love design. I think design is one of the most
amazing, creative forms that has ever existed in the history of humankind. It's just really
fascinating, beautiful, challenging domain. And so I've often, I thought, think about it. I try
to think, what is a good design and how do I get to, how do I design software that's good? What are
the techniques for that? But over time, I noticed, to my shock,
nobody teaches it. Literally, other than the course I eventually started at Stanford,
I don't think there's a single course anywhere in the world where software design, not tools
or processes, but the act of software design is the primary element of the course. And so this just
kind of graded on me for, I don't know, a decade or more. And once I got back to academia at
Stanford and now I would have this experience in industries, so I'd had a lot more software
development experience and more ideas myself, I started thinking about this and I finally decided
I'm just going to, who knows what's going to happen, but I'm just going to try teaching a course, see what I can do.
And so that forced me to start thinking about my ideas and try and capture them in sort of simple principles.
You said no one teaches design. And I'll tell you the perspective from like someone working at a tech company.
Like usually we don't interview new grads or people with a few years experience on this on software architecture topics.
Usually there's interviews coding and then software architecture or design a complex system.
And the reason being, well, you need to work in the industry for several years to start to get a sense for this thing.
But I have a feeling you kind of, you know, you turn this upside down.
You're you've kind of proven or, well, you're attempting to do with the class that design can be taught even for students who have recently learned to code.
What was your approach and what has the response been from the people who've done it, especially now that, you know, some of those folks have been out in the industry for years?
I'm sure they're coming back with some of their experience because they now have a skill set that a lot of their peers do not.
Yeah, so I decided to teach this class.
And then the question is, well, how do I teach it?
And the model I used was my English writing classes from high school.
I don't know if this is the way it's still done today.
But back when I took English, the way you learned to write is you would get an assignment.
You'd write something your teacher would mark it up.
And then you would rewrite it and submit it again.
And you might do several iterations on it.
And I think the key elements are first getting a.
feedback. So you have somebody that can criticize your work. And then second, redoing to incorporate
that feedback. And it's the process of redoing something, I think, where you really internalize
the feedback and the concepts. So that's the way the class is taught. It's over a course of a
quarter. People do basically three stages where they build something significant. And we do extensive
code reviews. For example, I read every line of code for all the teams in the class, which means
And what do people build? What is the project or what was one of the projects?
So actually, the first two projects happen to be the RAF consensus protocol divided up in the two phase.
And that actually turns out to have some really interesting design problems that confound students and lead to lots of mistakes.
So it's this process of they and when they start off, I give them no clues, no hints, no structure.
They have to do it completely from scratch.
This is the first time in their lives.
They've ever done anything like that.
So it's actually, it's both very fun and very scary for the students.
And then we do this extensive code review where they review it in class and other students read their projects and give feedback.
And then I read every line of code and I spend about an hour with each team.
They typically get 50 to 100 comments for me on their, so two to three thousand lines of code they've written.
And then they go back and they rework.
And I think that's when the aha moments come from students.
When they get the feedback from me where I can point out code is complicated.
People generally know that code is complicated.
But then I can point out, here's why it's.
complicated because you didn't follow this principle that we've been talking about. And here's how,
if you apply the principle, you can make it simpler. And then they come back with their second
projects and the second projects are so much better. And you can tell the students, the students are
really excited because they can kind of feel their power. They can feel that I was able to make this
a lot better. And so, you know, I was worried about how the students would react to the class. So it's an
extremely positive experience for the students. You can tell over the course of the quarter
the way they think about software has changed, really in significant ways. And actually, I warned that
at the end of the quarter, I say, you know, I just want to warn you, when you go into companies,
you're going to find you know a lot of stuff that people in the companies don't know, even much more
senior engineers. So then we talk about how do you deal with that? Because as a junior employee,
you may not have much ability to change the company. But anyhow, so I totally, totally believe design can be
taught. Now, you still need experience. You know, it's not like you're not going to be a world
class program after one quarter in my course. But I think that's, they can start the process in
motion and give you a new way of thinking about software that you've never thought about in your
classes up until now. Yeah, and I think you can probably like my senses that the students who go
through this, this class and, you know, they build up their experience. They also learn about
themselves. They learn how they can challenge themselves, how they can talk about it.
Other software developers take, you know, like when you enter the industry, like, in the first few years, you're just going to like learn the hard way.
Like I remember that when I was a new grad or a junior developer, you know, started out of college, right?
I was actually still doing college, but I was working at a workplace.
And a senior developer told me, I need to do this, you know, did the planning.
We're going to use this technology.
You need to implement this and this.
And I just had a bad feeling about it.
But I did it.
And it just became worse and worse.
and more and more complicated, and the solution that it was some in-house database and
performance issues, and it got bad, it got really bad. And, you know, the developers, the senior
developer stepped away. And in the end, like, weeks into the project, the customer is frustrated
because, like, a page load took 15 seconds, which is, like, it's not, it was not okay. And then I just,
like, over a weekend, I worked, I must have worked for, like, I don't know, 20 plus hour. I just
rewrote the whole thing, the way I would have done it and all of the things were fixed,
etc. But it felt to me like I was kind of like, I was thinking like, am I being crazy?
Like, like this experienced person told me to do this. I just didn't really have the vocabulary.
I didn't have the faith in myself as well that I can do this. So and everyone goes through these
things eventually, right? Like you kind of learn, you burn yourself, but I feel you might be giving
those students a bit of a shortcut to maybe avoid some of these pitfalls.
I suspect that experience was really good for you.
Oh, it was really good.
Totally.
To do it the wrong way and see your gut feeling validated.
So next time around, you can probably kind of put some words to that and talk more with more authority about why that's a problem.
And then going back and doing it the right way and seeing how much better is.
I mean, that must have been a really great experience for you.
Like, nice, the cool thing is that I think all these things are like really good learning.
It's like I wouldn't have it any other way.
Salvation through suffering, maybe.
Yeah, but I feel that's sometimes that's the most memorable learning, no?
Honestly, I think almost all learning is about making mistakes.
Yeah.
That the way you learn, the most powerful ways to learn are to make mistakes, see, understand why they're mistakes and then fix them.
And to me, education is about basically creating a safe space where people can make mistakes and learn from them.
And I tell the students in the class about this.
I tell them, you know, you're going to get a tremendous amount of criticism.
I tell them, I am going to pick every single knit with your code.
You're going to think there.
You could probably be mad at me for things I'm picking, but I'm going to show you every single thing that's wrong because I want you to be aware of that.
And one of the things I hope students get out of the class is realizing that's a really productive experience.
It's actually good for me to have people come in and challenge me, scrutinize my code and give me feedback.
Because I think a lot of developers out there are kind of sensitive.
Maybe they worry that if somebody criticizes their code, maybe that means they weren't such a good coder.
Or maybe they think if I have to come up with a second idea, maybe I'm not that smart.
Only dumb people have to do things twice.
Smart people always get things right the first time.
So then you latch on to this.
I can't ever admit that my first idea isn't great.
And so I think it's really important.
The whole idea of making mistakes is so important and so constructive.
We need to, you know, we need to honor that, I think, as engineers.
Slightly different topic, but you and Uncle Bob, Robert Martin, had an interesting discussion
about his book, Clean Code, online, where you both, like, wrote your thoughts on different parts.
And there were a few parts where your opinions diverged.
And I was interested in getting into some of these.
So first was on short methods and the method is doing just one thing.
Robert Martin is a big fan of doing so.
He's saying this will lead to cleaner code, clear responsibility, and so on.
And you had a slightly different take on this.
Well, I sure do.
So I mentioned earlier on that design is about tradeoffs.
And if you take any idea and take it to the extreme, you end up in a bad place.
And so I think clean code has done that in many places.
And this was my biggest overall concern. And so method size is one of them. So, of course, I think
we agree that really long methods are probably harder to understand and deal with than shorter
methods. So there's some value in shortness. But it isn't the method length per se that's most
important. To me, it's this notion of depth. Are we hiding complexity? And so what happened in
clean code is that shortness was taken as an absolute good with no limits on it. The more
you, the shorter, the better. And so a three-line method is better than a five-line method,
according to clean code. And the problem with that is that, well, maybe that one method is a little
bit easier to understand, but by having shorter methods, you now have a lot more methods. And so
you have a lot more interfaces. And now the complexity of the interfaces ends up actually
making the system more complicated than it was before.
And in particular, his style, he is comfortable if methods are entangled, having multiple short
methods where, in fact, they're so entangled that you can't understand one method without actually
looking at the code of the other methods at the same time.
Yeah, so it might as well.
To me, I see no benefit of that.
I think to me, that has made things worse, not better.
That if things are really related, you're better off pulling them together.
So don't think about the notion of depth is it kind of captures the tradeoffs, that we want to have a lot of functionality, but it needs to have a relatively simple interface.
And so I think that notion will keep you from going astray in either one direction or the other.
Whereas, for example, the single responsibility principle, the do one thing principle, that just pushes you relentlessly in one direction without any bounds and you get in trouble that way.
And it's interesting how, you know, you talked about methods, you know, being short, doing one thing and you can have a lot of them or you can like group them and have bigger methods that do do more thing, but they're more sensible.
I was thinking as you're talking about this in the industry, we've had a similar thing with microservices.
So I happen to work at Uber at the time where it was popularized that the company had more than 5,000 microservices.
And we had a lot of really small microservices.
And what happened over the years is, at least in my, I cannot speak for the whole company,
but I can talk about the domain I was, which was in the payments domain, we had a lot of small
services because they were easy to spin up.
They did like one thing or two things or a few things.
And after a while, we realized like, huh, it's just really tough to maintain to know which
lives there, a lot of communication back and forth.
So we started to just pull them together and create like mids, I would say like midsize
services that kind of had a domain responsibility.
And it wasn't either extreme, but like I think we saw that one extreme, it sounds good.
It sounded really good, by the way, initially, and it has benefits.
But over time, it just wasn't as practical.
So it's somewhat similar to what you say.
Like extremes on one end are not great.
It's not great to have like one massive service that does everything.
You know, Uber used to have that.
It was called API and it did everything.
And then it got broken into smaller things.
And then it came back into like kind of domains or reasonably size one.
So you could actually keep track in your head.
You could understand here are the different parts that are there.
Okay, you can go inside and then you can understand the part.
So there's, I think there's a level of when does it make sense?
How can you follow those kind of things as well?
I think there's a, you know, again, you can err on both sides.
But I think these days people often err on the side of over decomposing.
And I think so it's a clean code for example advocates that what I consider to be over decomposing.
us's problems. And so one of the things I tell my students is often you can make something deeper
by actually combining things together. If they were closely related, you may discover that if you
bring them together into one class or one method or one module or one subsystem, you end up with
the combined functionality, but with a simpler overall API and without having two separate
things with a lot of dependencies between them, which is really bad. Again, you can overdo this.
So everything is tradeoffs, but you could often make things better by making the units a little bit larger.
Another area of this agreement was test-driven development, and we touched on a little bit.
Robert Martin is a big fan of using TDD as a way to write code, write the test first, then write the code that makes it pass.
This method was also pretty popular in the early 2000s.
It's kind of gotten a little bit out of style.
Your take was different as well.
Yeah, I'm not a fan of TDD.
Because I think it works against design.
So again, to me, software, so tests are important.
I love unit tests.
I write them for everything I do.
They're essential.
If you're a responsible developer, you write unit tests with very high coverage.
So let's agree on that.
But we want the development process to be focused on design.
I think that should be the center of everything we do in development should be organized
towards getting the best possible design.
And I think TDD works against that because it encourages you to do a little.
little tiny increment of design. I write one test and then I implement the functionality to make that
test pass. Then I write one more test and write the functionality to make that test pass. And so
there's no point in the process where you're encouraged to step back and think about the overall task,
the big picture. How do all these pieces fit together? What's the most pleasing, simple, clean
architecture that will handle that will solve 10 problems rather than coming up with 10 points solutions
individual problems. And so it results in what I believe the risk is you can up at an extremely
tactical style of development that produces just a horribleness. So that's my concern. And we had this
long back and forth about it. And I think the main reason that Bob likes TDD is it ensures that the
test get written because you have to write the test before the code. And so I agree that should be
written. But I don't think there's anything, he was not able to convince me that there's any particular
advantage in writing the test before the code other than ensuring that the tests get written.
I can't see any reason that makes the design better, and I can see a lot of reasons why it might
make the design a lot worse. I think an interesting question is, what should be your units of
development? You know, you're going to do development is always in chunks of work. What should those
chunks be? And I would argue those chunks should be abstractions, not individual tests.
That's too small of a chunk again. You want to think in a big enough chunk that you can
consider trade-offs and try and come up with a fairly general-purpose solution that will solve
many problems. By the way, one of the most important elements of design, I think, is pushing
yourself towards general purpose to avoid specialization as much as you possibly can. And so the
TDD approach encourages you to do something very specialized to pass each test, rather than thinking
about the general purpose thing that solves many problems in one place. Oh, all right. Yeah, that is true.
That is true.
In fact, I remember, like, at some point when we did, we did some TDD mobbing where we
passed the keyboards around and someone would write a test, someone would make it pass.
We would try to, it felt a bit artificial because when you wrote more code that you needed
to come to, they're like, no, no, don't write that.
That doesn't make, just make the test pass.
So it almost felt a little bit of artificial.
And again, like, I'm sure there are times and cases where it could be useful, maybe
in a more formal way, maybe where it's more about adding, extending additional.
code where it's like very heavy in business logic.
Maybe that could be a good fit, but there might be a reason that it kind of slowly,
you know, became less popular.
And we're not talking about it too much these days.
One place where I'd recommend writing the test first is when you're fixing a bug.
I would argue write the test that will detect the bug and then fix it.
Although actually what I typically do is I honestly, I kind of cheat on this one.
I write the fix and then I write the test for the fix and then I back out the fix and make sure the test fails.
So I know that, but anyhow, that's one place where I think doing the test early can be useful.
Now, one more area that you disagreed is comments.
So Uncle Bob says unsurprisingly that you should have a few comments in the code.
The code should speak for itself.
You also did not fully subscribe to this one.
If the code could fully speak for itself, that would be wonderful.
I would have no objection.
But it can't.
And it never will, as far as I'm concerned.
There's just so much stuff that can't be described in the code itself.
And we ended up discussing examples where he said, look at this code.
It needs no comments, right?
And then I said, well, here's five questions people have that I don't see answered in this code.
And then he kind of hedged about that.
And so I don't know.
He's very, very biased against comments.
I'm not sure why if he had some scarring experience.
And he argues that he, I believe he basically said, he thinks that people lose more time by being misled by comments that are out of date than time lost because you haven't had adequate comments.
And that certainly is not my experience.
No, no.
Occasionally, no comments are out of date, but rarely, in any sense.
even then there's usually useful information.
And then he also made the, he argued that, well, if you're working in a project that you
and other developers were, you don't need any comments because everybody's got it all loaded
into their minds.
And I just don't agree with that.
Now, maybe his mind is better than my mind, but, you know, I can't keep everything in my
mind that I forget code within a few weeks of one I've written it, so I need those comments.
So the bottom line is there's just a lot of stuff you can't get from the code.
And then what is your kind of approach of like, how?
How do you do comments?
What do you like to put into comments?
Or is it just like whenever you feel like it just put there because it's going to be additional information that could help later?
Well, again, the number one rule is comments should tell you things that aren't obvious from the code.
And so, you know, there are a lot of bad comments out there where people are basically just duplicating stuff that's obvious from the code.
So no need for comments in those situations.
And, you know, in my students, projects of my class, I often take comments out, tell students this.
comment just repeats the code. You don't need it. I think where comments are most important is for
interfaces. This is where they're really, really important because the assumption of interfaces,
you don't want people to have to read the code of the thing that you're communicating with you,
talking about you just want to look at the interface. And there's simply, it is impossible in the
functional signatures of a module to provide all the information people need to use that module.
And so that's where comments are most important there.
to me, to me, that's the most important.
The second most important thing is documenting the member variables of classes.
That needs really extensive documentation.
And then I tend to find that inside methods, I don't tend to need a lot of comments.
Because if you know what the method's trying to do, the code typically speaks for itself pretty well there.
I tend to have comments where things are tricky or where there was unexpected stuff.
I only discovered, you know, when there were bugs and things like that.
But often my methods won't have any internal comments.
They'll just be the interface comment.
I think comments are going to have a bit of a resurgence at this debate potentially
because AI tools increasingly generate more code.
They often during whole methods.
You know, you can ask.
And what I've noticing is when I'm telling, you know, one of these AI assistants, like
generate something that does this for me, it generates a code, but it often adds inline methods,
which explains what it does.
And actually, in that case, because it's just coming to some of the.
quickly, it actually kind of helps me because I'm, I know these tools hallucinate and I actually
want to make sure what it does.
So it kind of helps me understand.
At the same time, it's a good question of why it's doing it.
You know, these are trained on typically code that's out there either open source or who
knows what kind of licensing.
So it probably is copying however it's seen it.
But this, you know, usually I would agree with you.
But in this case, maybe comments are not a bad thing.
Who knows?
It's an interesting.
Yeah, so I'm a little hesitant to say this because I'm fearing, a fearing I may be justifying bad habits.
But one thing I found is that AI tools can, to some degree, compensate for the lack of comments.
So I've been working in the Linux kernel, building a new network transport.
And, you know, actually, Linux kernel is not a bad piece of software, but it's pretty significantly under commented in my view.
And I spent a lot of my time just trying to figure out what is going on.
and Linux, what are the interfaces? How do we hook into this? ChatGPT has become my very best friend.
It's amazingly capable at answering questions about the Linux kernel that I can't answer
via Google search or any other way. It's not always correct. Sometimes it hallucinates,
but it's often right. And even when it's wrong, it typically gets me in the right vicinity and
helps me to figure out where to look to figure out how to answer my questions. So I think the AI
tools may be able to help.
But even saying that if the Linux development has just spent a little, a tiny amount of time
putting comments in, it would have made things so much easier than using Chad GPT to try
and figure it out.
So I don't think the need for comments is going to go away completely.
And we shouldn't use AI tools as an excuse for people not to write comments.
It's not yet.
So before the podcast, one interesting thing that you mentioned is you are actively writing
code. In fact, after this podcast, I think you're going to be getting back to writing code.
What are you working on right now? You mentioned something with the Linux kernel.
Yeah. So one of my PhD students, Ben-on-Montezeri, as his PhD dissertation, six or eight
years ago, developed a new transport protocol called HOMA, which is intended for use in
data centers. And the results he got in his dissertation really fabulous. It's 10 to 100 times
faster than TCP for a whole lot of interesting cases.
Wow.
And so rather than let this just come and go as a PhD project that nobody ever cares about,
I've taken it as my own personal project to see if it is actually possible to bring this
into widespread use and displace some of the TCP traffic and data centers.
So I have developed a Linux kernel implementation of that, which I'm continuing to enhance,
and I'm now in the process of upstreaming that into the kernel.
And so actually what I'm really dealing with is a whole bunch of it.
bunch of comments I've gotten from the Linux kernel developers about this and trying to fix all
the problems they pointed out. Here's another example of code reviews and the benefits of all of that.
And indeed, this afternoon, I'm getting ready to submit my next round of patches to the net
debilings.
How are you finding, is this your first contribution to a Linux kernel or have you previously worked on it?
Yeah, this is my first involvement with the Linux kernel. I have not.
How are you finding the process? Because we just had an episode on with one of the main Linux
kernel maintainers. And I'm curious. Is it overwhelming? Is it easier? Is it harder than what you thought?
So I've been warned that it might be difficult and painful and take a long time.
It's taking a fair amount of time. I think it's been, we may be coming up on six months since I
made my first submission of this. But I have to say that the people have been very reasonable.
And the feedback I've gotten has been high quality feedback. So I've had to
fix a lot of things, but these were all things where either I misunderstood something about
the kernel or they show me better ways to do it or pointed out complexities in my design,
which there were plenty of. And so I have no objection to the process so far. And I'm actually
pretty happy with it. And Homa is getting a lot better because of this. You know, I hope we'll
eventually reach closure and it'll find its way into the kernel. But it has seemed pretty
reasonable to me so far.
This is really encouraging to hear, and good luck with that.
So what are ideas from the history of software design or even software engineering that you
think might make a renaissance in the near future as we're looking at, you know, focus on tooling,
distributed systems of obviously AI tooling?
I'm not sure I can think of any idea that has come and gone and is going to come back again.
So I think, you know, I think there are ideas that have come and gone.
because we've learned how to do things better.
But hopefully we're getting better and better at this.
We're not just oscillating from good to bad, good to bad, back and forth.
So I can't think of, there's no idea I can think of, you know,
that people have forgotten about once in new and forgot about this,
going to come back into play again.
And then the book, this was first published in 2018.
So that's coming up seven years now.
if you were to write this book today, are there parts that you would add to it, that you would rewrite or even remove?
Yeah. So first, I never actually finished the explanation of the book. So the book came about after the class. When I started giving talks about the class, people said, you should write a book about this. And so I had a sabbatical in whatever was 2017, 2018. I used my sabbatical to write the book. So feedback on those. So first of all, there have been some things where I've adjusted my opinion since writing the book.
book, but there's already been a second edition of the book where I fixed most of those.
And hopefully the book you have is actually the second edition.
In fact, if you've gotten it in the last couple of years.
It is first edition.
I need to update the book.
Okay.
It has not changed dramatically, but the biggest change is more emphasis on this notion of
being general purpose and eliminating specializations.
And that's something I learned actually not from the book, but from the class, from
observing student projects in the class over a period of years.
I realize this idea is really fundamental to teaching students how to write less complicated
code.
So that's already in the book.
There's no big thing that I would want to change right now.
As I mentioned earlier, I think the part of the book that is most dangerous is this part
of an exception handling, which, as I mentioned, is easy for people to misinterpret and apply in
ways that I actually wouldn't agree with.
So if I were rewriting the book from scratch, I might think about that more carefully to make sure I choose my wording more carefully to help people avoid misinterpretation of that.
Now, one thing I hoped when I wrote the book, one thing I was hoping was that people would come in with new ideas that I hadn't thought of, and that I would learn from that and then get more ideas and gradually, you know, I'd be adding more and more stuff to the book.
So that has not happened very much so far.
There's not, I would have been delighted to have more.
I'd love for people to come and say, you are totally wrong.
This idea here in the book is totally wrong.
Here's why.
Here's how you should do it instead.
And there's not actually been as much of that as I had actually hoped for when I wrote the book.
I have a theory about why this might happen, which is that your class is so unique.
Software design in the wild is typically you have a problem, you build a solution.
You might explore some different trade.
office on a whiteboard, but then you build it and then you might go back and fix it.
You might have to maintain it.
You're going to learn about it.
But what you don't have is you don't have this ideal situation where let's say you have
two or three different teams building different things and then you compare it because in,
you know, in the industry or in tech companies, you just don't have that luxury.
And even if it's a bit wasteful.
So you never really have a situation where you can repeat something.
In my sense was that with your class, you actually could do this.
You could have a group of students go through, well, actually in the class, you know, the same problem.
People solve the different ways.
You can now see the differences.
They can see the differences.
And I'm wondering if it's just a thing that it may be this setup needs to happen in some level of either academia or nonprofit or somewhere where it is doable.
I'm not sure because I have been thinking of because this makes this book really special.
Like, your observation was not just like a lot of software architecture books are like, oh, here's something I found over working on these projects, which are all one-offs, but I learned these things.
And you're saying, I've seen this thing work better across the students.
And those who did it, you know, had better outcome repeatedly.
Yeah, that's something we can do in academia, I think, better than industry, because in industry, you don't have time for the revision.
And you're right.
One of the things about the class, I think that is really good.
There are nine teams, nine two-person teams in the course.
They all do the same projects.
And then they review each other's projects.
So during the code reviews, each student will read not the whole project, but a big chunk of two other projects and then review them in class.
And so the students, and so your partner is reviewing two different projects also.
So between the two of you, you've seen basically half of the rest of the work in class.
And I think that's also a really great source of learning from students.
really enjoy looking at each other's code and thinking about it.
And then after the first project, they asked me, they say,
am I allowed to use ideas from this other project when I revise my project?
Because normally in classes, you can't use anybody else's ideas in your work.
And I say, oh, absolutely.
You are encouraged to steal and cannibalize all the best ideas.
So that's something I think, yeah, where I think actually doing it in academia,
we can probably do a better job at industry.
You don't have enough time.
You can't let a student, a person spend whatever it is, 15 hours a week for 10 weeks going through an exercise like this.
You have too much other stuff for them to do.
But the outcome has been really nice.
So as closing, what are one or two books you'd recommend for software engineers to get better at their craft?
Well, obviously, we have your book, but outside of these.
So, unfortunately, there's not a lot of other stuff out there that I really like.
There are a couple of things.
Unfortunately, I don't remember the names of them.
But if people go to my homepage on the web and look, there's a link from there that will take you to the software design book.
And there's a short web page there.
And that has some other recommendations at the bottom of that people can look at.
We're going to link this in the show notes below.
And how could listeners be helpful to you or help you?
Well, I'm always interested in constructive criticism.
You know, I don't claim to have all of the answers.
I have my experiences and things I think I've learned, but we're not done with software design yet.
I'm sure there's a lot more to learn about that.
So I'd love to hear if people have ideas or if you think something I say is wrong.
I'd like to hear about it.
I'd love to hear what you think is wrong and why you think that's wrong.
The main thing, both in the class and in the book, what I'm hoping to do is to encourage more awareness and consciousness about software design in the developer community,
and get people thinking and talking about it.
And if we do that, I'm hoping that we can raise the overall level of design in the software that we build.
Yeah, and I'm thinking, especially in that we're going to see more co-generated just by nature.
As you mentioned, design will be more important at all levels, not just like the senior engineering level, but as you're like creating your own thing.
So hopefully we'll see more of this.
Well, John, this was really nice and a really interesting discussion.
and thank you so much for spending the time on this.
Thank you for inviting me.
I really enjoyed the discussion as well.
I hope you enjoyed this conversation as much as I did.
Thanks very much to John for sitting down with us.
If you've not read his book of Philadelphia Software Design, I can very much recommend it.
For more in-depth reading on software design, design docs, and related topics,
check out the Pragmatic Engineer Deep Dives.
We share a link to the show notes below.
If you enjoyed this podcast, please do subscribe on your favorite podcast platform and on YouTube.
A special thank you if you also leave a rating.
Thanks.
and see you in the next one.
