前言

原文如下:

How to Avoid the Curse of Premature Optimization

譯文

這真的幾乎是值得的。 從新手到專家,從架構到ASM,從機器效能到開發人員的性能優化,您和您的團隊都在縮短你們自己的目標是非常好的。 什麼? 我? 我的團隊? 這是一個非常大的指責。 讓我解釋下。 優化並不是聖杯,但它也同樣難以獲得。 我想與大家分享一些簡單的提示(和一些陷阱),幫助您將團隊的閱歷從自我破壞轉變為和諧,實現,平衡,最終優化。

什麼是過早優化?

過早優化是正在如下情况下嘗試優化效能:

  • 當第一次編碼算灋時
  • 在你需要確認基準之前
  • 分析在哪裡進行優化是有意義的之前
  • 處於比您的項目當前要求的水准較低時

現在我是一名優化師,Optimus. 至少在寫這篇文章時,我會假裝是一個optimist。 對你來說,你可以假裝名字是Optimus,如此這將更直接地說給你。 作為科技人員,你可能有時會想,這一年可能會是怎樣的一年,然而,儘管我們在不斷進步,但在某種程度上來說,這是一種可以接受的標準,讓人感到非常費時。 你想要瘦身。 高效的。 極好的。 有些人喜歡那些工作崗位要求的搖滾明星程式師(Rockstar Programmers),同時有領導能力。 所以當你的團隊編寫程式碼時,你鼓勵他們第一次做到這一點(即使“正確”是一個高度相對的術語,在這裡)。 他們知道這是聰明的程式設計者的管道,也是那些不需要浪費時間重建的管道。 我覺得,完美主義的強迫症有時在我心中也很强大。 你希望你的團隊現在多花費一點時間,從而節省很多以後的時間。 因為每個人都對分給的“其他人所寫的糟糕程式碼(他們到底在想什麼?)”步履維艱,這個簡寫是SCOPWWHWTT,因為我知道你喜歡叫不上名字的縮寫。 我也知道,你不希望你的團隊程式碼對他們自己或其他人來說是這樣的。 所以,讓我們看看能做些什麼來引導你的團隊走向正確的方向。

如何優化:歡迎來到這門藝術

首先,當我們想到程式優化時,我們通常會立即假定我們在談論效能。 即使這已經比它似乎更加模糊(速度?記憶體使用?等),所以讓我們停在那裡。 讓我們更加模糊! 剛開始。 我的大腦喜歡在可能的情况下創造秩序,所以我需要每一盎司的最優主義去思考我想說的是一件好事。 有一個簡單的(效能)優化的規則是不要這樣做。 這聽起來很容易遵循,但並不是每個人都同意這一點。 我也不完全同意這一點。 有些人會比其他人寫出更好的程式碼。 期望中,對於任何一個人來說,他們在一個全新的項目中編寫的程式碼質量會隨著時間的推移而不斷提高。 但是我知道,對於許多程式師而言,情况並非如此,因為他們知道的越多,他們將越來越多的嘗試過早地優化。
對於許多程式師來說,他們知道的越多,他們將越來越多的嘗試過早地優化。
囙此,這並不是一門精確的科學,但它只是為了抵消典型的科技人員內心的渴望來解决這個難題。 畢竟,這首先是吸引許多程式師的手段。 我明白這個。 但要求他們保存,以抵制誘惑。 如果現在需要一個問題解决的通路,人們總是可以在星期日的“數獨”(Sudoku)中玩耍,或者拿起一本Mensa書,或者用一些人為的問題去code golfing。 但是請把它放回repo,直到適當的時候。 這幾乎總是比預優化更聰明的路徑。 記住,這種做法已經足够臭名昭著了,人們會問,是否過早的優化是所有邪惡的根源(我不會走那麼遠,但我同意這種看法。)我並不是說我們應該在設計的每一個層面上都能想出最愚蠢的方法。 當然不是。 但是與其挑選最聰明的人,我們可以考慮其他的價值觀:

  • 最簡單的解釋給你的新員工
  • 最有可能通過最經驗豐富的開發人員通過程式碼審查
  • 最可維護的
  • 最快寫的
  • 最容易測試
  • 最便攜
  • 等等

但問題的癥結就在於此。 這不僅僅是為了避免對速度、程式碼大小、記憶體佔用、靈活性或未來的未來進行優化。 它是關於平衡的,關於你所做的事情是否符合你的價值觀和目標。 它完全是上下文相關的,有時甚至不可能客觀地衡量。

這是一門藝術。 (C.f. The Art of Computer Programming.)

為什麼這是一件好事? 因為生活就是這樣的,它是混亂的。

我們的面向程式設計的大腦有時想在混亂中創造秩序,以至於我們最終以諷刺的結果來成倍地新增混亂。 這就像試圖強迫別人愛你一樣的衝突。 如果你認為你已經成功了,那就不再是愛了; 與此同時,你又被綁架了,你可能需要比以往更多的愛,這個比喻是我所能選擇的最尷尬的。 無論如何,如果你認為你已經找到了一個完美的系統,那麼在它持續的時候好好享受它吧,我想。沒關係,失敗是學習的好機會。

牢記UX

讓我們來探索一下用戶體驗是如何在這些潜在的優先順序中進行的。 畢竟,在某種程度上,即使是想要表現良好的東西,也會是關於UX。 如果您在UI上工作,無論程式碼使用什麼框架或語言,都會有一定數量的模範和重複。 從程式設計人員的時間和程式碼的清晰度來看,這無疑是很有價值的。 為了幫助平衡優先順序的藝術,我想和大家分享一些故事。 在一份工作中,我工作的那家公司使用的是一個基於固執己見的科技堆棧的封閉原始程式碼企業系統。 事實上,它是如此的固執,將它賣給我們的供應商拒絕進行UI定制,這與棧的觀點不相符,因為對他們的開發人員來說,這是非常痛苦的。 我從未使用過他們的堆棧,所以我不譴責他們,但事實是這“有利於程式師,不利於用戶”的權衡在某些情况下對於我的同事是麻煩的。 最終,我編寫了一個協力廠商挿件重新實現這個系統使用者介面的一部分。 (這是一個巨大的生產力促進劑。我的同事喜歡它!十多年後,它仍然為每個人節約時間和時間)我並不是說,獨斷主義本身就是一個問題; 在我們的案例中,太多的問題成了一個問題。 作為一個反例,Ruby on Rails的一大吸引力在於它是固執的,在前端的生態系統中,由於有太多的選擇,很容易讓人頭暈目眩。 (給我一些意見,直到我能找出自己的!)相比之下,你可能會想要在你的項目中使你的每一件事的UX圓滿。 這是一個有價值的目標,但讓我來講述我的第二個故事。 在上述項目成功的幾年後,我的一比特同事來到我這裡,要求我通過自動化一個有時出現的混亂的現實場景來優化UX,這樣就可以用一次點擊就可以解决這個問題了。 我開始分析,是否有可能設計出一種算灋,它不會有任何錯誤的正面或負面的結果,因為這個場景的許多和奇怪的邊界情况。 我和我的同事談得越多,我就越意識到這些要求根本不可能得到回報。 這個場景只會在一個月的時間裏出現一次,讓我們說,現時只花了一個人幾分鐘就可以解决了。 即使我們能够成功地實現自動化,也沒有任何bug,但是需要花費幾個世紀的時間來完成需要的開發和維護時間,以節省我的同事所節省的時間。 在我看來,取悅別人的人很難拒絕,但我不得不縮短談話的時間。 所以讓電腦盡可能的幫助用戶,但只是在一個合理的範圍內。 你怎麼知道這個程度呢? 如何避免過早優化的魔咒我喜歡採用的一種方法是將UX與開發人員的設定檔程式碼進行比較。 從用戶那裡找出花費最多時間點擊或重複輸入相同的東西,看看是否可以優化這些互動。 您的程式碼可以對其最有可能輸入的內容進行一些有根據的猜測,並將其作為預設值嗎? 除了某些禁止的上下文(不點擊EULA確認?),這對用戶的工作效率和幸福感都有很大的影響。 如果可以的話做一些可用性測試。 有時,你很難解釋電腦做這些易於或不易於幫助什麼,…但總體來說,這個值可能對您的用戶非常重要。

避免過早優化:何時和如何優化

我們對其他情况的探討,現在我們明確地假設我們正在優化本文其餘部分的原始機器效能的某些方面。 我的建議方法也適用於其他目標,如靈活性,但每個目標都將有自己的困境; 主要的一點是,任何事情的過早優化都可能會失敗。 那麼,在效能方面,實際上有哪些優化方法呢? 我們開始幹起來。

這不是基層倡議,是Triple-Eh
TL;DR 意思是:從頂部工作。
在項目中可以提前進行更高層次的優化,較低層次的優化應該留在後面。 這就是所有你需要知道的“過早優化”一詞的大部分含義; 脫離這種順序做事有很大的可能性浪費你的團隊的時間和起到反效果。 畢竟,從一開始就不把整個項目寫在機器程式碼中,對嗎? 我們的AAA做法是按照這個順序進行優化:

  • 架構(Architecture)
  • 算灋(Algorithms)
  • 裝配(Assembly)

普遍的智慧是,算灋和資料結構通常是最有效的優化場所,至少在效能方面。 但是,請記住,架構有時會决定哪些算灋和資料結構可以被使用。 我曾經發現一個軟件做財務報告,通過多次査詢SQL資料庫進行每個金融交易,然後在用戶端進行一個非常基本的計算。 使用該軟件的小企業只使用了幾個月,即使他們相對較少的財務資料,使用全新的案頭和相當强大的服務器,報告生成時間已經達數分鐘了,這是他們需要相當頻繁地使用一個功能。 我最後寫了一個簡單的SQL語句,其中包含了總結邏輯,通過將工作移動到服務器來避免所有重複和網絡往返(甚至幾年的數據),我的版本可以在相同的舊硬體上以毫秒為間隔生成相同的報告。 有時,您對項目的架構沒有影響,因為在項目中,對於架構變更的可行性來說已經太晚了。 有時,你的開發人員可以繞過它,就像我在上面的例子中所做的那樣。 但是如果您在項目的開始,並且在它的體系結構中有一些發言權,那麼現在是優化它的時候了。
架构如何避免过早优化的魔咒
在一个项目中,架构是事后改变的最昂贵的部分,所以这是一开始就可以进行优化的地方。例如,如果你的应用程序是通过ostriches传递数据,您想要将其构造为低频率、高负载的数据包,以避免使一个糟糕的瓶颈变得更糟。在这种情况下,您最好有一个完整的俄罗斯方块的实现来招待您的用户,因为加载微调器不会削减它。(开玩笑的:几年前,我正在安装我的第一个Linux发行版本,Corel Linux 2.0,并且很高兴这个长期运行的安装过程包括了这一点。看到Windows 95安装程序的广告宣传片,我已经记住了很多次,这是当时的一股清新的空气。) 作为昂贵的架构更改的一个例子,前面提到的SQL报告的高度不可伸缩的原因在其历史上是很清楚的。该应用程序随着时间的推移而发展,从MS-DOS和本土化的自定义数据库的根源,甚至原本不是多用户的开始。当供应商最终切换到SQL时,模式和报告代码似乎已经被移植了一个。这让他们在他们的更新中留下了令人印象深刻的1,000%+性能改进,只要他们通过实际使用SQL的优势来完成架构转换。与我当时的雇主一样,我也很喜欢与客户打交道,很明显,在最初的转换过程中,我很想优先考虑编码效率。但在某些情况下,满足客户的需要,就像改锥转动螺丝一样有效。 架构在一定程度上是为了预测您的项目将需要多大程度的规模,以及以何种方式进行架构。由于架构是如此的高水平,所以我们很难在不把我们的注意力集中到特定的技术和领域的情况下将我们的“要和不要”弄清楚。

我不會這麼說,但其他人都這麼做

值得慶倖的是,互聯網上到處都是收集到的關於各種建築的智慧。 當你知道是時候優化你的架構時,研究陷阱基本上可以歸結為描述你的輝煌願景的術語。 很可能有人和你一樣思考,嘗試過,失敗了,重複了,並在部落格或書中發表了。 通過蒐索來完成流行詞識別可能是棘手的,因為對於您所稱的FLDSMDFR,其他人已經創造了SCOPWWHWTT這個術語,他們描述了你正在解决的同樣的問題,但是使用完全不同的詞彙。 開發人員社區來拯救! 用盡可能詳盡的描述來訪問StackExchange或HashNode,再加上您的構架中不是所有的流行語,囙此他們知道您做了充分的初步研究。 有人會很樂意啟發你。 與此同時,一些一般的建議可能是思考的好食物。

算灋和裝配

鑒於一個有利的架構,您的團隊中的編碼人員將會在那裡獲得最多T-bling的時間。 早期優化的基本避免也適用於此,但您的程式師會很好地考慮這一級的一些細節。 關於實現細節,我寫了一篇專門針對一線和高級程式師的關於程式碼優化的文章。 但是,一旦您和您的團隊實現了一些效能上的不優化,您是否真的將它放在了不再做的日程上呢? 你從來沒有優化? 你是對的。 對於專家來說,下一個規則是,不要做。

時間基準!

您的程式碼工作。 也許它是如此的慢,以至於您已經知道您需要優化,因為它的程式碼將經常運行。 也許你不確定,或者你有一個O(n)算灋,並認為它可能很好。 無論如何,如果這個算灋可能是值得優化的,那麼我的建議是相同的:運行一個簡單的基準測試。 為什麼? 不清楚我的O(n ³) 算灋不可能比別的更糟糕嗎? 那麼,有兩個原因:
您可以將測試套件添加到測試套件中,作為您的績效目標的客觀衡量標準,無論它們是否得到滿足。
即使是專家也可能無意中使事情變慢。 即使看起來很明顯。 真的很明顯。
不相信我的第二點?
如何從1400美元的硬體中獲得更好的效果,而不是7000美元的硬體
StackOverflow的傑夫·阿特伍德(Jeff Atwood)曾經指出,有時候(通常在他看來),購買更好的硬體比花費寶貴的程式師時間優化更具成本效益。 好的,所以假設你已經達到了一個合理客觀的結論,你的項目將適合這種情況。 我們進一步假設您要優化的是編譯時間,因為它是您正在開展的大量Swift項目,這已成為一個相當大的開發人員瓶頸。 硬體購物時間! 你買什麼? 很明顯,更昂貴的硬體往往比價格更便宜的硬體表現更好。 很顯然,一個7000美元的Mac Pro應該比一些中檔Mac Mini更快地編譯你的軟件,對吧? 錯誤! 事實證明,有時更多的內核意味著更有效的編譯…在這種特殊情况下,LinkedIn發現了他們的堆棧的相反的管道。 但我看到管理層犯了一個錯誤:他們在前後都沒有做過基準測試,發現硬體陞級並沒有讓他們的軟件感覺更快。 但是沒有辦法確切地知道; 而且他們仍然不知道瓶頸在哪裡,所以他們對效能仍然不滿意,耗盡了他們願意分配給這個問題的時間和金錢。
好的,我已經有了基準。 我可以進行優化嗎
是的,假設你已經决定了你需要。 但是,也許這個決定會等到所有的其他算灋都實現了,所以你可以看到這些移動的部件是如何組合在一起的,而這在效能分析中是最重要的。 這可能是一個小應用程序的應用級別,也可能只適用於一個子系統。 不管怎樣,記住,一種特定的算灋對於整個應用程序來說似乎很重要,但即使是專家,尤其是專家,也很容易誤診。

在你破壞(Disrupt)之前想一想

“我不知道你的人,但…”如何避免過早優化的魔咒作為思考的最後一部分,考慮如何將錯誤優化的想法應用到更廣泛的觀點:你的項目或公司本身,甚至是經濟的一個部門。 我知道,人們很容易認為科技會拯救我們的生活,我們也可以成為英雄,使之成為現實。 另外,如果我們不這樣做,別人也會這樣做。 但請記住,權力是腐敗的,儘管它的意圖是最好的。 我不會在這裡連結到任何特定的文章,但是如果你沒有在任何地方徘徊,那就值得去尋找一些關於擾亂經濟的更廣泛的影響,以及這些有時最終會帶來的影響。 您可能會對試圖通過優化來拯救世界的一些副作用感到驚訝。

後記

你注意到什麼了嗎,Optimus? 我唯一一次稱呼你Optimus的時候是在最開始,現在是在最後。 在整篇文章中,你並沒有被稱為Optimus。 說實話,我忘了。 我寫了整篇文章,沒有叫你Optimus。 最後,當我意識到我應該回去把你的名字寫在文章中的時候,我內心的一個小聲音說,不要這樣做。

了解基础知识

什么是过早优化?
尝试在第一次编码时进行优化。性能优化最好从最高级别在任何给定的时刻完成。对于新建项目,在架构阶段。对于遗留项目,通过正确的分析来确定瓶颈,而不是玩昂贵的猜测游戏。
为什么过早优化不好?
假设(假定)性能优化的代码实际上是您的第一优先级,高于正确性、清晰性、可测试性等等,这是一个隐藏的陷阱。另一个陷阱是,假设代码中的代码对总体性能有足够的影响,值得优化。过早优化全中。

文章目錄