慎入:史上最爛的代碼集合
實本沒有什么代碼是“史上最爛”的,要有也只有“史上更爛”的,我想隨便說說這個話題,也是源自豆瓣的一個討論。事實上,系統復雜了被罵代碼爛是一件司空見慣的事情。當然,也有一些短小的代碼片段,就足以看出代碼作者是個不怎么樣的人。
布爾類型的使用是很容易變成最爛代碼的:
- if (isTrue())
- if (isTrue())
- doSomething();
- if(boolVal == true) {
- .....
- }
有一些毫無意義的注釋:
- return 1; // 返回 1
- //如果標志為真,就返回true
- if(flag)
- return true;
更無意義的是這樣的變量命名:
- public static final int ONE = 1;
- public static final int TWO = 2;
也有人說,最爛的代碼片段應該是這樣的才對:
- }
- }
- }
- }
- }
- }
- }
- }
- }
還有曾經被罵到遍體流膿的12306.cn,代碼節選:
- var sig = 0;
- if(searchwordl.indexOf("'") > -1 || searchwordl.indexOf("\"") > -1 || searchwordl.indexOf("%") > -1 || searchwordl.indexOf("#") > -1 || searchwordl.indexOf("&") > -1 || searchwordl.indexOf("*") > -1 || searchwordl.indexOf("(") > -1 || searchwordl.indexOf(")") > -1 || searchwordl.indexOf("@") > -1 || searchwordl.indexOf("`") > -1 || searchwordl.indexOf("/") > -1 || searchwordl.indexOf("\\") > -1 || searchwordl.indexOf(",") > -1 || searchwordl.indexOf(".") > -1 || searchwordl.indexOf("=") > -1 || searchwordl.indexOf("<") > -1 || searchwordl.indexOf(">") > -1)
- sig = 1;
- searchwordl=searchwordl.replace("'","");
- //searchwordl=searchwordl.replace(" ","");
- searchwordl=searchwordl.replace("%","");
- searchwordl=searchwordl.replace("#","");
- searchwordl=searchwordl.replace("&","");
- searchwordl=searchwordl.replace("*","");
- searchwordl=searchwordl.replace("(","");
- searchwordl=searchwordl.replace(")","");
- searchwordl=searchwordl.replace("@","");
- searchwordl=searchwordl.replace("`","");
- searchwordl=searchwordl.replace("/","");
- searchwordl=searchwordl.replace("\\","");
- searchwordl=searchwordl.replace(",","");
- searchwordl=searchwordl.replace(".","");
- searchwordl=searchwordl.replace("=","");
- searchwordl=searchwordl.replace("<","");
- searchwordl=searchwordl.replace(">","");
- if(searchwordl == '請輸入搜索條件'){
- alert("請輸入搜索條件");
- return false;
- }
- if(searchwordl == ''){
- alert("請正確輸入搜索條件");
- return false;
- }
- if(sig == 1){
- alert("請正確輸入搜索條件");
- return false;
- }
- document.getElementById('searchword').value=searchwordl;
還有JavaScript的爛代碼,這實在太多了,就不貼了。越靈活的語言,越難駕馭,超級爛的代碼就越容易見到。
Tiago Fernandez做過一個投票,選舉最爛的Java API:
- 公式是:score = (I can live with) + (Painful * 2) + (Crappy * 3) + (Hellish * 4)
- 結果,你猜到了嗎?
Java的框架多、語法嚴格,對于限制那些要來搞破壞的程序員確實有幫助。但是真要搞破壞,要限制還是限制不住。以前我接觸過一個Portlet擴展類,一共好幾千行,當時覺得這代碼已經夠爛了。可是后來我看到了5000多行的存儲過程,還有7000多行的jsp頁面——我以前以為Java程序員的破壞力要遠遠小于C/C++程序員。看來,也不盡然。
我的經歷中接觸到的爛代碼,最常見的大概包括下面幾種:
一些命名的惡習,比如“cptct”這種縮略語縮略到幾乎是密碼電報的方法名,大概是受到Basic毒害,即便是早期的 Visual Basic 版本也在代碼中強制實施了一些約束(如變量名的長度、模塊中允許的變量數和模塊的大?。?。
早些年的web項目(甚至包括現在的一些小公司做的web項目),不懂解耦、不會分層,邏輯全部揉在一起,一坨屎一樣。頁面模板直接訪問數據庫、樣式代碼散落在世界各地,HTML寫死在各種邏輯里。
在某些程序員眼里,“復用”==“繼承”,只要有可復用的屬性、公共的方法,就設法用無敵霹靂繼承大法來解決,也不管適不適合,一級又一級,***一定是一棵偉岸無邊的繼承樹。
無窮無盡的工具類。這類代碼比繼承大法的代碼好不到哪去,XXHelper、XXTools這樣的靜態類滿山遍地都是,但是復用的眼光倒是比只會繼承多了一條路……
不會用標準庫函數、封裝好的類庫。我見過好幾個這樣的程序員,對于Integer、Long、Double這些數值對象類型的定義、方法幾乎完全不了解,倒是對String很熟悉,所有的轉換、校驗,全部都轉換成String以后完成,完成后再轉回來。
上帝類。本質是對類的職責單一不理解。用Java、C++的程序員寫出上帝類也就罷了,今年我居然聽朋友說到一個寫Ruby的有相當工作經驗程序員寫出一個巨大的上帝類來……
滿大街亂跑的設計模式。本質是過度設計。好好一個“new Template()”非要引入工廠,再搞一個策略模式、模板模式,不過癮,***加上注解來實現……
大部分的JavaScript、CSS。不解釋。
今天有同事說,代碼之所以成為爛代碼,很大可能是寫代碼的人會遇到比后來讀代碼的人多得多的問題,雖然寫代碼的人解決了大部分的問題,但是剩下的問題還是足以讓代碼遺臭萬年。不過我不這么看,我看到過年份比較早的VB代碼、還有Delphi代碼,雖然都是界面開發用的,雖然很多理念遠遠不及今天,代碼依然清晰易懂。
有的程序員說,工期緊、項目重,領導催得我天天吐血,迫不得已我寫出了爛代碼。客觀原因千千萬萬,我確實無話可說,畢竟在物質文明還非常虛弱的時候,還是不要扯精神文明的蛋。但是,優秀的程序員是有追求的,而人是會麻木的,總是把項目壓力掛在嘴邊的,給一個寬松的限期也不見得能如何。
還有的程序員說,唯物辯證法告訴我們,任何事物都有兩面性,所以我們要學習爛代碼中好的設計,并且把糟糕的設計引以為戒……我說,得了吧。爛就是爛,把屎放在冰激凌蛋筒里也還是屎,那么矯情干什么?
有很多程序員總有一種推倒重來的沖動,特別是看到爛代碼的時候。我也曾經如此。其實這是危險的。況且在很多情況下你的重寫未必有他原來的爛代碼好。也許你能解決其中的30個問題,卻引入了50個新問題。重構還是要在業務模型和流程清晰的情況下盡量小改動、劃模塊入手,大開大合總是危險的。
總說十五年前吃過多少多少苦的程序員我一點都不佩服,我佩服的是在十五年前那種條件和觀念下,依然能夠寫出現在看來都讓人無比舒坦代碼的優秀程序員。不寫爛代碼就是愛惜生命、節約資源、保護地球,寫好的代碼就是一個程序員的素質,沒有那么多理由可以講。