为“不理解自己的代码库”辩护
In defense of not understanding your codebase

原始链接: https://www.seangoedecke.com/in-defense-of-not-understanding-your-codebase/

关于代码库掌握程度的争论,往往分为两派:一派认为“编程即理论构建”(开发者必须拥有完整的思维模型),另一派则承认大规模、高人员流动环境的现实。 作者认为,彼得·诺尔(Peter Naur)的经典理论——即必须完全理解系统,否则就应将其废弃——对于现代庞大的代码库来说是不切实际的。在大型系统中,彻底的理解是不可能的。相反,高效的工程实践需要基于“部分正确的理论”开展工作,通过孤立的流程和迭代的变更来获得专业知识,而非追求全面理解。 虽然维持一个精确的思维模型令人满足,但这仅仅是众多价值中的一种。在专业环境中,工程师往往需要在对代码库的完全掌握与速度、合规性或遗留系统集成之间进行权衡。接受“部分理解”并非失败,而是应对现代软件复杂性的一项必要技能。归根结底,开发者必须有信心做出有根据的推测并管理其后果,因为对“完美”理解的追求,往往与构建和维护大规模生产系统的需求相冲突。

对不起。
相关文章

原文

As a software engineer, how well do you have to understand your own codebase?

My guess is that people who work on small codebases with low-turnover teams (say, Redis or games like The Witness) would say “obviously you have to understand it completely, otherwise you can’t do good work”. I’d also guess that people who work on large codebases with high-turnover teams (say, the Google web search backend or GitHub) would say “obviously you can’t understand it completely, you just have to do the best you can in your local area”.

These are two largely different ways of programming with different methods, practices and cultures. However, the first group is over-represented in online discussion about software engineering. I want to defend the second group against the first. In many software engineering environments, there’s nothing wrong with being in a state of partial understanding. In fact, in large systems a partial understanding is the best you can do.

Against “programming as theory building”

The best articulation of the “you have to understand your codebase” side is Peter Naur’s famous paper Programming as Theory Building. I like this paper, but I think it goes too far in that direction. Naur’s core point is that when programmers work on a program, the code is really just a by-product, and the main product they’re working on is their “theory of the program”. That’s made up of their intuitive sense of what’s happening and why, which can only be partially captured by code or documentation. If they lost the code, they could rewrite the program easily. If they lost their understanding (say, if the team experienced 100% turnover), they would struggle to make sense of the code.

So far, so good, but Naur goes further than this. He says that the theory should not be reconstructed from the code. According to Naur, you’re better off scrapping the program entirely and having a new team rebuild it from scratch, building up a new theory in the process:

reestablishing the theory of a program merely from the documentation, is strictly impossible … [therefore] the existing program text should be discarded and the new-formed programmer team should be given the opportunity to solve the given problem afresh

Anyone who’s been an effective software engineer at a large company knows that Naur is dead wrong about this. There are at least two reasons.

First, you simply can’t rebuild large software systems from scratch. Sufficiently large systems (if they have users) contain thousands of weird cases and quirks that cannot be reimplemented. Even a team that’s intimately familiar with the system couldn’t do it: there’s just too much stuff to juggle. Successful rewrites always start by carving out the existing codebase into small isolated chunks, then rewriting one chunk at a time. In other words, rewriting a software system involves making a bunch of changes to the old system. If you can’t change the old system, you certainly can’t replace it with a new one.

Second, abandoned systems are revived all the time. In a tech company with hundreds of millions of lines of code and thousands of engineers, it’s not uncommon for a codebase to have nobody left who’s familiar with it. All it takes is a few people to quit at the wrong time, or for a codebase to be unmaintained for a year. Not only have I seen other teams do this, I have personally taken ownership of abandoned codebases, figured them out, and gotten to a point where I could effectively work with them. It takes time, but building a new theory of the codebase is possible. You start by understanding one flow end-to-end, then slowly branch out from there, making careful changes as you go.

In sufficiently large codebases, everyone operates with an incorrect theory of the program. The defining feature of modern software systems is that they’re just way too big for anyone (or even a whole team) to keep in their head: nobody understands it all. To be effective, you have to figure out a way to work with a merely partially-correct theory. This is why I keep going on about taking a position and confidence. If you’re not sure about something, you can’t just sit back and wait for someone with a perfect understanding to come and give you the answer. If you’re a competent engineer, that person is you. You have to grit your teeth, make your most educated guess, and then deal with the consequences.

To be generous to Naur, it’s possible that in 1985 the average size of a program was several orders of magnitude smaller than today, and that when Naur writes about “large programs” he’s not talking about tens of millions of lines of code. Naur’s first example of a large program is a 200,000 line industrial monitoring program, and his second example is a compiler. In 1987, the first version of the compiler GCC was about a hundred thousand lines of code; in 2015 GCC was over fourteen million lines. I can believe that rewriting one or two hundred thousand lines of code is relatively straightforward, particularly if you get to reuse existing tests. Not so for one or two million.

Theory building is one tradeoff among many

LLMs are often cited as a tool that’s bad because it impedes the ordinary process of theory-building. I think this is overly simplistic. Like many software tools, LLMs are a double-edged sword: they make it harder to construct a detailed mental theory of the software, but they allow you to build a partial theory quickly and they can help you leverage that partial theory more effectively. This is a complex tradeoff that I’m still thinking about.

Setting LLMs aside, I’m confident that it’s silly to say that anything that interferes with your theory of the software must be bad. Here is a partial list of other things that make it harder to maintain a theory:

  • Other people being allowed to write code in your codebase
  • Having to implement legally-required features like accessibility and data protection
  • Allowing your colleagues to quit their jobs or move between teams
  • Having to upgrade software versions for security patches
  • Bringing in libraries or other dependencies

Like most things in software, “maintaining a theory of the codebase” is one value among many. Sometimes it’s the most important value and you sacrifice other values for it; other times you trade it off for speed, or legal compliance, or for political reasons.

Almost all engineers — particularly “pure” engineers — prefer to maintain an accurate mental model of their software. It’s more fun, less stressful, and feels more like “real engineering”. That’s why many engineers take up open-source projects in their spare time in order to work on small codebases by themselves: in order to do engineering work where they can maintain an accurate Naur theory of the codebase. I don’t think there’s anything wrong with that.

However, at work you are paid to do a job. In other words, they pay you money to adopt their set of engineering values. It’s hopefully well-understood that however much you might personally care about performance, sometimes you have to write slow code at your job (for instance, to get a project done on time, or to accommodate some awkward requirement). Maintaining a theory of the codebase is the same kind of thing.

edit: this post got some comments on lobste.rs. One interesting comment points out that the ability to reason “locally” about code (i.e. with a partial understanding) has been a core goal of CS from the beginning. This is also a good description of what I was trying to get at in How good engineers write bad code at big companies. Also, it’s amusing that this post was tagged as vibecoding because of one off-hand paragraph about LLMs. I still don’t think I’ll be tagging the post as AI on my blog.

Here's a preview of a related post that shares tags with this one.

联系我们 contact @ memedata.com