设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 IT综合资讯 查看内容

老码农冒死揭潜规则:如何写无法维护的代码

2014-11-26 11:38| 发布者: joejoe0332| 查看: 7207| 评论: 0|原作者: 老码农译|来自: 伯乐在线

摘要: 为了造福大众,在Java编程领域创造就业机会,兄弟我在此传授大师们的秘籍。这些大师写的代码极其难以维护,后继者就是想对它做最简单的修改都需要花上数年时间。而且,如果你能对照秘籍潜心修炼,你甚至可以给自己弄 ...


令人眩晕的命名

        用带有完全不相关的感情色彩的单词来命名变量。例如:
1
marypoppins = (superman + starship) / god;
          (欢乐满人间 = (超人 + 星河战队)/上帝;)
    这一招可以让阅读代码的人陷入迷惑之中,因为他们在试图想清楚这些命名的逻辑时,会不自觉地联系到不同的感情场景里而无法自拔。

何时使用 i

      永远不要把 i 用作最内层的循环变量。 用什么命名都行,就是别用i。把 i 用在其他地方就随便了,用作非整数变量尤其好。

惯例 — 明修栈道,暗度陈仓

忽视 Java 编码惯例,Sun 自己就是这样做的。幸运的是,你违反了它编译器也不会打小报告。这一招的目的是搞出一些在某些特殊情况下有细微差别的名字来。如果你被强迫遵循驼峰法命名,你还是可以在某些模棱两可的情况下颠覆它。例如,inputFilename 和 inputfileName 两个命名都可以合法使用。在此基础上自己发明一套复杂到变态的命名惯例,然后就可以痛扁其他人,说他们违反了惯例。

小写的 l 看上去很像数字 1

      用小写字母 l 标识 long 常数。例如 10l 更容易被误认为是 101 而不是 10L 。 禁用所有能让人准确区分 uvw wW gq9 2z 5s il17|!j oO08 `’” ;,. m nn rn {[()]} 的字体。要做个有创造力的人。

把全局命名重用为私有

      在A 模块里声明一个全局数组,然后在B 模块的头文件里在声明一个同名的私有数组,这样看起来你在B 模块里引用的是那个全局数组,其实却不是。不要在注释里提到这个重复的情况。

误导性的命名

    让每个方法都和它的名字蕴含的功能有一些差异。例如,一个叫 isValid(x)的方法在判断完参数x的合法性之后,还顺带着把它转换成二进制并保存到数据库里。

 

伪装

当一个bug需要越长的时间才会暴露,它就越难被发现。- Roedy Green(本文作者)

编写无法维护代码的另一大秘诀就是伪装的艺术,即隐藏它或者让它看起来像其他东西。很多招式有赖于这样一个事实:编译器比肉眼或文本编辑器更有分辨能力。下面是一些伪装的最佳招式。

 

把代码伪装成注释,反之亦然

          下面包括了一些被注释掉的代码,但是一眼看去却像是正常代码。
1
2
3
4
5
6
7
8
9
10
11
for(j=0; j<array_len; j+ =8)
{
     total += array[j+0 ];
     total += array[j+1 ];
     total += array[j+2 ]; /* Main body of
     total += array[j+3]; * loop is unrolled
     total += array[j+4]; * for greater speed.
     total += array[j+5]; */
     total += array[j+6 ];
     total += array[j+7 ];
}

如果不是用绿色标出来,你能注意到这三行代码被注释掉了么?

用连接符隐藏变量

          对于下面的定义
1
#define local_var xy_z

可以把 “xy_z” 打散到两行里:

1
2
#define local_var xy\
_z // local_var OK

这样全局搜索 xy_z 的操作在这个文件里就一无所获了。 对于 C 预处理器来说,第一行最后的 “\” 表示继续拼接下一行的内容。

 

 

文档

任何傻瓜都能说真话,而要把谎编圆则需要相当的智慧。- Samuel Butler (1835 – 1902)

不正确的文档往往比没有文档还糟糕。- Bertrand Meyer

既然计算机是忽略注释和文档的,你就可以在里边堂而皇之地编织弥天大谎,让可怜的维护代码的程序员彻底迷失。

 

在注释中撒谎

      实际上你不需要主动地撒谎,只要没有及时保持注释和代码更新的一致性就可以了。

只记录显而易见的东西

        往代码里掺进去类似于
1
/* 给 i 加 1 */
      这样的注释,但是永远不要记录包或者方法的整体设计这样的干货。

记录 How 而不是 Why

      只解释一个程序功能的细节,而不是它要完成的任务是什么。这样的话,如果出现了一个bug,修复者就搞不清这里的代码应有的功能。

该写的别写

      比如你在开发一套航班预定系统,那就要精心设计,让它在增加另一个航空公司的时候至少有25处代码需要修改。永远不要在文档里说明要修改的位置。后来的开发人员要想修改你的代码?门都没有,除非他们能把每一行代码都读懂。

计量单位

      永远不要在文档中说明任何变量、输入、输出或参数的计量单位,如英尺、米、加仑等。计量单位对数豆子不是太重要,但在工程领域就相当重要了。同理,永远不要说明任何转换常量的计量单位,或者是它的取值如何获得。要想让代码更乱的话,你还可以在注释里写上错误的计量单位,这是赤裸裸的欺骗,但是非常有效。如果你想做一个恶贯满盈的人,不妨自己发明一套计量单位,用自己或某个小人物的名字命名这套计量单位,但不要给出定义。万一有人挑刺儿,你就告诉他们,你这么做是为了把浮点数运算凑成整数运算而进行的转换。

      永远不要记录代码中的坑。如果你怀疑某个类里可能有bug,天知地知你知就好。如果你想到了重构或重写代码的思路,看在老天爷的份上,千万别写出来。切记电影《小鹿斑比》里那句台词 “如果你不能说好听的话,那就什么也不要说。”。万一这段代码的原作者看到你的注释怎么办?万一老板看到了怎么办?万一客户看到了怎么办?搞不好最后你自己被解雇了。一句”这里需要修改“的匿名注释就好多了,尤其是当看不清这句注释指的是哪里需要修改的情况下。切记“难得糊涂”四个字,这样大家都不会感觉受到了批评。

说明变量

      永远不要对变量声明加注释。有关变量使用的方式、边界值、合法值、小数点后的位数、计量单位、显示格式、数据录入规则等等,后继者完全可以自己从程序代码中去理解和整理嘛。如果老板强迫你写注释,就把方法体代码混进去,但绝对不要对变量声明写注释,即使是临时变量!

在注释里挑拨离间

        为了阻挠任何雇佣外部维护承包商的倾向,可以在代码中散布针对其他同行软件公司的攻击和抹黑,特别是可能接替你工作的其中任何一家。例如:
1
2
3
4
5
6
7
8
/* 优化后的内层循环
这套技巧对于SSI软件服务公司的那帮蠢材来说太高深了,他们只会
用 <math.h> 里的笨例程,消耗50倍的内存和处理时间。
*/
class clever_SSInc
{
.. .
}
    可能的话,除了注释之外,这些攻击抹黑的内容也要掺到代码里的重要语义部分,这样如果管理层想清理掉这些攻击性的言论然后发给外部承包商去维护,就会破坏代码结构。

程序设计

编写无法维护代码的基本规则就是:在尽可能多的地方,以尽可能多的方式表述每一个事实。- Roedy Green

    编写可维护代码的关键因素是只在一个地方表述应用里的一个事实。如果你的想法变了,你也只在一个地方修改,这样就能保证整个程序正常工作。所以,编写无法维护代码的关键因素就是反复地表述同一个事实,在尽可能多的地方,以尽可能多的方式进行。令人高兴的是,像Java这样的语言让编写这种无法维护代码变得非常容易。例如,改变一个被引用很多的变量的类型几乎是不可能的,因为所有造型和转换功能都会出错,而且关联的临时变量的类型也不合适了。而且,如果变量值要在屏幕上显示,那么所有相关的显示和数据录入代码都必须一一找到并手工进行修改。类似的还有很多,比如由C和Java组成的Algol语言系列,Abundance甚至Smalltalk对于数组等结构的处理,都是大有可为的。

Java 造型

      Java的造型机制是上帝的礼物。你可以问心无愧地使用它,因为Java语言本身就需要它。每次你从一个Collection 里获取一个对象,你都必须把它造型为原始类型。这样这个变量的类型就必须在无数地方表述。如果后来类型变了,所有的造型都要修改才能匹配。如果倒霉的维护代码的程序员没有找全(或者修改太多),编译器能不能检测到也不好说。类似的,如果变量类型从short 变成 int,所有匹配的造型也都要从(short) 改成 (int)。

利用Java的冗余

        Java要求你给每个变量的类型写两次表述。 Java 程序员已经习惯了这种冗余,他们不会注意到你的两次表述有细微的差别,例如
1
Bubblegum b = new Bubblegom();
        不幸的是 ++ 操作符的盛行让下面这种伪冗余代码得手的难度变大了:
1
swimmer = swimner + 1;

永远不做校验

      永远不要对输入数据做任何的正确性或差异性检查。这样能表现你对公司设备的绝对信任,以及你是一位信任所有项目伙伴和系统管理员的团队合作者。总是返回合理的值,即使数据输入有问题或者错误。

有礼貌,无断言

      避免使用 assert() 机制,因为它可能把三天的debug盛宴变成10分钟的快餐。

避免封装

      为了提高效率,不要使用封装。方法的调用者需要所有能得到的外部信息,以便了解方法的内部是如何工作的。

复制粘贴修改

      以效率的名义,使用 复制+粘贴+修改。这样比写成小型可复用模块效率高得多。在用代码行数衡量你的进度的小作坊里,这招尤其管用。

使用静态数组

      如果一个库里的模块需要一个数组来存放图片,就定义一个静态数组。没人会有比512 X 512 更大的图片,所以固定大小的数组就可以了。为了最佳精度,就把它定义成 double 类型的数组。


酷毙

雷人
1

鲜花

鸡蛋

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部