我見過的最糟糕代碼

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"本文最初發佈於jesuisundev.com網站,經原作者授權由InfoQ中文站翻譯並分享。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在本文中,我將向你展示我見過的一些最糟糕的代碼,它們被稱爲“魔鬼代碼”,會帶來很嚴重的後果。然而,我們發現通過一些好的實踐,你可以很容易規避它們。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"“魔鬼代碼”"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"需要改進的代碼與所謂的“魔鬼代碼”是不一樣的"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不管使用的是哪種語言,“魔鬼代碼”都很糟糕,因爲它會危及項目的穩定性和可維護性。在職業生涯中,我見過很多“魔鬼代碼”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當它堆積如山時,你的項目很快就會變成“十八層地獄”的樣貌。如果你喜歡到處捅婁子,那麼領導看你的眼光也會越來越不一樣。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"模棱兩可和前後矛盾"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很久以前,我在一個清晨醒來,被世界末日般的景象嚇了一跳。生產環境出現一個很大的錯誤,所有系統票證莫名其妙地返回“null”。到處都亂成一團。所有人都像無頭蒼蠅一樣到處亂跑。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我跑到公司,衝向工作站,第一步是看Kibana。但是,沒有日誌,什麼都沒有。爲了查明原因,我決定追溯票證的創建路徑。因此,我必須深入研究系統從誕生到現在創建的那些內部庫。經過一番調查,我找到了問題來源之一的一堆文件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後,我看到這樣的景象:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"\/\/ use id and expire to get ticket\nasync function get_ticket(i, expire) {\n return CheckisNotExp(expire).then(async function() {\n var t = await GetTicketModel(i)\n if (t) {\n return t\n } else {\n logger.error(JSON.stringify(t))\n return null\n }\n }).catch(async function(e) {\n logger.error(JSON.stringify(e))\n return null\n})\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"真有一個“i”變量嗎?這是一個id,對不對?它是整數還是UUID?到底是什麼到期了?是日期還是時間戳?爲什麼會有"},{"type":"codeinline","content":[{"type":"text","text":"camelCase"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"PascalCase"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"snake_case"}]},{"type":"text","text":"?帶有promise的異步註解和又一個異步註解?如果失敗,我們會返回null?簡直是魔鬼啊!"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那時,每隔5分鐘就有一半的公司同事向我發Skype消息,索取ETA修復。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不過,首先,有人需要知道這裏究竟發生了什麼。而我意識到,該爲這個問題負責的不是一個人,而是三個人。很久以前,其中兩個人離開了公司,而第三個人今天早上還沒來公司。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"根據Git的記錄,這三個人碰這個文件的時間各自差了很久。因此,他們留下了不一致的代碼、不同的樣式、不一樣的ECMAScript版本和不同的promise處理方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不管怎樣,在這段代碼中,一切都是模棱兩可的,一切都是不一致的。"},{"type":"text","marks":[{"type":"strong"}],"text":"這是一個絕佳的反面案例,你應該盡一切可能避免這種情況"},{"type":"text","text":"。不用說,代碼審查並沒有覆蓋到這裏。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了解決問題,我們必須快速重寫它,更改那些變量和函數的名稱,不能再出現歧異。而且,各處的Async\/Await都要做成相同的方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我還要確保自己不會漏掉任何錯誤,結果再返回一個null。如果出現什麼問題,這些錯誤肯定要破壞函數。異常應由上面的層來處理。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"\/\/ hotfix\n\/\/ @todo rewrite the ticket module entirely\nasync function getTicket(ticketUuid, ticketExpirationTimestamp) {\n await validTicketExpiration(ticketUuid, ticketExpirationTimestamp)\n const ticket = await getTicketByUuid(ticketUuid)\n\n return ticket\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最好的解決方案是重寫這個模塊的一部分。這裏的票證驗證邏輯很糟糕。但這並不是最要緊的事情。當務之急是找出並修復錯誤。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在更新代碼後,真正的錯誤開始浮出水面。"},{"type":"text","marks":[{"type":"strong"}],"text":"前一天所做的一個配置更改改變了票證創建行爲"},{"type":"text","text":"。返回到先前的配置則可以立即解決這個問題。接下來的一週時間裏,有問題的模塊被完全重寫。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"肉醬意麪"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很久以前,我正在做一個代碼乾淨整齊的產品。作爲優質產品,一切都在內部做好了優化。功能是用盡可能少的代碼開發的。代碼高度重視可讀性。由注重整潔代碼的工程師管理的代碼審查流程確保產品嚴格遵循所有最佳實踐。SOLID、DRY、KISS、YAGNI和你可以想到的其他首字母縮寫詞,這裏都能見得到。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"即使做到這個地步,這個產品的某個特殊部分也會間歇性地崩潰"},{"type":"text","text":"。在一個衝刺期間,我終於設法安排出時間來調查這件事。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很快,我意識到問題不在於產品。"},{"type":"text","marks":[{"type":"strong"}],"text":"那些錯誤只有一個共同點:一個依賴項"},{"type":"text","text":"。那是一個通過內部工件處理的內部依賴項。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"它由另一個團隊管理,而且——令人驚訝的是——這段代碼不是免費提供的。你必須先獲得許可才能看到它。因此,我請求了訪問權限來了解到底發生了什麼事情。然後,我收到了一條Slack消息,問我爲什麼要訪問源碼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“你好!爲什麼你需要訪問這個存儲庫?”"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“這是什麼意思?你知道我在這裏工作嗎?等等,我在路上。”"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我突然出現在他面前後,終於拿到訪問該項目的權限。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我在其中看到一個文件,大小爲300KB。300KB的文本,竟然有那麼大。它已經有好幾年沒人碰過了。上次碰過它的那個人,我完全不認識。簡直是最可怕的魔鬼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那是我一生中見過的規模最大的意大利麪條代碼。篇幅所限,我並沒有把所有代碼都放在這裏。下面的代碼只是一部分:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"\/\/ Thousands of lines of spaghetti codes\n\nif (global.Builder)\n{\n module.exports.buildPgs = function(pgs, options, limitNodes = 0)\n {\n var config = options.config || {};\n var builded = [];\n pgs.each(function(pg)\n {\n var supported = pg.prop('tagName') == \"INPUT\"\n && pr.attr['name'] == \"file\"\n && options.pgs.rel.active == \"\"\n && global.FileReader;\n if (!supported || !pg.f || pg.f.length == 0)\n return;\n \n for (var i = 0; i < pg.f.length; i++)\n {\n builded.push({\n file: pg.f[i],\n instanceConfig: _.extend({}, config)\n });\n \n if (isFunction(options.before))\n {\n var returned = options.before(pg.f.path);\n if (typeof returned === 'object' && global.status.in_progress)\n {\n if (returned.action == \"skip\")\n {\n var needsSkip = (typeof global.status.in_progress === 'boolean' && global.status.in_progress)\n || _.hasAny(\"cancel\", Global._quotes.BAD_DELIMITERS)\n || str.indexOf(Global._delimiter) > -1;\n \n if(needsSkip) return;\n }\n else if (typeof returned.config === 'object')\n {\n var LOCAL_BUILDER = new global.Builder(\"\/builder\/\" + options.module + \"\/\" + options.module + );\n \n for(var s=p,a=p.matchIndex(o),shift=0,i=0;i
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章