[元件如何正確歸類 ?]元件內聚性三大原則 : REP、CCP、CRP ====== `適當時機 x 適當分類` {%youtube wRyzCktcbNQ %} 大綱 ------ + 全新的專案 + 高內聚就能低耦合 + 內聚性三大原則 + REP , 再使用性 - 發佈等價原則 + CCP , 共同封閉原則 + CRP , 共同重複使用原則 + 內聚性張力圖 + 適當的時機,適當的分類 <br> 全新的專案 ------ 全新的專案,從無到有的開發 ### 過往的經驗 打算把很多重複的功能,都聚集成 一個獨立的元件 ### 類別分類 要將哪個類別歸類到哪個元件,是個重大的決定! 但大部分的時候,卻都是憑感覺分類。 <br> ### 內聚性三大原則 就是在告訴你 : 分類時,可以依據類別的什麼特性,來歸類成同一個元件。 除此之外 : **它甚至告訴你,現在就將類別,抽成共用元件,並不是恰當的「時機點」。** <br> 高內聚就能低耦合 ------ 延續元件耦合性的部分 ![001.principle](https://lh3.googleusercontent.com/-2Vqh6C_iJfM/X-YGgq12flI/AAAAAAAACw0/_wSEWsEkVmEDzE1K8SIwxK1VTvLcXumaACLcBGAsYHQ/s16000/001.principle.png) + [`Youtube : 元件耦合性 | 3 大原則 | 最少改動 x 最大收益`](https://youtu.be/cSQY0rA7FPU) <br> 在上一篇章中,已經知道: 元件之間建立關係,不應該是那麼的「隨心所欲」 <br> ### 高內聚,低耦合 高內聚在前,除了類別要先內聚成大顆粒的元件,才能互相依賴以外。從元件內部來看,如果都是相似且恰當的類別, **那麼元件在要使用特定功能時,要依賴的元件,就不會是分佈於程式各處,而會相對集中。** ![002.number](https://lh3.googleusercontent.com/-U1FLIvbTdus/X-YGj6ZNDTI/AAAAAAAACw4/zqXj9ZNXhagNMuprimgPPzeK9S72kHmSwCLcBGAsYHQ/s16000/002.number.png) 元件只會依賴必要的元件,整體系統的參照數量,就會降低。 同時也達成「低耦合」的目標 <br> 內聚性三大原則 ------ ![003.principle](https://lh3.googleusercontent.com/-M4ZNg2yqumU/X-YGlDMJmxI/AAAAAAAACw8/jQcEaXtl6cEPUwg_7L9qvyqgGxjidNxVACLcBGAsYHQ/s16000/003.principle.png) ### REP 再使用性 - 發佈等價原則 `再使用性的細緻度就是發佈的細緻度` ### CCP 共同封閉原則 將那些會因著相同理由、再相同時間發生變化的類別,收集到相同的元件之中。 將那些在不同時間、因著不同理由發生變化的類別,分割到不同的元件之中。 ### CRP 共同重複使用原則 `不要強迫元件的使用者依賴他們不需要使用的東西` <br> REP , 再使用性 - 發佈等價原則 ------ `The Reuse/Release Equivalence Principle` 再使用性的細緻度就是發佈的細緻度 這個原則是再說明,真正可以「再使用」的「元件」,必須是像發佈應用程式一樣; 擁有獨立的版本號與說明文件能夠「追蹤」與「紀錄」每一個時期,程式的變化,才是符合「再使用」的元件特性。 ![004-1.REP](https://lh3.googleusercontent.com/-thXo3SUbGH8/X-YGopele-I/AAAAAAAACxE/h-L9Lh9NKF4RQm5AwSllMuGK8JnskZ2rQCLcBGAsYHQ/s16000/004-1.REP.png) 也就是 再使用的「元件」,必須是已經「發佈」過的元件 <br> ### 為什麼 ? 這麼做的目的,是不希望當要使用現成的程式功能時,只是純粹的程式碼「複製」、「貼上」 ![004-2.REP](https://lh3.googleusercontent.com/-3_qfc41fvbA/X-YGrJ4JBzI/AAAAAAAACxI/So8rKWQid34U8jGl3ZP4MvXWMabUPb76wCLcBGAsYHQ/s16000/004-2.REP.png) 後續如果那段程式被更動了,追蹤與管理都會是一個大問題。 <br> ### 再使用性 更嚴謹的做法,就是將要「重用」的程式,獨立成一個可以任意部屬的元件。 在其他應用程式中,只需要知道外部的接口,而不需要知道原始的程式碼。 ![004-3.REP](https://lh3.googleusercontent.com/-0bYvogrZT08/X-YGupvhyNI/AAAAAAAACxM/63k4nzDSPPobz7GKcWpMryw7zWUieRVVQCLcBGAsYHQ/s16000/004-3.REP.png) 能夠方便的使用,也是「再使用性」的特徵 <br> CCP , 共同封閉原則 ------ `The Common Closure Principle` 將那些會因著相同理由、再相同時間發生變化的類別,收集到相同的元件之中。 將那些在不同時間、因著不同理由發生變化的類別,分割到不同的元件之中。 ### 延續「共同封閉原則」 上一個 REP 原則,說明 要「再使用」的元件,必須要像應用程式一樣發佈 因此,元件內部的類別組成,就必須要能夠實際的解決: + 特定的主題 + 特殊的目的 也就是「內聚性」必須要強 ![005-1.CCP](https://lh3.googleusercontent.com/-S-bTrONqbEg/X-YGxyoj4FI/AAAAAAAACxU/9s2N2KR6EUIYZ2VxaL7OCEVR4Sp_Y-0mACLcBGAsYHQ/s16000/005-1.CCP.png) 但該原則並沒有具體的說明,怎樣才算是「內聚性」強 **「CCP 共同封閉原則」與 「CRP 共同重複使用原則」就是用來補充 REP 原則,未具體說明的部分。** <br> ![005-2.CCP](https://lh3.googleusercontent.com/-IwFYaReizbQ/X-YGysTNZsI/AAAAAAAACxY/DzgIC5Hn7o4YipPoM9CSwOfnf_HCde60gCLcBGAsYHQ/s16000/005-2.CCP.png) 從描述上來看,可以很明顯地知道。分類的依據就是根據「變化」的可能性進行分類 ![005-3.CCP](https://lh3.googleusercontent.com/-iZiVHrdUxik/X-YGzluR6DI/AAAAAAAACxg/HjVK8zXnh5ot71UYNkOyGn29Ki-UFfolgCLcBGAsYHQ/s16000/005-3.CCP.png) <br> ### 為什麼 ? 因為軟體雖然是可變的,但還是希望「最少改動,最大收益」。 如果程式需要被更改,那麼當然希望更改的地方,都集中在同一個元件,而不是分散開來,到處都是。 ![005-4.CCP](https://lh3.googleusercontent.com/-WEAHRMmjDdg/X-YG6OXiMMI/AAAAAAAACxk/ZAbX7N0_l3sD2b2eaRBC25NaW3-6g8t_ACLcBGAsYHQ/s16000/005-4.CCP.png) <br> CRP , 共同重複使用原則 ------ `The Common Reuse Principle` 不要強迫元件的使用者依賴他們不需要使用的東西 ### 延續「CCP 共同封閉原則」 使用「變化」的可能性,進行分類後。 這個原則,則是要將分類好的元件內部,在做一個更細緻的分類。 ![006-1.CRP](https://lh3.googleusercontent.com/-LqrHqYkY3c0/X-YHBJ9TI-I/AAAAAAAACxs/qC07ycIoF9IRJZDUqVPFnOFmi3LRqs4HgCLcBGAsYHQ/s16000/006-1.CRP.png) <br> ### 為什麼 ? 因為一個元件中,使用者有可能只用了這個元件的很小一部分,其他的部分並不是使用者所需要的。 ![006-1.CRP](https://lh3.googleusercontent.com/-SCHVQqjV6os/X-YHCdxJTCI/AAAAAAAACx0/cBEjup8aD2ElM1vjV-MgvF_oR8WZeGdfQCLcBGAsYHQ/s16000/006-2.CRP.png) <br> 但依賴的關係仍然是建立,這個元件其他部分更動了,還是必須要重新編譯、驗證、佈署。 ![006-3.CRP](https://lh3.googleusercontent.com/-UZsXSxLT2U0/X-YHHlrDxYI/AAAAAAAACx8/S6zbg89QcRIbPgg1W9FrvWv946UnQEyNwCLcBGAsYHQ/s16000/006-3.CRP.png) 如果有更精簡的元件可以使用,就沒有理由非得要選擇你的元件 ![006-4.CRP](https://lh3.googleusercontent.com/-rIdCA9FSzGc/X-YHIj-sIxI/AAAAAAAACyA/40HwqdVRRkAai4lWVgiUU2C23U-s_jQSwCLcBGAsYHQ/s16000/006-4.CRP.png) <br> 所以,為了更強的內聚性,就是以使用者的角度,將元件進行分割 ![006-5.CRP](https://lh3.googleusercontent.com/-WAfJI6TxnBA/X-YHJtG6piI/AAAAAAAACyE/GNhAhjKEZqo9ZW8iGxmBiFqILER_vTqigCLcBGAsYHQ/s16000/006-5.CRP.png) ### 目標 元件內的類別,都是使用者剛好要使用到的部分 (元件不要依賴不需要的東西) <br> 內聚性張力圖 ------ 依據上述的三個原則,可以發現每個原則,所關注的重點都不太一樣 : ### REP 再使用性 - 發佈等價原則 `目標: 讓元件更好的被使用` 關注的是「重用性」 #### CCP 共同封閉原則 `目標: 讓元件更好的被維護` 關注的是「發展性」 ### CRP 共同重複使用原則 `目標: 讓元件更精準的定位` 關注的是「精確性」 <br> **這三個原則,彼此之間會互相拉扯,太多的關注某些原則,就會導致另外一個原則無法被確切的符合。** <br> 這種情況,可以描述成一個張力圖: ![007-1.diagram](https://lh3.googleusercontent.com/-2PRsB-2xfqA/X-YHOIFV_HI/AAAAAAAACyI/akj-JbZfAhsDmW2HIHqQ4267YaFKxdk7QCLcBGAsYHQ/s16000/007-1.diagram.png) 當開發者只關注其中的兩個頂點,而放棄另外一個頂點的原則時,程式必須要付出的代價。 <br> ### 只關注 CCP、CRP 原則,不在乎 REP 再使用性 - 發佈等價原則 ![007-2.diagram](https://lh3.googleusercontent.com/-j56p8CWHeCg/X-YHO8qaqyI/AAAAAAAACyM/ZGOIAaRtrnUaEfTI8wFDnIuVl5QKTzhcgCLcBGAsYHQ/s16000/007-2.diagram.png) 元件就會很難被重用 <br> ### 只關注 REP、CRP 原則,不在乎 CCP 共同封閉原則 ![007-3.diagram](https://lh3.googleusercontent.com/-NabKa1j1v_o/X-YHR8VwcUI/AAAAAAAACyQ/cMbbhPhJO1Yc0Vh2RRF5x9CmsA7bcq49gCLcBGAsYHQ/s16000/007-3.diagram.png) 修改時就會有太多的元件要被更動 <br> ### 只關注 REP、CCP 原則,不在乎 CRP 共同重複使用原則 ![007-4.diagram](https://lh3.googleusercontent.com/-sx52CfZAlPk/X-YHTQNGOuI/AAAAAAAACyY/ZQcJ3vpkc0grn7OknjRXotv7w-66vzJOACLcBGAsYHQ/s16000/007-4.diagram.png) 造成太多不必要的版本發佈 <br> ### 第四維度 因此在軟體設計中,還有一個必須要考慮的因素: 時間維度 對於大多數的應用程式,由於想要 : + 增加「更多的功能」 + 滿足「更多的需求」 ![007-5.important](https://lh3.googleusercontent.com/-rrigRT2FmNs/X-YHWxolXqI/AAAAAAAACyc/H8HHPkVSwRw6Tp17HVpsQXN28iIbSbzKQCLcBGAsYHQ/s16000/007-5.important.png) 「可發展性」的重要程度通常會大於「可重用性」 <br> 也就是說,在專案開發初期: CCP 原則的重要性會大於 REP原則(可發展比重複使用更重要) 所以這時,第一個應該要思考的是 如何恰當的「分類」,而不是思考未來該如何「重用」。 ![007-6.classification](https://lh3.googleusercontent.com/-kOG_ht8wHdw/X-YHZthw2PI/AAAAAAAACyk/K2Ax6bbsSiIqThvn_Rc6RfDz0ExgyeK1gCLcBGAsYHQ/s16000/007-6.classification.png) <br> ### 聚合原則重要性演變 重用的部分,必須加入了 CRP 原則,更精簡後,依循 REP 原則正式發佈: ![007-7.diagram-time](https://lh3.googleusercontent.com/-P7wgwZBK1f8/X-YHalj7COI/AAAAAAAACyo/N0u1Emwc8scxJY4o0HCqvA254NLYZ3sQQCLcBGAsYHQ/s16000/007-7.diagram-time.png) 此時,你的元件才會真正意義上的,具有「高內聚」的特性。 <br> 適當的時機,適當的分類 ------ 回頭來看 DDD 領域驅動設計 ![008-1.ddd](https://lh3.googleusercontent.com/-UC95kJRXo7M/X-YHfIdZPgI/AAAAAAAACys/T_LDCrDzqVElNDrVM9RQXrM22D7-LpaAACLcBGAsYHQ/s16000/008-1.ddd.png) + [`Youtube : 領域驅動設計 | 4 層架構 + 3 類物件 | 有想法 x 也有做法`](https://youtu.be/mducM_tUUEY) 四個分層,其實就是 CCP 原則的概略呈現。 <br> 而在每一層中,我通常的做法,都會在更細緻的依據業務情境,進行分類: ### Domain 層 ![008-2.ddd](https://lh3.googleusercontent.com/-RcJFTIMeP-o/X-YHiSoM5sI/AAAAAAAACy0/zFVwQJwjFuEDIMh6522KvbiYlIXbcQlJQCLcBGAsYHQ/s16000/008-2.ddd.png) 每個業務情境都會有各自的 Service Entity 與 vo <br> ### Application 層 每個業務流程也都會有各自的 Service 與 DTO ![008-3.ddd](https://lh3.googleusercontent.com/-g9gsOkopD1E/X-YHnn1ZkkI/AAAAAAAACy8/RDNeZ_zWEvogttEu0zii51B6FJneDnkQgCLcBGAsYHQ/s16000/008-3.ddd.png) 這種細緻化的方式,也是 CCP 原則 與 CRP 原則的綜合應用。 <br> ### REP 原則,具體的呈現 就像是我的 : **JavaProjUtil** ![008-4.util](https://lh3.googleusercontent.com/-zXm01IWHcUc/X-YHq7LFiqI/AAAAAAAACzI/NWibfhGNZwMuOh_Blk0Ibahe3cCHR0O_gCLcBGAsYHQ/s16000/008-4.util.png) **iOSProjUtil** ![008-4.util](https://lh3.googleusercontent.com/-PpbaLWS9erM/X-YHwLvHwJI/AAAAAAAACzM/1BKBK_hVOgsUVUGPTs5lTfbtaGgK0NAowCLcBGAsYHQ/s16000/008-5.util.png) 各種 Util 結尾的專案,可以獨立的發佈版本與提供說明文件。 + [`Youtube : 如何快速學習新技能 ? | 軟技能 x 十步學習法 | 學習「怎樣學習」`](https://youtu.be/Ya7XE47gPBo) <br> ### 動態的軟體,動態的原則 軟體是一個動態的東西,設計軟體元件內部的內聚性原則也是動態的。 身為優秀的軟體工程師,可能就會意識到,這個就是: 「軟體的本質」 與 「軟體的特性」 + [`Youtube : 軟體是什麼? | 軟體的本質又是什麼 ? | 軟體工程師深度思考的問題`](https://youtu.be/njAgG9e1Qco) <br> 掌握了這些原則,你就能: 在適當的時機點,出現適當的東西。 軟體的天堂之境:「最少改動,最大收益」,已經出現在不遠處。 ![009.paradise](https://lh3.googleusercontent.com/-LWek91Xp61k/X-YH9Nk-17I/AAAAAAAACzY/PTwKt6-RS9MpGWmP4M17Ay2fgHkNCodtACLcBGAsYHQ/s16000/009.paradise.png) <br> 語錄 ----- ### 工程師紀錄 有想法的人很多,有作法的人很少 -- 我以前的組長 參考資料 ------ + Clean Architecture 整潔的軟體設計與架構篇 + [維基百科-內聚性](https://zh.m.wikipedia.org/zh-tw/%E5%85%A7%E8%81%9A%E6%80%A7_(%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%B8) + [細談元件內聚性](https://www.jyt0532.com/2020/03/26/cohesion/) + [元件內聚性 Component Cohesion](https://medium.com/@f40507777/%E5%85%83%E4%BB%B6%E5%85%A7%E8%81%9A%E6%80%A7-1a1c334fc3f7)