【譯文】抽象漏洞法則
翻譯 :鄒永勝
歡迎訪問網易雲社區,了解更多網易技術產品運營經驗。
互聯網上有一個很關鍵的部分,你每天都依賴於它,它處於TCP協議中,它是互聯網的基本組成部分之一。
TCP協議是可信賴的傳輸層協議。這就意味著你采用TCP去發送數據,不會存在數據混亂或丟失的情況。
我們日常中的很多事情都在使用TCP協議,例如瀏覽網頁或者發送郵件。每一封郵件能夠穩定的到達正是由於TCP的可靠性。盡管其中有許多垃圾郵件。
作為比較,另外一個不可靠的傳輸數據的協議稱為 `IP`。沒有人能夠保證你發送的數據能夠達到,即使到達了,數據也許已經混亂了。如果你采用IP協議去發送一批數據,如果只有一半數據到達了,千萬別驚訝。即使是達到的數據中,也不能保證數據正確。
但是有個神奇現象:TCP是在IP協議之上的,TCP有義務采用一種不可信賴的方式去傳輸數據。
為了解釋這個神奇的現象,在真實的世界中以道德的角度來思考這個問題:
想象我們要從百老匯運送一批演員到好萊塢,我們采用汽車運輸的方式,橫跨幾個州。運輸過程中,有些車輛墜毀了,可憐的演員就這樣掛了。有些演員或醉酒、剪了頭發、紋了鼻子等,形象變化了,以至於好萊塢不再接受他們演出。與此同時,由於每輛車的行駛路線不同,導致每個演員的到達時間不一樣。現在假設有一種服務叫做好萊塢速遞,它能快速安全有序的運送演員到好萊塢,每個演員的到達順序和出發順序完美地保持一致。神奇的部分在於好萊塢速運除了把演員塞進車裏,然後橫跨幾個州運輸外,沒有其他辦法運輸。好萊塢速運會檢驗每個演員確保是否完好無損的到達,如果出現問題,就會請求總部,重新下發送一個與損壞的那個演員一模一樣的演員過來。如果到達後演員順序出錯,速運公司會重新給他們排序。如果有不明飛行物撞擊損壞了內華達州的道路,那麽所有的運輸車輛都會重新選擇亞利桑那州的道路。當到達目的地後,速運公司不會告知加州的好萊塢導演們中途發生了什麽,對於導演來講,他的演員們僅僅是比之前慢一點而已,至於中午的UFO撞擊事件他們壓根不知道。
也就是說,TCP的神奇之處就是計算機科學家們喜歡稱之為抽象的東西:掩蓋復雜的流程達到簡化的目的。事實證明,很多計算機編程都是由抽象構成的。什麽是字符串庫?這是一種使計算機能像操縱數字一樣容易操作字符串的方法。什麽是文件系統?這是一種假裝硬盤驅動器不是一堆可以在特定位置存儲二進制數據位的旋轉磁盤,而是一個文件夾內文件夾的分層系統,其中包含單個文件,這些文件又由一個或多個字節串組成。
回到之前的TCP。早些時候,為了簡單起見,我撒了個小謊,有些人現在耳中已經湧出了怒氣,因為謊言使得你瘋狂。之前我說TCP保證你的消息會到達。 實際上並非如此。 如果您的寵物蛇將連接計算機之間的網線咬斷了,那麽沒有任何IP數據包可以通過,自然通過TCP方式傳輸的任何數據都到達不了,自然你的消息無法到達。 與此同時如果公司中的系統管理員懲罰你,將你的網絡分配到一條過載的集線器上,只有部分IP數據包能夠通過,盡管此時TCP可以工作,但是一切都會變得非常慢。
這就是我所稱做的*抽象漏洞(leaky abstraction)*。TCP嘗試在一條極不穩定的網絡線路上提供穩定的服務,但是由於網路漏洞的限制,導致這種抽象並不能平穩的保護你的數據。這僅僅是我為了闡述抽象漏洞所闡述的一個例子:
> 某種意義上任何有意義的抽象都是由漏洞的
> - All non-trivial abstractions, to some degree, are leaky.
抽象失敗。有時比較少,有時卻很多。有存在漏洞的。有出錯的。當你有抽象的時候,漏洞總會。下面是一些例子。
- 有時就像在大型二維數組上叠代,純水平、垂直方向操作可能具有完全不同的性能,單純的一個方向所產生的錯誤可能會大於操作另外一個方向。即使程序員假裝他們擁有一個大的平面地址空間(實際上也是真是內存的一個抽象),當出現錯誤時,確定的物理空間提取數據比其他空間更耗時。
- SQL語言旨在抽象出查詢數據庫所需的過程性步驟,而只允許您定義所需的內容,並讓數據庫確定查詢數據庫的過程性步驟。但在某些情況下,某些SQL查詢比其他等價查詢查詢慢數千倍。一個著名的例子是,即使結果集相同,如果指定“where a=b and b=c and a=c”,那麽一些SQL服務器的速度要比只指定“where a=b and b=c”快得多。你不必關心程序,只需要規範。但是有時候抽象會泄露並導致糟糕的性能,你需要跳出查詢計劃分析器,研究它做錯了什麽,並找出如何使查詢運行得更快。
- 即使像NFS和SMB這樣的網絡庫允許您將遠程機器上的文件“當作本地的”來對待,但有時連接變得非常慢或中斷,文件停止工作就像本地一樣,並且作為程序員,你必須編寫代碼來處理這個問題。“遠程文件與本地文件相同”的抽象就泄露。這裏是UNIX系統管理員的一個具體例子。如果您將用戶的主目錄放在NFS掛載的驅動器上(一個抽象),並且你的用戶創建.forward文件以將其所有電子郵件轉發到其他地方(另一個抽象),此時NFS服務器在新電子郵件到達時關閉,則不會轉發消息,因為.forward文件找不到。抽象中的漏洞實際上引起了一些消息被拋棄。
- C++字符串類應該讓你覺得字符串是一流的數據。他們試圖抽象出字符串並讓你其表現像整數一樣簡單。幾乎所有C++字符串類都重載+運算符,因此可以編寫S+“bar”來連接。但是你知道嗎?不管他們怎麽努力,在地球上沒有C++字符串類,可以讓你鍵入“foo”+“bar”,因為C++中的字符串文字總是char *,從來沒有字符串。抽象出現了一個漏洞,語言不允許你插入。(有趣的是,隨著時間的推移,C++演進的歷史可以被描述為試圖在字符串抽象中插入漏洞的歷史。為什麽他們不能只給語言添加一個本地字符串類)
- 下雨的時候你不能開得那麽快,盡管你的車有擋風玻璃的雨刷、前燈、車頂和加熱器,這些都是起到保護你的作用,讓你不要擔心下雨的事實,但是你仍舊得擔心水上滑行。在英國,有時雨很大,你看不見前面很遠的地方,所以在雨中需要放慢速度,因為天氣永遠不可能完全被抽象出來,因為抽象法則有漏洞。
抽象漏洞法則有問題的一個原因是,抽象並沒有真正簡化我們的生活。當我培訓某人成為C++程序員時,如果我從來沒有教過他們關於字符型指針和指針算法的話,而是能直接進入STL字符串,那就很好了。但是有一天他們會編寫字符串拼接的時候,“foo”+“bar”,真正奇怪的事情就會發生,無論如何,我必須停下來教他們關於字符指針的所有知識。或者有一天,他們無法調用具有具有OUT LPTSTR參數的Windows API函數,直到他們了解了char*、指針、Unicode、wchar_t、TCHAR頭文件。
在向某人教授COM編程時,如果我能教他們如何使用Visual Studio向導和所有代碼生成特性就好了,但是如果出了什麽問題,他們就不知道為什麽以及怎麽調試它、修復它。因此我要教他們所有關於IUnknown、CLSID、ProgIDS...,天哪,還有好多細節要講!
在教授有關ASP.NET編程的知識時,如果我能教給他們,他們可以雙擊一些東西,然後在用戶單擊這些東西時編寫在服務器上運行的代碼,那就太好了。但是實際上,ASP.NET抽象了編寫HTML代碼以處理對超鏈接(<a>)的單擊事件和處理對按鈕的點擊的具體細節。問題:ASP.NET設計者需要隱藏的細節是,無法從HTML的超鏈接提交表單。他們的做法是,通過編寫幾行JavaScript並將之附加到超鏈接來實現這一點。很明顯,會有抽象的漏洞,如果最終端用戶禁用了JavaScript,ASP.NET應用程序就不能正常工作,並且如果程序員不理解ASP.NET在這個行為背後抽象了什麽,他們就不會知道什麽地方出錯了。
抽象漏洞法則意味著,每當有人提出一個全新的令人眼花繚亂的代碼生成工具,它使我們工作變得高效,您就會聽到很多人說“首先學習如何手動完成,然後使用自動化工具來節省時間。代碼生成工具就是人們嘗試去抽象一些工作,進行包裝。這僅僅能夠節省我們的工作時間,卻不能節省我們的學習成本。
矛盾的是所有的這些都意味著,編程工具變得越來越高級,越來越抽象,但是這使得我們成為一個熟練的程序員變得更加困難。
在我第一次微軟實習期間,我編寫了在Macintosh上運行的字符串庫。一個典型的任務:編寫一個Strcat版本,執行結果會返回指向新字符串結尾的指針。幾行C代碼。這是正確的做法,這些是從K&R(一本關於C語言的很薄的書)中學習的。
今天,為了在CityDesk工作,我需要去了解Visual Basic、COM、ATL、C++、InnoSetup、Internet Explorer內部結構、正則表達式、DOM、HTML、CSS和XML。
十年前,我們可能已經想象到,新的編程範式將使編程變得更容易。事實上,這些年來我們創建的抽象確實使得我們處理軟件開發中的復雜性變得簡單,這些復雜性在10或15年前我們不必處理,比如GUI編程和網絡編程。雖然這些很優秀的工具,像現代的面向對象的編程範式,讓我們快速完成許多工作。但是突然有一天我們發現一個問題,是該種範式的抽象漏洞,修復它需要2周。並且當你需要雇傭一個程序員來使用VB編程時,很明顯VB程序員是不夠的,因為每次發現VB抽象漏洞時,他們都會完全陷入焦慮中。
抽象法則正在拖累我們。
本文章翻譯自 Joel Spolsky 的 [The Law of Leaky Abstractions](https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/)
免費領取驗證碼、內容安全、短信發送、直播點播體驗包及雲服務器等套餐
更多網易技術、產品、運營經驗分享請點擊。
相關文章:
【推薦】 6月第5周業務風控關註 | 《網絡安全等級保護條例(征求意見稿)》本周正式發布
【推薦】 如何讓你產品的用戶擁有一流的上傳體驗
【推薦】 網易寶系統架構之我見:高可用篇
【譯文】抽象漏洞法則