开发健壮的企业级应用的研究-计算机应用
·当前位置: 学海荡舟-论文 >> 论文资料 >> 计算机论文 >> 计算机应用
开发健壮的企业级应用的研究


               目 录
摘要…………………………………………………………………………………….I
ABSTRACT…………………………………………………………………………..II
1 什么是企业级应用 4
2 为什么我们需要开发健壮的企业级应用 6
3 什么是健壮的企业级应用 7
3.1 什么是健壮的企业级应用 7
3.2 企业级应用的一般结构 7
3.3 健壮的企业级应用的一般结构 8
4 怎样开发健壮的企业级应用 11
5 面向对象编程技术 12
5.1 依赖于抽象,而不要依赖于具体实现 12
5.2 使用委派而不是继承 13
5.3 “客户—服务器”关系中,应该是“瘦”客户类,“胖”服务器类 15
5.4 类存在的意义是提供的服务,而非保存的数据 15
5.5 单一功能的方法 17
5.6 单一职责的接口 18
5.7 用接口来隔离实现类 18
5.8 直接使用编程语言的概念进行设计 19
5.9 尽量使用模式来解决问题 19
6 面向方面编程技术 20
6.1 AOP的重要概念 22
6.2 实现AOP的主要技术策略 25
6.3 Spring AOP框架 27
6.4 如何更好的使用AOP 28
7 面向关注软件开发 29
8 敏捷开发方法的代表作—XP 30
8.1 XP的前提 30
8.2 为什么需要XP 31
9 融合XP的软件开发过程 32
9.1 获取需求 32
9.2 测试驱动开发和验收测试级重构 33
9.3 单元测试驱动开发和单元测试级重构 35
9.4 小结 36
10 使用Java开发企业级应用的参考架构 36
10.1 JavaEE 36
10.2 “经典”的JavaEE架构 36
10.3  Java开源软件 38
10.4 不用EJB的简单Java EE架构 38
10.5 使用“轻量级容器”的Java EE架构 42
11 总结 45
11.1 “源代码就是设计” 45
11.2 总结 45
                致  谢 46
               参 考 文 献 46

什么是企业级应用

 企业级应用(Enterprise Applications),顾名思义,就是企业经营中需要使用的应用程序。又叫作企业信息系统(Enterprise Information System)或者管理信息系统(Management Information Systems)。其主要任务是最大限度的利用现代计算机及网络通讯技术加强企业的信息管理,通过对企业拥有的人力、物力、财力、设备、技术等资源的调查了解,建立正确的数据,加工处理并编制成各种信息资料及时提供给管理人员,以便进行正确的决策,不断提高企业的管理水平和经济效益。可以说,它的涵盖面是非常广的,很难给它下一个确切的定义,但是我可以罗列一些个人的理解。[1]

 先举几个例子。企业级应用包括工资单、患者记录、发货跟踪、成本分析、信誉评估、保险、供应链、记账、客户服务以及外币交易等。企业级应用不包括车辆加油、文字处理、电梯控制、化工厂控制器、电话交换机、操作系统、编译器以及电子游戏等。

 企业级应用一般都涉及到持久化数据。数据必须持久化是因为程序的多次运行都需要用到它们—实际上,有些数据必须持久化若干年。在此期间,操作这些数据的程序往往会有很多变化。这些数据的生命周期往往比最初生成它们的那些硬件、操作系统和编译器还要长。在此期间,数据本身的结构一般也会被扩展,使得它在不影响已有信息的基础上,还能表示更多的新信息。即使是有根本性的变化发生,或公司安装了一套全新的软件,这些数据也必须被“迁移”到这些全新的应用程序上。

 企业级应用一般都涉及到大量数据—一个中等规模的系统往往都包含1GB以上的数据,这些数据是以数百万条记录的方式存在的。巨大的数据量导致数据的管理成为系统的主要工作和挑战!早期的系统使用的是索引文件系统,如IBM的VSAM和ISAM。现代的系统往往采用数据库。数据库有层次数据库、网状数据库、关系数据库和对象数据库,还有对象—关系数据库。现在最成熟,应用也最多的是关系数据库。数据库的设计和演化已使其本身成为新的技术领域。

 数据库在企业级应用中处于重要的地位。选择性能优良的数据库和有效的使用数据库,是开发企业级应用的一项核心工作!

 最近兴起的使用XML文件存储少量数据这一技术。实际上,XML文件格式,就是早期的层次数据库。它具有丰富的表达能力和简单的优点,但是数据库发展的历史已经表明,XML文件不可能取代现在的关系数据库和对象—关系数据库。

 企业级应用一般还同时涉及到很多人同时访问数据。对于很多系统来说,人数可能在100人以下,但是对于一些基于Web的系统,人数则会呈指数级增长。要确保这些人都能够正确地访问数据,就一定会存在这样或那样的问题。即使人数没有这么多,要确保两个人在同时操作同一数据项时不出现错误,也是存在问题的。事务管理工具可以处理这个问题,但是最为程序员,我们仍然要正确地使用它们,这同样不容易做到。
 企业级应用还涉及到大量操作数据的用户界面。有几百个用户界面是不足为奇的。用户使用频率的差异很大,他们也经常没什么技术背景。因此,为了不同的使用目的,数据需要很多种表现形式。

 企业级应用也很少单独存在,通常需要与企业的合作伙伴的企业级应用集成。这些各式各样的系统是在不同时期,采用不同的技术开发的。甚至连通讯机制都不相同:基于Socket的系统、CORBA系统、COM系统、Java的RMI、EJB和消息系统,以及最新的Web Service等。企业经常希望能够用一种同一的通信技术来集成所有的系统。然而,每次这样的集成工作都很难真正实现,留下来的就是一个个风格各异的集成环境。

 即使是某个企业统一了集成技术,他们还是会遇到业务过程中的差异,以及数据库中数据概念的不一致性。不同部门、不同系统,甚至不同时期,都会对业务数据有不同的定义和理解。

 随着企业级应用的发展和集成,整个企业的企业级应用程序就成了一个不同技术、不同数据混杂在一起组成的复杂系统。不断的修改和添加新功能,也使系统的Bug越来越多,修改和添加新功能变得越来越困难。

 对于一些人来说,“企业级应用”这个词指的是大型系统。但是要注意,并不是所有的企业级应用都是大型的,尽管它们可能都在为企业提供巨大的价值。

为什么我们需要开发健壮的企业级应用

 开发企业级应用程序并不是一件简单的事情,开发出一个能令客户满意的企业级应用程序更非易事。这需要考虑太多的事情、克服太多的难关—技术上、商业上、人际关系上的。

 事实上,企业级应用的主要成本和困难并不在开发软件这个时期,而是在软件的维护阶段。企业级应用在其交付使用后,其维护阶段在软件生命周期或生存期中占较大比重,有的可达软件生命周期总成本(TCO)的50-70%。因为,企业的业务环境一直处于不断的变化之中,这就要求企业级应用也要能够适应企业的变化。而这些可能的变化,对于开发者来说,是很难预见的。如果开发的企业级应用,其架构没有很强的适应能力、不够健壮的话,那么在维护阶段修改软件,或者增加新功能将是极其困难的,甚至是不能做到,必须推倒重来!

 业务需求的变化,才是企业级应用最大的风险和难点!而且,这种变化,基本上每个项目都会出现,这是企业级应用开发的“常态”。甚至,一般在软件开发的过程中,就会出现业务需求的变化。

 现在,市面上有很多套装的企业级应用,如ERP,CRM,财务软件等。很多企业花了大价钱买了回来,但是应用下来,失败的案例很多。不仅造成了软件购置费用的浪费,更严重的是扰乱了企业正常的业务活动,造成了严重的损失。也使不少企业对信息化望而却步。

 企业,作为市场经济的主体,其面临的内外部环境是在不断变化的,企业本身也会针对这种变化,经常性的调整其组织结构和业务流程。并不存在适用于所有企业的一套一成不变的组织结构和处理流程。

 使用套装软件,就好比是“削足适履”,为了适应软件的需要,改变企业原来运转正常的组织结构和业务流程,实在是不智之举。企业级应用程序,是为企业服务的,应当服从企业的需要,而不是相反,企业成了软件的奴隶!

 IBM的广告词“随需应变的软件”,就是企业级应用软件业者理想中的软件。可是,依靠IBM,就能够开发出“随需应变的软件”吗?当然不可能,一切只能够靠我们程序员自己才能做到!

什么是健壮的企业级应用

 “随需应变的软件”,就好像是塑胶泥,我们可以任意拿捏,变化出不同的形状。“随需应变的软件”,必然是健壮的软件,不论怎样折腾,都能够应对自如。

 什么是“健壮的企业级应用”,对此我无法给出一个精确的定义,我只能够罗列一些我的理解。

 “健壮的企业级应用”,其各个部分应该是低耦合、高内聚的。其内部的各个模块之间的关系最低,且可以互相替换,从而可以方便地拆卸、替换和修改各个模块。

 其核心思想,就是“接口”。各个部分之间通过接口,并且只通过接口互相衔接,一起合作。只要接口相同,那么这些模块就可以互相替换。对于其他模块来说,其合作部分的具体实现是不重要的。

 这样,我们在需要“随需应变”的改变软件时,只要简单的提供在原有系统上接插上不同的实现模块即可。

 这实际上,就是面向对象(OO)思想的一种体现。更深入的说,就是“抽象”的思想。把具体的源代码通过接口屏蔽、抽象起来。这样,只要接口不变,那么无论源代码怎样变化,都不会影响整个软件的正常运行。

 当然,不仅企业级应用需要“健壮”,任何软件都应该是健壮的。但是,在企业级应用程序的开发和维护过程中,由于其需求的多变性,就更需要是“健壮”的。

企业级应用的一般结构

 现在,让我们再来看一看企业级应用的结构。企业级应用在结构上,一般可以分为三大模块:表现模块,业务模块,领域模块。这里,我将它们称作“模块”,而不是“层”。很多人喜欢划分“层次”,但我觉得划分“模块”更合适。因为,“层”有上下之分,只能是上层调用下层;而“模块”就没有上下之分,可以根据实际情况任意调用。这里,我不想分清什么是上层,什么是下层,用模块来表示应该更加合适。
 一、表现模块
 表现模块,又叫作客户端。用于向客户提供使用软件系统的途径。一般有图形用户界面GUI,命令行界面,文本文件等等。这个模块,仅仅是用来接收用户请求,再将这个请求委派给业务模块提供的方法(这就是业务模块提供的服务),从而实现软件的功能。一个软件的好坏与否,与之无直接的关系。
 二、业务模块
 业务模块,封装了为特定的业务需求提供服务的方法。表现模块就是通过它提供的方法来实现业务需求的。所以,业务模块是直接对应于系统的业务需求的,是系统的关键和最重要的部分。
 三、领域模块
 也许你会问:既然业务模块已经提供了客户所需的功能,那么还要这个领域模块干什么呢?其实,这个领域模块就是为业务模块服务的更底层的功能。
 在整个软件系统中,存在一些实体。这些实体包含了一些数据和责任,它们的交互协作,就可以实现软件系统的业务功能。
 实现一个个业务需求的业务模块,可能需要这些实体中的一个或者多个的功能和数据。
 这些实体的集合,就是领域模块。由此可见,领域模块实际上才是整个系统的核心和灵魂。业务模块也只有委托它们才能提供系统所需的业务功能。
健壮的企业级应用的一般结构
 健壮的企业级应用,在结构上又应该是怎样的呢?
 一、表现模块
 表现模块仅仅是一个界面,用于向用户提供使用系统的途径而已。所以,尽可能“薄”的表现模块,就是理想的表现模块。“薄”的表现模块,就可以在用户想要改变用户界面时,轻松的加以改变。改变用户界面,是系统变化最多的需求。
 使用MVC模式设计的表现模块,可以分为3个组成部分:M(Model)模型,V(View)视图,C(Control)控制器。
 其中,模型,是一些类,它们封装了视图所要呈现给用户的数据,也用来将用户操作信息传递给后台的控制器模块。
 视图,就是用户界面,是用户看到的那部分。它能够接受用户的请求,并将请求信息发送给控制器,再在控制器完成操作之后,从模型类中获得数据,展现给用户。
 控制器,它接收到用户请求之后,就委托业务模块的业务服务对象提供的服务,完成业务功能。如果有数据需要返回给用户,就将数据存放到Model模型类中,以备视图取用。控制器,虽然是表现层的一部分。但是,它实际上是“业务代表模式”的一种应用。所谓业务代表,是指在客户端和业务服务层之间,增设一个“代表层”,所有客户端到服务器的调用,都“委托”该层完成。[9]业务代表虽然身处表现模块内,但实际上执行的是调用业务服务模块功能的任务,完成的是业务功能。因此,不少人都将业务代表划分在业务模块内。我也认同这种划分方法。至少,我们可以认为,它是横跨表现模块和业务模块的一个部分。
 表现模块中,模型和视图两部分通常都很小,而且它们是表现模块固有的,不能够省略,就算够“厚”(比如,富客户端技术),也没办法变小。
 实际上,我们说企业级应用的表现模块太“厚”,都是指太“厚”的控制器。理想的控制器,只应该根据接收到的界面上不同的请求,调用业务模块的不同业务服务,完成这些请求,然后将得到的数据塞进Model模型类即可。
 我们常常犯的错误,就是在控制器中塞进了太多的应该放在业务模块的业务服务类中的代码。实际上,判断控制器是不是太厚,有一个非常简单的方法:假设我们使用另一种表现模块技术,那么,这个新的表现模块中的控制器类中有多少代码和现有的控制器是重复的。如果存在重复代码,就使用“重构”技术,先将它们提炼成方法,然后再移到业务模块的业务服务类中。这样,我们就能够得到一个理想的“瘦”表现模块!
 二、业务模块
 业务模块,包括2个部分:一个是表现模块的控制器,它是“业务代理”,提供的也是与业务相关的服务。我认为,把它划分在业务模块也许比表现模块更加合适。另一个是业务服务模块,我用Service表示它,它封装了为特定的业务需求提供服务的方法。它与控制器配合,共同完成用户需要的业务功能。
 既然理想中的控制器是“瘦”的,而且所有的重复代码都移到了业务服务模块中。那么,理想的业务服务模块必然是“胖”的。
 实际上,控制器和业务服务模块,是典型的“客户—服务器模式”。控制器作为客户,需要调用作为服务器的业务服务模块提供的服务,来完成用户需要的功能。所以,服务器越胖,提供的服务越多,那么系统的重复代码就越少,功能也越强大!
 三、领域模块
 业务服务模块和领域模块,实际上也是典型的“客户—服务器模式”。业务服务模块虽然提供的服务功能强大,很“胖”。但是,它的“胖”也是有限度的!它的“胖”来自于控制器中理应属于它管辖的重复代码。实际上,在“控制器模块—业务服务模块”这对“客户—服务器”关系中,是控制器模块“瘦”,而业务服务模块“胖”。
 而在“业务服务模块—领域模块”这对“客户—服务器”关系中,则是作为“客户”的业务服务模块“瘦”,而作为“服务器”的领域模块“胖”。
 领域模块,主要就是领域模型(也叫作业务对象Bussiness Object)。领域模型,封装了业务实体的数据,还提供一些处理这些数据的服务(“服务”在编程语言中就是由方法提供的)。一般,在企业级应用中,有一些领域模型需要持久化存储,就是保存到数据库(关系型数据库或对象数据库)、文本文件、XML文件、序列化文件等持久地存储起来,已备下次再用。这时,需要持久化的业务对象就需要对应的提供数据访问服务的类(也叫作DAO,Data Access Object数据访问对象)。
 这样,一般的企业级应用的领域模块,主要有两个模块:领域模型(Domain Model)和数据访问服务模块(DAO)。
 在“业务服务模块—领域模块”这对“客户—服务器”关系中,
应该把业务服务模块中所有可以移到领域模块的领域模型类和数据访问服务类中的代码都移到领域模型类和数据访问服务类中去。
 因为,业务模块的控制器和业务服务模块,它们与领域模块的领域模型和数据访问服务模块之间的关系是“多对多”的关系。一个业务模块可以使用零个或者多个领域模块;一个领域模块也可以被零个或者多个业务模块所调用!所以,领域模块越“胖”,提供的服务越多,业务模块就越少重复代码,系统的功能就越强大!
 现在,很多程序员都接受了UML的用例驱动开发的思想。诚然,用例驱动开发的思想确实很好,但是很多程序员都由此犯了一个毛病:他们常常按照用例为系统的源代码分包(就是Java中的Package,.Net中的namespace),错误的将领域模块的领域模型、DAO数据访问服务类和业务模块的控制器、业务服务类划分在一个包里。实际上,领域模块和业务模块完全不同,它们并不是从属于某一个用例的,而是属于整个系统的,可以被多个业务模块共同使用的。
 如果把领域模块放在首次用到它们的业务模块之中。那么我们就很难在其他业务模块调用它们时很好的使用它们。因为,其他业务模块的使用,可能会要求领域模型类和DAO类增加新的字段和方法。而将它们放在另一个业务模块所在的包里,我们就很难将这些新增的功能放到领域模型类和DAO类中,使它们更“胖”。而是会倾向于在控制器类和业务服务类中增加方法。这样,就会导致各个业务模块中出现重复代码,引发逻辑重复。
 
怎样开发健壮的企业级应用
 企业级应用程序,按照是否能够“随需应变”来划分,可以分为两类:健壮的和脆弱的。
 画一根数轴,我把它叫作“软件健壮度”图。“健壮”在正方向,“脆弱”在负方向。有很多技术原理和开发方法,可以让我们的应用程序更加健壮,而违反这些原理和方法,我们的应用程序就会变得更加脆弱,修改和扩充新功能也更加困难。
 要想开发出健壮的企业级应用,首先需要的就是开发人员扎实的编程技能和对编程原理的清楚认识和应用。没有高水平的开发人员,而奢谈“健壮的企业级应用”,是毫无意义的。
 
面向对象编程技术
 面向对象编程技术(OOP,object-oriented programming)是近几十年来编程领域最伟大的成就。健壮的企业级应用程序,甚至任何健壮的软件,必须首先是一个很好的实践了OO思想的软件。脱离了OO,就不用奢谈什么合格的软件了!
 面向对象编程技术,早已经从昔日的神坛上走了下来。今天,任何一门主流的编程语言都是支持面向对象编程的。现在,几乎所有的程序员都自称已经掌握了面向对象编程的技术。但是,真正掌握OO的程序员却远远没有这么多。而且,面向对象编程技术还在飞速发展的过程中,我们还远没有发掘出它的全部内涵。
 并不是说,你使用了面向对象的编程语言开发软件,你就能够开发出实践了OO思想的软件。
 要想开发出健壮的企业级应用,我们需要的是全面皈依OO!
 面向对象编程的几个原理[2]:
依赖于抽象,而不要依赖于具体实现
 具体来说,就是依赖于接口(Interface),而不要依赖于接口的具体实现类。或者是,依赖于父类(最好是抽象的),而不是具体实现的子类。又或者是,依赖于父接口,而不是子接口。总之,只使用提供了所需方法的最基本的类型。这样,当程序需要改变时,我们就可以仅仅提供另一个“服务器”实现类或者实现子类,然后在“客户类”新建实例的地方更换成这个新实现类即可,无须更换“客户类”的调用代码。在使用IOC(反转控制)容器,如Spring框架时,我们甚至可以不用改动“客户类”的任何代码,而只需更改元数据(在Spring 框架中,是简单的Xml文件),将旧的实现类的类名换成新的即可。
 使用越是抽象的接口或者类,我们可以选用的实现类也就越多!
 我们知道,在Java语言中有这样几种作用域:Private私有,Protected保护,Package包,public公共。按照“依赖于接口Interface”这一原则,我们又有了一个新的作用域:Publish已发布。接口Interface中声明的方法就是已发布的。既然我们现在是通过接口来使用实现类的方法,那么就是说,即使实现类还有其他的Public可见方法,我们也不会调用它们。

  • 上一篇论文:
  • 下一篇论文: