如何編寫不可維護的php代碼?

為什麼要寫不可維護的代碼?

因為沒人能搞定你的代碼,那意味著你的工作是不可替代的,誰也取代不了你。你找了個鐵飯碗。

第一步

找一家適合的公司,一般從招聘信息就能看出來,比如招聘里提到要求精通access資料庫,需要將asp遷移到php,會css+div。

這種公司你去了之後,從第一天就要顯示自己的專業性,開會時一定要大聲,讓所有人都聽到你的觀點,談論面向對象架構,分散式大數據企業級,設計思想的轉變,「足夠好」還不夠好,確保所有人都把你的觀點當作編程的指導。

不可維護的的基本點,一任何人都不能在不破壞其他部分的情況下改動代碼。 可維護性是維護人員可輕易的定位代碼,弄清執行情況,你的工作是讓別人找不到你的代碼,而去弄不清邏輯,改動一部分就讓其他部分出bug。二,你的代碼應該看起來可維護。如果看起來就不可維護,別人就會起疑心。

最加實踐

1 打破編程慣例 你的代碼完全不遵守任何任何慣例。你應該混合使用tab和空格,周一變數使用駝峰式,周四使用蛇底式,每個二月29號使用蒙古式。當然作為中國人,一定要用拼音縮寫。

2 不用注釋,你不應該花時間寫注釋,只在必要的時候,寫上冗長的不必要的注釋。比如/**這裡是變數聲明與賦值的部分,給變數a賦值1,給變數2賦值2,執行加操作,求a加b的值返回數值型3

3. 使用記事本

或者其它沒有代碼高亮的程序, 很快你的小夥伴就受不了然後離開團隊, 不用理他們的抱怨, 如果他們問為啥要用記事本, 你準備好下面的解釋: 記事本是一個高效率的系統(windows)自帶的軟體, 不需要學習, 不需要投入任何東西, 人人都可以使用,

你肯定在網上看到過別人推薦用其它的工具寫代碼比如word, 但是記著, 大牛都用記事本, 而你的公司只招大牛.

4. 不使用單元測試

如果有人問你為什麼不進行單元測試呢? 你義正嚴詞的告訴他們: 我被公司僱傭來是寫高質量代碼的, 我的代碼沒有bug. (不需要測試)

有些事情就是這樣簡單, 公雞打鳴, 太陽從東邊出來, 而你的代碼好使, 謝謝.

或者可以對一部分顯而易見的代碼做過度測試, 然後跳過其它部分.

5. 不使用模板引擎

模板引擎是用來分離業務邏輯和表現的工具, 這可能導致代碼易於維護,你絕對不允許這樣做. 就像Rasmus Lerdorf說的" PHP就是一個模板引擎".

如果你不得不用的話, 你可以把模板引擎亂用, 將業務邏輯嵌入表現里,精心的混合html,css和php, 還可以存儲到資料庫中.

你還可以用php生成JS, JS再生成HTML最後還附帶內聯的CSS, 棒極了,記著這些代碼可以存儲到資料庫中.

如果有人問: 你為什麼要這麼搞呢? 你馬上告訴他, 這叫封裝模式, 你的代碼為自己負責.

6. 版本控制

不可避免的流程, 但你可以說服成員們使用口頭上的溝通取代冷冰冰的版本控制系統.

你告訴他們真誠的溝通更有利團隊.

如果他們不聽,你可以把一小段但關鍵的代碼不提交到系統里. 這樣當他們自己打算部署時肯定出問題, 如果被發現了, 跟他們解釋說這部分代碼還有待改善.

告訴他們, 你只提交能教育新手的代碼, 他們全都依賴你,而你只貢獻最好的代碼

7.開發一個框架

作為公司的架構專家,最終你要自己做一個框架, 你的框架不使用任何其它框架的約定,包含所有的東西, 沒有人能弄明白你的框架工作原理.

同時,大夥對你這個高效率的先進框架讚不絕口

但千萬不要開源, 你的框架是如此的高效率,而你的公司為此投入巨大.是公司的寶貴財富.一旦開源, 你馬上會被取笑,而你的牛鼻馬上就被捅破了.


  • 繼承無節制

  • 複雜的類

  • 介面設計得太窄或太寬
  • 函數/方法參數超過三個

  • 大量IF嵌套

  • 使用$$foo

  • 籠統的命名

  • 不清楚的縮寫

  • 使用三維以上的數組

  • 自己造輪子

  • 複雜邏輯沒有單元測試

  • 文件組織沒層次
  • 代碼格式不一致無規約
  • 太深的依賴樹
  • 複製黏貼
  • hack的庫沒文檔
  • 過度優化
  • 懶惰不重構
  • 不要看代碼整潔之道


以前看到的,在這分享(翻譯來自老碼農冒死揭開行業黑幕:如何編寫無法維護的代碼,作者 伯樂在線 - 老碼農,已徵得作者同意)

============================================================

如何編寫無法維護的代碼讓自己穩拿鐵飯碗

– 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 字元用於變數命名是完全合法的,包括 ?, D, 和 ? 等。在簡單的文本編輯器里,除了拷貝/粘貼,基本上沒法輸入。

其他語言的命名

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

數學命名

      用數學操作符的單詞來命名變數。例如:

openParen = (slash + asterix) / equals;

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

令人眩暈的命名

      用帶有完全不相關的感情色彩的單詞來命名變數。例如:

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(本文作者)

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

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

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

for(j=0; j&

如果不是用綠色標出來,你能注意到這三行代碼被注釋掉了么?

用連接符隱藏變數

      對於下面的定義

#define local_var xy_z

可以把 「xy_z」 打散到兩行里:

#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,天知地知你知就好。如果你想到了重構或重寫代碼的思路,看在老天爺的份上,千萬別寫出來。切記電影《小鹿斑比》里那句台詞 「如果你不能說好聽的話,那就什麼也不要說。」。萬一這段代碼的原作者看到你的注釋怎麼辦?萬一老闆看到了怎麼辦?萬一客戶看到了怎麼辦?搞不好最後你自己被解僱了。一句」這裡需要修改「的匿名注釋就好多了,尤其是當看不清這句注釋指的是哪裡需要修改的情況下。切記「難得糊塗」四個字,這樣大家都不會感覺受到了批評。

說明變數

      永遠不要對變數聲明加註釋。有關變數使用的方式、邊界值、合法值、小數點後的位數、計量單位、顯示格式、數據錄入規則等等,後繼者完全可以自己從程序代碼中去理解和整理嘛。如果老闆強迫你寫注釋,就在方法體里胡亂多寫點,但絕對不要對變數聲明寫注釋,即使是臨時變數!

在注釋里挑撥離間

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

    /* 優化後的內層循環
    這套技巧對於SSI軟體服務公司的那幫蠢材來說太高深了,他們只會
    用 & 里的笨常式,消耗50倍的內存和處理時間。
    */
    class clever_SSInc
    {
    .. .
    }

    可能的話,除了注釋之外,這些攻擊抹黑的內容也要摻到代碼里的重要語義部分,這樣如果管理層想清理掉這些攻擊性的言論然後發給外部承包商去維護,就會破壞代碼結構。

程序設計

編寫無法維護代碼的基本規則就是:在儘可能多的地方,以儘可能多的方式表述每一個事實。- Roedy Green

    編寫可維護代碼的關鍵因素是只在一個地方表述應用里的一個事實。如果你的想法變了,你也只在一個地方修改,這樣就能保證整個程序正常工作。所以,編寫無法維護代碼的關鍵因素就是反覆地表述同一個事實,在儘可能多的地方,以儘可能多的方式進行。令人高興的是,像Java這樣的語言讓編寫這種無法維護代碼變得非常容易。例如,改變一個被引用很多的變數的類型幾乎是不可能的,因為所有造型和轉換功能都會出錯,而且關聯的臨時變數的類型也不合適了。而且,如果變數值要在屏幕上顯示,那麼所有相關的顯示和數據錄入代碼都必須一一找到並手工進行修改。類似的還有很多,比如由C和Java組成的Algol語言系列,Abundance甚至Smalltalk對於數組等結構的處理,都是大有可為的。

Java 造型

      Java的造型機制是上帝的禮物。你可以問心無愧地使用它,因為Java語言本身就需要它。每次你從一個Collection 里獲取一個對象,你都必須把它造型為原始類型。這樣這個變數的類型就必須在無數地方表述。如果後來類型變了,所有的造型都要修改才能匹配。如果倒霉的維護代碼的程序員沒有找全(或者修改太多),編譯器能不能檢測到也不好說。類似的,如果變數類型從short 變成 int,所有匹配的造型也都要從(short) 改成 (int)。

利用Java的冗餘

      Java要求你給每個變數的類型寫兩次表述。 Java 程序員已經習慣了這種冗餘,他們不會注意到你的兩次表述有細微的差別,例如

Bubblegum b = new Bubblegom();

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

swimmer = swimner + 1;

永遠不做校驗

      永遠不要對輸入數據做任何的正確性或差異性檢查。這樣能表現你對公司設備的絕對信任,以及你是一位信任所有項目夥伴和系統管理員的團隊合作者。總是返回合理的值,即使數據輸入有問題或者錯誤。

有禮貌,無斷言

      避免使用 assert() 機制,因為它可能把三天的debug盛宴變成10分鐘的快餐。

避免封裝

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

複製粘貼修改

      以效率的名義,使用 複製+粘貼+修改。這樣比寫成小型可復用模塊效率高得多。在用代碼行數衡量你的進度的小作坊里,這招尤其管用。

使用靜態數組

      如果一個庫里的模塊需要一個數組來存放圖片,就定義一個靜態數組。沒人會有比512 X 512 更大的圖片,所以固定大小的數組就可以了。為了最佳精度,就把它定義成 double 類型的數組。

傻瓜介面

      編寫一個名為 「WrittenByMe」 之類的空介面,然後讓你的所有類都實現它。然後給所有你用到的Java 內置類編寫包裝類。這裡的思想是確保你程序里的每個對象都實現這個介面。最後,編寫所有的方法,讓它們的參數和返回類型都是這個 WrittenByMe。這樣就幾乎不可能搞清楚某個方法的功能是什麼,並且所有類型都需要好玩的造型方法。更出格的玩法是,讓每個團隊成員編寫它們自己的介面(例如 WrittenByJoe),程序員用到的任何類都要實現他自己的介面。這樣你就可以在大量無意義介面中隨便找一個來引用對象了。

巨型監聽器

      永遠不要為每個組件創建分開的監聽器。對所有按鈕總是用同一個監聽器,只要用大量的if…else 來判斷是哪一個按鈕被點擊就行了。

好事成堆TM

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

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

      這段很可能看起來不怎麼好笑。別擔心,只是時候未到而已。

友好的朋友

      在C++ 里盡量多使用friend聲明。再把創建類的指針傳遞給已創建類。現在你不用浪費時間去考慮介面了。另外,你應該用上關鍵字private 和 protected 來表明你的類封裝得很好。

使用三維數組

      大量使用它們。用扭曲的方式在數組之間移動數據,比如,用arrayA里的行去填充arrayB的列。這麼做的時候,不管三七二十一再加上1的偏移值,這樣很靈。讓維護代碼的程序員抓狂去吧。

混合與匹配

      存取方法和公共變數神馬的都要給他用上。這樣的話,你無需調用存取器的開銷就可以修改一個對象的變數,還能宣稱這個類是個」Java Bean」。對於那些試圖添加日誌函數來找出改變值的源頭的維護代碼的程序員,用這一招來迷惑他尤其有效。

沒有秘密!

      把每個方法和變數都聲明為 public。畢竟某個人某天可能會需要用到它。一旦方法被聲明為public 了,就很難縮回去。對不?這樣任何它覆蓋到的代碼都很難修改了。它還有個令人愉快的副作用,就是讓你看不清類的作用是什麼。如果老闆質問你是不是瘋了,你就告訴他你遵循的是經典的透明介面原則。

全堆一塊

      把你所有的沒用的和過時的方法和變數都留在代碼里。畢竟說起來,既然你在1976年用過一次,誰知道你啥時候會需要再用到呢?當然程序是改了,但它也可能會改回來嘛,你」不想要重新發明輪子」(領導們都會喜歡這樣的口氣)。如果你還原封不動地留著這些方法和變數的注釋,而且注釋寫得又高深莫測,甭管維護代碼的是誰,恐怕都不敢對它輕舉妄動。

就是 Final

      把你所有的葉子類都聲明為 final。畢竟說起來,你在項目里的活兒都幹完了,顯然不會有其他人會通過擴展你的類來改進你的代碼。這種情況甚至可能有安全漏洞。 java.lang.String 被定義成 final 也許就是這個原因吧?如果項目組其他程序員有意見,告訴他們這樣做能夠提高運行速度。

避免布局

      永遠不要用到布局。當維護代碼的程序員想增加一個欄位,他必須手工調整屏幕上顯示所有內容的絕對坐標值。如果老闆強迫你使用布局,那就寫一個巨型的 GridBagLayout 並在裡面用絕對坐標進行硬編碼。

全局變數,怎麼強調都不過分

      如果上帝不願意我們使用全局變數,他就不會發明出這個東西。不要讓上帝失望,盡量多使用全局變數。每個函數最起碼都要使用和設置其中的兩個,即使沒有理由也要這麼做。畢竟,任何優秀的維護代碼的程序員都會很快搞清楚這是一種偵探工作測試,有利於讓他們從笨蛋中脫穎而出。

再一次說說全局變數

      全局變數讓你可以省去在函數里描述參數的麻煩。充分利用這一點。在全局變數中選那麼幾個來表示對其他全局變數進行操作的類型。

局部變數

      永遠不要用局部變數。在你感覺想要用的時候,把它改成一個實例或者靜態變數,並無私地和其他方法分享它。這樣做的好處是,你以後在其他方法里寫類似聲明的時候會節省時間。C++程序員可以百尺竿頭更進一步,把所有變數都弄成全局的。

配置文件

      配置文件通常是以 關鍵字 = 值 的形式出現。在載入時這些值被放入 Java 變數中。最明顯的迷惑技術就是把有細微差別的名字用於關鍵字和Java 變數.甚至可以在配置文件里定義運行時根本不會改變的常量。參數文件變數和簡單變數比,維護它的代碼量起碼是後者的5倍。

子類

    對於編寫無法維護代碼的任務來說,面向對象編程的思想簡直是天賜之寶。如果你有一個類,裡邊有10個屬性(成員/方法),可以考慮寫一個基類,裡面只有一個屬性,然後產生9層的子類,每層增加一個屬性。等你訪問到最終的子類時,你才能得到全部10個屬性。如果可能,把每個類的聲明都放在不同的文件里。

編碼迷局

迷惑 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開頭的表示8進位),你也可以充分利用這個特性。

造型

      把所有數據都以 void * 形式傳遞,然後再造型為合適的結構。不用結構而是通過位移位元組數來造型也很好玩。

嵌套 Switch

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

利用隱式轉化

      牢記編程語言中所有的隱式轉化細節。充分利用它們。數組的索引要用浮點變數,循環計數器用字元,對數字執行字元串函數調用。不管怎麼說,所有這些操作都是合法的,它們無非是讓源代碼更簡潔而已。任何嘗試理解它們的維護者都會對你感激不盡,因為他們必須閱讀和學習整個關於隱式數據類型轉化的章節,而這個章節很可能是他們來維護你的代碼之前完全忽略了的。

分號!

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

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

使用八進位數

      把八進位數混到十進位數列表裡,就像這樣:

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

嵌套

      儘可能深地嵌套。優秀的程序員能在一行代碼里寫10層(),在一個方法里寫20層{}。

C數組

      C編譯器會把 myArray[i] 轉換成 *(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 一塊空間而已。用不著釋放內存,讓用戶定期重啟動系統,這樣不就清除了堆么。重啟之後系統需要追蹤的就那麼一點東西,比起解決所有的內存泄露簡單得不知道到哪裡去了!而且,只要用戶記得定期重啟系統,他們也永遠不會遇到堆空間不足的問題。一旦系統被部署,你很難想像他們還能改變這個策略。

其他雜七雜八的招

如果你給某人一段程序,你會讓他困惑一天;如果你教他們如何編程,你會讓他困惑一輩子。 — 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 模塊里,你寫上:

#include &

Stdcode.h 是有的。但是在 stdcode.h 里,還有個引用:

#include "a:\refcode.h"

然後,refcode.h 就沒地方能找到了。

(【譯者注】為啥找不到呢?仔細看看,現在還有人知道 a: 是什麼嗎?A盤!傳說中的軟盤…)

到處都寫,無處會讀

至少要把一個變數弄成這樣:到處被設置,但是幾乎沒有哪裡用到它。不幸的是,現代編譯器通常會阻止你做相反的事:到處讀,沒處寫。不過你在C 或 C++ 里還是可以這樣做的。

============================================================

英文原版: https://www.thc.org/root/phun/unmaintain.html


這個話題,我敢肯定不少開發者有思考過!但畢竟不是什麼光明正大的事情,自己做就是了,在項目高調使用就傻逼了。或許樓主不是這樣的,只是想拿出來消遣一下大家,找個話題來讓大家發揮罷了。

既然是消遣,我就誰便聊聊。

明確一下,以下當我用到「碼農」來描述時,它是一個貶義詞。)

----------------

我認可人性是自私,因此,有碼農會這麼做。而我的意思則是,別把自己太當回事,這世界不會離開了誰就不轉了!

「因為沒人能搞定你的代碼,那意味著你的工作是不可替代的,誰也取代不了你。你找了個鐵飯碗。」這是一個偽命題,碼農自己的意淫。

ok,我假設存在不可維護的代碼。

請問這樣的代碼還是得由你來維護吧?也就是說,還是有人來維護的,只是別人維護起來不太合適或不太方便而已。既然這樣,按我們這一行的規矩,領導是不在乎你用什麼方法和技術的,只會給一個截止時間讓你來完成,對吧?

在這種情況下,這樣的代碼會只會讓你陷入毫無節制的無謂的加班。除非這個項目不重要,但又需要有人來維護,那麼確實可以獲得某種相對穩固的飯碗。但不重要的項目,誰會花高價請一個碼農來維護呢?不會太高的,企業不會是傻子!

然而,人又是需要往高處走的,畢竟這個社會很現實,誰也不會跟錢有仇。很難維護的代碼最後只能讓你越陷越深,最後要麼自己滾蛋,要麼繼續拿著差不多的薪水,如果這就是你想要的鐵飯碗,那麼我就無話可說了。

請問這種事情你會幹嗎?

很多碼農自己總是認為自己最聰明,能寫出一些相對難維護的代碼就以為自己在智商上高別人一籌,別那麼天真好嗎??的好多碼農就是這樣,以為能寫個程序就裝逼,總以為別人是傻逼。

好吧,假設普通碼農智商只有120,而你是130甚至140以上,請問這種差別在做人做事上會有本質的差別嗎?

其實啊,正常人的智商都差不了太多的,對於別人不可以維護,意味著你維護起來也不太容易。同理,你維護起來容易的,別人就不會太難,只要開發經驗差不多,熟悉只是多一點點時間而已,因而不存在絕對維護不了的代碼,只是不太願意去維護罷了,別自我意淫——「我的代碼不可維護」可以嗎?

的確,我不否認存在很難維護的代碼,但是如果一個人要是以這樣的心態去書寫代碼,他的修為一定是有限的,因為代碼能力和程序造詣需要大量的項目去實踐。

或許,一兩個項目沒有人發現你是這樣的心態,但我相信能夠大多人或項目一定存在能識別這種鬼魅伎倆的人存在,而且一定不少。因此,重要的核心的項目會讓這樣的人去負責嗎?或者,只讓你一個人去負責嗎?

這是不太可能的。如果不能有太多的機會獨立去實現那些重要的核心的項目,請問你的代碼修為又怎麼提高呢?如果你是天才,天生就牛逼,請問這樣的你又何必寫不可維護的代碼呢?

所以,正真牛逼的程序開發者是不屑於去書那些「寫不可維護」的代碼的!因為這對他自己沒有任何好處!

-----下面講一個我碰到碼農的故事-----

時間在2014年10月份,我負責一個電商項目招了一個1977年出生的老碼農,本來不太想要他的,因為傳統項目出來的,但我覺得他的項目經驗還可以,而且進度有點兒緊,所以就要了他。

當然,一開始的時候我安排給他的事都能順利完成,但是卻總是有些做法讓人不能接受,比如使用aaa,bbb,ccc,zzz這樣的變數名。當然,這也是我們沒有做好規範,而且自己身上還一大堆業務要親自去寫,發現這樣的問題後就他為什麼要這樣做?

回復就是,時間趕,先實現邏輯再回來改。好吧,這是事實。我認了,進度確實很趕,自己都自身難保,先過了吧。

就這樣項目上了線,1個多星期趕一個交互比較複雜的電商側邊欄項目(天貓、VIP、聚美等電商右側那個黑色工具條)。當我回頭看他實現的那部分代碼,雖說說不上不可維護,但確實很難改,因為很多沒有意義的變數名,一會兒駝峰一會兒蛇線,還有很多沒有注釋的高度抽象的函數(如果有興趣,我可以發一份給大家瞅瞅),截個圖證明一下,這已是我重新格式化後的代碼了:

對了,這不是php,而是前端js,不過大家都是玩代碼的,不可維護的道理是一樣的。再補充一下,當時的我做了4年開發(php2年多3年的樣子,前端是1年多不到2年),那時已轉專職前端開發,負責的是某垂直電商的前端架構;那傢伙是超過10年的老碼農,絕大多是時候PHP+前端混合開發(老資格的程序員大多是這種情況,我做php那會兒也這樣),招進來是前端崗位。

我把他招進來是看到他多年的開發經驗,就沒再細看他做的代碼,或者說覺得沒必要沒要看原來的代碼,就這樣進來了。而且,價格很便宜,轉正9K,試用期7.5K。別誤會,這是他自己開的價格,我立馬找HR確認了這個價格,讓他趕緊把人弄過來,10年以上的程序開發經驗只要白菜價,這等好事哪裡找啊?

但是,和他合作了一個項目之後,我後悔了。當時他試用期還沒過,我是想把他開掉了,但是找不到人來負責,我自己有一大堆雜事,只好又忍了。其實,從這點上看,我?的也不是什麼好鳥,反正工資又不是我開,那些個爛代碼又不想自己去弄,項目上線後公司又給我升職又加薪的,懶得煩這個問題,就這樣讓他混過了試用期。

但是,這個項目到了2015年後,投資人打算撤資,於是團隊面臨解散。我們核心的技術團隊和市場團隊找到了新的投資商,重啟了一個品牌和域名繼續干。我依然負責前端架構和新項目的發版流程設計,但這個10年的碼農是唯一一個被剔除出局的,後來就沒再直接聯繫。有同事說,他後來加入了一個新公司,薪水翻翻,但不到1個月就被開掉了,不知道什麼原因。

好吧,這就是書寫無可維護代碼的碼農的故事。絕對真人真事。

說實話,後來我自己重新實現了一遍他的業務,其實沒什麼難度。經過這個事情之後,我現在負責的項目,如果有發現這樣的人,不管他多牛逼,我一定不會忍。就今年國慶前吧,我們的項目就有一個15K的前端,能力不錯,就因為又類似的代碼跡象,就在項目攻關雙節大促前夕,我依然把人開掉了,殺雞給猴看。

當然,我不知道為什麼有人做了10年的開發都可以忍受7-8K的薪水,而我?一個2年多的前端少於30K是絕對不幹的,就因為從來沒有想過書寫別人難以維護的代碼,而是希望當我請假的時候,項目中能力最弱的那個人也能修改我出產的代碼。

就這樣,你可以說我吹牛,不爽就噴我。又不會少收RMB,股份期權又沒少掉,噴吧。

------------------

好了,你可以繼續研究不可維護的代碼,我也就隨便說說,你別當真。


然後過了一段時間,自己也看不懂了


熟讀下面的條款,然後反過來做

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren"t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you"re Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it"s a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let"s do more of those!


你就正常寫。


1、保證變數的龐大數量,無論有用的還是無用的。

2、在程序中時不時加入對無用變數的賦值,用些簡單的函數也可以(影響程序效率)。

3、使用編輯器的替換功能,將空格、換行、縮進全部替換為空。

4、這個關鍵了,用隨機字元串替換掉變數名,為了效果,就用15位以上的隨機英文字母字元串吧!記得寫一份對應的表方便以後自己維護。。

如果覺得第四步麻煩,寫個腳本做這種事也蠻簡單的嘛。哈哈。


不要為變數和函數隨便地取名!!!

正確的姿勢應該是:

1.認真地為它們取好名字

2.互換一下它們的名字

這樣的破壞力絕對大!比亂取名還厲害!

哈哈哈!想想都醉了!!!哈哈哈


不可維護的代碼寫起來並不難,但是:如果老闆讓你在現有的功能想加一個功能的時候,請問你怎麼來維護自己的代碼?

另外,你這樣做,當老闆把你送上法庭的時候,你可能發現,你欠下的債,是你一輩子都還不清的。

===============2015年10月13日更新==================

對不起,我對我之前不負責任的言論道歉。

如果想寫出不可維護的PHP代碼的話,請參考Discuz!

這是我今生見過的最著名的,開源,且幾乎不可維護的PHP項目了。


如果我是老闆,碰到這樣的員工,我寧願下血本換人重構,也要把你開除了


不用循環 用 goto

盡量不要if else 換成 三元表達式,不停嵌套

命名 a b c

不要換行

不要縮進

多用 $$$$$$$a這樣的


小的時候,我爸爸帶著我和我弟弟在山上勞動。 我和我弟弟心血來潮就想學著大人去用鋸子鋸樹,但是力量不足的情況下,我和我弟弟費了關天的力氣才鋸完,鋸痕還非常 不齊。

之後我爸爸笑了說:不知道的還以為這棵樹是被老鼠咬的呢。

所以,覺得你盡量的寫好,然後接手的人依然會很頭大,名種搞不懂。做為一個接手過這種代碼的過來人來說,人家根本不會維護的,直接推倒重建。

要想公司不炒你,還是老老實實學本領吧,一套精妙無比的代碼,即使人家維不懂,依然想的是征服,而不是棄用。


那你應該用 perl(


本來看著題目以為提問者是想避免寫出不可維護的代碼,看完描述後只想離題地說一下自己的想法,很短,也是我自己要學習編程的想法。

一個好的程序員應該有匠人精神,無論什麼情況下,都應該寫規範和標準的代碼,讓每個程序員接觸到都能愉快地閱讀。


感覺有點作-_-#


然後公司要新增功能,就沒有然後了。


為什麼會有這種想法 T_T


建議題主了解一下國際混亂c語言大賽,你就知道如果要寫出符合你要求的代碼,你所需要的技能水平絕對可以支持你不用寫出這樣的代碼就能混得很牛逼了。


這不是我在貼吧的帖子嗎?

我竟然能在知乎看到我發的帖子,我tm也是醉了。

這帖子是反諷,是反諷,是反諷。是程序員的思維直?還是文章諷刺不明顯?

很多人煞有介事的說,樓主這麼干會被開除吧?我真為你的單純感到蛋疼。

我說說當初發這個帖子的初衷,我在一個國外網站看到的一篇文章,當時覺得很有意思,外國的程序員展開了熱情洋溢的討論。還給出了許多富有建設性具體指導(續寫了一篇詳細的)。

當時我想翻譯來的,但是沒有時間,就草草總結一下修改了少部分內容以適應國情,由於是倉促間寫出來的,就發到了對質量要求不高的貼吧里。

有意思的是中外網友的回復區別真很大。 其實不光這篇文章,在youtube,reddit,和貼吧很多帖子都能體現。

總結就是「歪會玩」,而天朝大部分還走在「正經臉」和「傻白甜」的大道上。


我絕不容忍我的代碼不可維護,我會經常檢閱代碼,一旦有錯亂現象絕逼改掉


推薦閱讀:

「Facebook 開發的高性能PHP虛擬機 HHVM 比官方的 PHP解釋器 快超過9倍」的說法是否屬實?
Zend opcode是如何被執行的?是要編譯為機器碼再執行嗎?
能在郵件中嵌入PHP嗎?
如何反駁服務端程序員聲稱SELECT出來的數據直接丟給客戶端的代碼最好?
xlsx格式規範,不知類似文件應該從哪找?

TAG:前端開發 | HTML | 程序員 | JavaScript | PHP |