1 晨后綜合癥和包的發(fā)布
你曾有過這樣的經(jīng)歷嗎?工作了一整天,終于完成了某項(xiàng)功能后回家,不料第二天早晨一來卻發(fā)現(xiàn)那項(xiàng)功能不再工作了。原因是什么呢?因?yàn)橛腥吮饶阕叩酶恚⑶腋牧四闼蕾嚨哪承〇|西!這就是所謂的“晨后綜合癥"。受“晨后綜合癥”困擾的團(tuán)隊(duì)常常幾周時(shí)間都無法構(gòu)建出一個(gè)穩(wěn)定的版本,每個(gè)人都忙于一遍遍更改他們的代碼,試圖使之能夠相容與其他人所做的最近更改,從而造成團(tuán)隊(duì)士氣低落,效率不高,陷入了可怕的集成地獄中。為此有的團(tuán)隊(duì)在集成期間禁止 check in ,這顯然不是一個(gè)好辦法,一方面,如果不用技術(shù)手段很難避免有意或無意的 check in ,另一方面開發(fā)者為了進(jìn)行后續(xù)開發(fā)而又不影響當(dāng)前集成的版本,可能不得不手工進(jìn)行版本管理, 再有,它使團(tuán)隊(duì)成員間的協(xié)作也變得困難。
對(duì)包進(jìn)行發(fā)布能有效避免晨后綜合癥的發(fā)生。造成晨后綜合癥的原因在于依賴者所依賴的包是變化的,這就使依賴者工作于一個(gè)不穩(wěn)定的基礎(chǔ)之上,對(duì)被依賴者的改變,依賴者必須作出相容的改變。采用包的發(fā)布機(jī)制,依賴者必須選擇被依賴包發(fā)布的一個(gè)特定版本,而發(fā)布后的包,其內(nèi)容是不允許變化的,因此依賴者所依賴的東西就不會(huì)改變;同時(shí),被依賴包的任何改變都必須作為一個(gè)新版本發(fā)布,而依賴者有權(quán)決定是否采用這個(gè)新版本,換句話說,是否接受被依賴者的改變是由依賴者決定的,而在此之前,依賴者是不得不被動(dòng)地接受被依賴者的改變。
2 包的設(shè)計(jì)原則
要對(duì)包進(jìn)行發(fā)布,首先要先設(shè)計(jì)好包,對(duì)規(guī)模較大的應(yīng)用來說,劃分包的組合很多,僅僅把看起來像是適合在一起的類放進(jìn)相同的包中,得到的往往是一種不好的包結(jié)構(gòu):發(fā)布很困難、不容易重用、難于更改等等,這種包結(jié)構(gòu)帶來的可能是更多的麻煩。顯然我們需要一些原則來指導(dǎo)包的劃分,以下列出這些原則,前三個(gè)原則用來指導(dǎo)把類劃分到包中,關(guān)注包的內(nèi)聚性,后三個(gè)原則用來處理包之間的相互關(guān)系,關(guān)注包的耦合性。
2.1 REP 重用發(fā)布等價(jià)原則
重用的粒度就是發(fā)布的粒度。
如果一個(gè)包中的軟件是用來重用的,那么它就不能再包含不是為了重用目的而設(shè)計(jì)的軟件。換句話說,一個(gè)包中的軟件要么都是可重用的,要么都不是可重用的。簡(jiǎn)單地聲明一個(gè)類是可重用的做法是不現(xiàn)實(shí)的,我們所重用的任何東西都必須同時(shí)被發(fā)布和跟蹤。如果一個(gè)包同時(shí)包含了可重用的類和不可重用的類,那么當(dāng)不可重用的類發(fā)生變化時(shí),就要進(jìn)行一次包的發(fā)布,而原本不受影響的重用者就需要決定是否采用新版本,以及采用新版本后可能的編譯,連接和測(cè)試工作。這些內(nèi)耗操作是應(yīng)該避免的。
2.2 CRP 共同重用原則
一個(gè)包中的所有類應(yīng)該是共同重用的。如果重用了包中的一個(gè)類,那么就要重用包中的所有類。
在大多數(shù)情況下,一個(gè)可重用抽象需要多個(gè)類來表達(dá),該原則規(guī)定這些類應(yīng)該在一個(gè)包中,而屬于不同抽象的類不應(yīng)該在一個(gè)包中。乍看起來,這條原則和 REP 有點(diǎn)相似,但實(shí)際上還是不同的,比如,抽象 A 包括類 A1、A2、A3 ,抽象 B 包含類 B1、B2、B3 ,從 REP 原則來看,這個(gè)包沒有什么不對(duì),因?yàn)樵摪能浖际强芍赜玫模鼌s違反了 CRP 原則,因?yàn)橹赜谜咄耆梢灾恢赜?nbsp;A 抽象的類或只重用 B 抽象的類,這樣當(dāng)任一抽象的改變都會(huì)導(dǎo)致該包重新發(fā)布,雖然該發(fā)布對(duì)某一抽象的使用者是無意義的,但是他們?nèi)匀恍枰枰匦买?yàn)證和重新發(fā)布,這會(huì)白費(fèi)相當(dāng)數(shù)量的努力。
2.3 CCP 共同封閉原則
包中的所用類對(duì)于同一類性質(zhì)的變化應(yīng)該是共同封閉的。一個(gè)變化若對(duì)一個(gè)包產(chǎn)生影響,則將對(duì)該包中的所有類產(chǎn)生影響,而對(duì)其他的包不造成任何影響。
REP 和 CRP 關(guān)注的都是重用性, CCP 關(guān)注的是可維護(hù)性。對(duì)大多數(shù)的應(yīng)用來說,可維護(hù)性的重要性是超過可重用性的。一個(gè)變化(包括需求上的,設(shè)計(jì)上的等等)可能會(huì)引起多個(gè)類的更改, CCP 要求我們把這些類放在一個(gè)包中,同時(shí)把那些不受影響的類放到其他的包中,因此一個(gè)包只有一個(gè)引起變化的原因,一個(gè)變化只對(duì)一個(gè)包產(chǎn)生影響,這樣大大減少了重新發(fā)布的次數(shù)和重新發(fā)布對(duì)其他包的影響,從而提高了軟件的可維護(hù)性。
2.4 ADP 無環(huán)依賴原則
在包的依賴關(guān)系圖中不允許存在環(huán)。
如果包的依賴關(guān)系圖中存在環(huán),就會(huì)導(dǎo)致環(huán)上的所有軟件包必須同時(shí)發(fā)布,如下圖,
由于 P3 使用了 P1 中的一個(gè)類而形成了依賴環(huán),若要發(fā)布 P1 ,必須先發(fā)布 P2 和 P3 ,而發(fā)布 P3 又要先發(fā)布 P1 和 P2,P1、P2、P3 實(shí)際上已經(jīng)變成了同一個(gè)大包,于是工作于這些包上的開發(fā)人員不可避免地會(huì)遭受晨后綜合癥。
去掉依賴環(huán)的方法有兩個(gè):
-
使用DIP。如圖,把Y的接口和實(shí)現(xiàn)分離,
-
增加新包。如圖,把 P1 和 P3 都依賴的類移到一個(gè)新包中
2.5 SDP 穩(wěn)定依賴原則
朝著穩(wěn)定的方向進(jìn)行依賴。
如果一個(gè)包被很多包所依賴,那么它就是穩(wěn)定的,因?yàn)橐顾幸蕾囉谒陌軌蛳嗳萦趯?duì)它所做的更改,往往需要非常大的工作量。一個(gè)系統(tǒng)中的所有包并非都應(yīng)該都是穩(wěn)定的,因?yàn)槿绻菢拥脑挘到y(tǒng)將很難更改。 SDP 指導(dǎo)我們處理穩(wěn)定包和不穩(wěn)定包之間的關(guān)系:不穩(wěn)定的包應(yīng)該依賴于穩(wěn)定的包,一個(gè)包應(yīng)該依賴于比他更穩(wěn)定的包。你設(shè)計(jì)了一個(gè)不穩(wěn)定的包,期望它能隨變化容易地更改,可當(dāng)它被一個(gè)穩(wěn)定的包依賴后,它就再也不會(huì)易于更改了,這就使軟件難于修改和變化。
2.6 SAP 穩(wěn)定抽象原則
包的穩(wěn)定程度應(yīng)該和其穩(wěn)定程度一致。
一個(gè)系統(tǒng)的高層構(gòu)架和設(shè)計(jì)決策應(yīng)該被放進(jìn)穩(wěn)定的包中,因?yàn)檫@些構(gòu)架決策不應(yīng)該經(jīng)常改變,然而穩(wěn)定包的不易更改的特點(diǎn)會(huì)使這些架構(gòu)決策不靈活,顯然只用穩(wěn)定性來度量一個(gè)包是不夠的, SAP 告訴我們:穩(wěn)定的包也應(yīng)該是抽象的。它應(yīng)該包含抽象類,系統(tǒng)通過在其他包中實(shí)現(xiàn)該穩(wěn)定包中的抽象類來進(jìn)行擴(kuò)展,而該穩(wěn)定包無需修改,從而在保持穩(wěn)定的同時(shí)也不失靈活性。
3 包的設(shè)計(jì)過程
幾年前當(dāng)我還不知道這些包的設(shè)計(jì)原則時(shí),認(rèn)為包就是系統(tǒng)的高層的功能分解,應(yīng)該在項(xiàng)目開始時(shí)就設(shè)計(jì)好,結(jié)果遭受了失敗。實(shí)際上,包的依賴關(guān)系圖和描繪系統(tǒng)的功能之間幾乎沒有關(guān)系,它是系統(tǒng)可構(gòu)建性的映射圖。項(xiàng)目開始時(shí),我們還不知道系統(tǒng)中有哪些類,更不必說它們之間的關(guān)系,在這種情況下不僅很難創(chuàng)建出包依賴關(guān)系圖,即使創(chuàng)建出來也很可能是不合理的。包的依賴關(guān)系結(jié)構(gòu)應(yīng)該是和系統(tǒng)的邏輯設(shè)計(jì)一起增長(zhǎng)和演化的,項(xiàng)目開始時(shí)不必考慮包,系統(tǒng)仍以類的粒度組織,隨著開發(fā)的進(jìn)行,類越來越多,對(duì)依賴關(guān)系進(jìn)行管理,避免項(xiàng)目開發(fā)中出現(xiàn)晨后綜合癥的需要也不斷增長(zhǎng),此時(shí)我們應(yīng)用 CCP 原則對(duì)把可能一同變化的類組織成包進(jìn)行發(fā)布,隨著系統(tǒng)的不斷增長(zhǎng),我們開始關(guān)注創(chuàng)建可重用的元素,于是開始使用 CRP 和 REP 來指導(dǎo)包的組合。最后使用 ADP、SDP、SAP 對(duì)包圖進(jìn)行度量,去掉不好的依賴。
4 你真的采用了包的發(fā)布機(jī)制了嗎
如果說某個(gè)做產(chǎn)品的團(tuán)隊(duì)沒有采用包的發(fā)布機(jī)制,它也許會(huì)大叫冤枉:我們明明是進(jìn)行了發(fā)布的呀,你看,這不是我們發(fā)布的1.0、1.2版本嗎?事實(shí)上,任何一個(gè)產(chǎn)品都離不開包的發(fā)布,只不過對(duì)這樣的團(tuán)隊(duì)而言,他們系統(tǒng)里真正意義上的包只有一個(gè),那就是整個(gè)系統(tǒng),而該包的發(fā)布常常是在經(jīng)過了晨后綜合癥的洗禮之后,是在開發(fā)基本完畢后進(jìn)行的,實(shí)際上,我們更應(yīng)該在產(chǎn)品的開發(fā)過程中使用這一機(jī)制,這樣,產(chǎn)品的開發(fā)過程才會(huì)以合理,有序的方式進(jìn)行,產(chǎn)品才能盡快地交付。