當談到開發(fā)問題時,人們總會談?wù)摳鞣N定律。但對于大多數(shù)人來說,總有一些是你不了解的,這個問題就需要使用程序員最喜歡的方法解決了:最近 GitHub 上的一個「定律合集」項目突然登上了趨勢榜第二位,Star 數(shù)上千,該項目對一些最常見的定律進行了概括,詳情見下文。 大家都是資深程序員,以后就不要老念叨「真香定律」了。
本文包含對一些定律、原則和模式的解釋,但并不主張其中任何一項。是否要應(yīng)用哪個定律一直是一個爭論性問題,并且很大程度上取決于你在做哪方面的工作。 這些規(guī)則目錄如下: 定律
原則
對于以上如此多的定律和原則,我們選取了其中一些定律和所有的原則進行編譯。現(xiàn)在,先簡單看一下定律吧↓↓ 定律 阿姆達爾定律 維基百科:計算機科學界的經(jīng)驗法則,因吉恩·阿姆達爾而得名。它代表了處理器并行運算之后效率提升的能力。阿姆達爾定律是固定負載(計算總量不變時)時的量化標準。 舉例說明,如果一個程序由兩部分(A和B)組成,A必須有單個處理器執(zhí)行,B可以并行執(zhí)行,那么在執(zhí)行該程序的系統(tǒng)中增加多個處理器帶來的好處是有限的。它可能會大大提升B的速度,但A的速度會保持不變。如下如所示: 從圖中可以看出,一個程序如果只有50%的部分可并行處理,那它使用10個以上處理單元時,處理速度將不會有很大的提升。而一個程序如果有95%的部分可并行處理,即使使用的處理單元超過1000個,其處理速度也會顯著提高。 侯世達定律 維基百科:做事所花費的時間總是比你預(yù)期的要長,即使你的預(yù)期中考慮了侯世達定律。 當你估計做一件事要花費多長時間時,可能會想到這一定律。軟件開發(fā)中的老生常談是,我們往往很難估計交付某個東西所需要的準確時間。 炒作周期 & 阿瑪拉定律 維基百科:我們總是高估一項技術(shù)的短期效益,而低估其長期效果。 此定律被描述為鼓勵人們思考科技所能帶來的長期影響的言論。同時,阿瑪拉定律也被人們稱為是對“炒作周期”(技術(shù)成熟度曲線)最形象的說明。如下圖所示: 簡言之,這一周期表明,新技術(shù)及其潛在影響通常會引起一陣興奮。然后很多團隊快速投入該技術(shù),然后有時會對結(jié)果感到失望。這可能是因為技術(shù)還不夠成熟,也可能是因為現(xiàn)實應(yīng)用還沒有完全實現(xiàn)。 經(jīng)過一段時間后,技術(shù)的能力增加,使用技術(shù)的實際機會也增加,置身其中的團隊最終開始受益。 海勒姆法則 網(wǎng)絡(luò)定義:當一個 API 有足夠多的用戶時,你在約定中承諾什么都無所謂,所有在你系統(tǒng)里面被觀察到的行為都會被一些用戶直接依賴。 海勒姆法則指出,當你的API有非常多的用戶時,API中的所有行為最終都會被某個人所依賴。舉個簡單的例子:非功能性元素,如API的響應(yīng)時間。稍微復(fù)雜一點的例子:依賴對錯誤消息應(yīng)用正則表達式來確定API錯誤類型的用戶。 摩爾定律 該定律認為,集成電路中的晶體管數(shù)量大約每兩年翻一番。 該定律通常用來表示半導(dǎo)體和芯片技術(shù)發(fā)展的絕對速度。從上世紀70年代到90年代末,摩爾的預(yù)測一直非常精準。但近年來,該趨勢已經(jīng)發(fā)生了細微的變化,部分原因在于組件小型化程度受到的物理限制。然而,并行化的發(fā)展以及半導(dǎo)體技術(shù)和量子計算領(lǐng)域潛在的革命性變化,可能意味著摩爾定律在未來幾十年仍將適用。 復(fù)雜性守恒定律(泰斯勒定律) 該定律認為每個系統(tǒng)內(nèi)都有一定的復(fù)雜性不可減少。 系統(tǒng)中的某些復(fù)雜性是“不經(jīng)意的”??赡苁怯山Y(jié)構(gòu)不良、錯誤或只是建模不良造成的結(jié)果。這些不經(jīng)意造成的復(fù)雜性是可以減少(或消除)的。但是,有些復(fù)雜性是“固有的”,是由亟待解決問題的內(nèi)在復(fù)雜性造成的。而這種復(fù)雜性可以移動,但無法消除。 這個定律有趣的一點在于,即使簡化整個系統(tǒng),也無法降低內(nèi)在的復(fù)雜性。這種方法只不過是將復(fù)雜性轉(zhuǎn)移到了用戶一方,然后用戶必須以更復(fù)雜的方式行事。 帕金森瑣碎定律 該定律認為,大型組織會花費大量時間和精力來討論無關(guān)緊要的瑣事,但是真正重大的決議反而可以輕松過關(guān)。 這是因為,在討論非常專業(yè)而且金額龐大的事情時,一般人由于缺乏專業(yè)知識,不敢隨便發(fā)言,以免失言,貽笑大方,因此多半都會肯定(或逃避)該重大方案,而提些與主題無關(guān)的雞毛蒜皮小事。相對的,對于簡單的瑣碎小事,由于平常大家都會接觸到而且有相當?shù)恼J識,反而意見特別多,帕金森稱此現(xiàn)象為瑣碎定律。 Unix 哲學 Unix哲學認為,軟件組件應(yīng)該很小,而且應(yīng)該把注意力放在具體的事件上。將小的、簡單的、定義良好的單元組合在一起,而不是使用大的、復(fù)雜的、多用途程序,這樣可以使構(gòu)建系統(tǒng)變得更加容易。 像“微服務(wù)架構(gòu)”這樣的現(xiàn)代實踐就應(yīng)用了這種哲學。在該架構(gòu)中,服務(wù)很小,且集中做某件事,使得復(fù)雜的行為由簡單的構(gòu)件組成。 Wadler 定律 該定律認為:在任何語言設(shè)計中,討論這個列表中某個特性所花費的總時間與它位置的冪成正比。 1.語義 2.語法 3.詞匯語法 4.注釋的詞匯語法 (簡言之,如果在語義上花1小時來討論,那將在注釋語法上花8小時)。 與帕金森瑣碎定律相似,Wadler 定律認為,當設(shè)計一種語言時,花在語言結(jié)構(gòu)上的時間與這些特征的重要性相比很不成比例。 原則 在這篇文章中,作者表示原則是指導(dǎo)程序猿開發(fā)新應(yīng)用的一些方針。在碼代碼的過程中,我們經(jīng)常會遇到各種困難,當然也有各種約定俗成的規(guī)則。例如最簡單的命名法,有的默認為使用下劃線、使用小駝峰或大駝峰式的命名,只有了解這些規(guī)則,編寫的代碼才是優(yōu)美的。 穩(wěn)健性原則 在維基百科中,穩(wěn)健性原則(Robustness Principle)描述為:“寫代碼要保守,要能接受其它方面的各種信息”。 該原則通常應(yīng)用于服務(wù)器應(yīng)用的開發(fā),它表示發(fā)送的內(nèi)容應(yīng)該盡可能少且符合要求。但如果可以處理不符合要求的輸入,那么你的目標應(yīng)該希望允許各種非一致性的輸入。 該原則的目標是構(gòu)建一個穩(wěn)健的系統(tǒng),對于輸入端,只要對方的意圖仍可以理解,那么我們就應(yīng)該需要處理非標準格式的輸入。然而,接受格式錯誤的輸入有潛在的安全影響,特別是當這種輸入的處理方式還沒有經(jīng)過良好的測試。 SOLID 該原則是一個縮寫,即:
如上所示, SOLID 指代了面向?qū)ο缶幊毯兔嫦驅(qū)ο笤O(shè)計的五個基本原則。當這些原則被一起應(yīng)用時,它們使得程序員能開發(fā)更容易進行軟件維護和擴展的系統(tǒng)。SOLID常應(yīng)用在測試的驅(qū)動開發(fā)上,并且是敏捷開發(fā)以及自適應(yīng)軟件開發(fā)的基本原則的重要組成部分。下面讓我們看看這5個基本原則都是什么吧。 單一功能原則 在維基百科的描述中,單一功能原則(Single responsibility principle)規(guī)定每個類都應(yīng)該有一個單一的功能,并且該功能應(yīng)該由這個類完全封裝起來。所有它的(這個類的)服務(wù)都應(yīng)該嚴密的和該功能平行(功能平行,意味著沒有依賴)。 這一原則表明模塊或類應(yīng)該只完成一件事。這意味著對程序特性的單個小修正,應(yīng)該只需要在一個組件中進行更改。例如,更改驗證密碼的方式應(yīng)該只需要更改程序特定的某個模塊。 保持一個類專注于單一功能點,這樣做的重要原因是它會使得類更加穩(wěn)健。如果我們知道正在修改的組件只有一個功能,那么測試會變得更簡單,新的修改也就好處理了。例如上面,修改密碼驗證應(yīng)該只影響與密碼驗證相關(guān)的特性,如果我們要對具有多功能的模塊進行修改,這樣進行推斷就要復(fù)雜多了。 開閉原則 在面向?qū)ο蟮木幊讨校_閉原則規(guī)定:軟件中的對象(類、模塊、函數(shù)等等)對于擴展應(yīng)該是開放的,但是對已存行為的修改是封閉的。這意味著,一個實體需要允許在不改變源代碼的前提下變更它的行為。 該特性在產(chǎn)品化的環(huán)境中特別有價值,因為在產(chǎn)品化中改變源代碼需要代碼審查,例如單元測試等方法確保產(chǎn)品使用的質(zhì)量。遵循這種原則的代碼在擴展時并不發(fā)生改變,因此無需上述過程。 舉個栗子,假設(shè)某個模塊能夠?qū)?Markdown 文本轉(zhuǎn)換為HTML。如果模塊可以擴展新的特性,即能處理新提出的Markdown 特性而不修改模塊內(nèi)部,那么這就表示它對擴展是開放的。 這一原則與面向?qū)ο蟮木幊烫貏e相關(guān),我們可以設(shè)計易于擴展的對象,但也要避免設(shè)計不穩(wěn)定的對象,因為它們的現(xiàn)有行為可能會以意想不到的方式發(fā)生改變。 里氏替換原則 里氏替換原則(Liskov Substitution principle)是對子類型的特別定義。里氏替換原則的內(nèi)容可以描述為: 派生類(子類)對象可以在程序中代替其基類(父類)對象。也就是說,如果一個模塊依賴于某個類,那么該模塊就需要能使用該類的派生類,且不會發(fā)生系統(tǒng)錯誤。 舉個栗子,如果我們有一種方法,它可以從表征文件的結(jié)構(gòu)中讀取XML文本。如果該方法的基類是“file”,那么它能調(diào)用從“file”派生的任意類。 這一原則對于面向?qū)ο蟮木幊谭浅V匾?,我們必須仔細建模類的層次結(jié)構(gòu),以避免讓系統(tǒng)用戶感到困惑。 接口隔離原則 接口隔離原則(interface-segregation principles)指明用戶(client)應(yīng)該不依賴于它不使用的方法。接口隔離原則拆分龐大臃腫的接口成為更小的和更具體的接口,這樣用戶將會只需要知道他們感興趣的方法。這種縮小的接口也被稱為角色接口(role interfaces)。接口隔離原則的目的是系統(tǒng)解開耦合,從而容易重構(gòu)、更改和重新部署。 舉個栗子,假設(shè)我們有一種能夠從表征文件的結(jié)構(gòu)中讀取XML文檔的方法。這種方法只需要讀取字節(jié)以及在文件中前移或后移即可。如果該方法因為文件結(jié)構(gòu)的一種非相關(guān)性特征改變而需要進行更新(如用于表征文件安全的權(quán)限模型的更新),則該原則無效。文件最好實現(xiàn)‘seekable-stream’接口并讓XML reader使用。 該原則與面向?qū)ο缶幊叹哂刑厥獾南嚓P(guān)性,其中接口、層次和抽象類型用于最小化不同組件之間的耦合。鴨子類型(duck typing)通過消除顯式接口來執(zhí)行該原則。 依賴反轉(zhuǎn)原則 在傳統(tǒng)的應(yīng)用架構(gòu)中,低層次的組件設(shè)計用到高層次的組件中,這一點提供了逐步的構(gòu)建一個復(fù)雜系統(tǒng)的可能。在這種結(jié)構(gòu)下,高層次的組件直接依賴于低層次的組件去實現(xiàn)一些任務(wù)。這種對于低層次組件的依賴限制了高層次組件被重用的可行性。 依賴反轉(zhuǎn)原則的目的是把高層次組件從對低層次組件的依賴中解耦出來,這樣使得重用不同層級的組件實現(xiàn)變得可能。把高層組件和低層組件劃分到不同的包/庫,該方式也促進了這種解耦。由于低層組件是對高層組件接口的具體實現(xiàn),因此低層組件包的編譯是依賴于高層組件的,這顛倒了傳統(tǒng)的依賴關(guān)系。眾多的設(shè)計模式,比如插件、服務(wù)定位器或者依賴反轉(zhuǎn),則被用來在運行時把指定的低層組件實現(xiàn)提供給高層組件。 具體而言,依賴反轉(zhuǎn)原則規(guī)定:
舉個栗子,如果我們有一個從網(wǎng)站讀取元數(shù)據(jù)的程序,且主組件包含下載網(wǎng)站內(nèi)容的組件和讀取元數(shù)據(jù)的組件。如果我們考慮依賴反轉(zhuǎn)原則,那么主組件只能依賴于某些抽象組件,其中某個抽象組件只能獲取比特數(shù)據(jù)、另一個只能從比特流中讀取元數(shù)據(jù)。主組件并不知道任何關(guān)于TCP/IP、HTTP或HTML等協(xié)議或格式的相關(guān)信息。 這一原則是比較復(fù)雜的,因為它似乎反轉(zhuǎn)了系統(tǒng)的依賴性關(guān)系。在實踐中,該原則意味著獨立的編排模塊必須確保使用了正確的抽象類型實現(xiàn)。例如在上面的例子中,元數(shù)據(jù)讀取模塊還是需要一些抽象類型的實現(xiàn),即HTTP文件下載器和HTML元標簽讀取器。 |
|