【元件如何正确归类 ?】元件内聚性三大原则 : REP、CCP、CRP

适当时机 x 适当分类

大纲

  • 全新的专案
  • 高内聚就能低耦合
  • 内聚性三大原则
    • REP , 再使用性 - 发布等价原则
    • CCP , 共同封闭原则
    • CRP , 共同重复使用原则
  • 内聚性张力图
  • 适当的时机,适当的分类

全新的专案

全新的专案,从无到有的开发

过往的经验

打算把很多重复的功能,都聚集成 一个独立的元件

类别分类

要将哪个类别归类到哪个元件,是个重大的决定!

但大部分的时候,却都是凭感觉分类。

内聚性三大原则

就是在告诉你 :

分类时,可以依据类别的什麽特性,来归类成同一个元件。

除此之外 :

它甚至告诉你,现在就将类别,抽成共用元件,并不是恰当的「时机点」。


高内聚就能低耦合

延续元件耦合性的部分

001.principle


在上一篇章中,已经知道:

元件之间建立关系,不应该是那麽的「随心所欲」

高内聚,低耦合

高内聚在前,除了类别要先内聚成大颗粒的元件,才能互相依赖以外。从元件内部来看,如果都是相似且恰当的类别,那麽元件在要使用特定功能时,要依赖的元件,就不会是分布於程序各处,而会相对集中。

002.number

元件只会依赖必要的元件,整体系统的参照数量,就会降低。

同时也达成「低耦合」的目标

内聚性三大原则

003.principle

REP 再使用性 - 发布等价原则

再使用性的细致度就是发布的细致度

CCP 共同封闭原则

将那些会因着相同理由、再相同时间发生变化的类别,收集到相同的元件之中。
将那些在不同时间、因着不同理由发生变化的类别,分割到不同的元件之中。

CRP 共同重复使用原则

不要强迫元件的使用者依赖他们不需要使用的东西


REP , 再使用性 - 发布等价原则

The Reuse/Release Equivalence Principle

再使用性的细致度就是发布的细致度

这个原则是再说明,真正可以「再使用」的「元件」,必须是像发布应用程序一样;

拥有独立的版本号与说明文件能够「追踪」与「纪录」每一个时期,程序的变化,才是符合「再使用」的元件特性。

004-1.REP

也就是

再使用的「元件」,必须是已经「发布」过的元件

为什麽 ?

这麽做的目的,是不希望当要使用现成的程序功能时,只是纯粹的程序码「复制」、「贴上」

004-2.REP

後续如果那段程序被更动了,追踪与管理都会是一个大问题。


再使用性

更严谨的做法,就是将要「重用」的程序,独立成一个可以任意部属的元件。
在其他应用程序中,只需要知道外部的接口,而不需要知道原始的程序码。

004-3.REP

能够方便的使用,也是「再使用性」的特徵

CCP , 共同封闭原则

The Common Closure Principle

将那些会因着相同理由、再相同时间发生变化的类别,收集到相同的元件之中。
将那些在不同时间、因着不同理由发生变化的类别,分割到不同的元件之中。

延续「共同封闭原则」

上一个 REP 原则,说明 要「再使用」的元件,必须要像应用程序一样发布

因此,元件内部的类别组成,就必须要能够实际的解决:

  • 特定的主题

  • 特殊的目的

    也就是「内聚性」必须要强

005-1.CCP

但该原则并没有具体的说明,怎样才算是「内聚性」强

「CCP 共同封闭原则」与 「CRP 共同重复使用原则」就是用来补充 REP 原则,未具体说明的部分。


005-2.CCP

从描述上来看,可以很明显地知道。分类的依据就是根据「变化」的可能性进行分类

005-3.CCP


为什麽 ?

因为软件虽然是可变的,但还是希望「最少改动,最大收益」。

如果程序需要被更改,那麽当然希望更改的地方,都集中在同一个元件,而不是分散开来,到处都是。

005-4.CCP


CRP , 共同重复使用原则

The Common Reuse Principle

不要强迫元件的使用者依赖他们不需要使用的东西

延续「CCP 共同封闭原则」

使用「变化」的可能性,进行分类後。

这个原则,则是要将分类好的元件内部,在做一个更细致的分类。

006-1.CRP


为什麽 ?

因为一个元件中,使用者有可能只用了这个元件的很小一部分,其他的部分并不是使用者所需要的。

006-1.CRP


但依赖的关系仍然是建立,这个元件其他部分更动了,还是必须要重新编译、验证、布署。

006-3.CRP

如果有更精简的元件可以使用,就没有理由非得要选择你的元件

006-4.CRP


所以,为了更强的内聚性,就是以使用者的角度,将元件进行分割

006-5.CRP

目标

元件内的类别,都是使用者刚好要使用到的部分 (元件不要依赖不需要的东西)

内聚性张力图

依据上述的三个原则,可以发现每个原则,所关注的重点都不太一样 :

REP 再使用性 - 发布等价原则

目标: 让元件更好的被使用

关注的是「重用性」

CCP 共同封闭原则

目标: 让元件更好的被维护

关注的是「发展性」

CRP 共同重复使用原则

目标: 让元件更精准的定位

关注的是「精确性」

这三个原则,彼此之间会互相拉扯,太多的关注某些原则,就会导致另外一个原则无法被确切的符合。


这种情况,可以描述成一个张力图:

007-1.diagram

当开发者只关注其中的两个顶点,而放弃另外一个顶点的原则时,程序必须要付出的代价。


只关注 CCP、CRP 原则,不在乎 REP 再使用性 - 发布等价原则

007-2.diagram

元件就会很难被重用

只关注 REP、CRP 原则,不在乎 CCP 共同封闭原则

007-3.diagram

修改时就会有太多的元件要被更动

只关注 REP、CCP 原则,不在乎 CRP 共同重复使用原则

007-4.diagram

造成太多不必要的版本发布

第四维度

因此在软件设计中,还有一个必须要考虑的因素:

时间维度

对於大多数的应用程序,由於想要 :

  • 增加「更多的功能」
  • 满足「更多的需求」

007-5.important

「可发展性」的重要程度通常会大於「可重用性」

也就是说,在专案开发初期:

CCP 原则的重要性会大於 REP原则(可发展比重复使用更重要)

所以这时,第一个应该要思考的是

如何恰当的「分类」,而不是思考未来该如何「重用」。

007-6.classification


聚合原则重要性演变

重用的部分,必须加入了 CRP 原则,更精简後,依循 REP 原则正式发布:

007-7.diagram-time

此时,你的元件才会真正意义上的,具有「高内聚」的特性。


适当的时机,适当的分类

回头来看 DDD 领域驱动设计

008-1.ddd

四个分层,其实就是 CCP 原则的概略呈现。


而在每一层中,我通常的做法,都会在更细致的依据业务情境,进行分类:

Domain 层

008-2.ddd

每个业务情境都会有各自的 Service Entity 与 vo


Application 层

每个业务流程也都会有各自的 Service 与 DTO

008-3.ddd

这种细致化的方式,也是 CCP 原则 与 CRP 原则的综合应用。


REP 原则,具体的呈现

就像是我的 :

JavaProjUtil

008-4.util

iOSProjUtil

008-4.util

各种 Util 结尾的专案,可以独立的发布版本与提供说明文件。


动态的软件,动态的原则

软件是一个动态的东西,设计软件元件内部的内聚性原则也是动态的。

身为优秀的软件工程师,可能就会意识到,这个就是:

「软件的本质」 与 「软件的特性」

掌握了这些原则,你就能:

在适当的时机点,出现适当的东西。

软件的天堂之境:「最少改动,最大收益」,已经出现在不远处。

009.paradise


语录

工程师纪录

有想法的人很多,有作法的人很少
	
            -- 我以前的组长

参考资料


<<:  Day 26 - 当AI有了常识之後, 超越人类? -GAN(2)

>>:  Day53. 中介者模式

[Day30] AWS Elastic Load Balancing (ELB)

Elastic Load Balancing 可在多个目标 (例如 Amazon EC2 执行个体、...

自动化 End-End 测试 Nightwatch.js 简易化 selector

在 E2E 测试撰写时,前端可以利用 aria-label 或客制化的 testing tag 来方...

[ Day 12 ] React 的生命周期 - Updating

今天要来进入到生命周期的第二个环节: Updating 更新,继上篇的 Mounting 元件挂载...

Day4 - 几何抽象

目前近几年的不管是唱片 演唱会 线上设计风格开始走向几何风格形象 金曲30很美的背景设计 gerne...

重新学习JavaScript#JavaScript能做甚麽?

JavaScript (简称JS)是一种物件导向的程序语言 "object orient ...