信息化项目的"升维"设计、“降维"开发与需求分析经验

    做开发的人员,通常都少不了抱怨,这需求怎么又变化了?改改改,加班、加班...
    那么在设计的时候,有没有可能以通用的架构,不变应万变呢?
    如何让一个系统设计的尽可能灵活,就需要适当的“升维设计”,而在权衡可变性,时间,成本的时候,又需要“降维设计”。

一、软件系统的整体思考

    前一段时间,看了一些系统的的源码,经常在思考,如果从无到有设计这样的系统,那我的思路应该是怎么样的,如何一步步的去实现呢?
    比如看的dubbo,druid,spring IOC等源码时,抽象的说,实现的目的都是简单的。比如druid就是一个连接池,对所有的数据库操作都经过一个过滤器链监控。dubbo是soa治理,就是要注册,监控服务提供与消费者,再一步步做大。又类似于电脑就是由CPU,内存,主板,硬盘,显示器等组成。又类似于汽车有发动机,变速箱,传动,轮子等组成一样。抽象的东西是最稳定的,各种品牌的电脑,手机都由这几部分组成。
    其实这些道理很简单,大家都懂,但这种抽象思维能力,如何与具体的开发结合起来呢?

    是常工作经常说自己做的就是增删改查业务,上面提到的dubbo之类的jvm中的产品,虽然充分展示了抽象设计的思维,只有抽象思维才能整合各种各样的技术,比如传输有netty,mina..rpc支持http,redis,rmi...注册支持dubbo,multicast,zookeeper...序列化有dubbo,hessian,java,jason...负载集群都支持很多策略。但这与业务系统来说,还是不够直观感性。而工作流系统却是一个业务抽象整合的经典产品。下面以此为例说明。


二、工作流产品是一个经典的抽象思维,“升维”设计的产品

    因为一直做信息化项目,少不了各种各样的流程处理,接触了很多简化设计,也有接触了一些工作流产品。工作流是一个经典的抽象思维出来的产品,仔细反思工作流产品的诞生过程对于我们业务系统的设计很有帮助。
    没有工作流产品的时候,如果系统中只有二、三个流程,可能就单独定义一下流程,但你会思考,有没有可能当无数个流程处理?一旦提到无限个,就出现了新的维度,考虑到通用,抽象的情况了。

    我理解的工作流产品的抽象产生过程如下:



    简单介绍一下:
  • 1.我们自己设计一个流程,业务中按些流程走,就是一个定义与实例的过程。有点象类与对象的关系。没有信息系统时也会有这种关系,比如请假过程,公司制定个标准,每个人请假就是走流程,而且会各自不一样,但公司只要制定一个制度。
  • 2.定义流程中主要是岗位与操作,岗位比如有申请、审核、审批等岗位,操作可能有提交,提交多人,多部门等情况。一个岗位可以定义名称,但岗位有什么人,每个业务系统就不一样了。而流程实例中会操作不同的业务,比如请假,比较处理公文,他们各自的属性不同,但在流程中有相同的东西,比如当前岗位状态。
  • 3.共同的东西抽取出来,可以定义任意个数的流程,也可以描述各个抽象实例的具体流动状况。那么设计上就多出来适应任意流程定义的这样一个维度出来了。
  • 4.通过上面的“升维设计”,一个能适应多种流程的东西被提取出来。产生了工作流产品。工作流中记录的只是一个流动中的骨架,而不同的流程中的血肉都由不同的系统来处理。
  • 5.比如记录在流程中的没有任何业务信息的纯任务与业务系统中一个岗位填写的内容组合就是一个完整的岗位任务。所以使用中获取一个人的任务要向工作流要,而显示出任务的内容要向业务系统中要。

    上面的抽象过程后,还需要一个整合的过程,抽象的骨架部分存放在一起,比如所有的抽象流程实例放一个表中,所有抽象的任务实例放一个表中。

三、目前业务中其他“升维”设计的例子。

    简单的例子就是字典表的使用,比如各种选择项,新手可能设计成常量,一般都会设计成可变的量,用户可以自己配置。那所有的选择项共同放在统一的字典表中,字典表还会设计成缓存,毕竟读多写少。
    1.最近一直做的某办的统计项目,统计表头可以调整,抽象就看也是一种字典,当然就放在字典项中。但类似的情况下,有的人会建一张表,因为样子上表头不是传统的下拉选择项。
    考虑到表头可能有特殊的页面效果要求,可以单独设计操作页面,而不影响后台的业务类与存储。
    考虑到表头的版本,可以做一个表头根节点。可以完整复制一个表头产生新的表头来修改。
    表头有了,表头下的数据就会有各种不同,用户新建一个表头,不可能新建一个与表头对应的数据表,所以不同表头的数据要整合在一起。
    把不同的统计表的数据放在一个数据库表中,那只要数据库表有足够字段。数据要有对应的表头ID,字段本身没有明确意义。每个表头的数据项要定义出对应字段的名字。

     以前做过一些统计相关的系统,一般数据值都会设计一个表,表的字段都有明确的意义,所以上面的设计,相对固定数据库表就是一种“升维设计”。

     2.最近还要考虑另一个办的效能项目,由于有定制表头的要求,自然基本的思路就与上面的相同。表头定制后,还要配置与数据表的字段名称的关联关系。


     3.还有一个项目。是整合多个子系统的人员组织,每个子项目都有各自的人员,单位信息。从设计上就要把信息进行拆分。
     比如:任何一个单位都有与各子系统无关的基本信息,但单位在一些子系统中又有别名。这就是共性与个性的拆分。考虑到支持任意多个子系统的情况。就需要对此进行“升维设计”。主要的对象就是:单位基础信息,子系统信息,单位在某个子系统中个性的信息。
     人员的情况也是一样。一个人有自已的基础信息,与其它都不搭界。但在不同单位表现的属性不一样,比如工作中是:小张。业余代课是:张老师。那就有共性与个性之分。这样,人员与单位本身是没有关系的,人员在某个子系统的单位中就有了个性的信息。
     共性的整合在一起,个性的整合在一起。

     4.还有一个是实现千差万别的自定义表单的设计。表单会与工作流结合,以实现最大的产品化。不同的表单如何抽象呢?
     确实真没什么共同点,字段各不相同,意思各不相同。但是硬要说有什么共同,那就是都叫表单。那用户要产生不同的表单,总不能在代码中建库,建类,建操作吧?当然也这是可以做到的,动态生成java文件编译,由jvm再动态编译使用也可以。

     如果要把这些表单都放在一起,只能把内容打包在一起,要组织数据,就要有一个存贮方案。可以简单用分割符号,进一步用jason,那当然还有一个方案就是xml。XML还可以配合xlst显示表单,差不多这是最好的方案了吧。但我不知道这样一个整体存在数据库中,如何按文本时间等字段查询,检索呢?全文检索不算。而且在工作流中流动时,除了岗位写意见外,很可能在不同的岗位,更改主表单的部分内容,且不说展示的要求,仅仅是这样的配置出来就很复杂了吧。我认为因为相似度不高,抽象出来造成的问题就很多,要么配置很复杂,要么应变能力不足。

     我还想到一种办法,就是上面提到处理任意统计报表的方法,就是做一个通用表单表,字段足够多,比如固定30个文件字段,10个时间字段...把表单的属性与特定的字段匹配起来,这样常用的sql查询都可以使用,只是多了些影射。这个方案只是思考,还没有实践。等着先把上面的表头实践做好。


四、有了“升维”设计,为何还需要“降维”开发

    如果项目中没有工作流产品,你会“升维开发”,在业务中实现一个工作流产品吗?肯定不会。考虑到成本,时间,开发人员能力等要素,在“升维设计”之后,很多时间必须进行“降维开发”。
   
    “升维设计”必不可少,这样把问题考虑的足够全面,才能有效的取舍。


五、目前业务中“降维”开发例子

     工作流是我使用最多的情况。而我也根据实际情况简化不同的地方。

     1.  已经有工作流产品了,为何不直接用?
     有的流程很简单,使用一个产品化的东西显的庞大了。而且流程的信息不可自由控制,调试算法不好自由变更。有听说用状态机?我不知道这是什么,不过工作流通常都包括了状态与操作两个不可缺少的部分,听状态机的名字就有不足。

     2.在某局的项目中,流程定义用了两张表。但在某办的项目中用了一张表。
     某局的流程很复杂,所以用了两张表,还自由定义了特殊的岗位,比如阅读岗位的任务,完全不影响流程走向的。貌似一般的工作流产品中没有,而且我可以自由增加、减少并行的任务。这就是自己设计定义流程的优势。

     而另一个项目中,某办的流程是父子流程,但是各自流程是单线控制,所以只用了一张表就实现了。

     3.流程实例种类不多时,通常不用拆开成共性与个性部分
     前面讲工作流,把流程对象看成骨架与血肉的组合。但通常业务中仅有几个流程操作对象,各自的业务对象表中除了业务信息,还有流程ID,当前状态等骨架。不多时就可以设计在一起,流程的任务调度(合并,分支,顺序)时,可以对这个业务对象表的抽象类进行操作。实际推动流程时传入继承类即可。

    合并业务信息与流程信息是目前绝大多数模块使用的方式。


  4.但最新的某办的系统要按工作流产品方式拆分了。
     最近的一个项目,可能有很多的业务对象要走流程,而且业务对象之前不走流程,已经有现成的表了。我在上面补上工作流的骨架是一个繁琐的工作,不如这个时候按工作流产品的经验,把骨架分开,把所有的业务对象的骨架部分放在业务实例公共表,与任务分配公共表中。既然拆分了,拿到业务对象时只是业务信息,通常还要关联拿到关联流程信息展示。

     这种拆分也是因为项目的特殊情况决定的,这样保持合理结构时,工作量最小,还保持灵活性。


六、把握合理的“维度”的基本要求

     有时候会说产品化,仿佛花时间,弄出一个产品,只要简单的配置一下就给用户了,坐着收钱就可以了。但为什么很难出产品呢?举个例子,比如一个房子的设计想产品化可能吗?砖头,钢筋,窗户,地板都可以产品化,但房子整体是个变化多端的事物。配置成活动板房,那能卖出去多了呢?


    首先抽象思维能力,从一堆业务对象中察觉出共性与个性。

    相关的技术储备,看大量优秀的设计,从中体会实现拆分的具体工具。

    从小事开始,如果在系统中,业务数据冗余,重复,那就想办法去优化。处理的操作有某种相似,就想办法用一个通用的方式去解决。

    我很喜欢做产品化的原型系统,对于这样的系统,在使用时不是当产品来用,而是当毛坯来用,直接改原型的源码,来丰富,或者简化后使用,在相当程度中节省了部分重复的工作,也节省了复杂产品的配置工作,至少特殊情况产品不支持的状况。


七、把握合理的“维度”的需求分析要求

    需求做到位才能在具体情况下确定“维度”。我们知道,软件是分层次的,越是接近客户端越是变化越多,越是后台数据库越是稳定。我经常用造房子来类比软件设计,用户关注的是分隔,装饰。而设计人员最首先要保证基础结构的稳定性,比如梁柱的位置、大小关系(不知道建筑、结构与客户之间是不是也会权衡退让,结构做不到的应该就没办法了)。后面会讲讲如何找出基础结构。

    也许有的做需求的只是简单的归纳与转述,我理解的需求要做到明确软件所涉及的对象以及对象之间的关系,差不多重要的ER关系心中有数,这样基础结构稳定才算是到位。

   需求的困难表现在以下方面

    1.需求来源的多样性
  提出需求的来源于一般工作人员,领导,上级领导。一般来源,基础结构不太会动,领导关注显示效果,实时数据,统计功能,当然也有全面关注的情况。

    2.需求提出人员的考虑有限
  客户人员平时还有很多的业务要忙,无论是整理都花时间,所以考虑的也许从自己这方面考虑,不一定全面,内部的关系也不一定会深入思考,很难由表及里。而且有的业务是跨部门的,不一定准确。有的需求都由不同的部门人员提出,

    3.需求有合理与不合理的鉴别
  虽然客户的需求都是尽量满足的,但要从逻辑上来说,有些可能有矛盾,更多的是有些需求可能会把不重要的地方设计的很复杂,对当前的时间进度,未来维护,交接,项目后期都造成问题。对于已有业务系统的变更来说,有的需求除非进行大的变更,否则难以支持新需求。

    4.未来需求的不确定性
  未来的需求,有的人说先满足现在,有一定道理,但是在下手做之前,多提出问题,多考虑一下,先花一点时间动动脑子是值得的。因为不同的结构支持的变化幅度是不同的,比如简单的流程可能一张表,复杂的流程就要用复杂的设计了。复杂的当然也支持简单的,但花的时间,精力是更多的。有的需求用户会说这个几乎不变,但设计上只有存在不存在,存在一种就要考虑到。另外,一些类别,要仔细签定可变性。


    5.需求暂无实际业务支撑
  如果有实际业务支撑,一般考虑的都比较全面,没有的话,有些就只有拍脑袋想了,考虑不同的情况,发生变化的情况就会比较多。

    6.表达方式沟通的问题
  前面说软件是分层次的,这也是隔离变化的需要,也是高聚合低耦合的设计需求。一个协做的系统要做好,相互之间了解是最重要的。各自的思路可能不一样,用户提的从其它角度思考的,可能比较散,而设计人员想好的逻辑关系去试着满足上层的要求。相互之间的思路可能不同。


    无论如何,需求最主要的是要达到基础业务的ER清楚稳定。至于上层UI的显示,当然越详细越好,但这暂时并不重要。下面以面象对象的表述介绍我常用的思考方式,找出对象之间的关系。

    1.分清稳定对象与业务对象

   通常我把系统中的稳定对象与业务变化对象两类。有些稳定对象可能是经过一定的业务操作产生的,开始是业务对象,后变成稳定对象。稳定对象在业务中会产生属性的不断变化。说到对象不一定是实体,也许一个动作也是对象。

   比如字典对象就是稳定对象,业务中使用的,就拿其业务ID用。业务ID有时也是CODE。
   比如工作流建好就是一个稳定对象,业务中关联一个流程ID,按其配置流动。
   比如之前了解过一个考试系统,那稳定的对象比如考生、老师,教室,学校等。业务主干就是发起一次考试,业务中的从属对象就是这次考试中的老师与教室的组合,学生与教室的组合,与科目的组合。也许一下从复杂的关系中找不出具体有那几个对象,可以这样尝试。
   列出一些实际组合都放在一条记录中:学生ID 教室ID 科目ID 一次考试ID。
张、201、数字、07高考;李、201、数字、07高考;...后面三个是可以不变的,那就可以剥离出一个组合:教室、科目、一次考试。还能继续剥离吗?一次考试的教室考几个科目应该没有。所以有重复,还可以继续剥离。这样几个对象就出来了,一次考试对象,与科目的组合对象。再与教室的组合对象...这些都是业务对象,在一个核心主业务下才存在。

    2.分清主业务对象与从业务对象
   
    上面已经提到了主业务对象与从业务对象。这里想说说碰到的一些具体情况。之前某办的业务对象的操作都做好了,设计也都好了,用了一阵了。
    突然出现业务批量处理的情况了!!!!

    那问题就来了,主业务对象是之前的业务对象,还是新的批量组合对象呢?这个组合稳定吗?我的流程到底以哪个为准?一个业务对象还是一批业务对象?及时用户说偶尔才会有一批,那对我们设计来说,有一个特例就是可能有无数个一样。

    后来这个批量是比较易变的,最终组合只是个标识而已,当然也会涉及到同批量中的数据复制。

    还有一个办的情况有点不一样,我就仔细问问,如果是作为整体处理,相当成把业务对象装进袋子,只是袋子外面只有一张业务处理单据。后来确定是整体,虽然多数可能里面就一个业务对象。所以业务主对象是批次,而不是批次中的对象。相关的基本列表显示的主体是批次,业务对象在批次内再进行一次列表显示。

    以后碰到主业务对象,我都会问问,会不会业务对象批量处理?


八、顺便提提最近业务中的一些概念处理

    1.快照:快照就是那一个时刻的数据,可以说是一种冗余。比如纸质业务中有每个月的数据统计,但业务系统中,只是一个查询条件而已。不需要快照下来,查询还更灵活。

    2.状态机:仅仅是状态目前都是不够用的。或者就很简单的状态字典,利用字典表,多数情况是状态与操作的组合。根据上面介绍的实际业务流程情况,我会进行灵活的“降维”处理。

    3.转移成历史数据:目前我们的行业的业务数据量级肯定不多,一般很多年都不需要转移,有问题是设计与优化。通常的股票,银行交易中查数据有时间要求,以前的数据另外查询,而且间隔不能超过多久。因为那些数据量肯定是天量,而且可能转移到其它的大数据相关的存储结构中了,比如hbase,列数据库。


    总结:需求与设计中尽可能确定好业务中的可变性,实践中用掌握的工具与经验恰当减少冗余,适当拆分出不变。

猜你喜欢

转载自herman-liu76.iteye.com/blog/2379045