日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

《軟件設(shè)計(jì)的哲學(xué)》解讀

 菌心說 2021-09-19

引言

本書的英文名稱為《A Philosophy of Software Design》,由斯坦福大學(xué)教授、Tcl 語言發(fā)明者 John Ousterhout所著,在bookstack上有g(shù)dut-yy等人翻譯的中文版。

很少有人能夠在哲學(xué)層面來思考軟件設(shè)計(jì)并成書,本書就是一個特殊的存在,而本文將帶您一起領(lǐng)略這篇著作的思想精髓。

文章圖片1

A Philosophy of Software Design

復(fù)雜性的表現(xiàn)

在作者看來,軟件開發(fā)的復(fù)雜性主要從以下三個方面表現(xiàn)出來:

  1. 變更放大:看似簡單的需求,卻需要在許多不同地方進(jìn)行修改
  2. 認(rèn)知負(fù)荷:開發(fā)者必須花更多時(shí)間來學(xué)習(xí)所需知識
  3. 未知的未知:開發(fā)者不知道需要了解哪些信息、修改哪些地方才能完成任務(wù)

“對未知的未知”顯然是三種表現(xiàn)里面最糟糕的一種,這些我們應(yīng)該很容易理解,甚至可能深有體會。

文章圖片2

軟件開發(fā)復(fù)雜性的三種表現(xiàn)

復(fù)雜性的定義

我們已經(jīng)知道了復(fù)雜性的表現(xiàn),那么如何更為精確地表達(dá)復(fù)雜性呢?作者給出了一個數(shù)學(xué)公式,通過它,可以幫助我們更好地抓住復(fù)雜性的本質(zhì):

文章圖片3

用數(shù)學(xué)方法表示復(fù)雜性

在公式中,系統(tǒng)的總體復(fù)雜度(C)由每個部分的復(fù)雜度(cp)乘以開發(fā)人員在該部分上花費(fèi)的時(shí)間(tp)加權(quán)。

我們可以由此公式看出,軟件系統(tǒng)開發(fā)的復(fù)雜度突出地表現(xiàn)為開發(fā)人員完成工作所需的時(shí)間。

復(fù)雜性的成因

在了解了“是什么”之后,我們進(jìn)入“為什么”環(huán)節(jié),來看一下有哪些原因會導(dǎo)致復(fù)雜性。

作者研究得出,導(dǎo)致復(fù)雜性的原因主要是以下兩個方面:

  1. 依賴性:無法孤立地理解和修改給定的一段代碼
  2. 模糊性:重要和關(guān)鍵的信息不夠明顯
文章圖片4

復(fù)雜性的原因

過度的依賴性導(dǎo)致變化放大和高認(rèn)知負(fù)荷,而信息模糊會產(chǎn)生對未知的未知,還會增加認(rèn)知負(fù)擔(dān)。

依賴關(guān)系是軟件的基本組成部分,不能把它完全消除。軟件設(shè)計(jì)的目標(biāo)之一是減少依賴關(guān)系的數(shù)量,并使依賴關(guān)系保持盡可能簡單和明顯。模糊通常來自文檔的不足,但也可以歸為設(shè)計(jì)問題。如果系統(tǒng)設(shè)計(jì)簡潔明了,則所需的文檔將更少。

這樣,軟件開發(fā)復(fù)雜性的問題就轉(zhuǎn)化為:如果我們找到最小化依賴關(guān)系和模糊性的設(shè)計(jì)技術(shù),那么我們就可以降低軟件的復(fù)雜性。

復(fù)雜性的規(guī)律

作者還告訴我們,復(fù)雜性是不斷累積而來的,越到后期的修復(fù)成本越大。復(fù)雜性不是由單個災(zāi)難性錯誤引起的,而是隨著時(shí)間的流逝,通過眾多小的依賴性和模糊性逐漸發(fā)展而來的。

由于復(fù)雜性增量累積的特點(diǎn),一旦累積了過多的復(fù)雜性,其修復(fù)成本也將是巨大的,開發(fā)人員妥協(xié)的可能性將更大,進(jìn)而累積更多的復(fù)雜性。

復(fù)雜性的應(yīng)對思維

按照套路,我們現(xiàn)在要研究“怎么辦”了。

根據(jù)作者研究,要想馴服開發(fā)的復(fù)雜性,需要建立如下思維:

  1. 投資心態(tài):當(dāng)前進(jìn)行少部分投入,可以避免將來大量投入
  2. 零容忍:對復(fù)雜性零容忍,避免累積過多,導(dǎo)致無法解決

所謂投資心態(tài),就是開發(fā)時(shí)要有成本收益概念,強(qiáng)調(diào)要避免短視,要認(rèn)識到現(xiàn)在的小投入,可避免將來更大的投入。

這里,作者提出了“戰(zhàn)略編程”和“戰(zhàn)術(shù)編程”兩個概念,戰(zhàn)術(shù)編程通常只顧完成當(dāng)前任務(wù),具有短視性,而戰(zhàn)略編程則會考慮長遠(yuǎn),會從投資心態(tài)看問題。一開始,戰(zhàn)術(shù)性的編程方法將比戰(zhàn)略性方法更快地取得進(jìn)展。但是,在戰(zhàn)術(shù)方法下,復(fù)雜性積累得更快,從而降低了生產(chǎn)率。隨著時(shí)間的流逝,戰(zhàn)略編程會顯現(xiàn)出優(yōu)勢。

文章圖片5

戰(zhàn)略編程(Strategic)與戰(zhàn)術(shù)編程(Tactical)定性對比

千里之堤毀于蟻穴,大錯誤都是由小錯誤不斷累積起來導(dǎo)致的。所以,另一個重要的思維就是要零容忍,不能忽視和放過任何問題,而這通常是很難做到的。

復(fù)雜性的應(yīng)對方法

如果把依賴關(guān)系也作為一種信息的話,就可以認(rèn)為信息過載才是復(fù)雜性的根源,而戰(zhàn)勝復(fù)雜性的方法就是想盡辦法精簡信息。簡化信息,避免信息過載,就是要防止不必要的信息泄露,并避免重復(fù)信息。

隨著技術(shù)的發(fā)展,會出現(xiàn)一些好的工具,來幫助我們管理和簡化信息,但是這治標(biāo)不治本,簡化信息還是要從軟件設(shè)計(jì)入手。

代碼開發(fā)涉及的核心信息包括“在哪里”、“做什么”和“如何做”,其中“在哪里”信息對應(yīng)于軟件系統(tǒng)的設(shè)計(jì)和規(guī)約等,“做什么”對應(yīng)于接口,“如何做”則對應(yīng)于接口的實(shí)現(xiàn)。我們需要做的就是把“如何做”隱藏起來,并精簡“在哪里”和“做什么”的信息。

因此,作者提出了“深模塊”的概念,即接口簡單,而實(shí)現(xiàn)“復(fù)雜”的代碼塊,這里的“模塊”泛指我們通常所說的模塊、類、方法等。從投資角度來說,模塊帶來的收益是其功能,模塊的成本是其接口(就系統(tǒng)復(fù)雜性而言),模塊的接口代表了模塊強(qiáng)加給系統(tǒng)其余部分的復(fù)雜性:接口越小越簡單,引入的復(fù)雜性就越小。因此,最好的模塊是那些提供強(qiáng)大功能但具有簡單接口的模塊。

文章圖片6

深模塊(Deep Module)與淺模塊(Shallow Module)

匯總一下,應(yīng)對開發(fā)復(fù)雜性的方法,就是要通過設(shè)計(jì)手段,充分利用深模塊技術(shù),在避免信息泄露的同時(shí),減少模塊間依賴關(guān)系,從而降低文檔需求,從各方面精簡信息。

復(fù)雜性應(yīng)對實(shí)操

為了幫助讀者更好地應(yīng)對軟件開發(fā)的復(fù)雜性,作者還在實(shí)際操作層面進(jìn)行了探討,給出了很多具體指導(dǎo)意見和建議,有些觀點(diǎn)甚至與流行做法有悖,我們一起來看一下。

關(guān)于私有字段:

通過聲明變量和方法為私有來隱藏類中的變量和方法并不等同于信息隱藏,其往往通過屬性或公共方法對外泄露了信息。

關(guān)于裝飾器設(shè)計(jì)模式:

裝飾器模式的動機(jī)是將類的專用擴(kuò)展與更通用的核心分開。但是,裝飾器類往往很淺,它們引入了大量的樣板,以實(shí)現(xiàn)少量的新功能。

關(guān)于消除變量跨層傳遞的方法:

變量跨層傳遞帶來復(fù)雜性。消除傳遞變量并不容易,包括共享對象、全局變量和最常用的上下文對象三種方法。

關(guān)于配置參數(shù):

配置參數(shù)將復(fù)雜度給了調(diào)用方,反倒提升了使用的復(fù)雜度。

降低復(fù)雜度的決策:

如果被降低的復(fù)雜度與該模塊的現(xiàn)有功能密切相關(guān),或者降低復(fù)雜度將導(dǎo)致其他地方的許多簡化,則降低復(fù)雜度最有意義。

關(guān)于日志記錄:

消除日志記錄淺方法的辦法是將日志記錄語句放置在檢測到錯誤的位置。

關(guān)于方法的長度:

一個方法重要的是其深淺,而不是長度。如果方法的接口簡單而實(shí)現(xiàn)復(fù)雜,則其長度并不重要。

關(guān)于異常處理:

異常處理是軟件系統(tǒng)中最糟糕的復(fù)雜性來源之一,拋出異常很容易,處理它們則很困難。

關(guān)于注釋:

代碼內(nèi)文檔在設(shè)計(jì)中起著重要的作用,對于幫助開發(fā)人員理解系統(tǒng)和有效工作至關(guān)重要。注釋還可以隱藏復(fù)雜性,沒有注釋,用戶必須閱讀代碼才能使用方法,則方法的所有復(fù)雜性都將暴露出來。

低級注釋可提高精度,高級注釋可增強(qiáng)直覺。編寫注釋的最佳時(shí)間是在過程開始時(shí),這不僅可以產(chǎn)生更好的文檔,還可以產(chǎn)生更好的設(shè)計(jì),并使編寫文檔的過程更加愉快。

確保注釋更新的最佳方法是將注釋放置在它們描述的代碼附近,注釋離其關(guān)聯(lián)的代碼越遠(yuǎn),正確更新的可能性就越小。

如果注釋比代碼更高級,更抽象,則注釋更易于維護(hù)。

關(guān)于命名:

良好的名字是一種文檔形式,它們使代碼更易于理解,減少了對其他文檔的需求,并使檢測錯誤更加容易。最好的命名是那些將注意力集中在對底層實(shí)體最重要的東西上,而忽略那些次要的細(xì)節(jié)。

良好名稱具有兩個屬性:精度和一致性。

關(guān)于一致性:

一致性是降低系統(tǒng)復(fù)雜性并使其行為更明顯的強(qiáng)大工具。一致性會產(chǎn)生認(rèn)知影響力:一旦您了解了某個地方的工作方式,就可以使用該知識立即了解其他使用相同方法的地方。如果系統(tǒng)的實(shí)施方式不一致,則開發(fā)人員必須分別了解每種情況,這將花費(fèi)更多時(shí)間。

關(guān)于繼承:

繼承會在父類及其每個子類之間創(chuàng)建依賴關(guān)系。父類和子類通常都訪問父類中的類實(shí)例變量,這會導(dǎo)致繼承層次結(jié)構(gòu)中的類之間的信息泄漏,并且使得在不查看其他類的情況下很難修改層次結(jié)構(gòu)中的一個類。在使用繼承之前,請考慮基于組合的方法是否可以提供相同的好處。如果沒有繼承的可行選擇,請嘗試將父類管理的狀態(tài)與子類管理的狀態(tài)分開。

關(guān)于敏捷開發(fā):

敏捷開發(fā)的風(fēng)險(xiǎn)之一是它可能導(dǎo)致戰(zhàn)術(shù)編程。敏捷開發(fā)傾向于使開發(fā)人員專注于功能,而不是抽象,它鼓勵開發(fā)人員推遲設(shè)計(jì)決策,以便盡快生產(chǎn)可運(yùn)行的軟件。漸進(jìn)式開發(fā)通常是一個好主意,但是漸進(jìn)式開發(fā)應(yīng)該是抽象的,而不是功能??梢酝七t對特定抽象的所有想法,直到功能需要它為止。一旦需要抽象,就要花一些時(shí)間進(jìn)行簡潔的設(shè)計(jì)。

關(guān)于測試:

測試,尤其是單元測試,在軟件設(shè)計(jì)中起著重要作用,因?yàn)樗鼈冇兄谥貥?gòu)。沒有測試套件,對系統(tǒng)進(jìn)行重大結(jié)構(gòu)更改很危險(xiǎn)。

測試驅(qū)動開發(fā)是一種軟件開發(fā)方法,程序員可以在編寫代碼之前先編寫單元測試。測試驅(qū)動的開發(fā)過于增量,在任何時(shí)間點(diǎn),很容易破解下一個功能以進(jìn)行下一個測試通過,沒有明顯的時(shí)間進(jìn)行設(shè)計(jì),因此很容易陷入混亂。

關(guān)于設(shè)計(jì)模式:

設(shè)計(jì)模式解決了常見的問題。如果設(shè)計(jì)模式在特定情況下運(yùn)作良好,那么您可能很難想出另一種更好的方法。設(shè)計(jì)模式的最大風(fēng)險(xiǎn)是過度使用,使用現(xiàn)有的設(shè)計(jì)模式并不能完全解決所有問題,當(dāng)自定義方法更加簡潔時(shí),請勿嘗試將問題強(qiáng)加到設(shè)計(jì)模式中。與軟件設(shè)計(jì)中的許多想法一樣,設(shè)計(jì)模式良好的概念并不一定意味著更多的設(shè)計(jì)模式會更好。

關(guān)于性能:

干凈的設(shè)計(jì)和高性能是兼容的,復(fù)雜的代碼通常會很慢,因?yàn)樗鼤?zhí)行多余或多余的工作。在少數(shù)需要優(yōu)化性能的情況下,找到對性能最重要的關(guān)鍵路徑并使它們盡可能簡單。

復(fù)雜性應(yīng)對總結(jié)

在書的最后,作者對全書觀點(diǎn)進(jìn)行了總結(jié)。

類似Martin Fowler寫的《重構(gòu)》一書,John Ousterhout教授也提出了一些設(shè)計(jì)上的“壞味道”,他稱之為“危險(xiǎn)信號”:

  • 淺層模塊:接口相對于其實(shí)現(xiàn)過于復(fù)雜,“收益”低于“成本”
  • 信息泄漏:特定知識分散在多個不同地方
  • 時(shí)間分解:不同模塊間在執(zhí)行順序上有要求,泄露了時(shí)序信息
  • 過度暴露:接口調(diào)用者為調(diào)用常用功能,而必須關(guān)注很少使用功能的調(diào)用
  • 直通方法:方法幾乎不做任何實(shí)事,只是傳遞參數(shù)
  • 重復(fù)代碼:重復(fù)的代碼意味著信息的泄露
  • 通?;旌?/strong>:特定用途代碼與通用代碼沒有完全分開
  • 關(guān)聯(lián)方法:兩方法之間的依賴性很大,使用其中一個之前必須了解另一個
  • 冗贅注釋:代碼完全可以表達(dá)注釋的意思
  • 額外細(xì)節(jié):接口注釋向用戶泄露了其不需關(guān)注的細(xì)節(jié)
  • 模糊名稱:變量或方法的名稱太過模糊,無法傳遞有用信息
  • 難以取名:很難為實(shí)體提供準(zhǔn)確而直觀的名稱
  • 難以描述:需要冗贅的文檔才能描述清楚接口
  • 晦澀代碼:一段代碼的行為或含義不容易理解

作者還總結(jié)了一些應(yīng)對復(fù)雜性的設(shè)計(jì)原則:

  • 復(fù)雜性是逐步增加的,勿因惡小而為之,勿因善小而不為
  • 只是可以工作的代碼還不夠,需要進(jìn)行規(guī)劃,做一些降低復(fù)雜性的設(shè)計(jì)
  • 持續(xù)進(jìn)行少量投資以改善系統(tǒng)設(shè)計(jì),一旦開始推遲設(shè)計(jì)改進(jìn),就很容易變成永久性推遲
  • 模塊應(yīng)較深,深模塊是隱藏信息的絕佳途徑
  • 接口應(yīng)設(shè)計(jì)為對最常見的用法簡單,接口的有效性等效于其最常見功能的復(fù)雜性
  • 簡單的接口重于簡單的實(shí)現(xiàn),接口更影響復(fù)雜性
  • 通用模塊更深,通用模塊相比專用模塊泄露的信息更少,往往更簡單
  • 通用和專用代碼分開,下層代碼更通用,上層代碼更專用
  • 不同的層應(yīng)具有不同的抽象,不同的層有相似的抽象,意味著信息泄露
  • 復(fù)雜度下沉,不要將問題拋給調(diào)用方
  • 消除異常和特殊情況,在實(shí)現(xiàn)中自動處理異常和特例,以簡化調(diào)用方
  • 設(shè)計(jì)兩次,每次通過提供備選方案來改善設(shè)計(jì),并提升設(shè)計(jì)技能
  • 注釋應(yīng)描述代碼中不明顯的內(nèi)容,以使信息明朗
  • 軟件的設(shè)計(jì)應(yīng)易于閱讀而不是易于編寫,應(yīng)該讓使用者簡單
  • 軟件開發(fā)的增量應(yīng)該是抽象而不是功能,敏捷開發(fā)中應(yīng)及時(shí)進(jìn)行抽象設(shè)計(jì),避免功能堆砌

結(jié)語

到這里,我們已經(jīng)一起完成了“是什么”、“為什么”、“怎么辦”等問題的回答,對于“好不好”這個問題的答案,就留待我們實(shí)踐中解答吧。

感謝作者和譯者。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多