操練嚴格才好打仗 A Hard Drill Makes an Easy Battle

作者:周思博 (Joel Spolsky)
譯:Paul May 梅普華
Tuesday, November 20, 2001
屬於 Joel on Software, https://www.joelonsoftware.com/2001/11/20/a-hard-drill-makes-an-easy-battle/

我覺得 VMWare 實在是棒到不行。過去幾星期我們要讓 CityDesk 在各種32位元的 Windows 上都能動,這個程式幫助非常大。我安裝了幾十套虛擬機器,有單純的 DOS 分割 (作為安裝其他OS的起點)和各種 NT 4.0 的組合,還有中文和希伯來文的 Win2K (雖然我們的程式是用英文也沒什麼特別的東西,還是在這些系統上找到各式各樣的問題),還有從 1995 年 8 月起發行五花八門的 Win 95/98/Me 版本,甚至還有包括一台主網域控制器的小型網路來測試 FogBUGZ 的安裝。

VMs.gif

要讓程式在五花八門的 Windows 系統上都能動是件大工程。這是 Java 等「寫一次程式,到處都可跑」系統的真正訴求。理論上如果用 Java 虛擬機器,辛苦的是要提供這所有平台相容性的 VM 供應商。可是實際上 Java 程式師都已學到,程式本身實在是太脆弱太敏感,達不到完美的效果。以前我用 Java 開發某個遊戲時就瞭解到,由於 Java 無法保證行程執行的時間(這種妥協似乎沒什麼問題,反正 CPU 排程基本上就是無法預測的),實際上會讓某些行程在麥克塔上永遠卡住,要等其他行程嘗試執行 I/O 才會繼續。這和我預期的不一樣而且也讓我的遊戲在麥金塔上不太刺激。(這是1996年的事。所以不要寫信告訴我要如何避開或修正,也不用解釋這個問題已經修好了。)

昨天遇到的「當日之蟲」就是個類似的整人例子。Michael 用古老的 Windows API GlobalAlloc 配置了一些記憶體。然後呼叫另一個函數 GlobalSize 取得該記憶體的大小。在我們的開發系統上(Windows 2000),GlobalSize 會傳回當初配置時相同的值。配置13個位元組,GlobalSize 就會傳回 13。

某個用 Windows 98 的使用者回報了一個問題:「複製貼上沒有作用」。就像上面的畫面所顯示,我裝了一套 Windows Me VM 還有 VB6。在用除錯器逐行追蹤程式時,我注意到 GlobalSize 呼叫,回想起 Win 95 時代 GlobalSize 會傳回真實配置到的區塊大小,數字會比你要配置的而且通常是64的倍數。這就是問題所在。

現在,改變 GlobalSize 行為的微軟程式師可能認為自己並沒有破壞任何東西。GlobalSize 函數的文件明白地寫著:「記憶體區塊的大小可能會大於比記憶體配置時要求的大小。」事實上微軟人可能認為,讓 GlobalSize 傳回所要求的大小是個無害的小小改進。很顯然的,舊程式碼並不會相信 GlobalSize 的傳回值,所以能不受影響繼續動。有什麼理由不改進這個函數呢?

並不是每個程式師在使用每個函數時都會細讀對應的每一行文件,另外只要程式會動了,就會去做其他事情。更何況文件裡並沒有把所有東西都寫得很清楚,像我這裡討論的這類細節就很少寫在文件裡。而這正是這類問題發生的原因。其實除了微軟人以外,全世界都已發現這個問題,看看 WINE (譯註:一個 Windows 環境模擬器)程式師失敗的原因,當他們推出第二個網路瀏覽器時,突然間每個人都注意到原先賴以讓網頁顯示正常的某個問題不見了。另外 IE6 依照標準去處理表格中文字的<CENTER>行為,結果無數編 HTML 網頁的人都在哀嘆,因為他們的網頁用 IE6 來看都變成和婚禮喜帖一樣靠左對齊了。

我們要怎麼處理這種狗屎呢?Larry Wall 說過一句很有名的話:「大家直覺上都知道,要電腦程式彼此溝通,最好的方法就是提供時要嚴格,接收時要寬鬆。」我認為 HTML 的演進已經證明這並不是什麼好主意。事實上 API 對於輸入參數愈嚴謹,程式愈有可能在奇怪的狀況上仍舊運作。Java 的設計者就做得很對,他們決定Java 的規格應該要清楚明確,不要讓編譯器開發者有任何選擇餘地(至少不要像 C 那樣無道理的寬鬆,連基本型別的大小都不定)。俄羅斯蘇沃洛夫元帥說得好:「操練嚴格才好打仗。」你希望你的編譯器和開發環境儘可能的嚴謹;你希望能讓 GlobalSize 傳回任意亂數,這樣才不會養成習慣去依賴一些某一天會消失不見的機制;你希望在中文 Windows 2000 上套用法國的區域設定,再搭配離譜的配色、DVORAK 鍵盤、軌跡球、640x480 VGA 顯示模式和大大醜醜的字型,然後拿來當開發環境,這樣才會記得在程式裡做所有對應的調整。這樣一來你的應用程式就會柔軔堅強,連有人小數點是用逗號而非句點這種蠢問題也能大笑面對。你的程式會用俄國口音說:哈哈哈,我都拿逗點來當早餐

總而言之,這是讓軟體在幾億台電腦上都能跑的方法。只在一台電腦或是在一個受控制的環境下開發程式是很簡單,不過你會變得軟弱無力。總有一天你要在第二台電腦上執行,然後你就會熬夜在那台電腦上安裝完整的開發環境,然後再查兩個小時之後,終於發現自己沒有考慮到安裝路徑裡可能出現空白字元,因為第一台電腦沒有這種情形。

可以指望的是,未來虛擬機器的概念(不管它是 Java、.NET 還是別的玩意)將會減少這種痛苦,不過時候還未到。現在我還是很高興能花十分鐘除錯,就能讓喜歡把 Windows 文字設成粉紅色或橙色的人都能正常執行我的程式。在一整年的開發時間裡,我們大概用了三星期去修正組態相關的問題。小小的代價卻讓潛在客戶群由美國版 Windows 2000 擴展到整個 NT 4、95、98、Me、和 XP 家族,再加上全球各種語言版本。酷。

這些網頁的內容為表達個人意見。
All contents Copyright © 1999-2006 by Joel Spolsky. All Rights Reserved.