“我不做笔记,不列提纲,诸如此类的事情一概不做。我只是拼命敲那个该死的东西。” —— 斯蒂芬·金

在写作(尤其是小说写作)中,作者往往分为两类:一类习惯先拟定大纲,再逐步展开;另一类则通过写作本身来发现故事。而在编程领域,我们似乎没有类似的区分。于是,我想引入一个概念:探索式编程。

何谓“探索式编程”?

探索式编程是一种通过先写代码来理解问题的实践,而不是事先进行某种设计过程或思考。

这意味着探索式程序员在开始写代码前,并不总是有一个计划;他们更关注的是当下的处境:

  • 我们希望通过这段新代码解决什么矛盾?
  • 是哪些情境催生了这个需求?
  • 系统的各个部分是如何交互的?

探索式程序员只有在写代码的过程中,看到代码带来的“反作用力”,才逐渐理解并形成前进的计划。

在别人眼里,探索式程序员往往显得杂乱或缺乏纪律。与写大纲的程序员合作时,可能会产生一些错位的紧张感。写大纲的人看到探索式程序员的“随意”方式可能会感到不安,而探索式程序员则会困惑于对方提出的一些看似“时机不对”的问题。

在当今偏好更结构化技术(静态类型系统、强制内存安全、模式校验工具等)的文化下,探索式编程很容易被贴上“坏习惯”的标签。但我们必须区分创造过程和最终产物。完全没有理由认为探索式程序员就不能写出高度结构化、严格的最终成果。

旁注:探索式编程 ≠ 自底向上设计

探索式编程和自底向上设计不是同一回事。
尽管探索式程序员可能更喜欢自底向上的设计,而写大纲的人可能更倾向自顶向下设计,但这两者其实是正交的维度。

自顶向下设计描述的是你解决问题的“切入角度”,而不是你理解问题的“过程”。
比如:你在编码前写了一份详细的设计文档,定义了核心原语以及它们如何组合来解决问题。这显然是一个写大纲的人在进行自底向上的设计。

为何要“探索式编程”?

即便对写大纲的程序员来说,探索式编程也可能带来不少好处。

当我们带着“寻找解决方案”的心态去解决问题时,很容易陷入最熟悉的方案。探索式编程的本质,正好可以避免这种陷阱。

因为探索式编程一开始并没有“现成的解决方案”,所以写下的代码更多是探索系统的行为。
通过这样做,你不是把过去的方案或别人描述的方案装进脑子,而是逐渐加载起一系列系统本身的约束条件——这些约束正是你的解决方案必须满足的。

对我来说,这几乎是唯一可行的方式。只要我试图在写代码前做大纲,那份大纲往往会在几个小时内被抛弃。事先写好的设计文档,即便被批准,也完全不能让我满意。只有当我开始写代码时,我才真正开始理解问题。

所以,接下来的部分不会写大纲的好处——不是因为它没有,而是因为我不是写那部分的人。(同样,我也不会写探索式编程的坏处,因为我相信每个人都能轻松列出它们。)

旁注:帮助探索式编程的工具

我觉得今天的大多数工具都不是为探索式编程设计的。
例如:在运行系统中进行实时编程(看看大多数 Clojure 或 SmallTalk 程序员的工作方式),对探索式程序员来说极其宝贵。

那些能让你即时可视化、随时对系统某部分做监控的工具,会让探索过程变得更快更容易。
这种“动态性”(与类型无关)正是我们经常忽视的东西。

接纳“探索式编程”

写作界已经学会接受:有些人就是探索型写作者。对他们来说,写作前先做大纲反而会让他们无法按自己想要的方式写作。

我对编程社区的呼吁也是一样的:我们应该接受探索式编程。

我并不是主张禁止所有设计文档(它们当然有用),而是希望大家认识并接受:有些人思考的方式不同。

不够有条理,并不是低劣的方式;能在写代码前想清楚所有细节,也不是更高明的方式。

也许我误读了当下的文化氛围(或者你在几年后读到时,文化已经转变)。

也许探索式编程已经备受推崇,而写大纲反而被轻视。如果是这样,请把我上面说的一切反过来。

我希望我们能认识到:没有唯一的答案。软件设计是一种主观的活动,对于每个人来说都不一样。


Original author: Jimmy Miller

Original link: Discovery Coding

Translated by GPT-5, edited by me (机智的小鱼君)