怎麼理解「premature optimization is the root of all evil」?

個人經驗是在web開發中,如果早期不考慮資料庫結構,各種數據介面的話,後期的擴展和優化會很難做,這句話是不是放之四海而皆準呢?如果不是這段Donald Knuth的名言該如何理解


你的經驗沒錯。如果一開始把系統的每個部分都只做到20%的水準,那麼後期你會發現80-20規則不成立,根本沒有什麼瓶頸可以"優化",你得把每個部分都提升到50%水準再說別的。

問題是Don Knuth不是普通程序員,他的基線可能是80%,而他的優化是從80%提升到95%。而很多人把他的話拿來支持自己只做到20%。

Knuth說的是從B到C的事兒。在他的思維里就沒有從A到B這個區間。


我想,Donald Knuth這裡說的是為時過早的優化,而不是指早期的設計,你說的資料庫結構,各種介面等等,應該是設計範疇的,Design,而不應該是優化,Optimiziation。

再說這一句話,優化往往是針對某一個點,某一個性能瓶頸而進行的,而在早期,這個點根本不存在,或者在後期可能都會發生改變,之前的優化功夫都白費了。

他這裡說的是優化,不是你理解的設計。設計當然應該先做,而優化則是後期的工作。


我所理解的「過早的優化」中的「優化」是指一些提升性能有限並且和代碼可讀性相衝突的Trick。典型例子:

1.寫代碼過程中注意While循環快呢,還是For循環快。

2.為了避免函數調用所謂的額外開銷,將一個函數寫的巨長,巨複雜。


首先我想表態:優化是有不同層次的。比如說,我們說循環展開、尾遞歸轉化等技術都是指編碼層次上的;像還有一些比如:管理事件率、引入並發、維持數據多個副本、優先順序調度等,這些屬於架構層次上的。

如你所述, 「考慮資料庫結構,各種數據介面 」這些東西的優化肯定不屬於具體編碼細節層次的優化。而Knuth 這段話主我認為主要是細化到編碼層次上而提出的具體經驗,所以放到其他層次上就不一定適用了。

比如,我們開發軟體前,架構師可能做出個這麼一個決定:使用並發的處理架構並優化負載均衡演算法。但這個決定甚至是編碼前就實現了,這說明Knuth錯了么?不是的,只是情況變了,兩者說的不是一個應用場景而已。


因為「用可能錯誤的方式解決正確的問題」,要遠遠好過「用可能正確的方式解決可能錯誤的問題」。

「可能錯誤」的方式,是成本最低的方式。只要問題正確,永遠可以 always-steping-forward。「可能正確」的方式,有可能,而且很有可能是昂貴的方式(實現成本,維護成本)。如果最後發現問題錯誤,就是 one step forward, two step backward。

這就像戰爭。重視情報,隨機應變。No funny trick.

不過這也像戰爭,如果你能洞悉敵人,那麼出奇制勝收益更大。歸根結底,架構師是在賭他對系統行為的猜測。這種賭博的風險,在多次架構類似的產品之後可以降低。「風險來自收益」是這些不同個案後面不變的真理。Knuth 沒法在短短一句話里把所有問題講明。所以,when in doubt, use brutual force。但經驗積累的自信和決心與「in doubt」是一個有關人生哲理的問題。


少談主義,少喊口號。整天想著過早優化是萬惡之源,整天想著測試驅動,整天想著設計模式,整天想著這樣所謂的好的經驗,還怎麼寫代碼。


優化都是在需求滿足的前提下才有意義。我記得某本教科書裡面是這麼寫的。很同意知友的觀點,如果問題本身就是不成立的,那再怎麼解決也是錯誤的。

說下我的具體感受吧,我把優化分成兩類,局部優化和全局優化。

局部優化的流程一般是發現問題,精確案例,用工具或者經驗定位熱點,然後修復。有點類似於帖膏藥,其實可以理解為修復臭蟲。這類優化隨著經驗和知識的積累,是可以在設計初期預見到的(但不是刻意花時間去找它們)。

我想題主問的其實更適合於全局優化:全局優化解決的問題更偏向系統的局限性:在滿足a,b,c…等需求的前提下,就是有那麼幾個需求性能不達標。所以,這類問題,不在系統完工之前是發現不了的。

其實沒有完美的解決方案,就是對需求優先順序重新排序,爭取讓盡量多的用戶滿意。所以,全局優化很多時候不是一個技術問題了,需要技術以外的部門參與決策。

當然,如果有足夠牛逼,足夠了解需求的工程師在足夠時間下是可是完成逼近於完美的系統。但是哥們,現實情況下能滿足一個就很牛逼了。

最後總結一下,從來沒有真正意義上的優化,優化就是需求平衡,犧牲不必要的需求來保全更重要的。


現在在上哈佛的OS161,我們編程一個迷你操作系統,面對很多設計選擇。有的時候想到一個問題很容易就繼續想怎樣抽取共同點,如何encode一些數據結構等,但是最主要的幾個問題:

  • 想不全:優化的設計一般和使用方式結合的更加緊密,所以其他的使用方式用不到
  • 用不到:很多編碼最後都會被刪掉,好不容易設計好最後沒用
  • 容易錯:初期的bug最麻煩,我們操作系統的scheduling algorithm用了一個 min heap, 畫了我們很大精力不說,後期遇到bug總是但是是這個min heap有問題。。。


你說的是那是設計,人家那句里說的是優化,不是一回事。

不過如果你是互聯網行業的,那設計也不要考慮什麼擴展性啊之類的,產品經理從來都是翻臉比翻書還快的,你提前設計好的介面有99%的概率在新需求下是不work的,所以不要自找麻煩,有新需求推了重寫就是了。不想重寫就跳槽,後來的人不管你代碼寫的多漂亮都會重寫的,不然沒法體現自己的價值。當然更大的概率是產品還沒有挺到需要重寫的時候就死了。

不過在天朝做產品有一件事情是必須要在設計階段就考慮好的,就是只要一個地方用戶可以發布一點兒自己生產的東西上去,那麼一定要提前把審核流程設計進去。不說了,都是淚。。。


→_→

/*

我是來找摺疊的

*/

意思是丫的先把feature做完再說!有的總比沒有強。。。。客戶急著要成品咱急著要收錢呢。。。

個人感覺除非是開發各種大型程序,一般不用專門考慮資料庫結構,各種數據介面什麼的。。。。。。一般用戶覺不出來。。要什麼優化。。。你這不是自找麻煩嘛。。。

(暴漏了我平常開發的玩意兒都小的可憐的硬傷。。。)

贊同 @陳良喬 的說法。設計是非常非常非常重要的一環,和優化沒關係。

PS

新時代的碼農們要擁抱Lean methodology啊,哈哈哈。


The Sixth Commandment

Simplify only after the function is correct.


個人想法:對於無論是design還是optimization,小到寫的每一行代碼,都需要考慮到穩定性-小到數據結構的穩定性,演算法的穩定性,大到架構穩定性,業務模型的穩定性,在層次化中越低對穩定性要求越高,在任何的一次tradeoff時,穩定性始終是一個重要的標準.

任何技術的引入,除了它本身看來適用於現有場景外(這是必須做到的),也會帶來一些限制,無論你有沒有意識到,這些限制加入到了你的產品設計上下文里,以後的設計或優化時你會發現你不得不把這些限制考慮進去.所以,除非你很能非常清晰的分析出來這些限制對後續的發展會有多大的影響,當然如果你真這麼做就太認真了,個人覺得需要對技術的直覺,直覺必須是積累+提煉出來的,這也就是程序員的效率所在之一.

優化同樣有它的上下文,如果你的優化放在了錯誤的層次或許會有反作用力,如果你的數據結構無法很好的應對數據量的增長,你應該要很清楚這些潛在的限制才是.否則一個小小的參數變化都可能會懲罰你的優化,同時破壞了穩定性,於是你需要付出額外的成本.

優化也需要建立在穩定性的基礎上,這句話對應"過早",為時過早,關鍵是"時",如何選擇"對"的"時".對或不對沒法放之四海而皆準,比如你老闆會對你說業務又有大調整了.


這覺得這句話改一下更好理解:

premature micro-optimization is the root of all evil.


推薦閱讀:

國產資料庫發展情況如何?
寫一個資料庫最難的地方在哪?最精華的地方在哪?分幾步?
如何評價國產高性能存儲引擎 TerarkDB ?
华为自研的数据库gaussdb怎么样?
維護人員不小心把資料庫刪除了要賠償嗎?

TAG:Web開發 | 資料庫 | 軟體開發 | 編程 | 網站優化 |