打印
[信息]

【转】老码农冒死揭开行业黑幕:如何编写无法维护的代码

[复制链接]
5632|53
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 俺是村长他爹 于 2016-9-6 23:14 编辑

如何编写无法维护的代码

让自己稳拿铁饭碗 ;-) —— Roedy Green

简介

永远不要(把自己遇到的问题)归因于(他人的)恶意,这恰恰说明了(你自己的)无能。 —— 拿破仑

为了造福大众,在Java编程领域创造就业机会,兄弟我在此传授大师们的秘籍。这些大师写的代码极其难以维护,后继者就是想对它做最简单的修改都需要花上数年时间。而且,如果你能对照秘籍潜心修炼,你甚至可以给自己弄个铁饭碗,因为除了你之外,没人能维护你写的代码。再而且,如果你能练就秘籍中的全部招式,那么连你自己都无法维护你的代码了!


你不想练功过度走火入魔吧。那就不要让你的代码一眼看去就完全无法维护,只要它实质上是那样就行了。否则,你的代码就有被重写或重构的风险!



总体原则

Quidquid latine dictum sit, altum sonatur.
(随便用拉丁文写点啥都会显得高大上。)

想挫败维护代码的程序员,你必须先明白他的思维方式。他接手了你的庞大程序,没有时间把它全部读一遍,更别说理解它了。他无非是想快速找到修改代码的位置、改代码、编译,然后就能交差,并希望他的修改不会出现意外的副作用。

他查看你的代码不过是管中窥豹,一次只能看到一小段而已。你要确保他永远看不到全貌。要尽量让他难以找到他想找的代码。但更重要的是,要让他不能有把握忽略任何东西。

程序员都被编程惯例洗脑了,还为此自鸣得意。每一次你处心积虑地违背编程惯例,都会迫使他必须用放大镜去仔细阅读你的每一行代码。

你可能会觉得每个语言特性都可以用来让代码难以维护,其实不然。你必须精心地误用它们才行。



命名

“当我使用一个单词的时候” Humpty Dumpty 曾经用一种轻蔑的口气说, “它就是我想表达的意思,不多也不少。“
– Lewis Carroll — 《爱丽丝魔镜之旅》, 第6章

编写无法维护代码的技巧的重中之重是变量和方法命名的艺术。如何命名是和编译器无关的。这就让你有巨大的自由度去利用它们迷惑维护代码的程序员。

妙用 宝宝起名大全

买本宝宝起名大全,你就永远不缺变量名了。比如 Fred 就是个好名字,而且键盘输入它也省事。如果你就想找一些容易输入的变量名,可以试试 adsf 或者 aoeu之类。

单字母变量名

如果你给变量起名为a,b,c,用简单的文本编辑器就没法搜索它们的引用。而且,没人能猜到它们的含义。
创造性的拼写错误

如果你必须使用描述性的变量和函数名,那就把它们都拼错。还可以把某些函数和变量名拼错,再把其他的拼对(例如 SetPintleOpening 和 SetPintalClosing) ,我们就能有效地将grep或IDE搜索技术玩弄于股掌之上。这招超级管用。还可以混淆不同语言(比如colour — 英国英语,和 color — 美国英语)。

抽象

在命名函数和变量的时候,充分利用抽象单词,例如 it, everything, data, handle, stuff, do, routine, perform 和数字,像这样命名的好例子有 routineX48, PerformDataFunction, DoIt, HandleStuff还有 do_args_method。

首字母大写的缩写

用首字母大写缩写(比如GNU 代表 GNU’s Not Unix) 使代码简洁难懂。真正的汉子(无论**)从来不说明这种缩写的含义,他们生下来就懂。

辞典大轮换

为了打破沉闷的编程气氛,你可以用一本辞典来查找尽量多的同义词。例如 display, show, present。在注释里含糊其辞地暗示这些命名之间有细微的差别,其实根本没有。不过,如果有两个命名相似的函数真的有重大差别,那倒是一定要确保它们用相同的单词来命名(例如,对于 “写入文件”, “在纸上书写” 和 “屏幕显示” 都用 print 来命名)。 在任何情况下都不要屈服于编写明确的项目词汇表这种无理要求。你可以辩解说,这种要求是一种不专业的行为,它违反了结构化设计的信息隐藏原则。

首字母大写

随机地把单词中间某个音节的首字母大写。例如 ComputeReSult()。

重用命名

在语言规则允许的地方,尽量把类、构造器、方法、成员变量、参数和局部变量都命名成一样。更高级的技巧是在{}块中重用局部变量。这样做的目的是迫使维护代码的程序员认真检查每个示例的作用域。特别是在Java代码中,可以把普通方法伪装成构造器。

使用非英语字母

在命名中偷偷使用不易察觉的非英语字母,例如

typedef struct { int i; } ínt;

看上去没啥不对是吧?嘿嘿嘿…这里的第二个 ínt 的 í 实际上是东北欧字母,并不是英语中的 i 。在简单的文本编辑器里,想看出这一点点区别几乎是不可能的。

巧妙利用编译器对于命名长度的限制

如果编译器只区分命名的前几位,比如前8位,那么就把后面的字母写得不一样。比如,其实是同一个变量,有时候写成 var_unit_update() ,有时候又写成 var_unit_setup(),看起来是两个不同的函数调用。而在编译的时候,它们其实是同一个变量 var_unit。

下划线,真正的朋友

可以拿 _ 和 __ 作为标示符。

混合多语言

随机地混用两种语言(人类语言或计算机语言都行)。如果老板要求使用他指定的语言,你就告诉他你用自己的语言更有利于组织你的思路,万一这招不管用,就去控诉这是语言歧视,并威胁起诉老板要求巨额精神损失赔偿。

扩展 ASCII 字符

扩展 ASCII 字符用于变量命名是完全合法的,包括 ß, Ð, 和 ñ  等。在简单的文本编辑器里,除了拷贝/粘贴,基本上没法输入。

其他语言的命名

使用外语字典作为变量名的来源。例如,可以用德语单词 punkt 代替 point。除非维护代码的程序员也像你一样熟练掌握了德语. 不然他就只能尽情地在代码中享受异域风情了。

数学命名

用数学操作符的单词来命名变量。例如:

openParen = (slash + asterix) / equals;
(左圆括号 = (斜杠 + 星号)/等号;)

令人眩晕的命名

用带有完全不相关的感**
沙发
俺是村长他爹|  楼主 | 2016-9-6 23:14 | 只看该作者
编码迷局

迷惑 C

从互联网上的各种混乱C 语言竞赛中学习,追随大师们的脚步。

追求极致

总是追求用最迷惑的方式来做普通的任务。例如,要用数组来把整数转换为相应的字符串,可以这么做:

char *p;
switch (n)
{
case 1:
p = "one";
if (0)
case 2:
p = "two";
if (0)
case 3:
p = "three";
printf("%s", p);
break;
}

一致性的小淘气

当你需要一个字符常量的时候,可以用多种不同格式: ‘ ‘, 32, 0×20, 040。在C或Java里10和010是不同的数(0开头的表示16进制),你也可以充分利用这个特性。

造型

把所有数据都以 void * 形式传递,然后再造型为合适的结构。不用结构而是通过位移字节数来造型也很好玩。

嵌套 Switch

Switch 里边还有 Switch,这种嵌套方式是人类大脑难以**的。

利用隐式转化

牢记编程语言中所有的隐式转化细节。充分利用它们。数组的索引要用浮点变量,循环计数器用字符,对数字执行字符串函数调用。不管怎么说,所有这些操作都是合法的,它们无非是让源代码更简洁而已。任何尝试理解它们的维护者都会对你感激不尽,因为他们必须阅读和学习整个关于隐式数据类型转化的章节,而这个章节很可能是他们来维护你的代码之前完全忽略了的。

分号!

在所有语法允许的地方都加上分号,例如:

if(a);
else;
{
int d;
d = c;
}
;

使用八进制数

把八进制数混到十进制数列表里,就像这样:

array = new int []
{
111,
120,
013,
121,
};

嵌套

尽可能深地嵌套。优秀的程序员能在一行代码里写10层(),在一个方法里写20层{}。

C数组

C编译器会把 myArray 转换成 *(myArray + i),它等同于 *(i + myArray) 也等同于 i[myArray]。 高手都知道怎么用好这个招。可以用下面的函数来产生索引,这样就把代码搞乱了:

int myfunc(int q, int p) { return p%q; }
...
myfunc(6291, 8)[Array];

遗憾的是,这一招只能在本地C类里用,Java 还不行。

放长线钓大鱼

一行代码里堆的东西越多越好。这样可以省下临时变量的开销,去掉换行和空格还可以缩短源文件大小。记住,要去掉运算符两边的空格。优秀的程序员总是能突破某些编辑器对于255个字符行宽的限制。

异常

我这里要向你传授一个编程领域里鲜为人知的秘诀。异常是个讨厌的东西。良好的代码永远不会出错,所以异常实际上是不必要的。不要把时间浪费在这上面。子类异常是给那些知道自己代码会出错的低能儿用的。在整个应用里,你只用在main()里放一个try/catch,里边直接调用 System.exit()就行了。在每个方法头要贴上标准的抛出集合定义,到底会不会抛出异常你就不用管了。

使用异常的时机

在非异常条件下才要使用异常。比如终止循环就可以用 ArrayIndexOutOfBoundsException。还可以从异常里的方法返回标准的结果。

狂热奔放地使用线程

如题。


测试

在程序里留些bug,让后继的维护代码的程序员能做点有意思的事。精心设计的bug是无迹可寻的,而且谁也不知道它啥时候会冒出来。要做到这一点,最简单的办法的就是不要测试代码。

永不测试

永远不要测试负责处理错误、当机或操作系故障的任何代码。反正这些代码永远也不会执行,只会拖累你的测试。还有,你怎么可能测试处理磁盘错误、文件读取错误、操作系统崩溃这些类型的事件呢?为啥你要用特别不稳定的计算机或者用测试脚手架来模拟这样的环境?现代化的硬件永远不会崩溃,谁还愿意写一些仅仅用于测试的代码?这一点也不好玩。如果用户抱怨,你就怪到操作系统或者硬件头上。他们永远不会知道真相的。

永远不要做性能测试

嘿,如果软件运行不够快,只要告诉客户买个更快的机器就行了。如果你真的做了性能测试,你可能会发现一个瓶颈,这会导致修改算法,然后导致整个产品要重新设计。谁想要这种结果?而且,在客户那边发现性能问题意味着你可以免费到外地旅游。你只要备好护*和最新照片就行了。

永远不要写任何测试用例

永远不要做代码覆盖率或路径覆盖率测试。自动化测试是给那些窝囊废用的。搞清楚哪些特性占到你的例程使用率的90%,然后把90%的测试用在这些路径上。毕竟说起来,这种方法可能只测试到了大约你代码的60%,这样你就节省了40%的测试工作。这能帮助你赶上项目后端的进度。等到有人发现所有这些漂亮的“市场特性”不能正常工作的时候,你早就跑路了。一些有名的大软件公司就是这样测试代码的,所以你也应该这样做。如果因为某种原因你还没走,那就接着看下一节。

测试是给懦夫用的

勇敢的程序员会跳过这个步骤。太多程序员害怕他们的老板,害怕丢掉工作,害怕客户的投诉邮件,害怕遭到起诉。这种恐惧心理麻痹了行动,降低了生产率。有科学研究成果表明,取消测试阶段意味着经理有把握能提前确定交付时间,这对于规划流程显然是有利的。消除了恐惧心理,创新和实验之花就随之绽放。程序员的角色是生产代码,调试工作完全可以由技术支持和遗留代码维护组通力合作来进行。

如果我们对自己的编程能力有充分信心,那么测试就没有必要了。如果我们逻辑地看待这个问题,随便一个傻瓜都能认识到测试根本都不是为了解决技术问题,相反,它是一种感性的信心问题。针对这种缺乏信心的问题,更有效的解决办法就是完全取消测试,送我们的程序员去参加自信心培训课程。毕竟说起来,如果我们选择做测试,那么我们就要测试每个程序的变更,但其实我们只需要送程序员去一次建立自信的培训课就行了。很显然这么做的成本收益是相当可观的。



编程语言的选择

计算机语言正在逐步进化,变得更加傻瓜化。使用最新的语言是不人性的。尽可能**使用你会用的最老的语言,先考虑用穿孔纸带,不行就用汇编,再不行用FORTRAN 或者 COBOL,再不行就用C 还有 BASIC,实在不行再用 C++。

FORTRAN

用 FORTRAN 写所有的代码。如果老板问你为啥,你可以回答说有很多它非常有用的库,你用了可以节约时间。不过,用 FORTRAN 写出可维护代码的概率是0,所以,要达到不可维护代码编程指南里的要求就容易多了。

用 ASM

把所有的通用工具函数都转成汇编程序。

用 QBASIC

所有重要的库函数都要用 QBASIC 写,然后再写个汇编的封包程序来处理 large 到 medium 的内存模型映射。

内联汇编

在你的代码里混杂一些内联的汇编程序,这样很好玩。这年头几乎没人懂汇编程序了。只要放几行汇编代码就能让维护代码的程序员望而却步。

宏汇编调用C

如果你有个汇编模块被C调用,那就尽可能经常从汇编模块再去调用C,即使只是出于微不足道的用途,另外要充分利用 goto, bcc 和其他炫目的汇编秘籍。


与他人共事之道

老板才是真行家

如果你的老板认为他20年的 FORTRAN 编程经验对于现代软件开发具有很高的指导价值,你务必严格采纳他的所有建议。投桃报李,你的老板也会信任你。这会对你的职业发展有利。你还会从他那里学到很多搞乱程序代码的新方法。

颠覆技术支持

确保代码中到处是bug的有效方法是永远不要让维护代码的程序员知道它们。这需要颠覆技术支持工作。永远不接电话。使用自动语音答复“感谢拨打技术支持热线。需要人工服务请按1,或在嘀声后留言。”,请求帮助的电子邮件必须忽略,不要给它分配服务追踪号。对任何问题的标准答复是“我估计你的账户被锁定了,有权限帮你恢复的人现在不在。”

沉默是金

永远不要对下一个危机保持警觉。如果你预见到某个问题可能会在一个固定时间爆发,摧毁西半球的全部生命,不要公开讨论它。不要告诉朋友、同事或其他你认识的有本事的人。在任何情况下都不要发表任何可能暗示到这种新的威胁的内容。只发送一篇正常优先级的、语焉不详的备忘录给管理层,保护自己免遭秋后算账。如果可能的话,把这篇稀里糊涂的信息作为另外一个更紧急的业务问题的附件。这样就可以心安理得地休息了,你知道将来你被强制提前退休之后一段时间,他们又会求着你回来,并给你对数级增长的时薪!

每月一书俱乐部

加入一个计算机每月一书俱乐部。选择那些看上去忙着写书不可能有时间真的去写代码的作者。去书店里找一些有很多图表但是没有代码例子的书。浏览一下这些书,从中学会一些迂腐拗口的术语,用它们就能唬住那些自以为是的维护代码的程序员。你的代码肯定会给他留下深刻印象。如果人们连你写的术语都理解不了,他们一定会认为你非常聪明,你的算法非常深奥。不要在你的算法说明里作任何朴素的类比。

自立门户

你一直想写系统级的代码。现在机会来了。忽略标准库, 编写你自己的标准,这将会是你简历中的一个亮点。

推出你自己的 BNF 范式

总是用你自创的、独一无二的、无文档的BNF范式记录你的命令语法。永远不要提供一套带注解的例子(合法命令和非法命令之类)来解释你的语法体系。那样会显得完全缺乏学术严谨性。确保没有明显的方式来区分终结符和中间符号。永远不要用字体、颜色、大小写和其他任何视觉提示帮助读者分辨它们。在你的 BNF 范式用和命令语言本身完全一样的标点符号,这样读者就永远无法分清一段 (…), [...], {…} 或 “…” 到底是你在命令行里真正输入的,还是想提示在你的BNF 范式里哪个语法元素是必需的、可重复的、或可选的。不管怎么样,如果他们太笨,搞不清你的BNF 范式的变化,就没资格使用你的程序。

推出你自己的内存分配

地球人儿都知道,调试动态存储是复杂和费时的。与其逐个类去确认它没有内存溢出,还不如自创一套存储分配机制呢。其实它无非是从一大片内存中 malloc 一块空间而已。用不着释放内存,让用户定期重启动系统,这样不就清除了堆么。重启之后系统需要追踪的就那么一点东西,比起解决所有的内存泄露简单得不知道到哪里去了!而且,只要用户记得定期重启系统,他们也永远不会遇到堆空间不足的问题。一旦系统被部署,你很难想象他们还能改变这个策略。

使用特权

评论回复
板凳
whtwhtw| | 2016-9-7 10:37 | 只看该作者
高,实在是高

使用特权

评论回复
地板
sunhaojie| | 2016-9-7 11:38 | 只看该作者
就怕把自己给迷惑住了,然后自己需要维护很多年!

使用特权

评论回复
5
cbb0416| | 2016-9-7 13:35 | 只看该作者

使用特权

评论回复
6
294479435| | 2016-9-7 17:57 | 只看该作者

使用特权

评论回复
7
ticomi| | 2016-9-7 18:04 | 只看该作者
不建议这样做,提升自己才是关键!

使用特权

评论回复
8
muslimsali| | 2016-9-7 18:52 | 只看该作者
好**。

使用特权

评论回复
9
JLennon| | 2016-9-7 19:01 | 只看该作者
谁遇到这样的上任,真是倒了八辈子的血霉啊。

使用特权

评论回复
10
电子与核子| | 2016-9-7 19:29 | 只看该作者
呵呵,劳方对资方反抗的又一利器

使用特权

评论回复
11
kk118a| | 2016-9-7 20:32 | 只看该作者
做的人累死,看的人气四

使用特权

评论回复
12
皈依| | 2016-9-7 21:29 | 只看该作者
。。。这。。。看的人会哭的。

使用特权

评论回复
13
itelectron| | 2016-9-7 22:36 | 只看该作者
高人

使用特权

评论回复
14
Raeka| | 2016-9-8 20:11 | 只看该作者

使用特权

评论回复
15
crystal1987| | 2016-9-9 15:54 | 只看该作者
这是要坑死同行。

使用特权

评论回复
16
waiter| | 2016-9-9 18:16 | 只看该作者

使用特权

评论回复
17
waiter| | 2016-9-9 18:17 | 只看该作者
这个帖子要顶出来。。。。。

使用特权

评论回复
18
俺是村长他爹|  楼主 | 2016-9-9 23:01 | 只看该作者
waiter 发表于 2016-9-9 18:17
这个帖子要顶出来。。。。。

多谢多谢,
写的都是些行业内的小秘密,
行家们不要见怪啊!

使用特权

评论回复
19
俺是村长他爹|  楼主 | 2016-9-9 23:03 | 只看该作者


过奖过奖!
写得很不错
就转出来了!

使用特权

评论回复
20
俺是村长他爹|  楼主 | 2016-9-9 23:04 | 只看该作者
sunhaojie 发表于 2016-9-7 11:38
就怕把自己给迷惑住了,然后自己需要维护很多年!

有时候维护自己的代码,
比维护别人的代码还要痛苦,
因为不能骂自己,
好友硬着头皮及学习写!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

66

主题

168

帖子

2

粉丝