開發效率與執行效率,我們應該怎樣斟酌?


本文同時發在我的 Blog,在那裡或可獲得更好的閱讀體驗:

http://gulu-dev.com/post/2014-12-14-tradeoff-between-dev-efficiency-and-runtime-efficiency

簡單分析

老規矩,先簡單分析一下題目:

  • 開發效率通常反映在兩點上:1.開發新功能是否迅速;2.修復缺陷是否及時。
  • 所謂運行效率,通俗地說就是(生產環境下)系統運行速度快,平均響應時間短,均勻流暢。不管是功能上還是用戶體驗上,都沒有不必要的卡頓和等待。當因為某個因素性能開始惡化時,惡化的情況能隨該因素的增強而有一定的收斂。

既然談到取捨問題,顯然題主已經預設了「二者之間至少存在一定程度上的負相關」這一隱含假定。那麼這二者是否的確是此消彼長的對立關係呢?俺覺得還是值得討論的。下面俺將分別從 a) 項目類型和開發模式 b) 產品質量和工程質量 c) 項目管理和團隊建設 這三個角度具體地談一下。

----------------------------------------

項目類型和開發模式

在項目中前期,通常可以清晰地通過以下幾點來了解項目的基調和開發模式:

  1. 項目的大致開發周期和預期的團隊規模
  2. 行業內同類型項目的橫向對比
  3. 技術骨幹的經驗和背景

有同學會問,(作為團隊一員),這些因素雖然不難了解到,可是跟咱們討論的開發效率和運行效率有什麼關係?俺要說,這個關係可不小。項目開發中的很多變數,從立項的第一天起就被初始化成常量了。俗話說「兵熊熊一個,將熊熊一窩」,一個團隊的戰鬥力高低和能量釋放程度,先天的基因是一個很重要的因素(一不小心掉到基因決定論里了),下面我們具體看一下。

對於強調快速迭代,小步前進的敏捷團隊而言,通常項目規模也不會很大,複雜度也會較行業內同類型項目為低,如果能適當地輔以一些局部的深入挖掘和特色創新,就可以形成一定的差異度和競爭力了。

這種項目通常不具備壓倒性的優勢,也很可能(在初期)缺乏足夠的市場推廣資源,這種時候,相對較高的開發效率和迅速靈活的反應能力就成了生死存亡的關鍵。在這種情況下,對於技術骨幹而言,最重要的素質在於審慎地控制複雜度,絕大部分情況下不要主動選擇花樣作死,避免在無謂的細節上糾纏不清,盡量採用業界慣常做法(必要時可適當簡化)。 通過設計和流程上的管控 (而非細枝末節的優化),讓運行時的性能始終保持在可控的安全區域以內,是省心省力且比較有效的手段。回過頭來比較開發效率和運行效率,孰輕孰重,孰易孰難,就不難權衡了。

對於大型組織內的大型項目,就是另一番情景了。

先說結論,大型系統內的開發效率和運行效率相干性並不高,通常都與參與者的「整體上對系統的熟悉程度」和「問題域的相關經驗」嚴重相關。

為什麼這麼說呢?跟每個開發人員都得獨當一面的小團隊不同,大型組織內的成熟系統,往往有著相對較細緻的團隊分工和相對完善的開發流程。整體而言,大型組織的開發效率總是相對偏低是很正常的,正如越寬闊的江河流速越緩慢是一個道理。

再來看運行效率,由於龐大的系統有著巨大的慣性,大大小小的框架在經年累月的開發積累中已然成型,內部隱含著往往是海量的「不足為外人道」的專門知識和方案(以及大量的 workarounds 和 hacks),在這種情況下,哪怕是理論上非常優越(架構級和演算法級)的優化,實踐中都有可能被系統中的各種細節牽跘,以致無法達到預期的效果,有時甚至還會出現導致性能下降的咄咄怪事。

總得來說,對於大型系統而言,開發效率和運行效率相關性並不顯著。對於主導者而言,由於比小團隊擁有多得多的資源可供調配,這兩者不再是孤立的因素,而是需要從整體上去協調,規劃和取捨的諸多因素之二。對於參與者而言,「整體上對系統的熟悉程度」比「有更多的學院派的理論和技巧」在日常開發中更具價值;「問題域的相關經驗」比「寫代碼手速高/能刷ACM」在招聘求職時更有參考意義。

----------------------------------------

產品質量和工程質量

在工作中,我們經常會聽到有人這麼說:「xxx做功能很快的,三天一個模塊,五天一個系統」 云云。其實我從小就很羨慕這樣的同學,他們頭腦清晰,思維敏捷,見機果斷,手腳麻利,再複雜的問題丟給他們,也能須臾間找到要害,讓你不得不拍腿感嘆:「硬是要得!」。而我自己則是一個反應有點遲鈍木訥,經常慢半拍的人。同樣是一件事,我經常要回過頭慢慢想想,才能弄得明白來龍去脈。

後來隨著年歲漸長,我慢慢懂得,快有快的優勢,慢卻也有慢的好處。在日常開發中,一味圖快,唯快不破,速度至上,往往會導致工程質量的低下。更有一類開發團隊,打了雞血一樣生沖硬突,其實只是在彌補和掩飾指揮者內心的不安,慌張,焦慮和信心不足。

----------------------------------------

摘錄兩段純銀老師的話以增興味吧:

我們都知道,產品並不是功能越多越強就越有競爭力。你拚命加班,飛快迭代,發布各式各樣的型號版本,把自己搞得雞血沸騰,但最終決定勝負的並不是速度,而是精度。拿我很欽佩的Instagram舉例子,至今不開發Android版也不去完善網頁端,平均一兩個月才更新一個版本,不到一年用戶數已經突破了700萬大關!故而產品的理念與方向,比速度與激情更重要得多——但我看國內很多團隊就知道抄,東抄西抄,自己的想法很少,就算有想法也往往是「抄這家」「抄那家」的貪多求全。這樣的6X12,6X14又有何意義呢?真沒見過幾款產品單單靠「抄得快」「抄得全」就能成氣候。勤不僅不能補拙,還有可能造成設計過度與產品失衡,結果越補越拙……

-- 出自 [唯快不破?](唯快不破? - 純銀的日誌)

這個行業對速度的無條件信仰,已經到了病態的地步。不計其數的例子證明,市場表現最好的那個創新者,並不是同類中的第一個,甚至未必是前十個,也未必是版本更新最勤快的那個,而是產品最具感染力的那個。但大家還是在頭上綁著「唯快不破」的布條向前衝鋒。「快」的確是個好事,卻不是萬試萬靈的真理。快速發布和產品感染力之間沒有必然聯繫,如同多試錯和找准路之間也沒有必然聯繫。在創新市場強調速度,本質上是用體力支出來彌補信心不足。但體力並不是唯一的競爭項目。

-- 出自 [雜念·6月(下)](雜念?6月(下))

當然了,純銀老師更多的是在談產品,這裡我們為免偏題,只談技術。

----------------------------------------

俺認為,良好的設計決定了系統的基因。在設計良好的系統中,干正確的事情比干錯誤的事情更容易,更快;在恰當的場合提供方便的腳手架,讓開發和測試更便利;良好的解耦和內聚,讓開發者在局部改動中可以「從心所欲而不逾矩」。充斥不良設計的系統中,開發人員會覺得處處掣肘;再小的修改也會時刻擔心影響到完全不相干的東西;不僅新功能難以快速實現和驗證,優化同樣難以實施,或勉強實施後實際效果與預期相差甚遠。兩者之間,開發效率和運行效率可謂天差地遠。

其次,為團隊提供所能提供的最好的工具。工具的作用不應被低估。更好的硬體,更短的編譯時間,甚至更舒適的椅子,都會讓開發效率和工程質量提高不少,這方面的研究和結論非常多,我也就不再贅述了。軟體開發是一項以人為核心的活動,「在開發人員身上節省項目成本」是我能想像到的最鋪張浪費的管理行為。

除此之外,俺還在實踐中體會到一個心得:深思熟慮後一氣呵成的模塊,反而會有相對較高的質量,不太會出問題;那些一直以來沒有想通想透,雖然看起來功能運作良好,但仍需反覆修改調整的系統,在將來只會需要更多的修修補補。這一點王垠同學在 「半年來的工作感受」 和 「談"測試驅動開發"」 這兩篇文章中 (王垠同學的 blog 最近無法訪問,感興趣的同學可以自行搜索),也有類似的有趣表達。我選擇了一些摘錄如下:

……(前略) 在 Google 的六個月里,我無視同事對於測試的要求,從無到有的做出了如此精密的系統,一個測試都沒有寫照樣做得好,為什麼呢?因為我的代碼非常的簡單清晰,我隨時都可以把它們完整的呈現在頭腦裡面,從而讓「心靈之眼」可以看到可能出現的錯誤。也許這就是所謂的「邏輯思維」。

對測試過分依賴的人,往往不具有這樣的思維能力。他們不能夠看到代碼最簡單的本質,所以需要做很多試探,以求達到「近似解」。為了不至於偏差很多,就寫很多測試,用以捕捉和防止每一次的錯誤。這就像一個初學畫畫的人,一點一點的描,用橡皮反覆的擦,可總也抓不住事物的精髓。

……(中略)……

當我的代碼需要大量的測試才能確保正確的時候,那就是它該被推翻重寫的時候。所以我的代碼往往沒有任何補丁和變通,可以說是無懈可擊。這就像是一個真正會畫畫的人,他閉目沉思,然後一氣呵成。當然,優美的代碼並不是一蹴而就的,有的代碼被我推翻重來幾十次才最後成功,但我最後的代碼不留下絲毫錯誤的痕迹。所以我覺得,看一個程序員的水平,不要看他留下來多少行代碼,而要看他刪掉了多少行。

……

-- 出自 「半年來的工作感受」 (王垠)

是的,真正的優美源於簡單和優雅(Simplicity Elegance),這是我與上面摘錄文字的最大共鳴,也是為什麼軟體開發除了作為工程活動的一面之外,還展現出類似於園藝活動那樣的藝術特質。總得來說,俺認為,真正的開發效率來源於對問題域的深刻認識,這絕非一朝一夕之功,也絕非某個"絕頂"演算法的花拳繡腿,或某種「技巧性」的實現所能涵蓋。我們真正欣賞和追求的高效開發,應該是庖丁解牛式的深厚技藝中舉重若輕水到渠成的「快」,而非趕鴨子上架的加班趕工中匆匆寫就的勉強可以運行的代碼。

美的程序不可能從修修補補中來。它必須完美的符合事物的本質,否則就會出現上面的情況,有許許多多無法修補的特例。程序員跟畫家其實差不多……(中略)……在修改代碼的時候,你必須用「心靈之眼」看見代碼背後的事物。這也是為什麼很多高明的程序員不怎麼用調試器(debugger)的原因。他們只是用眼睛看著代碼,然後閉上眼,腦海里浮現出其中信息的流動,所以他們經常一動手就能改到正確的地方。

-- 出自 「談"測試驅動開發"」 (王垠)

----------------------------------------

所以寫出簡單正確的代碼,遠比寫出運行效率高的代碼要重要得多。在保證正確性的前提下,一個系統越簡單,當遇到瓶頸時改善它的性能就越容易。而且程序員工作時的心情和效率,與代碼質量關係很大。對比曾經歷過的項目,我發現:在結構良好,流暢整潔的代碼上工作時,往往心情愉快,能持續高效地產出所謂「優美的」代碼(邏輯漏洞少,性能較好);在混亂(甚至「骯髒」)的代碼上工作,往往很難鼓起勇氣去修改,強忍著草草了事,代碼質量也偏低,bug不斷。

在工程質量角度,最後再補充一句略有「負能量」的話吧,如果不顧團隊的具體情況,不能切實可靠地制定方案,一味貪多務得,疲於追求開發效率,那麼再好的 codebase 都會很快地腐爛。而且這個過程通常是不可逆的——想把好代碼弄糟很容易,把糟代碼弄好可就難了。當代碼糟到一定程度時,優秀的開發人員就會不可阻擋地離去,那麼離遊戲結束也就不遠了。

## 項目管理和團隊建設

現在我們假設開發團隊有 A, B 和 C 三種人,其中 A 是經驗非常豐富的領域專家,B 是正處於當打之年的程序員,C 是經驗不足但有成長慾望的新人。那麼如何搭配才算是比較理想的比例呢?

雖然不同的項目情況相差非常大,但我在實踐中慢慢體會到,一個相對比較理想的比例大致是 1:2:3。一個 A 掌好舵,保證你的方向,兩個 B 是你的左膀右臂,保證你的速度和力量,三個 C 是你的生力軍,保證你的潛力和活力。保持一個相對平衡的團隊結構,從長遠上總是比堆人的效率高得多。另外再說一下,這是一個非常非常主觀和粗略的估計,這麼簡單粗暴地給個數字,對於具體的項目情境通常是不靠譜的,還需要負責任的指揮者去量體裁衣,以免削足適履。

----------------------------------------

想必大家也已經看出來了,決定這一系統的關鍵就是 A 的質量。而往往由於 A 又要肩負一定的溝通(主要指對外部團隊和需求),行政(對組織而言)和管理(對內部團隊)的責任,無法做到全身心地投入在開發上,發揮的作用往往要打一個折扣。這一點,即使是公認戰力超高的卡神亦難免俗,卡神在 Rage 發布前夕 (2011年8月,ZeniMax 收購了 id software 兩年後) [說了如下一番話](Gamasutra - Carmack on Rage):

If anything, since the ZeniMax acquisition, it"s been great. I don"t even have to pretend to be an executive anymore. I don"t have to go to board meetings. I don"t have to do anything! I can just sit in my office and work.

My core is defined as being an engineer. I take resources and a goal, and I try and put them to the best use to get us there. That"s what I do. I don"t want to be doing anything else.

如果說 ZeniMax 的收購改變了什麼的話,到目前為止都挺好的。我再也不必假裝是個管事兒的了。不需要再參加董事會議,也不必「不得不」做什麼事兒了,我終於可以踏實地坐在辦公室里幹活了。

本質上我是一個工程師。給定一些資源和一個目標,我會儘可能地找到最理想的運作方式來實現這個目標,這就是我想做的,除此之外的其他事情我毫無興趣。

我想,除了少部分比較幸運的同學,對大部分技術專家而言,在現在以及未來很長的一段時間內,不用考慮商業上的妥協,能完全按照理想的步調和節奏去完成一部心目中的佳作,仍只是一個遙遠的夢想。這大約就是所謂的「人在江湖,身不由己」罷。

----------------------------------------

寫在最後

雜七雜八地說了這麼多,到最後已經有點歪樓了。那麼放幾句應景的話,與大家共勉吧。

「當你被迫把東西做得很簡單時,你就被迫直接面對真正的問題。當你不能用表面的裝飾交差時,你就不得不做好真正的本質部分。」

「當你擁有的資源越少、擁有越少的時間去思考,這些限制才能夠逼你作出真正關鍵的決定。而不是讓你在思慮周詳之後作出一個廢物。」

「嘗試將有用的人從雜音中分離出來,將有意願幫忙的人從一大堆無聊評論中分離出來是很難的。在Linux 8086項目中我的確錯誤地放棄了這一目標,如何將那些只會空談而又無所事事的人弄走是一門學問。」

「只有在成為某個領域的專家之後,你才會聽到心裡有一個細微的聲音說:「這樣解決太糟糕了!一定有更好的選擇。」不要忽視這種聲音,要培育它們。優秀作品的秘訣就是:非常嚴格的品味,再加上實現這種品味的能力。」

"The physics of software is not algorithms, data structures, languages and abstractions. These are just tools we make, use, throw away. The real physics of software is the physics of people."

----------------------------------------

[完]

Gu Lu

[2014-12-14]

本文同時發在我的 Blog,在那裡或可獲得更好的閱讀體驗:

http://gulu-dev.com/post/2014-12-14-tradeoff-between-dev-efficiency-and-runtime-efficiency


首先通過單元測試確保正確性。

對於應用軟體,按實際需求優化執行效率,需要看優化的開發成本是否合乎軟體的收益。

對於程序庫/中間件,由於可能被用到各種場合,盡量用最佳的演算法和數據結構,以大量測試數據來進行全面性能優化。


個人感覺,開發效率在多數情況下更重要。在運行效率不滿足你的要求的情況下,再考慮優化的問題。


看需求和投入。


自從牢記不要過早優化,我就沒有再思考這個問題了。

當然程序不能寫的爛得讓自己看著不舒坦。


如果以爭取訂單為導向,開發效率第一。如果以自身品牌形象維護為導向,執行效率第一。


先用開發效率高的趕緊開發出來,然後拿去騙VC的錢,然後用錢去買一堆碼奴,命令他們用執行效率高的給老子照著功能好好的重構優化一遍


看需求急不急,著急就吃糠咽菜,不急就白面饃饃。


推薦閱讀:

為什麼大部分碼農做不了軟體架構師?
大學可以逃課自主學習嗎?
求解一個C語言問題?
C++模板默認參數能不能是模板類本身?
在編程和演算法領域,有哪些經典問題?

TAG:程序員 | 軟體開發 | 編程語言 | 編程 |