來自程式設計“老者”們的須時刻謹記的七大教訓金典

51cto發表於2015-03-17

  在HBO電視劇集《矽谷》第一季第六集中,一家初創企業的創始人Richard陷入困境,並向一位看起來只有十三、四歲的男孩求助。

來自程式設計“老者”們的須時刻謹記的七大教訓金典

  這位少年天才瞄了Richard一眼並說道:“我本以為你會更年輕些。你今年有多大了,25歲?”

  “26歲,”Richard如實回答。

  “我的媽呀。”

  沒錯,軟體行業向來崇尚年輕化。如果大家已經擁有了自己的家庭,那麼在程式設計領域已經算是個老年人了。而如果大家已經年過廿五甚至已過而立,那麼各位未來的技術之路可能只會一路走低。

  唉,自以為是的傢伙並不總能完美地解決技術難題。儘管他們的大腦當中塞滿了關於最新、最流行的各類架構、框架以及堆疊的技術細節,但他們並不具備對軟體在本質層面為何能夠確切起效或者發生故障的實際認知。這些經驗只會在我們連續數週遭遇怪異甚至莫名其妙的錯誤之後慢慢積累並建立起來。

  正如《矽谷》的觀眾們心滿意足地看著第一季第六集結尾那位少年天才最終搞砸了一切,我們這些程式設計界的“老者”們也同樣樂於欣賞那群視我們為“過時之人”、但卻由於不聽前輩勸告而陷入困難的後起之秀們的沮喪表情。

  本著共享精神的考量、或者也算是給年輕人的一點教訓,在這裡我們總結出了一些遠不是憑藉聰明的頭腦加上幾周的實踐就能掌握的寶貴經驗。順帶一提,其中很多財富只有那些需要靠兩位十六進位制數字才能寫出自己年紀的老者們方可掌握。

  記憶體很重要

  就在不久之前,我們計算機裝置上的記憶體容量還在以MB為計量單位而非GB。當我組裝起自己的第一臺計算機(一臺Sol-20)時,其記憶體甚至只有可憐的KB級別。這臺裝置的主機板上接有約64塊記憶體晶片,每一塊大約配備18個插針。我記不清楚具體數目了,但我可以肯定每個接點都是由自己親手焊接完成。當焊接任務結束後,我還得重新處理那些無法通過記憶體測試的插針。

來自程式設計“老者”們的須時刻謹記的七大教訓金典

  如果大家像我一樣經歷過那段記憶體是金的往昔歲月,就會意識到這一點點資源有多麼寶貴。如今的年輕人們則不會那麼嚴謹,而更傾向於“差不多得了”的態度打理記憶體資源。他們會把指標搖來晃去,從不清理自己的資料結構,這一切都是因為記憶體成本如今已經非常低廉。他們只需要點選一個按鈕,就能為自己的雲例項新增16GB記憶體容量。如果每個人都能如此輕鬆地從Amazon手中租到配備244GB巨量記憶體的例項,鬼才會在程式設計當中認真考慮記憶體的分配問題。

  然而垃圾收集機制的工作效果總會有侷限,正如家長不可能無限度地為小朋友們打掃房間。大家可以分配規模龐大的堆,但最終我們仍然需要對記憶體加以清理。如果各位習慣了任意揮霍資源並在記憶體當中如流感一般來回穿梭,垃圾收集機制很可能出現體積膨脹的狀況——並最終塞滿看似充裕的224GB空間。

  除此之外,虛擬記憶體的興盛同樣帶來值得重視的隱患。如果我們的計算機由於記憶體不足而轉向利用磁碟進行資料交換,那麼軟體的執行速度將發生成百倍甚至上千倍的速度遞減。虛擬記憶體從理論層面講確實大有可為,但在實際效果角度看卻太過緩慢。程式設計師們需要清醒地意識到,記憶體資源在物質極大豐富的今天仍然非常珍貴。如果缺乏這種科學的觀念,那麼原本在開發階段執行速度理想的軟體很可能在投付實踐之後遭遇速度下滑。換言之,大家的工作成果根本無法實現規模化擴充。近年以來,可擴充套件能力已經成為一切技術方案的必要前提。因此請大家注意,在軟體或者服務遭遇瓶頸之前打理好記憶體資源。

  計算機網路速度緩慢

  負責市場營銷的員工們一直將雲服務包裝成類似於計算業務領域的萬靈藥,在這裡資料總能夠順暢無阻地往來遷移。如果大家希望在雲端儲存自己的資料,他們還準備好了能夠提供永久儲存、備份以及其它各類功能的簡單Web服務產品——總而言之一句話,事情交給服務供應商、您就放心吧。

來自程式設計“老者”們的須時刻謹記的七大教訓金典

  在萬事拜託這方面、營銷人員的宣傳內容的確屬實,但還有一點他們沒提——客戶需要等,長久地、不懈地等。進入與傳出計算機的全部流量都需要耗費時間。相較於CPU與本地磁碟驅動器之間的傳輸速度,計算機網路一直扮演著緩慢小烏龜的角色。

  程式設計界的前輩們可謂“生在新中國,長在紅旗下”,在那艱苦的歲月裡網際網路還根本連雛形都沒有。FidoNet會以對話方式將我們的資料路由至與可能接近目的地的其它計算機處。要想跨越國境線,大家的資料可能走得比人還慢——花費幾天時間穿越無數吱吱作響的調變解調器。這種痛苦的經歷告訴他們,正確的處理方式應該是儘可能多地以本地方式處理計算任務,並最大程度保證遠方的Web服務只需要處理規模較小的最終結果。今天的程式設計師們很可能無法體會這些由老一輩無產階級開發者們從實踐中辛苦積累而來的教訓,事實上雲端儲存給出的承諾並不可靠,而且直到最後幾毫秒內才可以放心將任務交給雲服務。

  編譯器中存在漏洞

  當我們遭遇故障之時,真正導致問題發生的往往並不是我們編寫出的程式碼本身。我們也許忘記了對某些專案進行初始化,或者沒能及時檢查某個null指標。無論實際原因是什麼,每一位程式設計師都明白當軟體出現故障時,責任必須由我們自己承諾——句號。

來自程式設計“老者”們的須時刻謹記的七大教訓金典

  事實上,最令人頭痛的並不是我們自己的程式設計失誤。有時候責任源自編譯器或者直譯器。儘管目前的編譯器與直譯器在穩定性方面相對可靠,但其距離完美仍有很長一段道路要走。必須承認,無數技術人員耗費大量心血才讓今天的編譯器與直譯器擁有當下的穩定性水平,但將這種穩定性認定為理所當然仍然不夠明智。

  需要提醒大家的是,編譯器與直譯器同樣有可能發生故障,我們也應當在遭遇問題時將針對二者的除錯工作考慮入其中。如果大家並不清楚編譯器為什麼出現問題,那麼追尋答案的過程很可能耗時數天甚至是數週。早在很久之前,程式設計師們前輩們就意識到有時候最理想的問題除錯途徑並不是測試自己的程式碼成果,而是將注意力集中在工具身上。如果大家習慣性地認為編譯器本身不會出問題,而且不假思索地把責任歸咎於程式碼的渲染計算過程,那麼往往耗費數天甚至數月也無法從工作中找到根本不存在的問題根源。年輕人啊,相信你們很快就能在實踐中成長起來。

  速度對於使用者而言極為重要

  很久以前,我曾經聽說IBM公司就可用性議題開展過一次調研,並發現人們的意識會在響應時間超過100毫秒之後出現波動。這一結論到底是真是假?我曾經就此求證於搜尋引擎,但網際網路掛掉了……而且我之後也忘記了再試一次。

來自程式設計“老者”們的須時刻謹記的七大教訓金典

  經歷了IBM大型機上那古董級綠屏應用時代的朋友們肯定知道,IBM公司將100毫秒這一導致人腦意識渙散的時間分水嶺設為響應速度閾值。有鑑於此,他們在I/O線路方面投入了大量精力。在銷售其大型機產品時,藍色巨人的工作人員們會以詳盡的規格列表指明裝置當中的I/O通道數量,這種作法與汽車製造商介紹自家發動機引數時如出一轍。誠然,這些裝置也會如現代產品一樣發生崩潰,但當它們處於正常運轉狀態時,這些資料總能通過預設通道順暢地流向終端使用者。

  我曾親眼目睹過不少一位程式設計人員絞盡腦汁地調整其由於大量JavaScript庫以及數量總量流向瀏覽器而導致崩潰的AJAX重量級專案。他們往往抱怨稱,將其陷入泥潭的緩慢創新成果與作為替代物件的陳舊綠屏終端相比較並不公平。但企業中的其它部門卻應該為此而慶幸。畢竟如今我們迎來了更美觀的圖形顯示效果並在應用程式中包含更多色彩表現。毫無疑問,CSS讓一切變得更酷、更漂亮,令使用者不滿的僅僅是其緩慢的響應速度。

  真正的Web永遠不可能像辦公網路那樣迅捷

  現代網站往往像是一隻用時間壘砌而成的小豬。其往往需要數秒鐘時間將MB級別的資料從JavaScript庫當中交付給瀏覽器。接下來,瀏覽器需要將這些多層MB資料推向JIT編譯器。如果我們能夠將世界範圍內全部jQuery重新編譯帶來的時耗加以累積,其總長很可能達到數萬甚至上百萬年。

來自程式設計“老者”們的須時刻謹記的七大教訓金典

  樂於使用基於瀏覽器的各類工具的程式設計師們往往會犯下一類常見錯誤——以無處不在的方式肆意濫用AJAX。這一切在辦公環境的演示過程中都能順利完成,畢竟在這類條件下伺服器本身就位於桌子後面的櫃子上。有時候“伺服器”也會執行在本地主機當中。當然,檔案能夠在彈指一揮間到達指定位置,執行的整個過程都非常順暢、甚至老闆在屋角進行測試時也能應對自如。

  不過當使用者身處DSL連線環境下或者需要通過一座已然過載的訊號塔以蜂窩網路進行路由時,結果又會如何?他們需要耗費大量時間等等庫內資訊的交付。如果無法在數毫秒當中順利抵達,他們往往會憤而在TMZ上發表文章大發牢騷。

  演算法的複雜程度至關重要

  在某個專案當中,我遇到了與《矽谷》居住中Richard面臨的同一個難題,而我也與他一樣、把求助的目光投向了一位尚未到飲酒年齡但已經對Greasemonkey的前世今生極為熟悉的朋友身上。他對我的程式碼進行了重寫,並把結果發還給我。在閱讀了各項變更之後,我意識到他僅僅是將程式碼內容變得更加精緻,但同時也把演算法的複雜程度由0(n)提升到0(n^2)。他堅持將資料放在列表當中以實現匹配,這麼做看起來確實很漂亮、但卻會隨著n值的提升而導致程式碼執行速度越來越慢。

來自程式設計“老者”們的須時刻謹記的七大教訓金典

  演算法複雜性議題在高校的電腦科學課程當中已經得到了詳盡的解讀。然而,很多出身科班、憑藉著聰明才智在週末自學掌握Ruby或者CoffeeScript的年輕人們根本沒能深入領會其精神。複雜性分析可能看似一種極為深奧的理論性事務,但其會隨著專案規模的變化而展現出完全不同的面貌。當n值較小時,一切都能夠輕鬆實現。特別是在記憶體容量充裕時,程式碼將以令人滿意的速度得以執行,這時即使糟糕的演算法也能夠在測試中得以通過。然而當使用者倍增再倍增時,那些包含有0(n^2)甚至0(n^3)的演算法會讓使用者陷入無盡等待的噩夢。

  當我詢問這位天才少年,能否把匹配流程轉化為一條二次演算法時,他撓了撓頭。他根本不知道我在說些什麼。後來,我利用一套雜湊表取代了他的清單,一切也就此迴歸順暢。不過時至今日,我想他一定已經老到到能夠理解這個話題的程度了。

  庫有可能糟糕透頂

  那些編寫庫的技術人員並不總是關注我們這些普通使用者的利益與訴求。他們確實在努力幫忙,但其關注重點往往集中在為整個世界作出貢獻身上——而非我們日常面臨的小小難題。他們最終打造出的往往是一把能夠解決多種不同版本問題的瑞士軍刀,而非針對當前問題作出深度優化的解決方案。庫專案的工程技術與編碼水平毋庸置疑,但執行速度卻可能不堪恭維。

來自程式設計“老者”們的須時刻謹記的七大教訓金典

  如果大家不在這方面多加註意,那麼庫本身很可能把我們的程式碼成果拖進速度緩慢的泥潭,而各位對此甚至一無所覺。我曾經請一位年輕的程式設計師幫我調整程式碼成果,因為我寫了十行程式碼來從字串中提取字元。

  “我可以用一條正規表示式與一行程式碼完成同樣的任務,”他自信地表示。“從十行到一行,這就是看得見、摸得著的改進。”但他並沒有意識到,他這一行程式碼在每一次進行正規表示式呼叫時,都需要經歷解析與重新解析的過程。他單純認為自己編寫的是一行程式碼,而我這是十行程式碼,因此他比我水平高到不知道哪裡去了。

  庫與API在適當運用的前提下能夠發揮巨大的作用。但如果以內部迴圈的方式加以使用,那麼他們完全可能對速度產生破壞性的影響——而當事人往往還完全摸不著頭腦。

相關文章