软件的主要任务
软件的核心任务不外乎是收集和整理数据,然后以用户需要的形式表现给他们而已,此外还有数据的存储,数据的传输等外围任务。
数据的收集,整理,表现,存储和传输就是软件的主要任务,它们也是程序员的主要工作内容,也是程序员编写代码的最终目的。
那么该如何编写代码让软件完成它的主要任务呢?编写代码的过程是否有规律可循?编写代码需要注意那些方面的问题?本人想就这些问题罗列自己一些粗浅的看法,并大家进行一些探讨。
一.软件构建从需求开始
需求即用户对软件功能的描述,用户通过需求告诉程序员他需要收集什么数据,这些数据该怎么处理,最后他希望看到什么结果。需求中描述的场景和内容是软件处理的核心领域,程序员需要通过代码把它表现出来。
即使用户是和你一样的程序员,需求也不可能完善到直接指导编码的地步,而且软件的构建是一个“邪恶(Wicked)”的过程,也就是说某些问题在设计阶段并不显山露水,只有在构建过程中它们才会逐渐暴露出来。这就要求程序员深入问题的领域,了解领域的相关知识,对领域做出合理的抽象,并在软件构建过程中不断完善它,直到完全实现用户需求,具备现代软件的八个主要特征。
二.何谓领域和领域模型
领域即业务领域,是用户进行业务活动的主要内容。一些领域是和现实世界中的实体对应的:如雇员管理系统中的雇员,图书管理系统中的图书,零售系统中的商品,而有些领域和现实世界中的虚拟实体相对应:如金融系统中的借贷关系,商务系统中的合同关系等。
软件的主要任务是数据的收集,整理,表现,存储和传输,而数据的基本单位就是领域模型。
领域模型是现实世界中的实体在代码中的体现和合理抽象,它能表现出实体的基本信息。如果可以说软件环境是现实业务活动在计算机世界的模拟的话,那领域模型就是现实实体在计算机世界的模拟。
三.软件构建的核心是领域模型的建立
领域模型是软件需要处理的数据的基本单元,只有建立起了领域模型,你才能知道软件需要收集,整理,表现,存储和传输的对象是什么。
建立领域模型是软件构建的核心环节,如果它没有被合理抽象出来的话,软件能提供的服务,数据的持久化和数据在软件中的表现都是空中楼阁,因此我们可以说,从现实世界中的实体中抽象出合理的领域模型是软件构建中提纲挈领的一个环节,这一步是软件各个层次的基石,也是软件构建的起点。
不建立领域模型并非一定不能造就出能运转正常的软件,所谓的表维护程序就是典型例子,它们由某些懒惰,愚蠢和无能的程序员造就,他们从来不去认真思考用户究竟想知道什么,程序究竟在处理什么,而是翻译堆砌代码,仅仅让它能跑出一个正确的结果而已,这样的程序员永远成为不了优秀的程序员,他们生产出的代码也是一堆有危害性的几乎无法维护的垃圾,这堆垃圾将给公司和个人带来潜在的危害,相对而言,对个人的危害性更大,有时甚至可以断送一个程序员的职业生涯。
四.如何建立起领域模型
途径一:分析业务中的业务流和业务规则,从中归纳出功能的基本单位,这个基本单位就是领域模型之一或领域模型的一部分.
途径二:从原型界面中观察显示的数据,它们是领域模型的外在体现.
途径三 :从持久化介质中推导领域模型,如从数据库的表结构和ER图中推导领域模型.
途径四:向领域专家问询业务流程中的核心单元是什么,甚至自己进入问题领域去学习探究。
途径五:将不熟悉的领域和相似的自己熟悉的领域做对照,类比出领域模型。
途径六:从已有的知识系统中学习,参考功能相似的软件代码,向优秀代码学习。
五.如何完善领域模型
领域模型是经常发生相互联系的,上一步只是建立了孤立的,仅能表现单个领域对象信息的模型,要使它们丰富完善起来,需要做以下工作:
1) 从程序的功能角度入手,考虑需要几个领域对象才能完成这个功能,再由此考虑领域对象之间的联系.这方面的典型例子是需要雇员类和资源类的协助,借贷关系才能完整的表现出来.
2) 从领域对象本身入手,考虑领域对象之间是否有级联,回溯,包含等常见关系.如个人信息包含地址信息,公司类和雇员类的级联关系,雇员类查找自己所属公司的回溯关系等.
3) 从反持久化入手,考虑把一个领域对象从存储介质中提取出来需要那些领域对象的帮助,这些领域对象是通过那种方式联系在一起的,这方面的典型例子是表之间的主键和外键,领域对象同样也要具有相对应的成员变量.
六.领域对象设计完成之后
一旦领域对象设计完成,程序的设计工作就可以说完成了一大半,其余工作都是围绕领域对象来进行,这些工作有:
1) 从考虑怎么为领域对象服务入手,为领域对象设计服务类,服务类的常用方法有添加,删除,更新,查询领域对象四种以及从ID取得一个领域对象,判断持有某个ID的领域对象是否存在等.具体的操作实际上由服务类的持久层类成员完成,服务类实际上起到的是一个领域对象上下传输通道的作用.一般来说Service层的六大函数是add,delete,update ,search, hasId(String id), getById(String id))再加上一些用于查询的函数。
2) 考虑到实现服务类中要求的方法,设计持久层类,其中的成员函数基本是服务类的六大方法的具体化,持久层类实际上起到一个把领域对象存储到持久介质中和从持久介质中取出领域对象的作用.如果持久层是关系型数据库的话,还需要设计领域对象对应的表以及表之间的关系ER图。
3) 从功能的角度设计控制层的函数和类,在这里控制层类调用服务层类来操作领域对象,业务逻辑主要体现在这里.
4) 从领域对象的输入输出和表现的角度设计各个表现层类.设计这一层类时应该从用户立场考虑而不是从代码编写者的立场考虑,怎么让用户感到直观,方便,快捷就怎么设计界面.
5) 在设计上述层次的同时,考虑到减少重复代码,突出主干代码而设计实用层类,把共通的操作都归纳到一起,这样既提高的代码的清晰程序和可读性,也使修改变得方便容易起来.
6) 如果有些变量在使用过程中是可能发生变化的,如数据库的地址,业务中一些硬编码信息等,这样的量就不该硬编码(Hard Code)在程序中,否则修改后还需要重新编译,打包,发布.而应该把这些量写在XML形式的配置文件里,在程序启动时读取.
七.软件的六大层次
上页的工作完成后,我们会得到以下六大层次:
1) Domain层
2) Service层(允许Control层访问,能访问Persistence层)
3) Persistence层(也称为DAO层,只允许Service层访问)
4) Control层(访问Service层和View层)
5) View层(仅被Control层访问)
6) Util层
八.一定要限制各层之间的无规则通信
如果不规定各层之间的通信规则,那么它们之间的通信将会肆意的发生,这将使软件结构混乱直到不可收拾的地步。
在分层中,有一点特别重要,即不同层次之间相互通信的规则。如果所有的层次都能和其它层次通信,你就完全失去了把它们分开带来的好处,应该通过限制层次之间的通信来让每个层次更加有意义
九.逐步完善六大层次中类的各个具体函数
这一层的设计包括把每个类细分为子程序。在上一步已经定义了其中一些子程序,这一步将使类更加细化丰富起来。
完整的定义出类内部的子程序,常常有助于更好的理解类的接口,反过来,这又有利于对类的接口进行进一步的修改。
将类分解为子程序时:首先要想到这个类的基本功能和在类层次中的定位是什么?其次要想到它被上级类调用的接口是什么和它该怎么调用下级类?再次要想到为丰富这些接口类中还需要那些字段和方法?最后考虑是用返回值还是异常来控制程序流程。
十.绘出各层次类的静态类图
静态类图能帮助我们思考各类之间的关系和类内部的各函数,通过静态类图我们还能发现各类共通的接口,由此可以对已有的类进行进一步抽象和归纳.
十一.最后的步骤:子程序内部的设计
在子程序层次上进行设计就是为每个子程序布置详细的功能。这里的设计工作包括绘制流程图,选择算法,组织子程序内部的代码块,考虑和工具层类的调用关系以及最后用编程语言编写代码。
在书写代码时,可能会遇到复杂的处理,这时可以通过流程图来理清思路,帮助思考.
十二.软件的最终需要具备的现代软件的八个典型特征
最小的复杂度:整个系统可以分解为简单而易于理解的各个部分.
易于维护:程序有良好的可维护性.
松散耦合,通过应用类接口中的合理抽象,封装性以及信息隐藏等原则,设计出相互关联尽可能最少的类.
适应变化: 能在不改变系统基本构架的基础上,适应未来的变化,有良好的扩展性,程序可扩展,可重用.
有明晰的层次,每层各司其职,有良好分工.
高扇入低扇出:系统很好的利用了较低层次上的工具类,重复代码很少或没有.
有良好的规范:无论多少人参与了项目,从代码看来犹如出自一人之手.
使用标准技术.(以上八点来自<<代码大全2>>)
软件编写完成后,可以自我审核一下看看是否达到了这些特征。
以上。