我第一次写代码,是大二那年。
一门叫"数据结构"的课,老师布置了一道作业。我在宿舍里熬了一个通宵,键盘一直敲到凌晨三点。屏幕上的报错改了一个又一个,程序终于运行起来,输出了一行正确的结果。
我靠在椅背上,盯着那行字看了很久。
那种感觉直到现在还记得。不是剧烈的兴奋,更像一种安静的满足。一个原本只存在于脑海里的东西,被我一点一点搬到了现实中。
敲下最后一行代码以前,它还只是一个模糊的想法。
然后我按下运行。
它活了。
后来我成了一名程序员,写了十年代码。
有些系统顺利上线,有些项目停在半路;有些功能曾经被很多人使用,后来又被新的版本悄悄替代。那些在深夜里反复排查的问题,当时仿佛占据了全部世界,几年以后再回头看,也许只剩下版本记录里一行已经说不清来历的提交。
代码是一种很容易消失的东西。
它会被重构、删除、覆盖,也会随着一套系统下线,从此无人问起。
可那个凌晨的感觉,一直留了下来。
我第一次知道,一个人可以把看不见的东西,变成某种能够运行、能够被别人使用的东西。
很多年后,我开始写文章,才发现自己似乎又回到了那个夜晚。
还是一块空白的屏幕。
还是一个尚未成形的念头。
只是这一次,我要写的,不再是给机器看的语言。
开始带团队,是工作第四年的事。
第一次做技术负责人,团队里加上我一共五个人。年纪最小的同事刚毕业,连Git都用得不太熟。我一边写代码,一边带他了解系统;一边赶项目进度,一边做设计评审。
那一年,我写了很多代码,也第一次认真写了很多文档。
以前我不太喜欢写文档。
在我看来,真正的工作是把功能做出来。文档只是代码之外的附属品,是项目结束后为了让流程显得完整而补上的东西。有时间整理文字,不如多写几个接口,早点让系统跑起来。
可后来我慢慢发现,文档写得清楚的项目,代码往往也更稳定。
不是因为文档本身有什么魔力,而是写文档的过程,会逼着人提前面对那些原本藏在脑海里的问题。
为什么要做?
真正要解决的是什么?
系统的边界在哪里?
如果依赖失败,如果规模扩大,原来的设计还能不能成立?
这些问题停留在脑海里时,总显得已经有了答案。人很容易把一幅大致的画面,误认为完整的设计。直到真正开始写,才会发现有些地方只是凭经验跳了过去,有些结论之间缺少桥梁,还有些所谓的"想清楚",不过是一团尚未被命名的感觉。
写下来,模糊才开始显形。
一句话接不上下一句话,往往不只是表达的问题,而是中间缺少了一段逻辑;一张架构图解释不清某个箭头,也可能意味着系统的责任边界根本没有想明白。
文档不是对思考的记录。
很多时候,文档就是思考发生的地方。
它让一套逻辑在进入系统以前,先在文字里运行一次。
我也见过许多跳过这一步的项目。
需求一来,团队立刻开始开发。页面很快搭起来,接口也陆续完成,最初的进度看上去非常快。
直到项目走到中间,那些一开始没有回答的问题才逐渐出现。
这个状态到底由谁维护?异常之后应该重试还是终止?上下游为什么对同一个字段有不同理解?最初以为只是一个简单功能,为什么改动沿着依赖一路扩散,最后牵动了半个系统?
于是大家开始返工、重构、补边界,重新解释那些原本以为已经达成共识的需求。
开始时"节省"的思考时间,最后以更加昂贵的方式被重新支付。
有些时间并没有真正省下来。
它只是变成了债,带着利息,在项目最忙乱的时候回来。
从那以后,我经常要求团队先写设计文档。
不是为了留档,也不只是为了让我评审,而是让写的人先看见自己的想法。
如果一件事无法被清楚地写下来,它通常也还没有清楚到可以被实现。
这并不是说,必须等所有问题都有答案以后才能动手。系统永远不可能在纸面上被完整推演,很多问题也只有真正进入现实才会出现。
但至少在第一行代码出现以前,我们应该知道自己为什么出发,准备走向哪里,又有哪些地方仍然没有答案。
后来开始写文章时,我重新遇见了同一个问题:
你真的想清楚了吗?
有一段时间,我很迷信工具。
我折腾过许多笔记软件,也认真研究过各种写作方法。从印象笔记到Notion,再到语雀,我配置目录、设计标签、寻找模板,花很多时间想象怎样才能建立一个完美的知识系统。
每换一个工具,我都会产生一种新的生活即将开始的错觉。
仿佛只要目录足够清楚,页面足够整洁,工作流足够顺畅,我就会自然而然地开始写作。
后来发现,并不会。
工具可以降低阻力,却不能替人写下第一句话。
有时候,准备甚至会变成一种精致的逃避。我们不断调整环境、研究方法、搭建系统,以此获得一种"已经开始"的满足感。
可文档始终是空的。
这和写代码时反复讨论框架有些相似。
技术选型当然重要。但如果团队一直停留在比较工具,却迟迟没有开始验证最重要的问题,那么再完善的选型,也可能只是推迟面对现实的方式。
工具解决的是"怎样写得更顺"。
它无法回答"你为什么要写"。
真正让一篇文章出现的,往往不是找到最好的软件,而是在某个普通的晚上坐下来,打开一页空白文档,先写下一句并不完美的话。
有了第一句,才会有第二句。
有了一个粗糙的版本,才有机会修改。
一个没有写出来的完美想法,最终仍然什么都不是。
我的第一篇文章写了很久。
反复修改,反复怀疑。今天觉得太浅,明天觉得太散;删掉一段,又担心文章失去了原来的意思。
迟迟不愿意发出去,是因为总觉得它还可以更好。
后来有一天,我还是按下了发布。
那一刻有一点像大二那年的凌晨。只是屏幕上不再出现"运行成功",也没有任何测试告诉我,这篇文章究竟对不对。
它并不完美。
可它存在了。
它从一个只有我知道的念头,变成了一件可以被别人看见的东西。至于别人会怎样理解,哪些句子会被记住,哪些地方会被略过,已经不再完全由我决定。
文字一旦离开作者,就开始拥有自己的路。
这对一个习惯了控制输入与输出的工程师来说,是一种陌生的体验。
也是一种松动。
后来我才明白,写代码和写作虽然都在把不可见的东西搬到外面,却训练着人两种几乎相反的能力。
代码要求你不断压缩歧义,直到一件事可以被机器准确执行。
文字却不必封闭所有含义。它需要足够清楚,让人能够进入;也要留下一点空白,让另一个人可以带着自己的经历继续往前。
一个教我怎样把世界说清楚。
另一个教我承认,世界并不总能被说清楚。
写代码时,你必须把逻辑翻译成明确的条件、变量和边界。输入是什么,输出是什么,一种状态怎样走向下一种状态,都需要被准确表达。
写作也在进行一种翻译。
只是它翻译的,常常不是完整的逻辑,而是那些尚未被整理好的感受、犹豫和经验。
你以为自己想写的是一个观点,写到中间才发现,真正牵动你的可能是另一件事。你原本想证明一个结论,写着写着,却看见了它背后的迟疑。
所以,写作并不只是把已经想好的内容誊写一遍。
它更像在一间没有开灯的房间里缓慢行走。文字照到哪里,你才第一次看见那里原来放着什么。
有些东西在被写下以前,连自己也不知道它存在。
我曾经以为,代码主要是写给机器看的。
后来带团队久了,才明白,机器只是执行代码,真正需要阅读代码的,往往是人。
几个月以后接手这段代码的人,需要从命名、结构和注释里理解,当时的人为什么这样设计,哪些边界不能越过,又有哪些看似多余的判断,其实是在保护某种曾经发生过的异常。
好的代码,不只是让机器正确运行。
它也在向后来的人解释自己。
从这个意义上说,程序员一直都在写作。只不过我们使用的是一种更加严格的语言,读者既有机器,也有其他工程师。
但代码和文章终究不同。
代码希望把歧义收束到机器可以执行的边界内。同样的输入,应该得到可以预期的输出。一个边界条件没有处理,系统就可能在某个深夜,用告警提醒你:这里并不成立。
文章却不需要把所有含义都关在同一个结果里。
一段程序的完成,意味着不同的机器可以按照同一种逻辑运行。
一篇文章真正开始生长,却往往是在不同的人从中读见不同的自己以后。
作者写的是一次离开,读者想起的也许是自己的某次告别;作者写的是一段低谷,另一个人读见的,可能是自己很久没有说出口的疲惫。
文字给那些难以说清的东西一个形状。
读者则带着自己的生命,补上形状之外的部分。
代码追求可以重复的结果。
文字允许无法预先设计的抵达。
这也改变了我理解管理的方式。
以前遇到问题,我的本能是寻找方案。
团队有冲突,就分析原因;项目有风险,就拆解任务;一个人状态不好,就想办法帮助他尽快恢复。
工程师习惯修复。
看见问题,就希望系统重新运行。
可人与系统不同。
系统里的异常通常应该被定位和消除,一个人的异常却可能只是某种尚未完成的变化。他还没有想清楚,还没有找到合适的表达,也还没有准备好走向下一步。
有时候,对方并不需要一个立即生效的方案。
他只是需要把那段尚未整理清楚的感受说完,需要有人在旁边多停留一会儿。
不是所有沉默都等待被打破。
也不是所有问题都应该立刻进入解决流程。
写作让我看见,表达以前还有感受,结论以前还有一段没有被说清楚的路。一个人最终说出口的话,可能只是水面上的部分,下面还有更深、更缓慢的东西。
代码教会我建立结构。
文字教会我尊重那些暂时无法进入结构的部分。
这两种能力并不冲突。
一个人既需要在复杂中寻找秩序,也需要在秩序之外,为真实留下位置。
好的系统需要清晰的边界。
好的关系,有时也需要一块暂时不被定义的空间。
我仍然喜欢写代码。
喜欢一个复杂问题被逐渐拆开,喜欢混乱的逻辑最终变得清楚,也喜欢按下运行之后,系统安静地完成它应该做的事。
但我也开始喜欢写作。
写作的价值,有时并不是得出一个结论,而是终于看见自己真正面对的是什么。
十年前,我把脑海里的逻辑写成代码,让一台机器按照我的设想运行。
现在,我试着把那些更模糊的东西写成文字:关于时间,关于选择,关于一个人在变化里怎样慢慢认识自己。
这一次,没有编译器替我检查。
我只能尽量诚实,尽量清楚,然后把剩下的部分交给阅读它的人。
文字离开我以后,可能抵达另一个人。
他也许会在某一句话前停下来,想起自己的某段经历。那一刻,文字不再只是我写下的东西。它进入了另一个人的生活,也获得了我无法预先设计的意义。
大二那年的凌晨,我第一次知道,一个人可以把看不见的东西,变成能够运行的东西。
很多年后,我坐在另一块屏幕前,重新学习把一些看不见的东西搬到外面。
光标仍然在闪。
空白仍然很大。
只是这一次,我不再急着让它给出一个正确答案。
我把那些从自己身上经过的东西写下来,然后交给另一个人。
机器给出结果。
人留下回声。