6年前读第一版本的时候,就感觉得到它是一本实用至上的秘笈。今年得知第二版由云风大侠翻译出来,电子版一出来,我迫不及待地从kindle上购买阅读,书的主体思想仍然不变,也增加了新的内容。有两点仍然是至关重要——dry(不要重复自己)原则和正交性原则,从工作一开始,我一直遵循这两点重要的原则来指导自己去编码,特别是重构时受益良多。狂妄地说一句,我很少加班,也是得益于这两条原则,因为我总能做到又快又好,又容易扩展。遗憾的是我见到过的大多公司的自研框架,基本上都违背了这两条的原则,都是违背得多或少的问题,好一点的框架就违背得少一点,明显容易维护一些,如果非常差的框架,就是违背了上面这两点原则的代码非常之多,维护起来的时间成本和效率之低,令人恶心,现在回想起来都觉得后怕,他们是靠写bug度日的。
也和那些工作了十几年的同事共事过,也和他们讨论过,他们也知道dry和正交性原则,可写出来的模块代码都是违背了这上面两点原则。归根到底是他们理解错了真正在应用场景时的dry原则,就拿我们棋牌行业的常见这一情况来举例,棋牌游戏子游戏非常之多,一般有红中麻将,南宁麻将,血战麻将,跑得快,斗地主。大多麻将的游戏游戏流程基本一致,算法大体相似。自然而然就有人想到应该把麻将游戏的算法逻辑放到一个公共算法类来借麻将调用,说这是遵循了dry原则,避免了代码重复。这一开始一切都很美好,没错二人麻将的平胡和血战麻将的平胡也是一样的,可后来突然增加了一款南宁麻将,他的平胡规则与常规的都不一样,这时就有人开始在公共模块里面插入if ==南宁麻将 这一类代码,反正就是加两行代码嘛,不太要紧的,至少不少人是这么想的。后来还有很多个别麻将他的清一色又与其他的大多数麻将的规则不一样,又在公共算法类里面添加了if==麻将 之类的代码,当游戏越来越多时,已经记不得改动这一行代码,到底会影响那一个麻将了。到最后的结局就是改好了这一款麻将的bug,另外一款的麻将又被干扰了,无尽无穷的bug,无穷无尽的加班接踵而至,最后受不了了就辞职了,继续祸害下一个公司。这里面错就错在他们以为10款麻将是这样的规则就一定是这样的规则了,缺乏对行业游戏的理解或者是对业务的理解严重不足。就算是基本的胡牌算法都不能抽象为公共类,因为长春麻将东南西北,有任何三个就是一个顺子了,与常规的并不符合。我的做法是每个麻将都有一个自己的逻辑算法类,绝不采用公共类算法的方案,他们代码90%极其相似,甚至可以明显让人感觉得到这不是违背dry原则了吗?大错特错,dry原则是两份相同的源码,不随业务的变迁有所例外,那就是重复。他们抽取公共类的做法,只能说是一开始当时的业务上来看是重复的,恰好我们相同。随着一小部分的麻将不同,导致穿插大量的if代码时,导致二人麻将改好了,南宁麻将又出错了,恰恰也违反了另一条极其重要的正交性原则。那么这里就有一个疑问,你怎么知道这份代码将来的是会有所变化的,不能抽取为公共类。这就要回到了程序员本身问题,写代码不仅仅是写代码,还要去了解行业,深入理解,你才能真正地写出易于扩展,随时应变业务变化的代码。可见想要写出好的框架并非易事,代码之外的功夫也同样重要。对于dry我那么熟悉也有冒犯到它的时候,那就是另一种比较多人容易中招情况,说说我的例子吧,当时要开发一个十三水,可市场部有两个地区的代理,一个是浙江的,一个是广西地方的,这两个地方的玩法,一开始总结出来就三条规则不太一样。那么就是几个if,else的事情,好那么我也是在客户端给一个地方选项就行了,以此来区别地方玩法,可是后面市场扩展,时间相当紧急,后来我就加了几十个if,esle来区别他们的规则,慢慢地出现了这边地方规则改好了,那边的又乱了,每一次改动都小心翼翼,还是经常出错,或者是很难测试到位。总是出现这边好了,那边坏的情况,后来我狠下心,确定这是两个游戏,只是刚好名字一样而已,之后就高枕无忧了。这一次教训让我彻底领悟了什么是dry和正交性。真正的dry不是我现在和你相同,未来我未必和你一样。真正的正交性是我在地球,你在月球,与我何干。
一个框架只要不违背dry和正交性原则,那么这个框架不会差到那里去。框架的维护难就在于很多时候你没有话语权,或者决策者又担心改动代码又影响了框架的稳定性,其实追求的都是短暂的稳定,自欺欺人罢了。 知易行难,知的是表面的道理,难的是如何知道你的知是错误的。无他,惟有多看名著,多交流,多磨练代码之外的功夫,陆游大诗人说得好——功夫在诗外。