午夜视频在线观看你懂的-国产对白videos高潮内射-成人国产一区二区三区av-亚洲欧美中文日本在线视频

前端教程
當(dāng)前位置: 主頁 > 資訊 > 前端教程
代碼恐怖故事:隱藏在復(fù)雜代碼庫中的恐怖秘密
發(fā)布日期:2023-07-10 閱讀次數(shù):

  本文講述了開發(fā)者們在復(fù)雜代碼庫中工作的經(jīng)歷和教訓(xùn),包括代碼復(fù)雜性帶來的問題、架構(gòu)決策、第三方庫引發(fā)的意外問題以及令人恐慌的編程錯誤,以及如何處理這些挑戰(zhàn)。

  無論你是軟件開發(fā)領(lǐng)域的老兵,或者剛剛踏上這個領(lǐng)域的新人,你可能都對在復(fù)雜的分布式軟件環(huán)境中工作所帶來的壓力和那些讓人瞠目結(jié)舌的驚魂時刻有著深深的認(rèn)識。我們深信,你一定曾面臨過代碼庫復(fù)雜性所引發(fā)的問題,也在調(diào)試的過程中歷盡艱辛,或者因為錯誤的設(shè)計決策而有過自己的“代碼恐怖故事”。

  畢竟,許多開發(fā)者都有類似的故事可以分享。我們決定每次邀請一位知名的開發(fā)者,分享他們的代碼恐怖故事。這一次,我們請來了 Daniel Beck——一位擁有豐富軟件開發(fā)經(jīng)驗的專家、產(chǎn)品開發(fā)的用戶體驗顧問,由他和我們分享他的代碼恐怖故事。

  Daniel 在軟件開發(fā)領(lǐng)域的經(jīng)驗相當(dāng)豐富!他從業(yè)的時間甚至可以追溯到該行業(yè)的早期階段。他開始工作時使用的瀏覽器還是 NCSA Mosaic。在那個時代,只需要掌握五個 HTML 標(biāo)簽,你就可以開始投入工作了。在他的職業(yè)生涯中,Daniel 積累了獨特的見解,我們堅信你們可以從中受益。

  大家如果感興趣可以訪問他的博客,大家的訪問能給他帶來更大的創(chuàng)作動力!blog

  在安裝新的 npm 模塊或引入他人的代碼時,必須深入考慮其潛在的風(fēng)險和影響。

  警惕那些基于個人審美重構(gòu)代碼,卻沒有提供適當(dāng)文檔或確保代碼完整性的團(tuán)隊成員。

  要認(rèn)識到即使像 Facebook 這樣的大公司也會犯錯誤,以免過分迷信他們,比如他們在 2021 年10月4日的 DNS 故障。

  有 BUG 的代碼總是可以修復(fù)的,而人的關(guān)系,那就要復(fù)雜得多,需要更加謹(jǐn)慎對待。

  Daniel:這個問題真的只有在回首過去的時候才顯得恐怖;當(dāng)時,我倒是自認(rèn)為這是我最得意的一次創(chuàng)作。(沒錯,這是我自己犯下的錯誤。)

  這個項目的目標(biāo)是設(shè)計一個內(nèi)容管理系統(tǒng),用于批量生成特殊類型的網(wǎng)站變體。我負(fù)責(zé)搭建前端系統(tǒng),輸入網(wǎng)站數(shù)據(jù),通過一系列精心設(shè)計的模板,生成最終的網(wǎng)站。

  那是在 20 世紀(jì) 90 年代末,那時整個行業(yè)都認(rèn)為 XML 是行業(yè)標(biāo)準(zhǔn),應(yīng)當(dāng)遵循。因此,我理所當(dāng)然地決定使用 XSLT 來構(gòu)建模板系統(tǒng)。

  如果你對 XSLT 不熟悉,它是一種非常純凈的語言,用于將 XML 結(jié)構(gòu)轉(zhuǎn)換為其他 XML 結(jié)構(gòu),因為 XML 被認(rèn)為是標(biāo)準(zhǔn),所以 XSLT 也是用 XML 編寫的。

  其中一些有趣的挑戰(zhàn)包括:XSLT 是嚴(yán)格的冪等的,從哲學(xué)的角度來看,這是很好的,但從實踐的角度來看,這意味著所有的循環(huán)操作都必須通過遞歸完成,因為增加一個用于迭代循環(huán)的變量會被視為一個副作用,因此是不允許的。流程控制最好通過數(shù)據(jù)的分解而不是分支邏輯來完成。對于習(xí)慣了腳本語言和標(biāo)記的人來說,這真的是一個大挑戰(zhàn)。

  我卻很喜歡它。我不再需要從后端的團(tuán)隊那里獲取我需要的具體數(shù)據(jù),所有的數(shù)據(jù)都會以一個巨大的 XML 塊的形式傳給我,我可以通過我日漸龐大的 XSL 模板塊生成我想要的任何東西。我覺得我有了超能力!我可以做任何事情!

  現(xiàn)在,需要明確的是,整個過程我都樂在其中,我完全清楚我正在使用的是一門注定要失敗的語言。這是在現(xiàn)代前端框架誕生之前很久的事情了,那個時候,“前端”技能通常意味著你熟悉 Photoshop、HTML、CSS,以及可能從其他網(wǎng)站“查看源代碼”功能獲取的一小部分 JavaScript 代碼。相比之下,這里有一種非常復(fù)雜,看起來很奇怪的“前端”語言,它需要一些比當(dāng)時的網(wǎng)絡(luò)開發(fā)者所習(xí)慣的計算機(jī)科學(xué)概念更為高級。

  但我卻很喜歡它,而且正在學(xué)習(xí)這些高級概念,并因為能做到這一點而。在大約一年的時間里,我構(gòu)建了一個相當(dāng)大的模板集,隨著我對我正在做的事情的理解逐漸深入,它們變得越來越不那么糟糕。到最后,我在編寫高度解耦的,符合最佳實踐的代碼,我覺得它們聰明,甚至有時候會覺得有些“優(yōu)雅”。我按照計劃發(fā)布了產(chǎn)品,收取了我的合同費用,然后帶著滿滿的信心投入到了下一份工作。

  我得到的消息是,在接下來的五年里,他們一直沒對這些 XSL 模板做過維護(hù),直到產(chǎn)品被全部淘汰并替換,因為在公司里真的沒有其他人能理解它們是如何運行的。顯然,那些我自認(rèn)為聰明、優(yōu)雅的代碼是多么糟糕。我的早期,簡單直接的代碼反而更易于理解和維護(hù)。

  這是一個重要的教訓(xùn)。直觀、易讀的代碼,無論其是否精巧,都優(yōu)于那些聰明且復(fù)雜的代碼。

  這是我作為自由職業(yè)開發(fā)者的歲月中的一次經(jīng)歷。一家經(jīng)常將大部分開發(fā)工作外包的中等規(guī)模公司,也是我的長期客戶,有些惶恐地找到我:他們將一個小型項目托付給了一個新的供應(yīng)商,工作已經(jīng)接近尾聲,即將達(dá)到上線的時刻。然而,一旦他們開始使用實際數(shù)據(jù)替代測試數(shù)據(jù),他們便開始遇到嚴(yán)重的性能問題:當(dāng)網(wǎng)站需要處理超出小數(shù)據(jù)量時,整個網(wǎng)站就會顯著地變慢。供應(yīng)商將問題歸因于硬件,并建議升級到更強(qiáng)大、更昂貴的服務(wù)器。在掏出這筆錢之前,客戶讓我來對此進(jìn)行實地考察。

  長話短說,問題最后被定位到是供應(yīng)商編寫的一個函數(shù)導(dǎo)致的,這個函數(shù)使得他們與數(shù)據(jù)庫的交互變得更加便捷:你只需要將 SQL 查詢語句輸入給它,它會打開數(shù)據(jù)庫連接,執(zhí)行查詢,返回結(jié)果,然后清理并關(guān)閉連接。

  這的確使他們的代碼非常易讀。然而,問題在于——我相信許多讀者可能已經(jīng)意識到——開啟和關(guān)閉數(shù)據(jù)庫連接是一個緩慢且耗資源的過程。理想情況下,你應(yīng)當(dāng)在開始時打開一次,執(zhí)行所有查詢,然后在全部完成后再關(guān)閉。但是,由于這些人的編程方式是對每一個獨立的操作都開啟和關(guān)閉連接,這就意味著有時需要打開和關(guān)閉數(shù)百次甚至數(shù)千次:一次是為了加載數(shù)據(jù)列表,然后每一項列表數(shù)據(jù)都需要再次開啟和關(guān)閉。難怪服務(wù)器會變得如此慢!

  最后,問題得到了簡單的解決——只需將 open 和 close 操作從實用程序中移除,將它們移到程序的起始和終止部分,而非在循環(huán)中重復(fù)執(zhí)行。然而,這是一個極好的例證,展示了快捷方式的潛在危險,以及使事情運行起來和理解為何它能運行以及它在后臺做了什么之間的差別。如果他們每次開啟和關(guān)閉數(shù)據(jù)庫都必須編寫代碼,他們可能就不會遇到這個問題了,但事實卻是,這個操作被隱藏在輔助函數(shù)里,所以人們很容易忽略。

  我每次安裝一個新的 npm 模塊或者以其他方式引入別人的代碼時,都會想起這個故事……這個模塊在做什么看似合理的事情,有可能會給我的工作帶來困擾嗎?

  我們擁有兩個獨立卻相關(guān)的網(wǎng)絡(luò)產(chǎn)品,由各自的團(tuán)隊分別使用不同的編程風(fēng)格在各自的代碼庫中進(jìn)行開發(fā)。我們的目標(biāo)是將這兩者整合成一個產(chǎn)品。

  由于兩個代碼庫的復(fù)雜性和龐大規(guī)模,要將它們重構(gòu)成一個整潔、統(tǒng)一的代碼庫無疑是一個長期的項目;與此同時,我們急需一個短期的解決方案。

  我們原本應(yīng)該保持原有的代碼不變,只需在統(tǒng)一的用戶界面上添加各個產(chǎn)品間的導(dǎo)航鏈接。

  然而,我們實際上做的是將產(chǎn)品 A 的所有代碼復(fù)制到產(chǎn)品 B 的代碼庫的子目錄中,希望能夠逐步重構(gòu)兩個產(chǎn)品的代碼,使之互相匹配,并在此過程中找出并消除重復(fù)功能。

  這個方法可能會取得好的結(jié)果!然而,一個事實打破了這種可能性,那就是那位負(fù)責(zé)復(fù)制代碼的工程師認(rèn)為在此過程中進(jìn)行部分重構(gòu)是個好主意。他根據(jù)自己的編程風(fēng)格,對兩邊的代碼進(jìn)行了大量的重大改動,完成程度各不相同。

  在這個過程中,他大部分時間都在設(shè)法避免對代碼產(chǎn)生明顯的破壞,然而他同事們并不知道他已經(jīng)做了一些未記錄的改動,這些改動也留下了難以察覺的陷阱。然后,他立即辭職,加入了一家競爭公司。

  所以,我們最終以原本預(yù)計的兩倍時間投入完成了那個艱難的重構(gòu),同時也進(jìn)行了代碼審查。我們最終完成了,但整個過程非常痛苦,是我至今為止最令人后悔的一次經(jīng)歷之一。

  最后我聽說,那家公司正在“拆分單體應(yīng)用”,并開始將那個統(tǒng)一的前端分解為獨立卻相關(guān)的產(chǎn)品。

  在 2021 年 10 月 4 日,F(xiàn)acebook 因 DNS 故障導(dǎo)致自身以及其相關(guān) API 大部分時間不可用。這也使得我們的應(yīng)用程序由于過度依賴這些 Facebook 的 API(我們默認(rèn)它們永遠(yuǎn)在線)而被迫下線。畢竟,這是我們都信任的 Facebook,沒人會預(yù)料到 Facebook 的服務(wù)會出現(xiàn)這樣的問題。

  為了修復(fù)這個問題,我們緊急進(jìn)行了大量代碼重寫。然而,就在我們幾乎完成部署并讓應(yīng)用程序在沒有那個 API 的情況下也可以正常運行的瞬間,他們的 API 服務(wù)恢復(fù)了。

  我一直嚴(yán)格確保自己不去訪問生產(chǎn)服務(wù)器,因為我不想成為那個無意間在生產(chǎn)環(huán)境中破壞某些東西的人。

  然而,我還是犯了錯誤:“這里還有一些未合并的代碼,讓我登錄服務(wù)器來處理一下?!苯Y(jié)果造成了意外!那天在 Slack 上的情況,我都截圖保存了下來:

  我職業(yè)生涯中真正的恐怖瞬間,則要追溯到 Slack 和 Hipchat 之前,回到電子郵件的時代。

  那是在一家小而成熟的初創(chuàng)公司。我們的一位客戶支持人員在深夜向團(tuán)隊的一部分人發(fā)送了一條消息,尋求處理一個特別苛刻的客戶問題的建議。我已經(jīng)不記得具體的問題是什么了,但那個問題演變成了一場工作時間之外的抱怨會,我們大家都在電子郵件中抱怨這些客戶多么難以應(yīng)對,他們的一些要求多么不合理。名單越來越長,從銷售到工程到首席執(zhí)行官,每個人都對此進(jìn)行了抨擊。最后,客服代表得到了她需要的答案,并將其發(fā)送給了客戶。

  然后這個消息回到了列表中:“呃...伙計們?我想我可能不小心把整個電子郵件線程都轉(zhuǎn)發(fā)給了客戶。”

  接下來的十分鐘內(nèi),所有人都陷入了沉默,心跳加速地翻閱整個回復(fù)鏈,尋找自己可能需要道歉的言論。最后結(jié)果證明是虛驚一場,她實際上并沒有將整個電子郵件線程發(fā)送給客戶。但那確實是一個我希望再也不要經(jīng)歷的驚魂時刻。有 BUG 的代碼很容易修復(fù),但人的關(guān)系破壞了就很難修復(fù)了。

  大多數(shù)開發(fā)者都有自己獨特的故事。你是否也曾親歷過一些“代碼恐怖故事”?歡迎在留言區(qū)分享討論。