程序员|糟糕的程序员比优秀的程序员差在哪里?( 二 )


目前微服务架构大行其道 , 但是 , 一些项目在没有解决软件牢固性的前提下 , 就硬着头皮进行微服务改造 , 结果可想而知 。 要知道 , 微服务是低耦合模块的服务化 , 首先需要的 , 就是低耦合的模块 , 然后才是微服务的架构 。 如果单体系统都做不到模块的低耦合 , 那么由此改造出来的微服务系统只会将问题加倍放大 , 最后就怪微服务了 。
粘滞性需求变更导致软件变更的时候 , 如果糟糕的代码变更方案比优秀的方案更容易实施 , 那么软件就会向糟糕的方向发展 。
很多软件在设计之初有着良好的设计 , 但是随着一次一次的需求变更 , 最后变得千疮百孔 , 趋向腐坏 。
晦涩性代码首先是给人看的 , 其次是给计算机执行的 。 如果代码晦涩难懂 , 必然会导致代码的维护者以设计者不期望的方式对代码进行修改 , 导致系统腐坏变质 。 如果软件设计者期望自己的设计在软件开发和维护过程中一直都能被良好执行 , 那么在软件最开始的模块中就应该保证代码清晰易懂 , 后继者参与开发维护的时候才有章法可循 。
一个设计腐坏的例子软件如果是一次性的 , 只运行一次就被永远丢弃 , 那么无所谓设计 , 能实现功能就可以了 。 然而现实中的软件 , 大多数在其漫长的生命周期中都会被不断修改、迭代、演化和发展 。 淘宝从最初的小网站 , 发展到今天有上万名程序员维护的大系统;Facebook从扎克伯格一个人开发的小软件 , 成为如今服务全球数十亿人的巨无霸 , 无不经历过并将继续经历演化发展的过程 。
接下来 , 我们就来看一个软件在需求变更过程中 , 不断腐坏的例子 。
假设 , 你需要开发一个程序 , 将键盘输入的字符 , 输出到打印机上 。 任务看起来很简单 , 几行代码就能搞定:
```
void copy()
<{p>int c;
while ((c=readKeyBoard()) != EOF)
writePrinter(c);

```
你将程序开发出来 , 测试没有问题 , 很开心得发布了 , 其他程序员在他们的项目中依赖你的代码 。 过了几个月 , 老板忽然过来说 , 这个程序需要支持从纸带机读取数据 , 于是你不得不修改代码:
```
bool ptFlag = false;
//使用前请重置这个flag
void copy()
<{p>int c;
while ((c=(ptFlag? readPt() : readKeyBoard())) != EOF)
writePrinter(c);

```
为了支持从纸带机输入数据 , 你不得不增加了一个布尔变量 , 为了让其他程序员依赖你的代码的时候能正确使用这个方法 , 你还添加一句注释 。 即便如此 , 还是有人忘记了重设这个布尔值 , 还有人搞错了这个布尔值的代表的意思 , 运行时出来bug 。
虽然没有人责怪你 , 但是这些问题还是让你很沮丧 。 这个时候 , 老板又来找你 , 说程序需要支持输出到纸带机上 , 你只好硬着头皮继续修改代码:
```
bool ptFlag = false;
bool ptFlag2 = false;
//使用前请重置这些flag
void copy()
<{p>int c;
while ((c=(ptFlag? readPt() : readKeyBoard())) != EOF)
ptFlag2? writePt(c) : writePrinter(c);

```
虽然你很贴心地把注释里的”这个flag“改成了”这些flag“ , 但还是有更多的程序员忘记要重设这些奇怪的flag , 或者搞错了布尔值的意思 , 因为依赖你的代码而导致的bug越来越多 , 你开始犹豫是不是需要跑路了 。
解决之道【程序员|糟糕的程序员比优秀的程序员差在哪里?】从这个例子我们可以看到 , 一段看起来还比较简单、清晰的代码 , 只需要经过两次需求变更 , 就有可能变得僵化、脆弱、粘滞、晦涩 。