一个工程师早就懂的道理
这一章写给写代码的读者(不写的也能看懂,类比自己会站立)。
课题分离讲了七章,其实软件工程师天天都在实践它——在代码里。只不过代码里它有另外的名字:模块边界、所有权、接口契约。把这套直觉平移到人际关系上,整本书的道理会突然变得像常识。
乱入 = 越界调用
软件里最基本的规矩:每个模块管好自己的状态,别的模块要影响你,必须走你暴露出来的接口。如果哪个模块绕过接口,直接伸手改你的内部变量——这叫什么?叫破坏性耦合,代码评审里一票否决。
人际关系里,这个操作天天在上演。父母直接修改你的「职业选择」变量,同事直接写入你的「情绪状态」变量,伴侣直接重写你的「日程安排」变量——全是绕过接口的越界调用。而课题分离说的事,翻译过来就是:
大白话:每个人是一个进程,自己的状态自己持有。别人想影响你,只能通过你暴露的接口(你的倾听、你的同意、你的选择)。任何绕过接口直接改你内部状态的行为,都是 bug,不是爱。
注意这个类比比「边界感」这种模糊的词强在哪:软件里的接口是双向约束的——既约束外部不许乱改我,也约束我不许乱改外部。课题分离也是双向的:我不让别人操纵我的课题,同样我也不伸手操纵别人的。第二章说的「只砍别人不砍自己是双标」,用工程语言讲就是:你不能一边要求自己的模块高内聚,一边对别人的模块随意侵入。
错误处理:别替别人的异常兜底
再看一个工程实践:错误处理。好的系统里,谁产生的异常谁处理;处理不了的,沿调用栈明确地上抛。烂系统的特征恰恰相反——异常到处乱飘,最后被一个不相干的模块默默吞掉,没人知道问题出在哪。
人际里的「吞异常」的模块,往往就是那个最负责任、最见不得别人出错的人:同事的锅他背,家人的情绪他接,孩子的后果他垫。短期看系统还在转,长期看两件事必然发生:一是产生异常的人永远学不会处理自己的异常(反正有人兜底),二是吞异常的人最终宕机。
课题分离在这个视角下就是一句话:让异常在产生的层被看见。孩子不学习产生的异常,让孩子自己接到;父母焦虑产生的异常,父母自己消化。你可以提供「错误处理工具」(第三章的援助),但不能把异常从他那里抢过来吞掉——那不是帮忙,那是剥夺他修复自己系统的机会。
依赖注入:你只能提供依赖,不能执行调用
第三个映射更细。工程里有个模式叫「依赖注入」:模块 A 需要模块 B 的能力,不是 A 去造一个 B,而是外部把 B 递给 A,A 用不用、怎么用,是 A 的事。
这正是第三章「把马带到水边」的工程版:你能做的是提供依赖——资源、信息、环境、支持。你不能做的是替对方执行调用——决定他必须用这个依赖、盯着他用、检查他用的结果。水边你带到了(依赖注入完成),喝不喝是他的调用(你只能等返回值)。
连「援助被拒绝时就该停止」都有对应:对方明确说「我不需要这个依赖」,你还反复注入,这在工程里叫强行装配,在人际里叫令人窒息的关心。
为什么这个类比不只是修辞
可能有人觉得这只是个讨巧的类比。但它比讨巧更深一层:软件工程用五十年血泪史验证过的原则,和人际关系的健康法则,指向同一个结构。
为什么软件必须模块边界清晰?因为边界不清的系统无法演化——改一处,处处崩。为什么人必须课题分离?因为课题不分的人生无法自主——动一处,处处被拽。边界不是冷漠,是可演化性的前提。系统如此,人生也如此。
所以下次你在人际关系里纠结「这事我该不该管」的时候,可以换个问法:如果这是一个代码评审,这段「我要伸手改他的状态」的逻辑,过得去吗?多数时候,你自己就会笑出来。
本章小结
工程师看课题分离,全是熟面孔:模块边界(各人持有各人的状态)、接口契约(影响必须经由对方同意)、错误处理(谁产生的异常谁接,别替人兜底)、依赖注入(只能提供资源,不能替人执行)。边界不是冷漠,是系统能长期演化的前提——对代码成立,对人生同样成立。
到这里,「分离」的部分讲完了。但分离只是把人从缠绕里解出来,解出来之后呢?一个个独立的、谁也不欠谁的人,幸福从哪来?这是下一章,也是整本书的落脚点。