GitHub最熱!碼代碼不得不知的所有定律法則
當談到開發問題時,人們總會談論各種定律。但對於大多數人來說,總有一些是你不了解的,這個問題就需要使用程序員最喜歡的方法解決了:最近 GitHub 上的一個「定律合集」項目突然登上了趨勢榜第二位,Star 數上千,該項目對一些最常見的定律進行了概括,詳情見下文。
大家都是資深程序員,以後就不要老念叨「真香定律」了。
- 項目鏈接:https://github.com/dwmkerr/hacker-laws
本文包含對一些定律、原則和模式的解釋,但並不主張其中任何一項。是否要應用哪個定律一直是一個爭論性問題,並且很大程度上取決於你在做哪方面的工作。
這些規則目錄如下:
定律
- 阿姆達爾定律
- 布魯克斯法則
- 康威定律
- 侯世達定律
- 炒作周期 & 阿瑪拉定律
- 海勒姆法則
- 摩爾定律
- 帕金森定律
- Putt"s Law
- 複雜性守恆定律(泰斯勒定律)
- 抽象漏洞定律
- 帕金森瑣碎定律
- Unix哲學
- The Spotify Model
- Wadler"s Law
原則
- 穩健性原則
- SOLID
- 單一功能原則
- 開閉原則
- 里氏替換原則
- 介面隔離原則
- 依賴反轉原則
對於以上如此多的定律和原則,我們選取了其中一些定律和所有的原則進行編譯。現在,先簡單看一下定律吧↓↓
定律
阿姆達爾定律
維基百科:計算機科學界的經驗法則,因吉恩·阿姆達爾而得名。它代表了處理器並行運算之後效率提升的能力。阿姆達爾定律是固定負載(計算總量不變時)時的量化標準。
舉例說明,如果一個程序由兩部分(A和B)組成,A必須有單個處理器執行,B可以並行執行,那麼在執行該程序的系統中增加多個處理器帶來的好處是有限的。它可能會大大提升B的速度,但A的速度會保持不變。如下如所示:
打開今日頭條,查看更多圖片從圖中可以看出,一個程序如果只有50%的部分可並行處理,那它使用10個以上處理單元時,處理速度將不會有很大的提升。而一個程序如果有95%的部分可並行處理,即使使用的處理單元超過1000個,其處理速度也會顯著提高。
侯世達定律
維基百科:做事所花費的時間總是比你預期的要長,即使你的預期中考慮了侯世達定律。
當你估計做一件事要花費多長時間時,可能會想到這一定律。軟體開發中的老生常談是,我們往往很難估計交付某個東西所需要的準確時間。
炒作周期 & 阿瑪拉定律
維基百科:我們總是高估一項技術的短期效益,而低估其長期效果。
此定律被描述為鼓勵人們思考科技所能帶來的長期影響的言論。同時,阿瑪拉定律也被人們稱為是對「炒作周期」(技術成熟度曲線)最形象的說明。如下圖所示:
簡言之,這一周期表明,新技術及其潛在影響通常會引起一陣興奮。然後很多團隊快速投入該技術,然後有時會對結果感到失望。這可能是因為技術還不夠成熟,也可能是因為現實應用還沒有完全實現。
經過一段時間後,技術的能力增加,使用技術的實際機會也增加,置身其中的團隊最終開始受益。
海勒姆法則
網路定義:當一個 API 有足夠多的用戶時,你在約定中承諾什麼都無所謂,所有在你系統裡面被觀察到的行為都會被一些用戶直接依賴。
海勒姆法則指出,當你的API有非常多的用戶時,API中的所有行為最終都會被某個人所依賴。舉個簡單的例子:非功能性元素,如API的響應時間。稍微複雜一點的例子:依賴對錯誤消息應用正則表達式來確定API錯誤類型的用戶。
摩爾定律
該定律認為,集成電路中的晶體管數量大約每兩年翻一番。
該定律通常用來表示半導體和晶元技術發展的絕對速度。從上世紀70年代到90年代末,摩爾的預測一直非常精準。但近年來,該趨勢已經發生了細微的變化,部分原因在於組件小型化程度受到的物理限制。然而,並行化的發展以及半導體技術和量子計算領域潛在的革命性變化,可能意味著摩爾定律在未來幾十年仍將適用。
複雜性守恆定律(泰斯勒定律)
該定律認為每個系統內都有一定的複雜性不可減少。
系統中的某些複雜性是「不經意的」。可能是由結構不良、錯誤或只是建模不良造成的結果。這些不經意造成的複雜性是可以減少(或消除)的。但是,有些複雜性是「固有的」,是由亟待解決問題的內在複雜性造成的。而這種複雜性可以移動,但無法消除。
這個定律有趣的一點在於,即使簡化整個系統,也無法降低內在的複雜性。這種方法只不過是將複雜性轉移到了用戶一方,然後用戶必須以更複雜的方式行事。
帕金森瑣碎定律
該定律認為,大型組織會花費大量時間和精力來討論無關緊要的瑣事,但是真正重大的決議反而可以輕鬆過關。
這是因為,在討論非常專業而且金額龐大的事情時,一般人由於缺乏專業知識,不敢隨便發言,以免失言,貽笑大方,因此多半都會肯定(或逃避)該重大方案,而提些與主題無關的雞毛蒜皮小事。相對的,對於簡單的瑣碎小事,由於平常大家都會接觸到而且有相當的認識,反而意見特別多,帕金森稱此現象為瑣碎定律。
Unix 哲學
Unix哲學認為,軟體組件應該很小,而且應該把注意力放在具體的事件上。將小的、簡單的、定義良好的單元組合在一起,而不是使用大的、複雜的、多用途程序,這樣可以使構建系統變得更加容易。
像「微服務架構」這樣的現代實踐就應用了這種哲學。在該架構中,服務很小,且集中做某件事,使得複雜的行為由簡單的構件組成。
Wadler 定律
該定律認為:在任何語言設計中,討論這個列表中某個特性所花費的總時間與它位置的冪成正比。
1.語義
2.語法
3.辭彙語法
4.注釋的辭彙語法
(簡言之,如果在語義上花1小時來討論,那將在注釋語法上花8小時)。
與帕金森瑣碎定律相似,Wadler 定律認為,當設計一種語言時,花在語言結構上的時間與這些特徵的重要性相比很不成比例。
原則
在這篇文章中,作者表示原則是指導程序猿開發新應用的一些方針。在碼代碼的過程中,我們經常會遇到各種困難,當然也有各種約定俗成的規則。例如最簡單的命名法,有的默認為使用下劃線、使用小駝峰或大駝峰式的命名,只有了解這些規則,編寫的代碼才是優美的。
穩健性原則
在維基百科中,穩健性原則(Robustness Principle)描述為:「寫代碼要保守,要能接受其它方面的各種信息」。
該原則通常應用於伺服器應用的開發,它表示發送的內容應該儘可能少且符合要求。但如果可以處理不符合要求的輸入,那麼你的目標應該希望允許各種非一致性的輸入。
該原則的目標是構建一個穩健的系統,對於輸入端,只要對方的意圖仍可以理解,那麼我們就應該需要處理非標準格式的輸入。然而,接受格式錯誤的輸入有潛在的安全影響,特別是當這種輸入的處理方式還沒有經過良好的測試。
SOLID
該原則是一個縮寫,即:
- S:單一功能原則
- O:開閉原則
- L:里氏替換原則
- I:介面隔離原則
- D:依賴反轉原則
如上所示, SOLID 指代了面向對象編程和面向對象設計的五個基本原則。當這些原則被一起應用時,它們使得程序員能開發更容易進行軟體維護和擴展的系統。SOLID常應用在測試的驅動開發上,並且是敏捷開發以及自適應軟體開發的基本原則的重要組成部分。下面讓我們看看這5個基本原則都是什麼吧。
單一功能原則
在維基百科的描述中,單一功能原則(Single responsibility principle)規定每個類都應該有一個單一的功能,並且該功能應該由這個類完全封裝起來。所有它的(這個類的)服務都應該嚴密的和該功能平行(功能平行,意味著沒有依賴)。
這一原則表明模塊或類應該只完成一件事。這意味著對程序特性的單個小修正,應該只需要在一個組件中進行更改。例如,更改驗證密碼的方式應該只需要更改程序特定的某個模塊。
保持一個類專註於單一功能點,這樣做的重要原因是它會使得類更加穩健。如果我們知道正在修改的組件只有一個功能,那麼測試會變得更簡單,新的修改也就好處理了。例如上面,修改密碼驗證應該隻影響與密碼驗證相關的特性,如果我們要對具有多功能的模塊進行修改,這樣進行推斷就要複雜多了。
開閉原則
在面向對象的編程中,開閉原則規定:軟體中的對象(類、模塊、函數等等)對於擴展應該是開放的,但是對已存行為的修改是封閉的。這意味著,一個實體需要允許在不改變源代碼的前提下變更它的行為。
該特性在產品化的環境中特別有價值,因為在產品化中改變源代碼需要代碼審查,例如單元測試等方法確保產品使用的質量。遵循這種原則的代碼在擴展時並不發生改變,因此無需上述過程。
舉個栗子,假設某個模塊能夠將 Markdown 文本轉換為HTML。如果模塊可以擴展新的特性,即能處理新提出的Markdown 特性而不修改模塊內部,那麼這就表示它對擴展是開放的。
這一原則與面向對象的編程特別相關,我們可以設計易於擴展的對象,但也要避免設計不穩定的對象,因為它們的現有行為可能會以意想不到的方式發生改變。
里氏替換原則
里氏替換原則(Liskov Substitution principle)是對子類型的特別定義。里氏替換原則的內容可以描述為: 派生類(子類)對象可以在程序中代替其基類(父類)對象。也就是說,如果一個模塊依賴於某個類,那麼該模塊就需要能使用該類的派生類,且不會發生系統錯誤。
舉個栗子,如果我們有一種方法,它可以從表徵文件的結構中讀取XML文本。如果該方法的基類是「file」,那麼它能調用從「file」派生的任意類。
這一原則對於面向對象的編程非常重要,我們必須仔細建模類的層次結構,以避免讓系統用戶感到困惑。
介面隔離原則
介面隔離原則(interface-segregation principles)指明用戶(client)應該不依賴於它不使用的方法。介面隔離原則拆分龐大臃腫的介面成為更小的和更具體的介面,這樣用戶將會只需要知道他們感興趣的方法。這種縮小的介面也被稱為角色介面(role interfaces)。介面隔離原則的目的是系統解開耦合,從而容易重構、更改和重新部署。
舉個栗子,假設我們有一種能夠從表徵文件的結構中讀取XML文檔的方法。這種方法只需要讀取位元組以及在文件中前移或後移即可。如果該方法因為文件結構的一種非相關性特徵改變而需要進行更新(如用於表徵文件安全的許可權模型的更新),則該原則無效。文件最好實現『seekable-stream』介面並讓XML reader使用。
該原則與面向對象編程具有特殊的相關性,其中介面、層次和抽象類型用於最小化不同組件之間的耦合。鴨子類型(duck typing)通過消除顯式介面來執行該原則。
依賴反轉原則
在傳統的應用架構中,低層次的組件設計用到高層次的組件中,這一點提供了逐步的構建一個複雜系統的可能。在這種結構下,高層次的組件直接依賴於低層次的組件去實現一些任務。這種對於低層次組件的依賴限制了高層次組件被重用的可行性。
依賴反轉原則的目的是把高層次組件從對低層次組件的依賴中解耦出來,這樣使得重用不同層級的組件實現變得可能。把高層組件和低層組件劃分到不同的包/庫,該方式也促進了這種解耦。由於低層組件是對高層組件介面的具體實現,因此低層組件包的編譯是依賴於高層組件的,這顛倒了傳統的依賴關係。眾多的設計模式,比如插件、服務定位器或者依賴反轉,則被用來在運行時把指定的低層組件實現提供給高層組件。
具體而言,依賴反轉原則規定:
- 高層次的模塊不應該依賴於低層次的模塊,兩者都應該依賴於抽象介面。
- 抽象介面不應該依賴於具體實現。而具體實現則應該依賴於抽象介面。
舉個栗子,如果我們有一個從網站讀取元數據的程序,且主組件包含下載網站內容的組件和讀取元數據的組件。如果我們考慮依賴反轉原則,那麼主組件只能依賴於某些抽象組件,其中某個抽象組件只能獲取比特數據、另一個只能從比特流中讀取元數據。主組件並不知道任何關於TCP/IP、HTTP或HTML等協議或格式的相關信息。
這一原則是比較複雜的,因為它似乎反轉了系統的依賴性關係。在實踐中,該原則意味著獨立的編排模塊必須確保使用了正確的抽象類型實現。例如在上面的例子中,元數據讀取模塊還是需要一些抽象類型的實現,即HTTP文件下載器和HTML元標籤讀取器。
※速度提高100萬倍,哈佛醫學院大神提出可預測蛋白質結構的新型深度模型
※GitHub放出重大更新:加入免費軟體包管理服務
TAG:機器之心 |