人生就像一棵决策树,
每一次选择,走向了不同的子节点。
我们不能后退,也没办法消除历史的影响。
因为时间是单向的,
没有办法更改历史,
只能以今天为基础继续向前。
对于软件,我们也倾向于持有相同的观点。
认为软件的维护成本在后期是不可能缩减的,
不得不背负以前失误的包袱。
然而,幸运的是,
软件其实并非如此。
软件问题,大多数都是设计的问题。
抽象和具体
和人生不同,
软件功能的实现,
限制条件相对宽松。
毕业生,决定考研还是就业,
只能选一个。
但是,软件可以选择DoWork。
越抽象,适用范围就越广。
越具体,就越容易被证明是个错误。
好的设计实践,
是把抽象和具体分开,
抽象的每一种实现都是可替换的。
随着软件的发展,
后期的维护成本才可能是常量复杂度的,
因为每一个历史性的错误实现,都是可更改的。
平凡的模块
武功高强的人们,
不会频出诡异的绝招,
招数越平凡,内耗就越小。
向外提供抽象接口的人,是在玩小伎俩,
不要将具体的实现方法托付给别人,
当问题出现时,让别人更改实现方案,是不可能的。
我们应该提供具体的功能,
功能内部,封装了我们自己的抽象和实现。
其中,抽象是对需求的提取,用来规范模块的外在表现,
实现是当前采用的解决方案。
随着时间的发展,当模块不再适用时,
我们就能在外在表现不变的前提下,
更改解决方案了。
不是只提供抽象接口,
而是把具体功能封装在抽象的接口下,
一起提供。
层次与后路
代码量增加,软件会越来越复杂,
难以定位问题,增加功能,
这其实是没有建立合理的代码层次。
在不同深度的层次上切换。
可以让我们总是面对简单可控的问题。
一千行的函数太复杂了,
那是因为代码本来不该写在一个函数中。
一万行代码太复杂了,
那是因为它本来不该写到一个文件中。
一百个文件太复杂了,
那是因为它们本来不该在一个文件夹下。
划分层次,才能留有后路。
每天关闭电脑前,检查自己的后路,是个好习惯。
可以让我们再打开电脑时,问题还是像今天这样简单。
唯一性和可选性
当我们遇到紧急问题时,
通常首先会想到一个权宜之计。
但是,从长久来看,
不得不做的事情总是会带来麻烦,
身不由己的决定,也是错误的根源。
我们应该想尽办法,推迟决定。
直到我们有两个方案,可以从中选择。
可选性意味着可控的未来。
软件的发展,像棋局一样,
必须仔细斟酌局势的变化,
才能避免因小失大。
在客观条件限制的范围内,
有经验的人做出选择,
新手慌张决定,
在尽可能多的选择中,才能酝酿出好的设计。
结语
软件不同于人生之处在于,
软件可以设计,还可以更改,
只是成本有别。
好的功能模块,在于内部的良好设计。
虽然外在表现没有什么不同。
好的设计和代码组织方式,
威力连绵不绝。
多一种选择,多一种可能。