JAVA老碼農(nóng)穩(wěn)拿鐵飯碗行業(yè)代碼規(guī)范

image

老碼農(nóng)如何編寫無法維護(hù)的代碼

讓自己穩(wěn)拿鐵飯碗 :D

— Roedy Green(翻譯版略有刪節(jié))

簡介

永遠(yuǎn)不要(把自己遇到的問題)歸因于(他人的)惡意,這恰恰說明了(你自己的)無能没卸。

— 拿破侖

為了造福大眾涕侈,在Java編程領(lǐng)域創(chuàng)造就業(yè)機(jī)會沪停,兄弟我在此傳授大師們的秘籍。這些大師寫的代碼極其難以維護(hù)裳涛,后繼者就是想對它做最簡單的修改都需要花上數(shù)年時(shí)間木张。而且,如果你能對照秘籍潛心修煉调违,你甚至可以給自己弄個(gè)鐵飯碗窟哺,因?yàn)槌四阒庑汉洌瑳]人能維護(hù)你寫的代碼技肩。再而且,如果你能練就秘籍中的全部招式,那么連你自己都無法維護(hù)你的代碼了虚婿!

image

你不想練功過度走火入魔吧旋奢。那就不要讓你的代碼一眼看去就完全無法維護(hù),只要它實(shí)質(zhì)上是那樣就行了然痊。否則至朗,你的代碼就有被重寫或重構(gòu)的風(fēng)險(xiǎn)!

總體原則

Quidquid latine dictum sit, altum sonatur.
(隨便用拉丁文寫點(diǎn)啥都會顯得高大上剧浸。)

想挫敗維護(hù)代碼的程序員锹引,你必須先明白他的思維方式。他接手了你的龐大程序唆香,沒有時(shí)間把它全部讀一遍嫌变,更別說理解它了。他無非是想快速找到修改代碼的位置躬它、改代碼腾啥、編譯,然后就能交差冯吓,并希望他的修改不會出現(xiàn)意外的副作用倘待。

他查看你的代碼不過是管中窺豹,一次只能看到一小段而已组贺。你要確保他永遠(yuǎn)看不到全貌凸舵。要盡量讓他難以找到他想找的代碼。但更重要的是锣披,要讓他不能有把握忽略任何東西贞间。

程序員都被編程慣例洗腦了,還為此自鳴得意雹仿。每一次你處心積慮地違背編程慣例增热,都會迫使他必須用放大鏡去仔細(xì)閱讀你的每一行代碼。

你可能會覺得每個(gè)語言特性都可以用來讓代碼難以維護(hù)胧辽,其實(shí)不然峻仇。你必須精心地誤用它們才行。

命名

“當(dāng)我使用一個(gè)單詞的時(shí)候” Humpty Dumpty 曾經(jīng)用一種輕蔑的口氣說, “它就是我想表達(dá)的意思邑商,不多也不少摄咆。“

– Lewis Carroll — 《愛麗絲魔鏡之旅》人断, 第6章

編寫無法維護(hù)代碼的技巧的重中之重是變量和方法命名的藝術(shù)吭从。如何命名是和編譯器無關(guān)的。這就讓你有巨大的自由度去利用它們迷惑維護(hù)代碼的程序員恶迈。

妙用 <cite style="margin: 0px; padding: 0px;">寶寶起名大全</cite>

買本寶寶起名大全涩金,你就永遠(yuǎn)不缺變量名了。比如 Fred 就是個(gè)好名字,而且鍵盤輸入它也省事步做。如果你就想找一些容易輸入的變量名副渴,可以試試 adsf 或者 aoeu之類。

單字母變量名

如果你給變量起名為a,b,c全度,用簡單的文本編輯器就沒法搜索它們的引用煮剧。而且,沒人能猜到它們的含義将鸵。

創(chuàng)造性的拼寫錯(cuò)誤

如果你必須使用描述性的變量和函數(shù)名勉盅,那就把它們都拼錯(cuò)。還可以把某些函數(shù)和變量名拼錯(cuò)顶掉,再把其他的拼對(例如 SetPintleOpening 和 SetPintalClosing) 菇篡,我們就能有效地將grep或IDE搜索技術(shù)玩弄于股掌之上。這招超級管用一喘。還可以混淆不同語言(比如colour — 英國英語驱还,和 color — 美國英語)。

抽象

在命名函數(shù)和變量的時(shí)候凸克,充分利用抽象單詞议蟆,例如 it, everything, data, handle, stuff, do, routine, perform 和數(shù)字,像這樣命名的好例子有 routineX48, PerformDataFunction, DoIt, HandleStuff還有 do_args_method萎战。

首字母大寫的縮寫

用首字母大寫縮寫(比如GNU 代表 GNU’s Not Unix) 使代碼簡潔難懂咐容。真正的漢子(無論男女)從來不說明這種縮寫的含義,他們生下來就懂蚂维。

辭典大輪換

為了打破沉悶的編程氣氛戳粒,你可以用一本辭典來查找盡量多的同義詞。例如 display, show, present虫啥。在注釋里含糊其辭地暗示這些命名之間有細(xì)微的差別蔚约,其實(shí)根本沒有。不過涂籽,如果有兩個(gè)命名相似的函數(shù)真的有重大差別苹祟,那倒是一定要確保它們用相同的單詞來命名(例如,對于 “寫入文件”, “在紙上書寫” 和 “屏幕顯示” 都用 print 來命名)评雌。 在任何情況下都不要屈服于編寫明確的項(xiàng)目詞匯表這種無理要求树枫。你可以辯解說,這種要求是一種不專業(yè)的行為景东,它違反了結(jié)構(gòu)化設(shè)計(jì)的信息隱藏原則砂轻。

首字母大寫

隨機(jī)地把單詞中間某個(gè)音節(jié)的首字母大寫。例如 ComputeReSult()斤吐。

重用命名

在語言規(guī)則允許的地方搔涝,盡量把類丝里、構(gòu)造器、方法体谒、成員變量、參數(shù)和局部變量都命名成一樣臼婆。更高級的技巧是在{}塊中重用局部變量抒痒。這樣做的目的是迫使維護(hù)代碼的程序員認(rèn)真檢查每個(gè)實(shí)例的作用域。特別是在Java代碼中颁褂,可以把普通方法偽裝成構(gòu)造器故响。

使用非英語字母

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

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

typedef struct { int i; } ínt;

</pre>

看上去沒啥不對是吧颁独?嘿嘿嘿…這里的第二個(gè) ínt 的 í 實(shí)際上是東北歐字母彩届,并不是英語中的 i 。在簡單的文本編輯器里誓酒,想看出這一點(diǎn)點(diǎn)區(qū)別幾乎是不可能的樟蠕。

巧妙利用編譯器對于命名長度的限制

如果編譯器只區(qū)分命名的前幾位,比如前8位靠柑,那么就把后面的字母寫得不一樣寨辩。比如,其實(shí)是同一個(gè)變量歼冰,有時(shí)候?qū)懗?var_unit_update() 靡狞,有時(shí)候又寫成 var_unit_setup(),看起來是兩個(gè)不同的函數(shù)調(diào)用隔嫡。而在編譯的時(shí)候甸怕,它們其實(shí)是同一個(gè)變量 var_unit。

下劃線腮恩,真正的朋友

可以拿 _ 和 __ 作為標(biāo)示符梢杭。

混合多語言

隨機(jī)地混用兩種語言(人類語言或計(jì)算機(jī)語言都行)。如果老板要求使用他指定的語言秸滴,你就告訴他你用自己的語言更有利于組織你的思路式曲,萬一這招不管用,就去控訴這是語言歧視缸榛,并威脅起訴老板要求巨額精神損失賠償吝羞。

擴(kuò)展 ASCII 字符

擴(kuò)展 ASCII 字符用于變量命名是完全合法的,包括 ?, D, 和 ? 等内颗。在簡單的文本編輯器里钧排,除了拷貝/粘貼,基本上沒法輸入均澳。

其他語言的命名

使用外語字典作為變量名的來源恨溜。例如符衔,可以用德語單詞 punkt 代替 point。除非維護(hù)代碼的程序員也像你一樣熟練掌握了德語. 不然他就只能盡情地在代碼中享受異域風(fēng)情了糟袁。

數(shù)學(xué)命名

用數(shù)學(xué)操作符的單詞來命名變量判族。例如:

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

openParen = (slash + asterix) / equals;

</pre>

(左圓括號 = (斜杠 + 星號)/等號;)

令人眩暈的命名

用帶有完全不相關(guān)的感情色彩的單詞來命名變量。例如:

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

marypoppins = (superman + starship) / god;

</pre>

(歡樂滿人間 = (超人 + 星河戰(zhàn)隊(duì))/上帝;)

這一招可以讓閱讀代碼的人陷入迷惑之中项戴,因?yàn)樗麄冊谠噲D想清楚這些命名的邏輯時(shí)形帮,會不自覺地聯(lián)系到不同的感情場景里而無法自拔。

何時(shí)使用 i

永遠(yuǎn)不要把 i 用作最內(nèi)層的循環(huán)變量周叮。 用什么命名都行辩撑,就是別用i。把 i 用在其他地方就隨便了仿耽,用作非整數(shù)變量尤其好合冀。

慣例 — 明修棧道,暗度陳倉

忽視 Java 編碼慣例项贺,Sun 自己就是這樣做的君躺。幸運(yùn)的是,你違反了它編譯器也不會打小報(bào)告开缎。這一招的目的是搞出一些在某些特殊情況下有細(xì)微差別的名字來晰洒。如果你被強(qiáng)迫遵循駝峰法命名,你還是可以在某些模棱兩可的情況下顛覆它啥箭。例如谍珊,inputFilename 和 inputfileName 兩個(gè)命名都可以合法使用。在此基礎(chǔ)上自己發(fā)明一套復(fù)雜到變態(tài)的命名慣例急侥,然后就可以對其他人反咬一口砌滞,說他們違反了慣例。

小寫的 l 看上去很像數(shù)字 1

用小寫字母 l 標(biāo)識 long 常數(shù)坏怪。例如 10l 更容易被誤認(rèn)為是 101 而不是 10L 贝润。 禁用所有能讓人準(zhǔn)確區(qū)分 uvw wW gq9 2z 5s il17|!j oO08 `'” ;,. m nn rn {[()]} 的字體。要做個(gè)有創(chuàng)造力的人铝宵。

把全局命名重用為私有

在A 模塊里聲明一個(gè)全局?jǐn)?shù)組打掘,然后在B 模塊的頭文件里再聲明一個(gè)同名的私有數(shù)組,這樣看起來你在B 模塊里引用的是那個(gè)全局?jǐn)?shù)組鹏秋,其實(shí)卻不是尊蚁。不要在注釋里提到這個(gè)重復(fù)的情況。

誤導(dǎo)性的命名

讓每個(gè)方法都和它的名字蘊(yùn)含的功能有一些差異侣夷。例如横朋,一個(gè)叫 isValid(x)的方法在判斷完參數(shù)x的合法性之后,還順帶著把它轉(zhuǎn)換成二進(jìn)制并保存到數(shù)據(jù)庫里百拓。

偽裝

當(dāng)一個(gè)bug需要越長的時(shí)間才會暴露琴锭,它就越難被發(fā)現(xiàn)晰甚。

– Roedy Green(本文作者)

編寫無法維護(hù)代碼的另一大秘訣就是偽裝的藝術(shù),即隱藏它或者讓它看起來像其他東西决帖。很多招式有賴于這樣一個(gè)事實(shí):編譯器比肉眼或文本編輯器更有分辨能力厕九。下面是一些偽裝的最佳招式。

把代碼偽裝成注釋地回,反之亦然

下面包括了一些被注釋掉的代碼扁远,但是一眼看去卻像是正常代碼。

image.gif

如果不是用單綠色標(biāo)出來落君,你能注意到這三行代碼被注釋掉了么?

用連接符隱藏變量

對于下面的定義

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

define local_var xy_z

</pre>

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

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

define local_var xy\

_z // local_var OK

</pre>

這樣全局搜索 xy_z 的操作在這個(gè)文件里就一無所獲了亭引。 對于 C 預(yù)處理器來說绎速,第一行最后的 “\” 表示繼續(xù)拼接下一行的內(nèi)容。

文檔

任何傻瓜都能說真話焙蚓,而要把謊編圓則需要相當(dāng)?shù)闹腔邸?/em>

– Samuel Butler (1835 – 1902)

不正確的文檔往往比沒有文檔還糟糕纹冤。

– Bertrand Meyer

既然計(jì)算機(jī)是忽略注釋和文檔的,你就可以在里邊堂而皇之地編織彌天大謊购公,讓可憐的維護(hù)代碼的程序員徹底迷失萌京。

在注釋中撒謊

實(shí)際上你不需要主動(dòng)地撒謊,只要沒有及時(shí)保持注釋和代碼更新的一致性就可以了宏浩。

只記錄顯而易見的東西

往代碼里摻進(jìn)去類似于

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

/* 給 i 加 1 */

</pre>

這樣的注釋知残,但是永遠(yuǎn)不要記錄包或者方法的整體設(shè)計(jì)這樣的干貨。

記錄 How 而不是 Why

只解釋一個(gè)程序功能的細(xì)節(jié)比庄,而不是它要完成的任務(wù)是什么求妹。這樣的話,如果出現(xiàn)了一個(gè)bug佳窑,修復(fù)者就搞不清這里的代碼應(yīng)有的功能制恍。

該寫的別寫

比如你在開發(fā)一套航班預(yù)定系統(tǒng),那就要精心設(shè)計(jì)神凑,讓它在增加另一個(gè)航空公司的時(shí)候至少有25處代碼需要修改净神。永遠(yuǎn)不要在文檔里說明要修改的位置。后來的開發(fā)人員要想修改你的代碼溉委?門都沒有鹃唯,除非他們能把每一行代碼都讀懂。

計(jì)量單位

永遠(yuǎn)不要在文檔中說明任何變量瓣喊、輸入俯渤、輸出或參數(shù)的計(jì)量單位,如英尺型宝、米八匠、加侖等絮爷。計(jì)量單位對數(shù)豆子不是太重要,但在工程領(lǐng)域就相當(dāng)重要了梨树。同理坑夯,永遠(yuǎn)不要說明任何轉(zhuǎn)換常量的計(jì)量單位,或者是它的取值如何獲得抡四。要想讓代碼更亂的話柜蜈,你還可以在注釋里寫上錯(cuò)誤的計(jì)量單位,這是赤裸裸的欺騙指巡,但是非常有效淑履。如果你想做一個(gè)惡貫滿盈的人,不妨自己發(fā)明一套計(jì)量單位藻雪,用自己或某個(gè)小人物的名字命名這套計(jì)量單位秘噪,但不要給出定義。萬一有人挑刺兒勉耀,你就告訴他們指煎,你這么做是為了把浮點(diǎn)數(shù)運(yùn)算湊成整數(shù)運(yùn)算而進(jìn)行的轉(zhuǎn)換。

永遠(yuǎn)不要記錄代碼中的坑便斥。如果你懷疑某個(gè)類里可能有bug至壤,天知地知你知就好。如果你想到了重構(gòu)或重寫代碼的思路枢纠,看在老天爺?shù)姆萆舷窠郑f別寫出來。切記電影《小鹿斑比》里那句臺詞 “如果你不能說好聽的話晋渺,那就什么也不要說宅广。”些举。萬一這段代碼的原作者看到你的注釋怎么辦跟狱?萬一老板看到了怎么辦?萬一客戶看到了怎么辦户魏?搞不好最后你自己被解雇了驶臊。一句”這里需要修改“的匿名注釋就好多了,尤其是當(dāng)看不清這句注釋指的是哪里需要修改的情況下叼丑。切記“難得糊涂”四個(gè)字关翎,這樣大家都不會感覺受到了批評。

說明變量

永遠(yuǎn)不要對變量聲明加注釋鸠信。有關(guān)變量使用的方式纵寝、邊界值、合法值星立、小數(shù)點(diǎn)后的位數(shù)爽茴、計(jì)量單位葬凳、顯示格式、數(shù)據(jù)錄入規(guī)則等等室奏,后繼者完全可以自己從程序代碼中去理解和整理嘛火焰。如果老板強(qiáng)迫你寫注釋,就在方法體里胡亂多寫點(diǎn)胧沫,但絕對不要對變量聲明寫注釋昌简,即使是臨時(shí)變量!

在注釋里挑撥離間

為了阻撓任何雇傭外部維護(hù)承包商的傾向绒怨,可以在代碼中散布針對其他同行軟件公司的攻擊和抹黑纯赎,特別是可能接替你工作的其中任何一家。例如:

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

/* 優(yōu)化后的內(nèi)層循環(huán)
這套技巧對于SSI軟件服務(wù)公司的那幫蠢材來說太高深了南蹂,他們只會
用 <math.h> 里的笨例程犬金,消耗50倍的內(nèi)存和處理時(shí)間。
*/
class clever_SSInc {
.. .
}

</pre>

可能的話碎紊,除了注釋之外佑附,這些攻擊抹黑的內(nèi)容也要摻到代碼里的重要語義部分樊诺,這樣如果管理層想清理掉這些攻擊性的言論然后發(fā)給外部承包商去維護(hù)仗考,就會破壞代碼結(jié)構(gòu)既琴。

程序設(shè)計(jì)

編寫無法維護(hù)代碼的基本規(guī)則就是:在盡可能多的地方诈泼,以盡可能多的方式表述每一個(gè)事實(shí)枣耀。

– Roedy Green

編寫可維護(hù)代碼的關(guān)鍵因素是只在一個(gè)地方表述應(yīng)用里的一個(gè)事實(shí)垛叨。如果你的想法變了鸵闪,你也只在一個(gè)地方修改翅雏,這樣就能保證整個(gè)程序正常工作撒穷。所以妆绞,編寫無法維護(hù)代碼的關(guān)鍵因素就是反復(fù)地表述同一個(gè)事實(shí)恋沃,在盡可能多的地方必搞,以盡可能多的方式進(jìn)行。令人高興的是囊咏,像Java這樣的語言讓編寫這種無法維護(hù)代碼變得非常容易恕洲。例如,改變一個(gè)被引用很多的變量的類型幾乎是不可能的梅割,因?yàn)樗性煨秃娃D(zhuǎn)換功能都會出錯(cuò)霜第,而且關(guān)聯(lián)的臨時(shí)變量的類型也不合適了。而且户辞,如果變量值要在屏幕上顯示泌类,那么所有相關(guān)的顯示和數(shù)據(jù)錄入代碼都必須一一找到并手工進(jìn)行修改。類似的還有很多底燎,比如由C和Java組成的Algol語言系列刃榨,Abundance甚至Smalltalk對于數(shù)組等結(jié)構(gòu)的處理弹砚,都是大有可為的。

Java 造型

Java的造型機(jī)制是上帝的禮物喇澡。你可以問心無愧地使用它迅栅,因?yàn)镴ava語言本身就需要它。每次你從一個(gè)Collection 里獲取一個(gè)對象晴玖,你都必須把它造型為原始類型读存。這樣這個(gè)變量的類型就必須在無數(shù)地方表述。如果后來類型變了呕屎,所有的造型都要修改才能匹配让簿。如果倒霉的維護(hù)代碼的程序員沒有找全(或者修改太多),編譯器能不能檢測到也不好說秀睛。類似的尔当,如果變量類型從short 變成 int,所有匹配的造型也都要從(short) 改成 (int)蹂安。

利用Java的冗余

Java要求你給每個(gè)變量的類型寫兩次表述椭迎。 Java 程序員已經(jīng)習(xí)慣了這種冗余,他們不會注意到你的兩次表述有細(xì)微的差別田盈,例如

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

Bubblegum b = new Bubblegom();

</pre>

不幸的是 ++ 操作符的盛行讓下面這種偽冗余代碼得手的難度變大了:

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

swimmer = swimner + 1;

</pre>

永遠(yuǎn)不做校驗(yàn)

永遠(yuǎn)不要對輸入數(shù)據(jù)做任何的正確性或差異性檢查畜号。這樣能表現(xiàn)你對公司設(shè)備的絕對信任,以及你是一位信任所有項(xiàng)目伙伴和系統(tǒng)管理員的團(tuán)隊(duì)合作者允瞧〖蛉恚總是返回合理的值,即使數(shù)據(jù)輸入有問題或者錯(cuò)誤述暂。

有禮貌痹升,無斷言

避免使用 assert() 機(jī)制,因?yàn)樗赡馨讶斓膁ebug盛宴變成10分鐘的快餐畦韭。

避免封裝

為了提高效率疼蛾,不要使用封裝。方法的調(diào)用者需要所有能得到的外部信息艺配,以便了解方法的內(nèi)部是如何工作的察郁。

復(fù)制粘貼修改

以效率的名義,使用 復(fù)制+粘貼+修改妒挎。這樣比寫成小型可復(fù)用模塊效率高得多绳锅。在用代碼行數(shù)衡量你的進(jìn)度的小作坊里,這招尤其管用酝掩。

使用靜態(tài)數(shù)組

如果一個(gè)庫里的模塊需要一個(gè)數(shù)組來存放圖片鳞芙,就定義一個(gè)靜態(tài)數(shù)組。沒人會有比512 X 512 更大的圖片,所以固定大小的數(shù)組就可以了原朝。為了最佳精度驯嘱,就把它定義成 double 類型的數(shù)組。

傻瓜接口

編寫一個(gè)名為 “WrittenByMe” 之類的空接口喳坠,然后讓你的所有類都實(shí)現(xiàn)它鞠评。然后給所有你用到的Java 內(nèi)置類編寫包裝類。這里的思想是確保你程序里的每個(gè)對象都實(shí)現(xiàn)這個(gè)接口壕鹉。最后剃幌,編寫所有的方法,讓它們的參數(shù)和返回類型都是這個(gè) WrittenByMe晾浴。這樣就幾乎不可能搞清楚某個(gè)方法的功能是什么负乡,并且所有類型都需要好玩的造型方法。更出格的玩法是脊凰,讓每個(gè)團(tuán)隊(duì)成員編寫它們自己的接口(例如 WrittenByJoe)抖棘,程序員用到的任何類都要實(shí)現(xiàn)他自己的接口。這樣你就可以在大量無意義接口中隨便找一個(gè)來引用對象了狸涌。

巨型監(jiān)聽器

永遠(yuǎn)不要為每個(gè)組件創(chuàng)建分開的監(jiān)聽器切省。對所有按鈕總是用同一個(gè)監(jiān)聽器,只要用大量的if…else 來判斷是哪一個(gè)按鈕被點(diǎn)擊就行了帕胆。

好事成堆TM

狂野地使用封裝和OO思想朝捆。例如

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

myPanel.add( getMyButton() );
private JButton getMyButton() {
return myButton;
}

</pre>

這段很可能看起來不怎么好笑。別擔(dān)心惶楼,只是時(shí)候未到而已右蹦。

友好的朋友

在C++ 里盡量多使用friend聲明诊杆。再把創(chuàng)建類的指針傳遞給已創(chuàng)建類〖呔瑁現(xiàn)在你不用浪費(fèi)時(shí)間去考慮接口了。另外晨汹,你應(yīng)該用上關(guān)鍵字private 和 protected 來表明你的類封裝得很好豹储。

使用三維數(shù)組

大量使用它們。用扭曲的方式在數(shù)組之間移動(dòng)數(shù)據(jù)淘这,比如剥扣,用arrayA里的行去填充arrayB的列。這么做的時(shí)候铝穷,不管三七二十一再加上1的偏移值钠怯,這樣很靈。讓維護(hù)代碼的程序員抓狂去吧曙聂。

混合與匹配

存取方法和公共變量神馬的都要給他用上晦炊。這樣的話,你無需調(diào)用存取器的開銷就可以修改一個(gè)對象的變量,還能宣稱這個(gè)類是個(gè)”Java Bean”断国。對于那些試圖添加日志函數(shù)來找出改變值的源頭的維護(hù)代碼的程序員贤姆,用這一招來迷惑他尤其有效。

沒有秘密!

把每個(gè)方法和變量都聲明為 public稳衬。畢竟某個(gè)人某天可能會需要用到它霞捡。一旦方法被聲明為public 了,就很難縮回去薄疚。對不碧信?這樣任何它覆蓋到的代碼都很難修改了。它還有個(gè)令人愉快的副作用街夭,就是讓你看不清類的作用是什么音婶。如果老板質(zhì)問你是不是瘋了,你就告訴他你遵循的是經(jīng)典的透明接口原則莱坎。

全堆一塊

把你所有的沒用的和過時(shí)的方法和變量都留在代碼里衣式。畢竟說起來,既然你在1976年用過一次檐什,誰知道你啥時(shí)候會需要再用到呢碴卧?當(dāng)然程序是改了,但它也可能會改回來嘛乃正,你”不想要重新發(fā)明輪子”(領(lǐng)導(dǎo)們都會喜歡這樣的口氣)住册。如果你還原封不動(dòng)地留著這些方法和變量的注釋,而且注釋寫得又高深莫測瓮具,甭管維護(hù)代碼的是誰荧飞,恐怕都不敢對它輕舉妄動(dòng)。

就是 Final

把你所有的葉子類都聲明為 final名党。畢竟說起來叹阔,你在項(xiàng)目里的活兒都干完了,顯然不會有其他人會通過擴(kuò)展你的類來改進(jìn)你的代碼传睹。這種情況甚至可能有安全漏洞耳幢。 java.lang.String 被定義成 final 也許就是這個(gè)原因吧?如果項(xiàng)目組其他程序員有意見欧啤,告訴他們這樣做能夠提高運(yùn)行速度睛藻。

避免布局

永遠(yuǎn)不要用到布局。當(dāng)維護(hù)代碼的程序員想增加一個(gè)字段邢隧,他必須手工調(diào)整屏幕上顯示所有內(nèi)容的絕對坐標(biāo)值店印。如果老板強(qiáng)迫你使用布局,那就寫一個(gè)巨型的 GridBagLayout 并在里面用絕對坐標(biāo)進(jìn)行硬編碼倒慧。

全局變量按摘,怎么強(qiáng)調(diào)都不過分

如果上帝不愿意我們使用全局變量讥邻,他就不會發(fā)明出這個(gè)東西。不要讓上帝失望院峡,盡量多使用全局變量兴使。每個(gè)函數(shù)最起碼都要使用和設(shè)置其中的兩個(gè),即使沒有理由也要這么做照激。畢竟发魄,任何優(yōu)秀的維護(hù)代碼的程序員都會很快搞清楚這是一種偵探工作測試,有利于讓他們從笨蛋中脫穎而出俩垃。

再一次說說全局變量

全局變量讓你可以省去在函數(shù)里描述參數(shù)的麻煩励幼。充分利用這一點(diǎn)。在全局變量中選那么幾個(gè)來表示對其他全局變量進(jìn)行操作的類型口柳。

局部變量

永遠(yuǎn)不要用局部變量苹粟。在你感覺想要用的時(shí)候,把它改成一個(gè)實(shí)例或者靜態(tài)變量跃闹,并無私地和其他方法分享它嵌削。這樣做的好處是,你以后在其他方法里寫類似聲明的時(shí)候會節(jié)省時(shí)間望艺。C++程序員可以百尺竿頭更進(jìn)一步苛秕,把所有變量都弄成全局的。

配置文件

配置文件通常是以 關(guān)鍵字 = 值 的形式出現(xiàn)找默。在加載時(shí)這些值被放入 Java 變量中艇劫。最明顯的迷惑技術(shù)就是把有細(xì)微差別的名字用于關(guān)鍵字和Java 變量.甚至可以在配置文件里定義運(yùn)行時(shí)根本不會改變的常量。參數(shù)文件變量和簡單變量比惩激,維護(hù)它的代碼量起碼是后者的5倍店煞。

子類

對于編寫無法維護(hù)代碼的任務(wù)來說,面向?qū)ο缶幊痰乃枷牒喼笔翘熨n之寶风钻。如果你有一個(gè)類顷蟀,里邊有10個(gè)屬性(成員/方法),可以考慮寫一個(gè)基類魄咕,里面只有一個(gè)屬性衩椒,然后產(chǎn)生9層的子類蚌父,每層增加一個(gè)屬性哮兰。等你訪問到最終的子類時(shí),你才能得到全部10個(gè)屬性苟弛。如果可能喝滞,把每個(gè)類的聲明都放在不同的文件里。

編碼迷局

迷惑 C

從互聯(lián)網(wǎng)上的各種混亂C 語言競賽中學(xué)習(xí)膏秫,追隨大師們的腳步右遭。

追求極致

總是追求用最迷惑的方式來做普通的任務(wù)。例如,要用數(shù)組來把整數(shù)轉(zhuǎn)換為相應(yīng)的字符串窘哈,可以這么做:

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

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

</pre>

一致性的小淘氣

當(dāng)你需要一個(gè)字符常量的時(shí)候吹榴,可以用多種不同格式: ‘ ‘, 32, 0x20, 040。在C或Java里10和010是不同的數(shù)(0開頭的表示8進(jìn)制)滚婉,你也可以充分利用這個(gè)特性图筹。

造型

把所有數(shù)據(jù)都以 void * 形式傳遞,然后再造型為合適的結(jié)構(gòu)让腹。不用結(jié)構(gòu)而是通過位移字節(jié)數(shù)來造型也很好玩远剩。

嵌套 Switch

Switch 里邊還有 Switch,這種嵌套方式是人類大腦難以破解的骇窍。

利用隱式轉(zhuǎn)化

牢記編程語言中所有的隱式轉(zhuǎn)化細(xì)節(jié)瓜晤。充分利用它們。數(shù)組的索引要用浮點(diǎn)變量腹纳,循環(huán)計(jì)數(shù)器用字符痢掠,對數(shù)字執(zhí)行字符串函數(shù)調(diào)用。不管怎么說嘲恍,所有這些操作都是合法的志群,它們無非是讓源代碼更簡潔而已。任何嘗試?yán)斫馑鼈兊木S護(hù)者都會對你感激不盡蛔钙,因?yàn)樗麄儽仨氶喿x和學(xué)習(xí)整個(gè)關(guān)于隱式數(shù)據(jù)類型轉(zhuǎn)化的章節(jié)锌云,而這個(gè)章節(jié)很可能是他們來維護(hù)你的代碼之前完全忽略了的。

分號!

在所有語法允許的地方都加上分號吁脱,例如:

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

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

</pre>

使用八進(jìn)制數(shù)

把八進(jìn)制數(shù)混到十進(jìn)制數(shù)列表里桑涎,就像這樣:

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

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

</pre>

嵌套

盡可能深地嵌套。優(yōu)秀的程序員能在一行代碼里寫10層()兼贡,在一個(gè)方法里寫20層{}攻冷。

C數(shù)組

C編譯器會把 myArray[i] 轉(zhuǎn)換成 *(myArray + i),它等同于 *(i + myArray) 也等同于 i[myArray]遍希。 高手都知道怎么用好這個(gè)招等曼。可以用下面的函數(shù)來產(chǎn)生索引凿蒜,這樣就把代碼搞亂了:

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

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

</pre>

遺憾的是禁谦,這一招只能在本地C類里用,Java 還不行废封。

放長線釣大魚

一行代碼里堆的東西越多越好州泊。這樣可以省下臨時(shí)變量的開銷,去掉換行和空格還可以縮短源文件大小漂洋。記住遥皂,要去掉運(yùn)算符兩邊的空格力喷。優(yōu)秀的程序員總是能突破某些編輯器對于255個(gè)字符行寬的限制。

異常

在這里我要向你傳授一個(gè)編程領(lǐng)域里鮮為人知的秘訣演训。異常是個(gè)討厭的東西弟孟。良好的代碼永遠(yuǎn)不會出錯(cuò),所以異常實(shí)際上是不必要的样悟。不要把時(shí)間浪費(fèi)在這上面披蕉。子類異常是給那些知道自己代碼會出錯(cuò)的低能兒用的。在整個(gè)應(yīng)用里乌奇,你只用在main()里放一個(gè)try/catch没讲,里邊直接調(diào)用 System.exit()就行了。在每個(gè)方法頭要貼上標(biāo)準(zhǔn)的拋出集合定義礁苗,至于會不會拋出異常你就甭管了爬凑。

使用異常的時(shí)機(jī)

在非異常條件下才要使用異常。比如終止循環(huán)就可以用 ArrayIndexOutOfBoundsException试伙。還可以從異常里的方法返回標(biāo)準(zhǔn)的結(jié)果嘁信。

狂熱奔放地使用線程

如題。

測試

在程序里留些bug疏叨,讓后繼的維護(hù)代碼的程序員能做點(diǎn)有意思的事潘靖。精心設(shè)計(jì)的bug是無跡可尋的,而且誰也不知道它啥時(shí)候會冒出來蚤蔓。要做到這一點(diǎn)卦溢,最簡單的辦法的就是不要測試代碼。

永不測試

永遠(yuǎn)不要測試負(fù)責(zé)處理錯(cuò)誤秀又、當(dāng)機(jī)或操作系統(tǒng)故障的任何代碼单寂。反正這些代碼永遠(yuǎn)也不會執(zhí)行,只會拖累你的測試吐辙。還有宣决,你怎么可能測試處理磁盤錯(cuò)誤、文件讀取錯(cuò)誤昏苏、操作系統(tǒng)崩潰這些類型的事件呢尊沸?為啥你要用特別不穩(wěn)定的計(jì)算機(jī)或者用測試腳手架來模擬這樣的環(huán)境?現(xiàn)代化的硬件永遠(yuǎn)不會崩潰贤惯,誰還愿意寫一些僅僅用于測試的代碼洼专?這一點(diǎn)也不好玩。萬一將來出了事用戶抱怨救巷,你就怪到操作系統(tǒng)或者硬件頭上壶熏。他們永遠(yuǎn)不會知道真相的。

永遠(yuǎn)不要做性能測試

嘿浦译,如果軟件運(yùn)行不夠快棒假,只要告訴客戶買個(gè)更快的機(jī)器就行了。如果你真的做了性能測試精盅,你可能會發(fā)現(xiàn)一個(gè)瓶頸帽哑,這會導(dǎo)致修改算法,然后導(dǎo)致整個(gè)產(chǎn)品要重新設(shè)計(jì)叹俏。誰想要這種結(jié)果妻枕?而且,在客戶那邊發(fā)現(xiàn)性能問題意味著你可以免費(fèi)到外地旅游粘驰。你只要備好護(hù)照和最新照片就行了屡谐。

永遠(yuǎn)不要寫任何測試用例

永遠(yuǎn)不要做代碼覆蓋率或路徑覆蓋率測試。自動(dòng)化測試是給那些窩囊廢用的蝌数。搞清楚哪些特性占到你的例程使用率的90%愕掏,然后把90%的測試用在這些路徑上。畢竟說起來顶伞,這種方法可能只測試到了大約你代碼的60%饵撑,這樣你就節(jié)省了40%的測試工作。這能幫助你趕上項(xiàng)目后端的進(jìn)度唆貌。等到有人發(fā)現(xiàn)所有這些漂亮的“市場特性”不能正常工作的時(shí)候滑潘,你早就跑路了。一些有名的大軟件公司就是這樣測試代碼的锨咙,所以你也應(yīng)該這樣做语卤。如果因?yàn)槟撤N原因你還沒走,那就接著看下一節(jié)酪刀。

測試是給懦夫用的

勇敢的程序員會跳過這個(gè)步驟粱侣。太多程序員害怕他們的老板,害怕丟掉工作蓖宦,害怕客戶的投訴郵件齐婴,害怕遭到起訴。這種恐懼心理麻痹了行動(dòng)稠茂,降低了生產(chǎn)率柠偶。有科學(xué)研究成果表明,取消測試階段意味著經(jīng)理有把握能提前確定交付時(shí)間睬关,這對于規(guī)劃流程顯然是有利的诱担。消除了恐懼心理,創(chuàng)新和實(shí)驗(yàn)之花就隨之綻放电爹。程序員的角色是生產(chǎn)代碼蔫仙,調(diào)試工作完全可以由技術(shù)支持和遺留代碼維護(hù)組通力合作來進(jìn)行。

如果我們對自己的編程能力有充分信心丐箩,那么測試就沒有必要了摇邦。如果我們邏輯地看待這個(gè)問題恤煞,隨便一個(gè)傻瓜都能認(rèn)識到測試根本都不是為了解決技術(shù)問題,相反施籍,它是一種感性的信心問題居扒。針對這種缺乏信心的問題,更有效的解決辦法就是完全取消測試丑慎,送我們的程序員去參加自信心培訓(xùn)課程喜喂。畢竟說起來,如果我們選擇做測試竿裂,那么我們就要測試每個(gè)程序的變更玉吁,但其實(shí)我們只需要送程序員去一次建立自信的培訓(xùn)課就行了。很顯然這么做的成本收益是相當(dāng)可觀的腻异。

編程語言的選擇

計(jì)算機(jī)語言正在逐步進(jìn)化进副,變得更加傻瓜化。使用最新的語言算什么好漢捂掰?盡可能堅(jiān)持使用你會用的最老的語言敢会,先考慮用穿孔紙帶,不行就用匯編这嚣,再不行用FORTRAN 或者 COBOL鸥昏,再不行就用C 還有 BASIC,實(shí)在不行再用 C++姐帚。

FORTRAN

用 FORTRAN 寫所有的代碼吏垮。如果老板問你為啥,你可以回答說它有很多非常有用的庫罐旗,你用它可以節(jié)約時(shí)間膳汪。不過,用 FORTRAN 寫出可維護(hù)代碼的概率是 0九秀,所以遗嗽,要達(dá)到不可維護(hù)代碼編程指南里的要求就容易多了。

用 ASM

把所有的通用工具函數(shù)都轉(zhuǎn)成匯編程序鼓蜒。

用 QBASIC

所有重要的庫函數(shù)都要用 QBASIC 寫痹换,然后再寫個(gè)匯編的封包程序來處理 large 到 medium 的內(nèi)存模型映射。

內(nèi)聯(lián)匯編

在你的代碼里混雜一些內(nèi)聯(lián)的匯編程序都弹,這樣很好玩娇豫。這年頭幾乎沒人懂匯編程序了。只要放幾行匯編代碼就能讓維護(hù)代碼的程序員望而卻步畅厢。

宏匯編調(diào)用C

如果你有個(gè)匯編模塊被C調(diào)用冯痢,那就盡可能經(jīng)常從匯編模塊再去調(diào)用C,即使只是出于微不足道的用途,另外要充分利用 goto, bcc 和其他炫目的匯編秘籍浦楣。

與他人共事之道

老板才是真行家

如果你的老板認(rèn)為他20年的 FORTRAN 編程經(jīng)驗(yàn)對于現(xiàn)代軟件開發(fā)具有很高的指導(dǎo)價(jià)值袖肥,你務(wù)必嚴(yán)格采納他的所有建議。投桃報(bào)李椒振,你的老板也會信任你昭伸。這會對你的職業(yè)發(fā)展有利梧乘。你還會從他那里學(xué)到很多搞亂程序代碼的新方法澎迎。

顛覆技術(shù)支持

確保代碼中到處是bug的有效方法是永遠(yuǎn)不要讓維護(hù)代碼的程序員知道它們。這需要顛覆技術(shù)支持工作选调。永遠(yuǎn)不接電話夹供。使用自動(dòng)語音答復(fù)“感謝撥打技術(shù)支持熱線。需要人工服務(wù)請按1仁堪,或在嘀聲后留言哮洽。”弦聂,請求幫助的電子郵件必須忽略鸟辅,不要給它分配服務(wù)追蹤號。對任何問題的標(biāo)準(zhǔn)答復(fù)是“我估計(jì)你的賬戶被鎖定了莺葫,有權(quán)限幫你恢復(fù)的人現(xiàn)在不在匪凉。”

沉默是金

永遠(yuǎn)不要對下一個(gè)危機(jī)保持警覺捺檬。如果你預(yù)見到某個(gè)問題可能會在一個(gè)固定時(shí)間爆發(fā)再层,摧毀西半球的全部生命,不要公開討論它堡纬。不要告訴朋友聂受、同事或其他你認(rèn)識的有本事的人。在任何情況下都不要發(fā)表任何可能暗示到這種新的威脅的內(nèi)容烤镐。只發(fā)送一篇正常優(yōu)先級的蛋济、語焉不詳?shù)膫渫浗o管理層,保護(hù)自己免遭秋后算賬炮叶。如果可能的話碗旅,把這篇稀里糊涂的信息作為另外一個(gè)更緊急的業(yè)務(wù)問題的附件。這樣就可以心安理得地休息了悴灵,你知道將來你被強(qiáng)制提前退休之后一段時(shí)間扛芽,他們又會求著你回來,并給你對數(shù)級增長的時(shí)薪积瞒!

每月一書俱樂部

加入一個(gè)計(jì)算機(jī)每月一書俱樂部川尖。選擇那些看上去忙著寫書不可能有時(shí)間真的去寫代碼的作者。去書店里找一些有很多圖表但是沒有代碼例子的書茫孔。瀏覽一下這些書叮喳,從中學(xué)會一些迂腐拗口的術(shù)語被芳,用它們就能唬住那些自以為是的維護(hù)代碼的程序員。你的代碼肯定會給他留下深刻印象馍悟。如果人們連你寫的術(shù)語都理解不了畔濒,他們一定會認(rèn)為你非常聰明,你的算法非常深?yuàn)W锣咒。不要在你的算法說明里作任何樸素的類比侵状。

自立門戶

你一直想寫系統(tǒng)級的代碼。現(xiàn)在機(jī)會來了毅整。忽略標(biāo)準(zhǔn)庫趣兄, 編寫你自己的標(biāo)準(zhǔn),這將會是你簡歷中的一大亮點(diǎn)悼嫉。

推出你自己的 BNF 范式

總是用你自創(chuàng)的艇潭、獨(dú)一無二的、無文檔的BNF范式記錄你的命令語法戏蔑。永遠(yuǎn)不要提供一套帶注解的例子(合法命令和非法命令之類)來解釋你的語法體系蹋凝。那樣會顯得完全缺乏學(xué)術(shù)嚴(yán)謹(jǐn)性。確保沒有明顯的方式來區(qū)分終結(jié)符和中間符號总棵。永遠(yuǎn)不要用字體鳍寂、顏色、大小寫和其他任何視覺提示幫助讀者分辨它們彻舰。在你的 BNF 范式用和命令語言本身完全一樣的標(biāo)點(diǎn)符號伐割,這樣讀者就永遠(yuǎn)無法分清一段 (…), […], {…} 或 “…” 到底是你在命令行里真正輸入的,還是想提示在你的BNF 范式里哪個(gè)語法元素是必需的刃唤、可重復(fù)的隔心、或可選的。不管怎么樣尚胞,如果他們太笨硬霍,搞不清你的BNF 范式的變化,就沒資格使用你的程序笼裳。

推出你自己的內(nèi)存分配

地球人兒都知道唯卖,調(diào)試動(dòng)態(tài)存儲是復(fù)雜和費(fèi)時(shí)的。與其逐個(gè)類去確認(rèn)它沒有內(nèi)存溢出躬柬,還不如自創(chuàng)一套存儲分配機(jī)制呢拜轨。其實(shí)它無非是從一大片內(nèi)存中 malloc 一塊空間而已。用不著釋放內(nèi)存允青,讓用戶定期重啟動(dòng)系統(tǒng)橄碾,這樣不就清除了堆么。重啟之后系統(tǒng)需要追蹤的就那么一點(diǎn)東西,比起解決所有的內(nèi)存泄露簡單得不知道到哪里去了法牲!而且史汗,只要用戶記得定期重啟系統(tǒng),他們也永遠(yuǎn)不會遇到堆空間不足的問題拒垃。一旦系統(tǒng)被部署停撞,你很難想象他們還能改變這個(gè)策略。

其他雜七雜八的招

*如果你給某人一段程序悼瓮,你會讓他困惑一天戈毒;如果你教他們?nèi)绾尉幊蹋銜屗Щ笠惠呑印?*

— Anonymous

不要重編譯 讓我們從一條可能是有史以來最友好的技巧開始:把代碼編譯成可執(zhí)行文件谤牡。如果它能用副硅,就在源代碼里做一兩個(gè)微小的改動(dòng) — 每個(gè)模塊都照此辦理姥宝。但是不要費(fèi)勁巴拉地再編譯一次了翅萤。 你可以留著等以后有空而且需要調(diào)試的時(shí)候再說。多年以后腊满,等可憐的維護(hù)代碼的程序員更改了代碼之后發(fā)現(xiàn)出錯(cuò)了套么,他會有一種錯(cuò)覺,覺得這些肯定是他自己最近修改的碳蛋。這樣你就能讓他毫無頭緒地忙碌很長時(shí)間胚泌。

挫敗調(diào)試工具 對于試圖用行調(diào)試工具追蹤來看懂你的代碼的人,簡單的一招就能讓他狼狽不堪肃弟,那就是把每一行代碼都寫得很長玷室。特別要把 then 語句 和 if 語句放在同一行里。他們無法設(shè)置斷點(diǎn)笤受。他們也無法分清在看的分支是哪個(gè) if 里的穷缤。

公制和美制 在工程方面有兩種編碼方式。一種是把所有輸入都轉(zhuǎn)換為公制(米制)計(jì)量單位箩兽,然后在輸出的時(shí)候自己換算回各種民用計(jì)量單位津肛。另一種是從頭到尾都保持各種計(jì)量單位混合在一起『蛊叮總是選擇第二種方式身坐,這就是美國之道!

持續(xù)改進(jìn) 要持續(xù)不懈地改進(jìn)落包。要常常對你的代碼做出“改進(jìn)”部蛇,并強(qiáng)迫用戶經(jīng)常升級 — 畢竟沒人愿意用一個(gè)過時(shí)的版本嘛。即便他們覺得他們對現(xiàn)有的程序滿意了咐蝇,想想看涯鲁,如果他們看到你又“完善“了它,他們會多么開心颁潭怼归苍!不要告訴任何人版本之間的差別,除非你被逼無奈 — 畢竟镜粤,為什么要告訴他們本來永遠(yuǎn)也不會注意到的一些bug呢幢踏?

“關(guān)于” ”關(guān)于“一欄應(yīng)該只包含程序名髓需、程序員姓名和一份用法律用語寫的版權(quán)聲明。理想情況下房蝉,它還應(yīng)該鏈接到幾 MB 的代碼僚匆,產(chǎn)生有趣的動(dòng)畫效果。但是搭幻,里邊永遠(yuǎn)不要包含程序用途的描述咧擂、它的版本號、或最新代碼修改日期檀蹋、或獲取更新的網(wǎng)站地址松申、或作者的email地址等。這樣俯逾,所有的用戶很快就會運(yùn)行在各種不同的版本上贸桶,在安裝N+1版之前就試圖安裝N+2版。

變更 在兩個(gè)版本之間桌肴,你能做的變更自然是多多益善皇筛。你不會希望用戶年復(fù)一年地面對同一套老的接口或用戶界面,這樣會很無聊坠七。最后水醋,如果你能在用戶不注意的情況下做出這些變更,那就更好了 — 這會讓他們保持警惕彪置,戒驕戒躁拄踪。

無需技能 寫無法維護(hù)代碼不需要多高的技術(shù)水平。喊破嗓子不如甩開膀子悉稠,不管三七二十一開始寫代碼就行了宫蛆。記住,管理層還在按代碼行數(shù)考核生產(chǎn)率的猛,即使以后這些代碼里的大部分都得刪掉耀盗。

只帶一把錘子 一招鮮吃遍天,會干什么就吆喝什么卦尊,輕裝前進(jìn)叛拷。如果你手頭只有一把錘子,那么所有的問題都是釘子岂却。

規(guī)范體系 有可能的話忿薇,忽略當(dāng)前你的項(xiàng)目所用語言和環(huán)境中被普羅大眾所接受的編程規(guī)范裙椭。比如,編寫基于MFC 的應(yīng)用時(shí)署浩,就堅(jiān)持使用STL 編碼風(fēng)格揉燃。

翻轉(zhuǎn)通常的 True False 慣例 把常用的 true 和 false 的定義反過來用。這一招聽起來平淡無奇筋栋,但是往往收獲奇效炊汤。你可以先藏好下面的定義:

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

define TRUE 0

define FALSE 1

</pre>

把這個(gè)定義深深地藏在代碼中某個(gè)沒人會再去看的文件里不易被發(fā)現(xiàn)的地方,然后讓程序做下面這樣的比較

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

if ( var == TRUE )
if ( var != FALSE )

</pre>

某些人肯定會迫不及待地跳出來“修正”這種明顯的冗余弊攘,并且在其他地方照著常規(guī)去使用變量var:

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

if ( var )

</pre>

還有一招是為 TRUE 和 FALSE賦予相同的值抢腐,雖然大部分人可能會看穿這種騙局。給它們分別賦值 1 和 2 或者 -1 和 0 是讓他們瞎忙乎的方式里更精巧的襟交,而且這樣做看起來也不失對他們的尊重迈倍。你在Java 里也可以用這一招,定義一個(gè)叫 TRUE 的靜態(tài)常量捣域。在這種情況下啼染,其他程序員更有可能懷疑你干的不是好事,因?yàn)镴ava里已經(jīng)有了內(nèi)建的標(biāo)識符 true竟宋。

第三方庫 在你的項(xiàng)目里引入功能強(qiáng)大的第三方庫提完,然后不要用它們。潛規(guī)則就是這樣丘侠,雖然你對這些工具仍然一無所知,卻可以在你簡歷的“其他工具”一節(jié)中寫上這些沒用過的庫逐样。

不要用庫 假裝不知道有些庫已經(jīng)直接在你的開發(fā)工具中引入了蜗字。如果你用VC++編程,忽略MFC 或 STL 的存在脂新,手工編寫所有字符串和數(shù)組的實(shí)現(xiàn)挪捕;這樣有助于保持你玩指針技術(shù)的高水平,并自動(dòng)阻止任何擴(kuò)展代碼功能的企圖争便。

創(chuàng)建一套Build順序 把這套順序規(guī)則做得非臣读悖晦澀,讓維護(hù)者根本無法編譯任何他的修改代碼滞乙。秘密保留 SmartJ 奏纪,它會讓 make腳本形同廢物。類似地斩启,偷偷地定義一個(gè) javac 類序调,讓它和編譯程序同名。說到大招兔簇,那就是編寫和維護(hù)一個(gè)定制的小程序发绢,在程序里找到需要編譯的文件硬耍,然后通過直接調(diào)用 sun.tools.javac.Main 編譯類來進(jìn)行編譯。

Make 的更多玩法 用一個(gè) makefile-generated-batch-file 批處理文件從多個(gè)目錄復(fù)制源文件边酒,文件之間的覆蓋規(guī)則在文檔中是沒有的经柴。這樣,無需任何炫酷的源代碼控制系統(tǒng)墩朦,就能實(shí)現(xiàn)代碼分支口锭,并阻止你的后繼者弄清哪個(gè)版本的 DoUsefulWork() 才是他需要修改的那個(gè)。

搜集編碼規(guī)范 盡可能搜集所有關(guān)于編寫可維護(hù)代碼的建議介杆,例如 SquareBox 的建議 鹃操,然后明目張膽地違反它們。

規(guī)避公司的編碼規(guī)則 某些公司有嚴(yán)格的規(guī)定春哨,不允許使用數(shù)字標(biāo)識符荆隘,你必須使用預(yù)先命名的常量。要挫敗這種規(guī)定背后的意圖太容易了赴背。比如椰拒,一位聰明的 C++ 程序員是這么寫的:

define K_ONE 1

define K_TWO 2

define K_THOUSAND 999

編譯器警告

一定要保留一些編譯器警告。在 make 里使用 “-” 前綴強(qiáng)制執(zhí)行凰荚,忽視任何編譯器報(bào)告的錯(cuò)誤燃观。這樣,即使維護(hù)代碼的程序員不小心在你的源代碼里造成了一個(gè)語法錯(cuò)誤便瑟,make 工具還是會重新把整個(gè)包build 一遍缆毁,甚至可能會成功!而任何程序員要是手工編譯你的代碼到涂,看到屏幕上冒出一堆其實(shí)無關(guān)緊要的警告脊框,他們肯定會覺得是自己搞壞了代碼。同樣践啄,他們一定會感謝你讓他們有找錯(cuò)的機(jī)會浇雹。學(xué)有余力的同學(xué)可以做點(diǎn)手腳讓編譯器在打開編譯錯(cuò)誤診斷工具時(shí)就沒法編譯你的程序。當(dāng)然了屿讽,編譯器也許能做一些腳本邊界檢查昭灵,但是真正的程序員是不用這些特性的,所以你也不該用伐谈。既然你用自己的寶貴時(shí)間就能找到這些精巧的bug烂完,何必還多此一舉讓編譯器來檢查錯(cuò)誤呢?

把 bug 修復(fù)和升級混在一起 永遠(yuǎn)不要發(fā)布什么“bug 修復(fù)”版本衩婚。一定要把 bug 修復(fù)和數(shù)據(jù)庫結(jié)構(gòu)變更窜护、復(fù)雜的用戶界面修改,還有管理界面重寫等混在一起非春。那樣的話柱徙,升級就變成一件非常困難的事情缓屠,人們會慢慢習(xí)慣 bug 的存在并開始稱他們?yōu)樘匦浴D切┱嫘南M淖冞@些”特性“的人們就會有動(dòng)力升級到新版本护侮。這樣從長期來說可以節(jié)省你的維護(hù)工作量敌完,并從你的客戶那里獲得更多收入。

在你的產(chǎn)品發(fā)布每個(gè)新版本的時(shí)候都改變文件結(jié)構(gòu) 沒錯(cuò)羊初,你的客戶會要求向上兼容滨溉,那就去做吧。不過一定要確保向下是不兼容的长赞。這樣可以阻止客戶從新版本回退晦攒,再配合一套合理的 bug 修復(fù)規(guī)則(見上一條),就可以確保每次新版本發(fā)布后得哆,客戶都會留在新版本脯颜。學(xué)有余力的話,還可以想辦法讓舊版本壓根無法識別新版本產(chǎn)生的文件贩据。那樣的話栋操,老版本系統(tǒng)不但無法讀取新文件,甚至?xí)裾J(rèn)這些文件是自己的應(yīng)用系統(tǒng)產(chǎn)生的饱亮!溫馨提示:PC 上的 Word 文字處理軟件就典型地精于此道矾芙。

抵消 Bug 不用費(fèi)勁去代碼里找 bug 的根源。只要在更高級的例程里加入一些抵銷它的代碼就行了近上。這是一種很棒的智力測驗(yàn)剔宪,類似于玩3D棋,而且能讓將來的代碼維護(hù)者忙乎很長時(shí)間都想不明白問題到底出在哪里:是產(chǎn)生數(shù)據(jù)的低層例程戈锻,還是莫名其妙改了一堆東西的高層代碼歼跟。這一招對天生需要多回合執(zhí)行的編譯器也很好用。你可以在較早的回合完全避免修復(fù)問題格遭,讓較晚的回合變得更加復(fù)雜。如果運(yùn)氣好留瞳,你永遠(yuǎn)都不用和編譯器前端打交道拒迅。學(xué)有余力的話,在后端做點(diǎn)手腳她倘,一旦前端產(chǎn)生的是正確的數(shù)據(jù)璧微,就讓后端報(bào)錯(cuò)。

使用旋轉(zhuǎn)鎖 不要用真正的同步原語硬梁,多種多樣的旋轉(zhuǎn)鎖更好 — 反復(fù)休眠然后測試一個(gè)(non-volatile的) 全局變量前硫,直到它符合你的條件為止。相比系統(tǒng)對象荧止,旋轉(zhuǎn)鎖使用簡便屹电,”通用“性強(qiáng)阶剑,”靈活“多變,實(shí)為居家旅行必備危号。

隨意安插 sync 代碼 把某些系統(tǒng)同步原語安插到一些用不著它們的地方牧愁。本人曾經(jīng)在一段不可能會有第二個(gè)線程的代碼中看到一個(gè)臨界區(qū)(critical section)代碼。本人當(dāng)時(shí)就質(zhì)問寫這段代碼的程序員外莲,他居然理直氣壯地說這么寫是為了表明這段代碼是很”關(guān)鍵“(單詞也是critical)的猪半!

優(yōu)雅降級 如果你的系統(tǒng)包含了一套 NT 設(shè)備驅(qū)動(dòng),就讓應(yīng)用程序負(fù)責(zé)給驅(qū)動(dòng)分配 I/O 緩沖區(qū)偷线,然后在任何事務(wù)過程中對內(nèi)存中的驅(qū)動(dòng)加鎖磨确,并在事務(wù)完成后釋放或解鎖。這樣一旦應(yīng)用非正常終止声邦,I/O緩存又沒有被解鎖乏奥,NT服務(wù)器就會當(dāng)機(jī)。但是在客戶現(xiàn)場不太可能會有人知道怎么弄好設(shè)備驅(qū)動(dòng)翔忽,所以他們就沒有選擇(只能請你去免費(fèi)旅游了)英融。

定制腳本語言 在你的 C/S 應(yīng)用里嵌入一個(gè)在運(yùn)行時(shí)按字節(jié)編譯的腳本命令語言。

依賴于編譯器的代碼 如果你發(fā)現(xiàn)在你的編譯器或解釋器里有個(gè)bug歇式,一定要確保這個(gè)bug的存在對于你的代碼正常工作是至關(guān)重要的驶悟。畢竟你又不會使用其他的編譯器,其他任何人也不允許材失!

一個(gè)貨真價(jià)實(shí)的例子 下面是一位大師編寫的真實(shí)例子痕鳍。讓我們來瞻仰一下他在這樣短短幾行 C 函數(shù)里展示的高超技巧。

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, &quot;Microsoft Yahei&quot;; background: none;">

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;
}

</pre>
  • 重新發(fā)明了標(biāo)準(zhǔn)庫里已有的簡單函數(shù)龙巨。

  • Realocate 這個(gè)單詞拼寫錯(cuò)誤笼呆。所以說,永遠(yuǎn)不要低估創(chuàng)造性拼寫的威力旨别。

  • 無緣無故地給輸入緩沖區(qū)產(chǎn)生一個(gè)臨時(shí)的副本诗赌。

  • 無緣無故地造型。 memcpy() 里有 (void)秸弛,這樣即使我們的指針已經(jīng)是 (void) 了也要再造型一次铭若。另外,這樣做可以傳遞任何東西作為參數(shù)递览,加10分叼屠。

  • 永遠(yuǎn)不必費(fèi)力去釋放臨時(shí)內(nèi)存空間。這樣會導(dǎo)致緩慢的內(nèi)存泄露绞铃,一開始看不出來镜雨,要程序運(yùn)行一段時(shí)間才行。

  • 把用不著的東西也從緩沖區(qū)里拷貝出來儿捧,以防萬一荚坞。這樣只會在Unix上產(chǎn)生core dump挑宠,Windows 就不會。

  • 很顯然西剥,os 和 ns 的含義分別是”old size” 和 “new size”痹栖。

  • 給 buf 分配內(nèi)存之后,memset 初始化它為 0瞭空。不要使用 calloc()揪阿,因?yàn)槟承┤藭貙?ANSI 規(guī)范,這樣將來保不齊 calloc() 往 buf 里填的就不是 0 了咆畏。(雖然我們復(fù)制過去的數(shù)據(jù)量和 buf 的大小是一樣的南捂,不需要初始化,不過這也無所謂啦)

如何修復(fù) “unused variable” 錯(cuò)誤

如果你的編譯器冒出了 “unused local variable” 警告旧找,不要去掉那個(gè)變量溺健。相反,要找個(gè)聰明的辦法把它用起來钮蛛。我最喜歡的方法是:

i = i;

大小很關(guān)鍵 差點(diǎn)忘了說了鞭缭,函數(shù)是越大越好。跳轉(zhuǎn)和 GOTO 語句越多越好魏颓。那樣的話岭辣,想做任何修改都需要分析很多場景。這會讓維護(hù)代碼的程序員陷入千頭萬緒之中甸饱。如果函數(shù)真的體型龐大的話沦童,對于維護(hù)代碼的程序員就是哥斯拉怪獸了,它會在他搞清楚情況之前就殘酷無情地將他踩翻在地叹话。

一張圖片頂1000句話偷遗,一個(gè)函數(shù)就是1000行 把每個(gè)方法體寫的盡可能的長 — 最好是你寫的任何一個(gè)方法或函數(shù)都不會少于1000行代碼,而且里邊是深度嵌套驼壶,這是必須的氏豌。

少個(gè)文件 一定要保證一個(gè)或多個(gè)關(guān)鍵文件無法找到。利用includes 里邊再 includes 就能做到這一點(diǎn)热凹。例如箩溃,在你的 main 模塊里,你寫上:

include <stdcode.h>

</pre>

Stdcode.h 是有的碌嘀。但是在 stdcode.h 里,還有個(gè)引用:

<pre style="margin: 0px; padding: 0px; font-family: monospace, Consolas, "Microsoft Yahei"; background: none;">

include "a:\refcode.h"

</pre>

然后歪架,refcode.h 就沒地方能找到了股冗。

(【譯者-老碼農(nóng)-注】為啥找不到呢?仔細(xì)看看和蚪,現(xiàn)在還有人知道 a:\ 是什么嗎止状?A盤烹棉!傳說中的軟盤…)

到處都寫,無處會讀 至少要把一個(gè)變量弄成這樣:到處被設(shè)置怯疤,但是幾乎沒有哪里用到它浆洗。不幸的是,現(xiàn)代編譯器通常會阻止你做相反的事:到處讀集峦,沒處寫伏社。不過你在C 或 C++ 里還是可以這樣做的。

【譯者注】:原文在后面還有一些內(nèi)容塔淤,翻譯時(shí)略有刪減摘昌。刪節(jié)的內(nèi)容主要是:

1.我看不懂的部分;

2.我覺得不怎么好笑的部分(其實(shí)很可能是因?yàn)闆]看懂所以找不到笑點(diǎn));

3.不容易引起現(xiàn)代程序猿共鳴的老舊內(nèi)容。

本人水平有限高蜂,時(shí)間匆忙聪黎,難免有誤,請讀者不吝指出备恤。謝謝稿饰!

-END-

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市露泊,隨后出現(xiàn)的幾起案子喉镰,更是在濱河造成了極大的恐慌,老刑警劉巖滤淳,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梧喷,死亡現(xiàn)場離奇詭異,居然都是意外死亡脖咐,警方通過查閱死者的電腦和手機(jī)铺敌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屁擅,“玉大人偿凭,你說我怎么就攤上這事∨筛瑁” “怎么了弯囊?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長胶果。 經(jīng)常有香客問我匾嘱,道長,這世上最難降的妖魔是什么早抠? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任霎烙,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘悬垃。我一直安慰自己游昼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布尝蠕。 她就那樣靜靜地躺著烘豌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪看彼。 梳的紋絲不亂的頭發(fā)上廊佩,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機(jī)與錄音闲昭,去河邊找鬼罐寨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛序矩,可吹牛的內(nèi)容都是我干的鸯绿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼簸淀,長吁一口氣:“原來是場噩夢啊……” “哼瓶蝴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起租幕,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤舷手,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后劲绪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體男窟,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年贾富,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了歉眷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡颤枪,死狀恐怖汗捡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情畏纲,我是刑警寧澤扇住,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站盗胀,受9級特大地震影響艘蹋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜票灰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一簿训、第九天 我趴在偏房一處隱蔽的房頂上張望咱娶。 院中可真熱鬧,春花似錦强品、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至逻锐,卻和暖如春夫晌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背昧诱。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工晓淀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盏档。 一個(gè)月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓凶掰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蜈亩。 傳聞我的和親對象是個(gè)殘疾皇子懦窘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355