在开发工作中,我们常常要将整体的开发内容分解成一些较小的部分,分而治之。 原因不限于以下几种:
分解和抽象使得开发内容更容易被理解。
可以将分解后的开发内容分配给多人开发。
分解后的开发时间更容易估算,进度更易于衡量,有利于做计划。
古人说“横看成岭侧成峰”,意指从不同的角度观察事物时会得到不同的抽象。开发工作与之类似,当开发者从不同的角度进行分解工作时,会对开发内容产生不同的理解,因此分解后得出的产物可能也并不相同。从哪些角度对开发内容的分解才是最优的?这往往没有固定的答案,要由分解的目的决定。下面会介绍9种常见分解角度。
形式与结构
形式与结构,指的是开发内容中全部的开发对象,以及它们之间的关系。比如,一个客户信用检查程序可能包含表、视图、锁对象、接口、类等一些开发对象,它们之间会存在一定的连接关系。
从这个角度分解的优点在于它十分具体,有一些属性可以通过求和直接得到,比如,表和字段的数量意味着要增加多少种存储信息。
对形式的分析可以提示开发者将连接关系较多的东西归为一组,如果把它们分解到不同的地方,可能会导致复杂度增加,需要很多额外的工作来传递信息,对开发内容的分析和理解将变得困难。
功能形式代表了静态存在的对象,而功能是指它们能做什么。功能是开发工作的价值体现。
一般来说,程序的命名即可提现它的功能。比如“供应商信用检查程序”显然指出了程序的功能是检查供应商的信用。如果将这个程序从功能角度分解,可以分解为设定信用额度的功能、计算占用额度的功能、集成到付款/采购流程的功能、从外部系统查询供应商信用的功能等。
按功能分解开发对象是最直观的分解方式之一,它有助于开发者从系统整体层面思考问题。比如,如果要考虑程序的性能问题,从功能角度的分解可以让人分析各个子功能的性能如何、它们集成到一起时有可能发生什么问题。又比如,如果要增加一个“黑名单/白名单”子功能的话,我们可以从功能角度审视这一新功能对其它各个子功能产生何种影响。
设计的自由度如果能把紧密耦合的对象归为一个模块,并使之与外界尽可能的隔离,就能在模块内部得到更大的自由度。
这里以为例,该项目的每个检查规则都位于单独的类中,这些类实现了同一个接口ZIF_ADV_CHECK,如下图。这使得每个类的开发者不需要与其它类的开发者共享任何信息,可以在自己负责的类中任意发挥,实现功能。而ZIF_ADV_CHECK约束了这些类,使它们遵循相同的检查接口约定。
另一种思路是把这些检查功能都放置在同一个类中,用不同的类方法实现它们,如下图。显而易见,这样做的好处是降低了总体复杂度(方法数不变,类减少为1个),缺点是不同的方法会共享类的信息,有可能出现一些跨方法的东西,这会降低设计的自由度。对检查接口的约束也成为了一种隐式的规则,这会增大开发者的心智负担,容易产生误解。
这两种做法没有绝对的优劣,abap-data-validator选择了前者,是因为开发者在经过权衡后认为,为了让社区的同行方便地增加自己的新的检查规则,付出增加一定的复杂度的代价是可以接受的。虽然到目前为止尚还没有人给这个项目贡献新规则。
程序的进化程序的功能通常有不断增加的趋势 ,我们把功能增加的过程称为进化。从进化的角度进行分解时,开发者需要考虑如何让新旧功能方便地结合。以创建采购订单的程序为例,如果考虑到程序未来会有对订单进行其它检查的需求,那么就要分解出单独的检查模块,并提供接口。这样的话,如果要增加供应商信用检查功能,那么只要通过这个接口来实现就好。从进化角度的分解可以让程序在在进化中保持架构的稳定。