[转载]如何编写无法维护的代码(3) -尊龙游戏旗舰厅官网
2019独角兽企业重金招聘python工程师标准>>>
这是一篇转载文章,最原始的是英文,这是英文原文的地址,然后由伯乐在线的老码农翻译,这是翻译原文的地址,由于翻译的原文很长,故在转载时拆分成为多篇。以下为转载的翻译:
(接前一篇)
测试
在程序里留些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 一块空间而已。用不着释放内存,让用户定期重启动系统,这样不就清除了堆么。重启之后系统需要追踪的就那么一点东西,比起解决所有的内存泄露简单得不知道 到哪里去了!而且,只要用户记得定期重启系统,他们也永远不会遇到堆空间不足的问题。一旦系统被部署,你很难想象他们还能改变这个策略。
其他杂七杂八的招
如果你给某人一段程序,你会让他困惑一天;如果你教他们如何编程,你会让他困惑一辈子。 — anonymous
不要重编译
让我们从一条可能是有史以来最友好的技巧开始:把代码编译成可执行文件。如果它能用,就在源代码里做一两个微小的改动 — 每个模块都照此办理。但是不要费劲巴拉地再编译一次了。 你可以留着等以后有空而且需要调试的时候再说。多年以后,等可怜的维护代码的程序员更改了代码之后发现出错了,他会有一种错觉,觉得这些肯定是他自己最近修改的。这样你就能让他毫无头绪地忙碌很长时间。
挫败调试工具
对于试图用行调试工具追踪来看懂你的代码的人,简单的一招就能让他狼狈不堪,那就是把每一行代码都写得很长。特别要把 then 语句 和 if 语句放在同一行里。他们无法设置断点。他们也无法分清在看的分支是哪个 if 里的。
公制和美制
在工程方面有两种编码方式。一种是把所有输入都转换为公制(米制)计量单位,然后在输出的时候自己换算回各种民用计量单位。另一种是从头到尾都保持各种计量单位混合在一起。总是选择第二种方式,这就是美国之道!
持续改进
要持续不懈地改进。要常常对你的代码做出“改进”,并强迫用户经常升级 — 毕竟没人愿意用一个过时的版本嘛。即便他们觉得他们对现有的程序满意了,想想看,如果他们看到你又“完善“了它,他们会多么开心啊!不要告诉任何人版本之 间的差别,除非你被逼无奈 — 毕竟,为什么要告诉他们本来永远也不会注意到的一些bug呢?
“关于”
”关于“一栏应该只包含程序名、程序员姓名和一份用法律用语写的尊龙游戏旗舰厅官网的版权声明。理想情况下,它还应该链接到几 mb 的代码,产生有趣的动画效果。但是,里边永远不要包含程序用途的描述、它的版本号、或最新代码修改日期、或获取更新的网站地址、或作者的email地址 等。这样,所有的用户很快就会运行在各种不同的版本上,在安装n 1版之前就试图安装n 2版。
变更
在两个版本之间,你能做的变更自然是多多益善。你不会希望用户年复一年地面对同一套老的接口或用户界面,这样会很无聊。最后,如果你能在用户不注意的情况下做出这些变更,那就更好了 — 这会让他们保持警惕,戒骄戒躁。
无需技能
写无法维护代码不需要多高的技术水平。喊破嗓子不如甩开膀子,不管三七二十一开始写代码就行了。记住,管理层还在按代码行数考核生产率,即使以后这些代码里的大部分都得删掉。
只带一把锤子
一招鲜吃遍天,会干什么就吆喝什么,轻装前进。如果你手头只有一把锤子,那么所有的问题都是钉子。
规范体系
有可能的话,忽略当前你的项目所用语言和环境中被普罗大众所接受的编程规范。比如,编写基于mfc 的应用时,就坚持使用stl 编码风格。
翻转通常的 true false 惯例
把常用的 true 和 false 的定义反过来用。这一招听起来平淡无奇,但是往往收获奇效。你可以先藏好下面的定义:
#define true 0 #define false 1把这个定义深深地藏在代码中某个没人会再去看的文件里不易被发现的地方,然后让程序做下面这样的比较
if ( var == true ) if ( var != false )某些人肯定会迫不及待地跳出来“修正”这种明显的冗余,并且在其他地方照着常规去使用变量var:
if ( var )还有一招是为 true 和 false赋予相同的值,虽然大部分人可能会看穿这种骗局。给它们分别赋值 1 和 2 或者 -1 和 0 是让他们瞎忙乎的方式里更精巧的,而且这样做看起来也不失对他们的尊重。你在java 里也可以用这一招,定义一个叫 true 的静态常量。在这种情况下,其他程序员更有可能怀疑你干的不是好事,因为java里已经有了内建的标识符 true。
第三方库
在你的项目里引入功能强大的第三方库,然后不要用它们。潜规则就是这样,虽然你对这些工具仍然一无所知,却可以在你简历的“其他工具”一节中写上这些没用过的库。
不要用库
假装不知道有些库已经直接在你的开发工具中引入了。如果你用vc 编程,忽略mfc 或 stl 的存在,手工编写所有字符串和数组的实现;这样有助于保持你玩指针技术的高水平,并自动阻止任何扩展代码功能的企图。
创建一套build顺序
把这套顺序规则做得非常晦涩,让维护者根本无法编译任何他的修改代码。秘密保留 smartj ,它会让 make脚本形同废物。类似地,偷偷地定义一个 javac 类,让它和编译程序同名。说到大招,那就是编写和维护一个定制的小程序,在程序里找到需要编译的文件,然后通过直接调用 sun.tools.javac.main 编译类来进行编译。
make 的更多玩法
用一个 makefile-generated-batch-file 批处理文件从多个目录复制源文件,文件之间的覆盖规则在文档中是没有的。这样,无需任何炫酷的源代码控制系统,就能实现代码分支,并阻止你的后继者弄清哪 个版本的 dousefulwork() 才是他需要修改的那个。
搜集编码规范
尽可能搜集所有关于编写可维护代码的建议,例如 squarebox 的建议 ,然后明目张胆地违反它们。
规避公司的编码规则
某些公司有严格的规定,不允许使用数字标识符,你必须使用预先命名的常量。要挫败这种规定背后的意图太容易了。比如,一位聪明的 c 程序员是这么写的:
#define k_one 1 #define k_two 2 #define k_thousand 999编译器警告
一定要保留一些编译器警告。在 make 里使用 “-” 前缀强制执行,忽视任何编译器报告的错误。这样,即使维护代码的程序员不小心在你的源代码里造成了一个语法错误,make 工具还是会重新把整个包build 一遍,甚至可能会成功!而任何程序员要是手工编译你的代码,看到屏幕上冒出一堆其实无关紧要的警告,他们肯定会觉得是自己搞坏了代码。同样,他们一定会感 谢你让他们有找错的机会。学有余力的同学可以做点手脚让编译器在打开编译错误诊断工具时就没法编译你的程序。当然了,编译器也许能做一些脚本边界检查,但 是真正的程序员是不用这些特性的,所以你也不该用。既然你用自己的宝贵时间就能找到这些精巧的bug,何必还多此一举让编译器来检查错误呢?
把 bug 修复和升级混在一起
永远不要发布什么“bug 修复”版本。一定要把 bug 修复和数据库结构变更、复杂的用户界面修改,还有管理界面重写等混在一起。那样的话,升级就变成一件非常困难的事情,人们会慢慢习惯 bug 的存在并开始称他们为特性。那些真心希望改变这些”特性“的人们就会有动力升级到新版本。这样从长期来说可以节省你的维护工作量,并从你的客户那里获得更 多收入。
在你的产品发布每个新版本的时候都改变文件结构
没错,你的客户会要求向上兼容,那就去做吧。不过一定要确保向下是不兼容的。这样可以阻止客户从新版本回退,再配合一套合理的 bug 修复规则(见上一条),就可以确保每次新版本发布后,客户都会留在新版本。学有余力的话,还可以想办法让旧版本压根无法识别新版本产生的文件。那样的话, 老版本系统不但无法读取新文件,甚至会否认这些文件是自己的应用系统产生的!温馨提示:pc 上的 word 文字处理软件就典型地精于此道。
抵消 bug
不用费劲去代码里找 bug 的根源。只要在更高级的例程里加入一些抵销它的代码就行了。这是一种很棒的智力测验,类似于玩3d棋,而且能让将来的代码维护者忙乎很长时间都想不明白问 题到底出在哪里:是产生数据的低层例程,还是莫名其妙改了一堆东西的高层代码。这一招对天生需要多回合执行的编译器也很好用。你可以在较早的回合完全避免 修复问题,让较晚的回合变得更加复杂。如果运气好,你永远都不用和编译器前端打交道。学有余力的话,在后端做点手脚,一旦前端产生的是正确的数据,就让后 端报错。
使用旋转锁
不要用真正的同步原语,多种多样的旋转锁更好 — 反复休眠然后测试一个(non-volatile的) 全局变量,直到它符合你的条件为止。相比系统对象,旋转锁使用简便,”通用“性强,”灵活“多变,实为居家旅行必备。
随意安插 sync 代码
把某些系统同步原语安插到一些用不着它们的地方。本人曾经在一段不可能会有第二个线程的代码中看到一个临界区(critical section)代码。本人当时就质问写这段代码的程序员,他居然理直气壮地说这么写是为了表明这段代码是很”关键“(单词也是critical)的!
优雅降级
如果你的系统包含了一套 nt 设备驱动,就让应用程序负责给驱动分配 i/o 缓冲区,然后在任何交易过程中对内存中的驱动加锁,并在交易完成后释放或解锁。这样一旦应用非正常终止,i/o缓存又没有被解锁,nt服务器就会当机。但 是在客户现场不太可能会有人知道怎么弄好设备驱动,所以他们就没有选择(只能请你去免费旅游了)。
定制脚本语言
在你的 c/s 应用里嵌入一个在运行时按字节编译的脚本命令语言。
依赖于编译器的代码
如果你发现在你的编译器或解释器里有个bug,一定要确保这个bug的存在对于你的代码正常工作是至关重要的。毕竟你又不会使用其他的编译器,其他任何人也不允许!
一个货真价实的例子
下面是一位大师编写的真实例子。让我们来瞻仰一下他在这样短短几行 c 函数里展示的高超技巧。
void* realocate(void*buf, int os, int ns) {void*temp; temp = malloc(os); memcpy((void*)temp, (void*)buf, os); free(buf); buf = malloc(ns); memset(buf, 0, ns); memcpy((void*)buf, (void*)temp, ns); return buf; }重新发明了标准库里已有的简单函数。
realocate 这个单词拼写错误。所以说,永远不要低估创造性拼写的威力。
无缘无故地给输入缓冲区产生一个临时的副本。
无缘无故地造型。 memcpy() 里有 (void*),这样即使我们的指针已经是 (void*) 了也要再造型一次。另外,这样做可以传递任何东西作为参数,加10分。
永远不必费力去释放临时内存空间。这样会导致缓慢的内存泄露,一开始看不出来,要程序运行一段时间才行。
把用不着的东西也从缓冲区里拷贝出来,以防万一。这样只会在unix上产生core dump,windows 就不会。
很显然,os 和 ns 的含义分别是”old size” 和 “new size”。
给 buf 分配内存之后,memset 初始化它为 0。不要使用 calloc(),因为某些人会重写 ansi 规范,这样将来保不齐 calloc() 往 buf 里填的就不是 0 了。(虽然我们复制过去的数据量和 buf 的大小是一样的,不需要初始化,不过这也无所谓啦)
如何修复 “unused variable” 错误
如果你的编译器冒出了 “unused local variable” 警告,不要去掉那个变量。相反,要找个聪明的办法把它用起来。我最喜欢的方法是:
i = i;大小很关键
差点忘了说了,函数是越大越好。跳转和 goto 语句越多越好。那样的话,想做任何修改都需要分析很多场景。这会让维护代码的程序员陷入千头万绪之中。如果函数真的体型庞大的话,对于维护代码的程序员就是哥斯拉怪兽了,它会在他搞清楚情况之前就残酷无情地将他踩翻在地。
一张图片顶1000句话,一个函数就是1000行
把每个方法体写的尽可能的长 — 最好是你写的任何一个方法或函数都不会少于1000行代码,而且里边是深度嵌套,这是必须的。
少个文件
一定要保证一个或多个关键文件无法找到。利用includes 里边再 includes 就能做到这一点。例如,在你的 main 模块里,你写上:
#includestdcode.h 是有的。但是在 stdcode.h 里,还有个引用:
#include "a:\\refcode.h"然后,refcode.h 就没地方能找到了。
(【译者-老码农-注】为啥找不到呢?仔细看看,现在还有人知道 a:\ 是什么吗?a盘!传说中的软盘…)
到处都写,无处会读
至少要把一个变量弄成这样:到处被设置,但是几乎没有哪里用到它。不幸的是,现代编译器通常会阻止你做相反的事:到处读,没处写。不过你在c 或 c 里还是可以这样做的。
【译注】:原文在后面还有一些内容,翻译时略有删减。删节的内容主要是:
我看不懂的部分;
我觉得不怎么好笑的部分(其实很可能是因为没看懂所以找不到笑点);
不容易引起现代程序猿共鸣的老旧内容。
(全部内容转载完毕)
转载于:https://my.oschina.net/songxinqiang/blog/542485
总结
以上是尊龙游戏旗舰厅官网为你收集整理的[转载]如何编写无法维护的代码(3)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇:
- 下一篇: python 多版本管理