我在蘋果公司學到的程式設計技巧

發表於2011-07-10

導讀:原文作者Joe Moreno在1998年至2007年期間就職於蘋果公司,是蘋果線上商店的一名開發人員。通過此文,也可對蘋果公司的一些產品開發細節有所瞭解。以下是全文。

當我還在蘋果線上商店工作的時候,我們從來沒有對線上網站做過負載測試。我們也不覺得需要這麼做。然而,當每次史蒂夫·賈伯斯在演示某個幻燈片過程中切換到線上商店時,會走下臺來等待,這是非常有趣的經歷。作為事後檢查的一部分,每次線上商店重新上線時,我們都會問自己伺服器的瓶頸在哪裡:是CPU、網路頻寬、磁碟I/O還是記憶體?雖然準確預測整個系統在實際環境中的行為非常困難,幸運的是我們有一整套的測試策略來確保在重新啟動之前有足夠的測試。


作者:Joe Moreno

負載測試 / Load Testing

許多公司用負載測試來試驗他們的web應用程式能夠支援怎樣的負載。一個最平常用到的,但是錯誤的方式是把web站點上線然後啟動負載測試。這種方式的問題在於,它不會告訴你web站點從線上狀態到不能提供服務這個過程中是如何執行的。當一個web站點在使用狀態時當機然後重新啟動,這時web站點表現出的行為,一定與負載測試狀態下有很大的區別。例如,我們發現在iTunes商店(iTunes Store)第一次啟動時,一個被信任的WebObjects元件不是執行緒安全的,而這個問題只有在該物件處於重負荷情況下才會出現。

初生牛犢 / Cutting My Teeth

當我第一次加入蘋果線上商店開發小組時,我和一位經驗豐富的軟體工程師搭檔,他教會我如何快速地熟悉程式碼庫,構建流程以及單元測試和元件測試。由於線上商店已經上線了,我們只有在對新程式碼進行測試以及蒐集資料之後才能釋出。

我的第一項任務是和搭檔一起實現一個在網路上用特性表形式蒐集產品資訊的簡單web服務。一般這樣的簡單web服務程式只需要一到兩天,而我們倆在師傅的一步步指導下花了一整個禮拜,通過結對程式設計方式完成了整個流程。(雖然我們採用結對程式設計,但是我們使用的是Agile/Scrum,而不是極限程式設計。每個開發小組可以在保證進度的前提下使用任何他們達成共識的開發技術。我服務的團隊碰巧有幾個經過訓練的scrum大師,他們得到了管理團隊的支援。)

在實際開始編寫產品程式碼之前,我們需要編寫單元測試。所有的軟體工程師都被要求先為他們的API編寫單元測試,這個一個很值得學習的規範。(編注:測試在敏捷當中非常重要,參考這篇《敏捷方法中測試人員的價值》。)接下來,我們在 Eclipse/WOLips上使用WebObjects/Java編寫程式碼,與此同時我們為應用程式設下關鍵的斷點,然後在除錯模式下執行,這樣我們就可以單步除錯程式碼。我見到了有太多在別處工作的軟體工程師,他們不斷地編碼然,就像他們在不斷地往牆上扔東西,然後看看到底會有什麼會粘在牆上(像碰運氣一樣)。

在我們檢入我們程式碼的同時,軟體倉庫會自動構建所有的應用程式,然後對它們執行單元測試。如果你的程式碼讓這次構建失敗,開發小組的每個人,包括一到兩位專案經理會受到郵件通知——你就是構建失敗的罪魁禍首。

令牌 / Token

我們有一段非常特殊的軟體程式碼,一次只能由一個軟體工程師檢出(check out)、編寫(work on)、然後檢入(check in)。你只有在得到一個物理令牌時才能夠接觸到這段程式碼。在我們這裡,這個令牌就是一個Darth Tater玩偶,它放在你的工作的格子間或者書架上最顯眼的地方。

蒐集度量資料 / Gathering Metrics

一旦我們的服務編碼完成,沒有錯誤,並且被檢入到程式碼倉庫後,我們開始元件測試並蒐集新程式碼的度量資料。這是另外一個在新手團隊裡被忽略的步驟。我懷疑“蒐集度量資料”這個步驟甚至都沒有被包含在Joel測試中,因為Joel Spolsky的產品是一個桌面應用程式而不是一個需要重負載測試的web程式(或者,也許這個被隱含在“你有測試工程師嗎?”這個步驟裡)

甚至在我們考慮將程式碼放到實時程式碼分支之前,我們就已經對程式碼進行了數百萬次的請求測試。在蘋果公司,我們有一個非常複雜的快取演算法,根據我們設定的目標,它可以儲存我們需要的任意數目的記錄。我們是否需要五百個或是五萬個產品的請求記錄快取呢?在一次冷啟動開始之後,我們是否需要對指定的產品用快取來“熱身”呢?在沒有任何的請求命中時,我們需要等多久才把一個產品從快取中移除並釋放記憶體呢?

附註一點,我們的快取通常是一個雜湊表。雜湊表的優點在於它的大O表示法執行時間是常量O(1)。當你在一個面試中被問道“什麼事最快的查詢函式”時,千萬不要說“一個B樹二叉樹”。完美的雜湊表通常會輕鬆勝出。

調整並完成 / Tweaking and Done

我們會不斷調整程式碼直到我們得到可接受的度量資料。我們的測量資料會對快取記憶體消耗多少以及滿足每個服務請求/響應的時間長短進行度量。根據我們的需求,我們會努力達到99.7%的服務請求在35毫秒之內返回,95%的請求在10毫秒之內返回,沒有單個請求超過50毫秒的響應時間。

這些測試在一個非常接近產品環境的實時資料庫的拷貝中執行。這不能完美地指出web應用程式一旦在實際環境中會如何執行。但是將它變成一個設定期望的很好的辦法,這不會需要很久時間。

在我們“疾跑”(Sprint)結束的時候,所有這些度量資料都會作為敏捷定義“完成”時演示的一部分。這時程式碼已經準備就緒可以被檢入質量保證的程式碼分支,在程式碼釋出上線之前還會進行功能測試。

編注:
1. 大O表示法:用來描述演算法的時間複雜度,O(1)的時間複雜度最低
2. 疾跑(Sprint):是scrum開發方法的一個最基本開發單元

 

原文:Joe Moreno  翻譯:敏捷翻譯唐尤華

如需轉載,但請註明原文/譯文出處、譯文超連結和譯者等資訊,否則視為侵權,謝謝合作!

相關文章