發(fā)布時間:2019-07-20 10:16??發(fā)布人:南京北大青鳥??發(fā)布來源:南京北大青鳥??瀏覽人數(shù):109
編寫除了自己沒人能看懂的代碼,是一種怎樣的體驗?
下面由作為資深挖坑程序員的我,手把手教大家這是怎么做到的?如果各位可以在接下來的時間多加練習,所謂青出于藍勝于藍,相信各位不但可以寫出別人無法維護的代碼,還可能在有朝一日,甚至能技藝爐火純青地寫出自己都維護不了的代碼。
編寫無法維護的代碼說難其實并不難,核心要點就是和編碼規(guī)范反其道而行之,如果在此基礎(chǔ)上再添加一些自己琢磨出的心得的話那就更加完美了。
掌握了這個要點還不夠,還要注意一個原則:不要讓我們的代碼一眼看上去就無法維護,格式之類的還是要注意些的,我們要追求的不是這種膚淺的表面上的無法維護,我們要的是實質(zhì)是無法維護的。
要是別人一眼就能看出你的代碼無法維護,那你的代碼就存在需要重寫或者重構(gòu)的風險了,那不成了前功盡棄親者痛,仇者快的事情了嘛。
《孫子兵法》有云“知己知彼,百戰(zhàn)不殆”,假如我們要想從心理上徹底擊敗后續(xù)的代碼維護人員,我們必須明白常規(guī)編程中的一些思維方式。
各位先想下,如果接手程序的是我們自己,而且代碼量比較大,一般我們是沒有時間去從頭到尾一行一行地讀一遍的,更不要說能理解代碼了。
為了能盡快地上線交差,程序員常見的做法是根據(jù)需求,先快速找到代碼中需要改動的那一部分邏輯,然后對這部分的代碼進行修改、測試。這種修改方式一次只能看到代碼的一小部分,管中窺豹。
所以我們要做的是確保讓代碼維護人員永遠看不到我們寫的代碼的全貌,要盡量保證代碼維護人員找不到他想要找到的那部分代碼。這還不是關(guān)鍵的,關(guān)鍵的是要讓修改者知道自己沒有忽略任何的東西。
每一個我們精心設(shè)計的這些小陷阱都會迫使代碼維護者像用放大鏡似的,仔細地閱讀我們的每一行代碼。
有些同學可能覺得這很簡單,認為只要按照上文中提到的反編程規(guī)范原則來進行即可。但是實際操作起來并沒有這么簡單,還需要配合我們的精心誤用才可。下面我們就對常用的一些核心技能娓娓道來。
這一部分我們先了解下注釋的正常用途:注釋是用來幫助開發(fā)者理解程序的,尤其是對于后來的開發(fā)者,通過注釋可以更快的了解代碼的實際作用。
正常情況下代碼注釋的原則一般是只在需要注釋的地方進行注釋。這是一句很正確的廢話,解釋起來就是很明顯就能看懂的代碼就不要去注釋的了,畢竟看注釋也是需要花費時間的。
另外一個原則就是在注釋中注明代碼的作用需要和代碼的實際作用是一致。
在實際工作中,在對代碼進行修改后一定要連同代碼的注釋也一起進行修改。關(guān)于注釋的其他的一些作用我們在此不再多說,光是這些就已經(jīng)足夠我們用的了。
如何利用代碼注釋寫出讓人無法理解的代碼呢?
這塊我分了兩種情況來描述,兩種情況對應(yīng)兩種處理方式,實用性比較強。
明顯型注釋
讓維護者浪費時間看顯而易見的注釋。
這部分的原則是維護者看完注釋后覺得“代碼比注釋容易讀多了”,目的就是誤導讀代碼的人。維護者在看代碼時,上眼一看代碼很清晰,但又一看竟然還有注釋。
此時讀代碼的人心里肯定是要嘀咕下:看來這代碼沒我想的這么簡單。
然后我們的注釋要寫的長一些,后是要閱讀者看不懂,改的時候猶豫不決。
如果有余力的話可以在注釋中教維護者怎么編程,這種一般殺傷力要比上面寫的會高一些,程序員反感的可能就是你要教他怎么編程了,尤其是教他這么簡單的編程,殺傷力加倍。
字面意思已經(jīng)很清楚了,正常情況下代碼中不用的部分我們一般會注釋掉或者直接刪除掉,即使這段代碼將來會使用到也不影響,可以從版本控制工具中再找回來。
針對性的做法就是給刪掉的代碼加個長長的注釋,寫明這段代碼為什么會被注釋起來,也向維護者傳達了一個信息,即這段代碼不是被”廢棄”的,而是”臨時”先不用。
這樣做的殺傷點就在,如果只注釋了代碼沒加注釋說明,根據(jù)實際經(jīng)驗大家多數(shù)會直接略過被注釋的代碼,而給代碼加了注釋后看代碼的人可能就要看看這個注釋了,不然會漏掉什么關(guān)鍵信息,畢竟代碼不是他寫的。
這種注釋就是我們經(jīng)常提到的“TODO”型注釋。正常情況下TODO注釋并非一無是處,比如在初始化項目的時候TODO注釋還是非常有用的,到項目release 時一般是建議去掉的,如果必須要留著一般需要寫明在具體什么日期會處理掉。一般是不推薦TODO型注釋長期存在于項目的代碼中,正常的處理邏輯一般是遵循有Bug盡快Fix,無Bug則去掉注釋。
通過上面的描述相信大家已經(jīng)知道這塊具體要怎么應(yīng)對了。個人建議是對于有待修改的多寫點TODO注釋,且不注明更改的原因以及計劃更改的時間,這樣后面的維護人員在看的時候可能連這塊到底是不是已經(jīng)改過了都搞不清楚,所以殺傷效果也是有一些的。
這部分的意思是造成代碼和注釋的不匹配,也就是注釋的信息不正確。
我們要做的就是改完代碼后不改注釋就行了,此種方式比較省事,額外工作一點也不用多做,但是稍微有些代價,需要注意的是好是在此類注釋中加個特殊的標記,防止自己后續(xù)看的時候把自己也繞進去。
樣板實例這塊就不用加了吧,場景太多了,大家在自己的一畝三分地上耕作時臨場發(fā)揮即可。
簡單說來就是寫明這段代碼為什么要這樣寫,當然肯定不是單純的原因。除了原因一般建議在注釋中寫上當時的情況,比如某年某月和某人在某地討論了這個問題,某人說這個問題應(yīng)該怎樣處理,你說這個問題不該這樣處理應(yīng)該那樣處理,后來某某人又加入了討論,某某人對倆的討論做了某某的評價,后決定要用現(xiàn)在的代碼去實現(xiàn)這塊的功能。
總之,原則就是把事情的細節(jié)描述清楚,越細越好。有些同學可能會建議將當天的天氣情況也寫上,還有討論中那個氣死人的S*名字也要帶上,我個人認為天氣可以酌情添加,但寫上S*名字是不太鼓勵的,畢竟同事一場,要相互愛護的,大家按照自己公司的實際情況來選擇具體的處理方式吧。
按照注釋的規(guī)范,注釋時不但要解釋程序的表述的意思,更重要的是寫明為什么寫,即代碼這么寫的原因是什么。
這樣應(yīng)對之策也已經(jīng)顯而易見了,對于復雜程序,比如一些特殊的邊界條件判斷,只寫下程序的字面意思,具體邊界值判斷為什么要這樣寫,為什么是這個值可以忽略掉,讓維護的人盡情去猜吧。
在這需要注明的是大部分程序注釋一般是用不到這種情況的,一般是推薦放在一些復雜算法的解釋上,越是復雜的算法越是推薦,原則就是把這部分應(yīng)該寫到文檔中的內(nèi)容寫到代碼中。
一定要把算法的所有的詳細設(shè)計都寫上,注釋內(nèi)容分段落,段落之間要分級,每個段落建議加上編號,這樣就基本可以保證代碼的注釋和文檔的內(nèi)容保持一致。后續(xù)的維護看到這樣的注釋的時候基本可以保證頭大一圈,如果此類注釋存在多處的話效果更佳。
鑒于樣板示例中注釋篇幅太長就不加示例了。
單位這部分和具體的業(yè)務(wù)場景相關(guān),比如時間相關(guān)的一般會有毫秒、秒、分鐘、小時、天、月、年等,涉及尺寸的場景如像素、英寸等,涉及文件大小的場景如字節(jié)、KB、MB、GB等。
這一類的代碼中我們的原則是不對單位進行注釋,只管使用,如果可以在代碼中各種單位混用,那自然是更加優(yōu)秀。
比如在關(guān)于文件處理的場景中,KB、MB、GB多個單位混合使用,這樣后來的維護人員要想搞懂這部分代碼中單位的真正含義就要下一番功夫了。
按照我們的正常邏輯,后面的人要想改這部分的代碼的邏輯首先要先弄懂各個數(shù)據(jù)的單位,搞清楚之前肯定是不敢隨意修改的,一般這種情況只有一種解決辦法那就是一遍遍的調(diào)試、測試程序來推算各個數(shù)據(jù)實際的單位,花費的時間自然是相當?shù)亩唷?/p>
這一招可以說是殺手锏級別的注釋,可以在程序中加一部分可有可無的代碼,而且是很明顯可有可無的那種,然后給這段程序加個注釋,注釋中寫明“千萬不要注釋掉或者刪除這段代碼,否則程序會出現(xiàn)異常!!!”,需要注意的是不要解釋會出現(xiàn)什么樣的異常。
這樣維護人員在看到這段代碼的時候肯定首先會聯(lián)想到自己以前看過的一些文章,并堅信這段“廢話代碼”肯定是不能刪除的。代碼中如果存在多處這種注釋的話效果更佳。
讓你的代碼和注釋交融在一起,算是入門級的代碼偽裝術(shù),主要目的是惡心后來的維護者,假使看代碼的人剛好頭昏腦漲的話肯定會直接懵逼一會,懵逼完之后再一陣惡心。
這種招式一般是建議用在C類程序的宏定義中,使用的原則也比較簡單,即宏名稱和具體的值雜糅使用即可,造成一種你中有我,我中有你的既視感。
這部分主要應(yīng)用在前端開發(fā)中,舉個例子大家就清楚了,比如Web界面上郵政編碼顯示為postal code,代碼中把變量名命名為zipcode,我相信不論誰看到這種情況都不敢直接改代碼的,肯定要反復確認一會postal code 對應(yīng)的變量到底是不是zipcode。
需要說明的是這里的隱藏不是說將宏定義藏到找不到的地方,那肯定是不行的,說不定我們自己還要進行修改呢。
這里說的宏定義隱藏是指將宏定義寫的不像宏定義,讓看代碼的人一眼看去覺得這不是一個宏,然后略過去。
這一招我只能用猥瑣來形容了,因為真的是猥瑣。產(chǎn)生的效果是即難閱讀也很難進行變量名的搜索。
這里說的是隱藏全局變量,方法就是在函數(shù)里面使用全局變量時不直接使用,而是以傳參的形式傳進來后進行使用,這樣很難分辨出這是一個全局變量。
正常重載后的函數(shù),其功能應(yīng)該和被重載的函數(shù)應(yīng)該是接近的,我們要做的就是讓重載后的函數(shù)和被重載函數(shù)的功能完全沒有關(guān)系。
這個時候看代碼的人如果基礎(chǔ)不牢的話,可能需要去溫習下函數(shù)重載的知識,是不是自己以前理解錯了。
操作符重載是一種很變態(tài)的招式,因為他會讓你的代碼變的非常的詭異,只要按照下面描述的方式進行使用基本可以把代碼的混亂程度直接拉升到藝術(shù)的級別,藝術(shù)就是打破常規(guī),所以一般只要不按照操作符重載推薦的使用方式去使用都能收到意想不到的效果。
樣板示例:類中重載 ! 操作符,重載后的功能不是取反而讓其返回一個整數(shù),于是當使用!!時會先調(diào)用被重載后的函數(shù),返回一個整數(shù),然后再取反,后返回個bool值,一臉懵逼。
這一招用上后我覺得看代碼的人如果不是穩(wěn)如老狗的老司機應(yīng)該會抱頭痛哭的。
這種基本上就是一種罵娘的命名方式,為啥會這么容易引起怒火,看個例子就知道了:gGEtpRoDucTnaME,有沒有腦裂的感覺?
名稱上毫無邏輯可言。
如果字母a – z 不夠使用,可以考慮字母+數(shù)字的組合,這樣一般就足夠使用了,畢竟數(shù)字是無限的。
變量名稱拼錯并不是隨意一個單詞就拼錯,此處指的是比較有創(chuàng)意的拼寫錯誤。
因為隨意的拼寫錯誤是很容易被發(fā)現(xiàn)的,高級的拼寫錯誤由于很難看出來,所以在進行變量搜索的時候根本搜不出來。 比如:SetPintle、SetPintalClosing。
函數(shù)或者方法的內(nèi)嵌結(jié)構(gòu)中使用和函數(shù)或者方法層面中同名的變量名,變量名多的話可能會一陣眩暈。
前面的注釋和變量命名可以說是本文的基礎(chǔ)篇,主要是較大家一些基本的編程技巧。這一篇作為進階的一篇,我會給大家介紹一下常見的一些稍微高端的編程技巧,廢話不多說,一起看下:
不管什么類型的指針一律都用聲明定義為void*,當實際用到時再轉(zhuǎn)換為需要的類型。
條件表達式這塊可以發(fā)揮的空間就比較大了,從實際編碼情況來看,每個簡單的條件表達式都可以進行拆分,看個例子就明白了。
10 == num,拆分為 num >= 99 && num <= 101
什么,一行多80個字符? 不行,這才哪到哪,一定要跨行,而且要跨多行,不能因為換行影響了我們寫代碼的那股激情。
原則就是越長越好,這樣后續(xù)閱讀代碼的人就需要來來回回地讀,想想都覺得累。
一個優(yōu)秀的程序員必須能夠在一行代碼中使用超過10個小括號(),如果覺得很難得話在一個函數(shù)里面使用超過5層的大括號也是可以的,還不行的話把嵌套的條件語句if … else 轉(zhuǎn)為[?:] 也是可以說明你是個優(yōu)秀的程序員的。
不要在代碼的循環(huán)中使用break,更不要使用goto,這樣可以保證一行break可以處理的代碼少要寫5層的if … else 來解決,一遇到break 就多出百十行代碼,想想都過癮,一天下來光看看新增的代碼行數(shù)就覺得充實。
XML 的強大是無人能及的,不是JSON、Yaml這些所能及的。項目中使用XML 可以幫助我們將原來只需要10行的代碼變?yōu)?00行(可能還不止)。XML是無所不能的,哪怕是自己封裝自己也是可以做到的,信XML 得永生,信XML 的自信!
測試,不存在的。
一般建議不要測試,測試是一種懦夫的行為,作為一個優(yōu)秀的程序員我們必須保持這種對自己代碼的自信,再者測試會影響你的生產(chǎn)力,直接影響你寫代碼的行數(shù),所以測試這一步直接跳過就好啦。
版權(quán)聲明:本文教你如何寫出沒人敢維護的代碼_中博培訓學校: http://www.docoa.com.cn/kczx/132.html 禁止一切方式轉(zhuǎn)載、抄襲!
相關(guān)內(nèi)容:
更多人關(guān)注: