20 個(gè)恐怖傳說:在技術(shù)上犯過的最糟糕錯(cuò)誤
每個(gè)開發(fā)人員內(nèi)心最害怕的事情是什么?在你的代碼開始運(yùn)行前的寧靜時(shí)刻,什么最讓你感到恐怖?你見過或?qū)戇^最可怕的代碼是什么?
錯(cuò)誤的權(quán)限
我負(fù)責(zé)一臺服務(wù)器,然后我通過 FTP 上傳了一些東西。顯示了一些奇怪的東西,所以我想權(quán)限可能需要改變一下。
不用說,我愚蠢地關(guān)閉了讀取權(quán)限并使網(wǎng)站癱瘓了。(當(dāng)沒有人能訪問時(shí),網(wǎng)站就沒啥用了。)
我花了幾個(gè)小時(shí)才修復(fù)好。這是很多年前我在一個(gè)機(jī)構(gòu)擔(dān)任唯一的網(wǎng)頁開發(fā)人員時(shí)的事情。
混亂的 HTML
我曾經(jīng)因 WordPress 的默認(rèn)主題有可用的更新而使一個(gè)客戶的網(wǎng)站癱瘓,這個(gè)客戶當(dāng)時(shí)是《華爾街日報(bào)》暢銷書榜上的一位作者。
他的開發(fā)人員在主題中硬編碼了 HTML,而不是創(chuàng)建一個(gè)子主題。而我運(yùn)行了更新操作。
那個(gè)年代,人們不容易實(shí)現(xiàn)每晚備份,所以我花了幾個(gè)小時(shí)打電話給托管提供商。像分階段發(fā)布、子主題、每晚備份或手動(dòng)備份這樣的東西現(xiàn)在都很常見,還有自動(dòng)更新和手動(dòng)回滾的能力。但在那個(gè)時(shí)代并不常見。
密鑰不再秘密
我想我們中的許多人在公共代碼中看到過密鑰?;蛘吡硪粋€(gè)經(jīng)典案例:我的一個(gè)朋友從開發(fā)服務(wù)器向 10 萬個(gè)用戶發(fā)送電子郵件。
Unix 混亂
這是一個(gè) Unix 的故事。今天在 Linux 中已經(jīng)修復(fù)了這個(gè)問題。
在我要向管理層進(jìn)行一個(gè)重要的新組件演示的前一天,我需要更新我的代碼(這是在 Git 存在之前的年代)。我進(jìn)入我的主目錄,找到項(xiàng)目目錄,然后刪掉了一切。不幸的是,在那個(gè)版本的 Unix 中,該命令會(huì)跟隨符號鏈接進(jìn)行刪除,并且我有一個(gè)鏈接指向代碼的最新版本(并不是所有代碼都在源代碼系統(tǒng)中,因?yàn)樗€處于測試階段)。
好在一天后,大樓里出現(xiàn)了網(wǎng)絡(luò)問題,因此演示推遲了一天,我們設(shè)法恢復(fù)了代碼。那是三十多年前的事情。即使現(xiàn)在我也不知道網(wǎng)絡(luò)問題是巧合,還是我們的系統(tǒng)管理員試圖幫助我們(如果是這樣,那確實(shí)奏效了?。?/p>
命令式編程
看到 CSS 文件中到處都是 !important;
而不是正確使用特異性。
我曾經(jīng)不得不覆蓋和定制一個(gè) WordPress 主題幾乎所有的 CSS,因?yàn)樵摼W(wǎng)站的所有者堅(jiān)持不換一個(gè)更接近他想要的設(shè)計(jì)的新主題。
那個(gè)主題開發(fā)者最后一次更新是在 2018 年,但網(wǎng)站至今仍在使用。
錯(cuò)誤引用
在我以前的職位上,我的前任在代碼注釋中引用了 Journey 的《Any Way You Want It》歌詞錯(cuò)誤。
Algol68 的幽靈
在上世紀(jì) 60 年代末到 70 年代初,Algol68 的復(fù)雜性使許多有影響力的人望而卻步,包括 Niklaus Wirth 在內(nèi)。我記得當(dāng)時(shí)最常見的抱怨之一是:“誰能為這樣一個(gè)復(fù)雜的怪物寫一個(gè)編譯器呢?” 但是事實(shí)上,許多人都開發(fā)過。此外,許多在 Algol68 中發(fā)展出來的或至少以形式化的概念出現(xiàn)在后來的其他語言中,尤其是在 C 語言和 Bourne shell 中(感謝 Steve Bourne)。
Algol68 的一些概念并沒有經(jīng)過很好的演化。例如,處理“書”和“章節(jié)”等的 I/O 概念在今天有些奇怪。像將字符集等問題留給實(shí)現(xiàn)本身處理似乎相當(dāng)過時(shí)。
但是其中一些概念在今天仍然極為重要,例如產(chǎn)生值的表達(dá)式、強(qiáng)類型化(Algol68 中稱為“模式”的類型)、堆內(nèi)存和垃圾回收、運(yùn)算符的定義和重載等等。
有好的地方,也有不好的地方。
Algol68 是一門值得學(xué)習(xí)的語言,即使只是為了了解現(xiàn)代計(jì)算中的許多想法的來源以及在路上丟失了多少。
密碼暴露
我為一個(gè)新的支持客戶進(jìn)行技術(shù)審計(jì)時(shí),發(fā)現(xiàn)之前的開發(fā)人員將密碼以明文形式存儲在整個(gè)主題中,并使用了糟糕的方式連接到遠(yuǎn)程數(shù)據(jù)庫。他們的 composer 文件也異常龐大。每次我嘗試在本地運(yùn)行網(wǎng)站時(shí),需要花費(fèi)五分鐘的時(shí)間。過時(shí)的依賴項(xiàng)、我無法訪問的倉庫,問題還有很多。
迷宮般的代碼
我見過的最可怕的代碼是一段 PDP-11 匯編語言,位于一個(gè)名為 RSTS 的操作系統(tǒng)的內(nèi)核中,今天已經(jīng)沒有人記得它了。當(dāng)時(shí)源代碼記錄在膠片上,我跟隨這段代碼路徑經(jīng)過幾個(gè)轉(zhuǎn)折,試圖弄清楚正在發(fā)生的事情。然后,我遇到了這條指令:
MOV R5,PC
我舉起雙手尖叫了起來。真的,我尖叫了。辦公室里的人以為我撞到頭了,或者心臟病發(fā)作了。
那個(gè)年代,內(nèi)存是寶貴的,MOV
指令使用的內(nèi)存比 BR
(即“分支”)指令稍微少一點(diǎn)。將寄存器 5 的內(nèi)容復(fù)制到程序計(jì)數(shù)器實(shí)際上是一個(gè)廉價(jià)的無條件跳轉(zhuǎn),跳轉(zhuǎn)到寄存器 5 中存儲的地址。但是,我不知道寄存器 5 中存儲了什么,也不知道如何找到它。
時(shí)至今日,將近 40 年過去了,我仍然想知道是誰寫出這樣的代碼,以及如何調(diào)試它。
差一個(gè)
我在自動(dòng)化行業(yè)工作,其中的可編程邏輯控制器(PLC)使用一些相當(dāng)奇怪的語言進(jìn)行編程。
讓我印象深刻的一個(gè)例子是,在 ST 語言中,你可以定義數(shù)組從索引 1 開始。這意味著第一個(gè)元素在位置 1 而不是 0。每當(dāng)我看到這個(gè)時(shí),我都會(huì)抓狂。
分歧
有一次在一個(gè)從測試環(huán)境到生產(chǎn)環(huán)境的發(fā)布期間,我讓 MongoDB 實(shí)例停機(jī)了 40 分鐘。我們的測試環(huán)境與生產(chǎn)環(huán)境有所分歧。只是一個(gè)數(shù)據(jù)庫配置的差異,沒什么太激動(dòng)人心的東西。但這是一個(gè)很好的教訓(xùn),要確保你的測試和生產(chǎn)環(huán)境保持同步!
神秘的低語
這是一個(gè)仍在運(yùn)行且正常的項(xiàng)目,但我已經(jīng)修改了代碼以隱藏源代碼。
for(int c =0; y < yyy && c < ccc; y++, c++){// some code here}
乍看起來,它似乎是一個(gè)無害的循環(huán)。但也許你會(huì)問為什么有兩個(gè)變量、兩個(gè)停止條件以及兩個(gè)增量。然后你會(huì)意識到只有一個(gè)初始化器,第二個(gè)變量(y
)在這個(gè)循環(huán)之前在不同的代碼塊中被初始化。
當(dāng)我意識到這一點(diǎn)時(shí),我花了大約一個(gè)小時(shí)的時(shí)間來理解為什么代碼是這樣編寫的,以及它應(yīng)該如何工作。顯然,代碼中沒有 c
的注釋,并且變量名是無意義的(代碼中被稱為 c
,y
有一個(gè)稍微具有意義的名稱,但不足以解釋它的意義,即使是今天我也不知道它的作用)。
關(guān)鍵數(shù)據(jù)
大約在 1980 年,我在大學(xué)畢業(yè)后得到了我的第一份工作。我是印第安那州一所工程學(xué)院的計(jì)算中心副主管。這是一個(gè)兩人 IT 部門的輔助職位。我在 PDP-11/40 上處理行政計(jì)算,使用 RK05 可移動(dòng)的“披薩碟”磁盤驅(qū)動(dòng)器(每個(gè)驅(qū)動(dòng)器容量為 2.5 MB)。每個(gè)行政辦公室都有一個(gè)驅(qū)動(dòng)器,而我工作的一部分就是每周進(jìn)行磁盤對磁盤的備份。但是那個(gè)夏天我很忙,連續(xù)四周沒有備份過注冊辦公室的數(shù)據(jù)。然后我意識到了風(fēng)險(xiǎn),所以我確保開始進(jìn)行每月的磁盤到磁帶備份。
我從 11/40 上卸載了注冊辦公室的磁盤驅(qū)動(dòng)器,然后裝在了帶有一臺 9 磁道磁帶驅(qū)動(dòng)器的 11/70 上,并開始進(jìn)行備份。幾分鐘后,我聽到磁盤驅(qū)動(dòng)器里傳來一陣刮擦的聲音。是的,磁頭撞上了磁盤。在短短幾分鐘內(nèi),我摧毀了所有注冊辦公室的數(shù)據(jù),以及最新的備份 —— 一個(gè)四周前的 9 磁道磁帶。
當(dāng)我不得不面對注冊辦公室主任,并告訴他我已經(jīng)摧毀了他所有的數(shù)據(jù)時(shí),那一刻真的很尷尬。
如今,我告訴新的 IT 人員,只有在你摧毀了某人的關(guān)鍵數(shù)據(jù),而且無法恢復(fù)時(shí),你才算是專業(yè)人士。永遠(yuǎn)記住你胃里的那種感覺。
憤怒的暴民
一個(gè)客戶篡改了 WordPress 核心代碼以添加后續(xù)在常規(guī)更新中發(fā)布的功能,但他們卻不明白為什么在每次嘗試更新 LearnDash 時(shí)網(wǎng)站都會(huì)崩潰。(他們也不喜歡我們的報(bào)告指出了他們糟糕的開發(fā)實(shí)踐。)于是他們趕我們走,稱我們是騙子和無能之輩。但直到今天,我仍然具有他們域名的委派訪問權(quán)限,以及兩個(gè)域名的生產(chǎn)和開發(fā)環(huán)境的 wp-admin 訪問權(quán)限。
此外,盡管我們給了一個(gè)加密位置的鏈接用于共享訪問憑據(jù),他們卻通過電子郵件發(fā)送了我們的登錄信息。
不要忘記備份
我在企業(yè)網(wǎng)絡(luò)上的工作經(jīng)驗(yàn)不多,所以我沒有使任何服務(wù)器崩潰過。然而,作為一個(gè)年輕人,我曾經(jīng)試圖幫助一個(gè)人解決 IT 問題,不知何故導(dǎo)致 Windows 95 崩潰,并不得不免費(fèi)重新安裝。
作為一個(gè)非常年輕的 Amiga 用戶,我最悲傷的時(shí)刻之一是我的保存磁盤壞掉了,里面裝滿了所有我的文件,原因是某種機(jī)械故障。如今,我已經(jīng)學(xué)會(huì)更好地備份我的重要個(gè)人文件。
萬惡之源
當(dāng)時(shí)我剛開始接觸 Linux,之前我用的是 DOS,借助 Norton Commander 進(jìn)行操作。后來,Midnight Commander 發(fā)布了,我非常喜歡它。當(dāng)時(shí)我使用的 Linux 發(fā)行版(Jurix)沒有打包 Midnight Commander,所以我自己從源代碼編譯了它,就像我那個(gè)時(shí)候使用的其他軟件一樣。它完美地運(yùn)行了,突然間我在 Linux 上感到更親切了。
這不是一個(gè)恐怖的故事。
我的同事告訴我不要以 root 身份運(yùn)行 Midnight Commander,無論它有多么讓人舒適。但是 root 權(quán)限很方便,感覺更像 DOS,所以我無視了他們的建議。結(jié)果就是:我意外地刪除了整個(gè) /etc
目錄的內(nèi)容。在那之前,我從來沒有用過備份功能,但是那一天我意識到備份實(shí)際上是有用的。
27 年過去了,我仍然記得這個(gè)故事,并定期進(jìn)行備份。
幻覺
最糟糕的項(xiàng)目是一家代理機(jī)構(gòu)讓我做的一個(gè)一屏的頁面,一開始看起來很簡單。我說我可以用一些 HTML、CSS,也許加點(diǎn) JavaScript,將其組合起來。但他們特別要求我不要這樣做。他們希望我將設(shè)計(jì)圖剪切下來,然后使用 CSS 在頁面中定位這些元素。他們還要求我將所有的 CSS 內(nèi)嵌到 HTML 文件中,因?yàn)樗麄冋娴闹幌胍?strong>一個(gè)頁面。
其中的文本都不是真實(shí)的文本。
除了定位這些圖片所需的元素之外,其他都不是真正的 HTML 元素。
我告訴他們,設(shè)計(jì)足夠簡單,我可以用實(shí)際的代碼將其組合起來,但他們不想要那樣。他們只想讓我花時(shí)間將這些碎片拼湊在一起,然后轉(zhuǎn)而做其他項(xiàng)目。他們讓我做了兩個(gè)類似的一屏網(wǎng)站。
這實(shí)在傷害了我的前端靈魂。為我來說,這個(gè)項(xiàng)目在身體上是痛苦的。這是一個(gè)試用合同職位,當(dāng)他們給我提供全職工作時(shí),我禮貌地拒絕了。
內(nèi)存破壞
對我來說,最可怕的事情就是 ANSI C99 中可能發(fā)生的內(nèi)存破壞。在一個(gè)屏幕錄像中,我捕捉到了這個(gè)(不完全是)超自然現(xiàn)象,可以在這個(gè) YouTube 視頻片段 中觀看到。
Image of gseqencer before memory corruption.
標(biāo)有 file
的 GtkEntry 顯示了一些隨機(jī)的符號。我檢查了一下 代碼,但沒有發(fā)現(xiàn)任何問題。
ags_export_soundcard_open_response_callback()
函數(shù)是一個(gè)回調(diào)函數(shù),用于處理 GtkFileChooserDialog
的 response
事件。(順便說一句,用于解決這個(gè)問題的工具是 valgrind。)
Image of gsequencer after memory corruption.
Python 的恐怖之處
我見過的最可怕的編程特性是 Python 中對 dict
的訪問權(quán)限。在運(yùn)行時(shí)改變對象的類型違背了我的編程行為準(zhǔn)則。
縫合怪網(wǎng)絡(luò)
在 2006 年,我用 Fedora 和一些腳本構(gòu)建了一臺防火墻,并說服了一家托管在合作數(shù)據(jù)中心的大型網(wǎng)站的客戶,將其專有的防火墻替換為我的防火墻。我建立了系統(tǒng)并在一個(gè)清晨的 4 點(diǎn)到達(dá)現(xiàn)場進(jìn)行安裝。那時(shí)我才發(fā)現(xiàn)(飽受痛苦地)他在防火墻后面有一個(gè)帶有公共 IP 地址的負(fù)載均衡器??蛻艚?jīng)歷了一個(gè) 5 分鐘的停機(jī)時(shí)間,但我重新連接了一切恢復(fù)到原來的狀態(tài)。
我發(fā)現(xiàn)了一種通過使用代理 ARP 來處理他復(fù)雜的網(wǎng)絡(luò)配置的方法。這個(gè)想法是,當(dāng)外部世界的任何人發(fā)出負(fù)載均衡器的 ARP 請求時(shí),我會(huì)進(jìn)行回應(yīng)。幾天后,我再次在凌晨 4 點(diǎn)出現(xiàn)并安裝了我的系統(tǒng)。這次,我把整個(gè)數(shù)據(jù)中心的所有設(shè)備都給搞宕了。我設(shè)置了我的代理 ARP 來回應(yīng)所有請求,因此局域網(wǎng)上的所有流量最終都找到了我并消失在黑洞中。
當(dāng)我意識到我做了什么時(shí),我把一切都恢復(fù)到原來的狀態(tài)。但是損害已經(jīng)造成。如果有人在 2006 年的一個(gè)清晨美國中部時(shí)間大約 4 點(diǎn)鐘嘗試瀏覽你最喜歡的網(wǎng)站,它沒有響應(yīng),那可能是我的錯(cuò)。我通過在機(jī)架上安裝并啟動(dòng)一個(gè)系統(tǒng),讓整個(gè)數(shù)據(jù)中心的網(wǎng)站都宕機(jī)了。
網(wǎng)站運(yùn)營商憤怒地抗議,而我則黯然離開。他們再也沒有邀請我回去再試。真是遺憾,我覺得再試試橋接可能會(huì)起作用。
你的恐怖故事
你最喜歡的與技術(shù)相關(guān)的恐怖故事是什么?在評論中告訴我們(但要友善,并更改項(xiàng)目名稱以保護(hù)無辜者?。?/p>