这里所说的软件特征指的是非功能性需求(non-functional requirement ),如质量、兼容性、稳定性,对应英文后缀“-ilities”。
比如对于学生管理系统软件,登录、选课、添加成绩是功能需求;而系统要求能够允许1000个人同时登录,这就属于非功能需求。
客户经常会要求我们实现这些非功能需求,因此在设计时,我们必须考虑这些因素。
仅仅满足功能的软件是远远不够的,还必须满足其它的特性。这里总结了七大特性,它们最终决定了一个软件的成与败。
1. 易用性 Usability
软件的易用性可以使用户高效地完成工作。以下问题可以检验易用性:
(1)是否需要借用其它事物来模拟说明用户界面?
(2)最常用的操作使用起来是否如鱼得水,方便快捷?
(3)用户能否很快地上手操作而不需要帮助?
(4)验证或错误提示信息是否合理?
2. 可维护性 Maintainability
软件的可维护性用来衡量系统应对变化的能力。增加新功能或修改原有功能,是否可行,且对系统其它功能影响甚小。
以下问题可以检验可维护性:
(1)整个项目团队是否理解代码架构,是否有标准的文档备案?
(2)所有代码是否可以进行回归测试?
(3)修改的工作量能否按人天精确估算出来?
3. 可伸缩性 Scalability
软件的可伸缩性用来衡量系统应对压力变化的能力。当某一时刻用户超预期地急剧增多时,系统性能并没有明显下降。以下问题可以检验可伸缩性:
(1)系统所能承受的最大峰值负载是多少?
(2)How many database records can create until critical operations slow down?
(3)提高可伸缩性的主要方法是横向的“scale out”还是纵向的"scale up"(即增加多个点还是增强每个点的能力)?
4. 高可用性 Availability
软件的高可用性用来衡量系统平均正常运行的时间(两次失败之间的运行时间,Mean Time Between Failure (MTBF))。
以下问题可以检验高可用性:
(1)系统要求最低正常运行时间是多少?
(2)系统可接受的最长宕机时间是多少?
(3)能否按计划安排宕机的时间、次数?
5. 可扩展性 Extensibility
软件的可扩展性用来衡量系统改变的能力。以下问题可以检验可扩展性:
(1)数据库Schema是否适应改变?
(2)系统是否允许依赖反转Inversion of Control (IoC)?
(3)最终用户是否可以扩展系统(脚本,用户自定义字段)?
(4)第三方软件能否方便地加入你的系统?
6. 安全 Security
软件的安全性是用来衡量系统的抵抗非法入侵者的能力以及为合法用户提供服务的能力。以下问题可以检验安全性:
(1)系统是否有基于角色的安全机制?
(2)Does code access security need to occur?
(3)哪些操作需要加以保护?
(4)如何管理用户?
7. 可移植性 Portability
软件的可移植性是用来衡量系统运行在多个平台的能力。以下问题可以检验可移植性:
(1)数据能否移植到其它系统?
(2)你的Web应用支持哪些浏览器?
(3)应用可以运行在哪些操作系统上?
当然,还有很多没有列在这里的特性,比如向下兼容性、互操作性、复用性等等。
您的“-ilities”列表包含哪些特性?按优先级排列,顺序如何?
参考文献:
1. 《The 7 Software “-ilities” You Need To Know》
2009年5月20日星期三
2009年5月4日星期一
JavaEEDesign_014:数据层(持久化层)面临的四大问题之四:性能问题(摘录+整理)
通过数据层访问数据自然会比直接访问数据的性能要差。但它提高了复用性和维护性,因此如果性能在可接受的范围内,使用数据层还是非常值得的。
除此之外,一些设计上的错误也会导致性能低下:
1. DAO 返回对象的粒度不合适。
不要把原始数据模型直接照搬成值对象,导致值对象粒度过细。
2. DAO 返回对象的深度超过三层。
嵌套超过三层的值对象,即使读取和更新少量对象都会造成巨大开销。
3. DAO find() 方法返回大量值对象。
数据层框架最适合用于OLTP (联机事务处理),即处理少量对象的小事务;而不适合用于OLAP(联机分析处理),即处理大量对象的大事务。
特别是嵌套聚集的使用会严重影响性能,比如某个查询返回1000本书,每本书有多个编辑。此时,应该考虑用其它方式实现,比如使用JDBC for Reading 模式,直接通过JDBC读取数据。
4. EJB常见设计问题。
(1)未缓存JNDI查找结果。
(2)未使用本地接口。
除此之外,一些设计上的错误也会导致性能低下:
1. DAO 返回对象的粒度不合适。
不要把原始数据模型直接照搬成值对象,导致值对象粒度过细。
2. DAO 返回对象的深度超过三层。
嵌套超过三层的值对象,即使读取和更新少量对象都会造成巨大开销。
3. DAO find() 方法返回大量值对象。
数据层框架最适合用于OLTP (联机事务处理),即处理少量对象的小事务;而不适合用于OLAP(联机分析处理),即处理大量对象的大事务。
特别是嵌套聚集的使用会严重影响性能,比如某个查询返回1000本书,每本书有多个编辑。此时,应该考虑用其它方式实现,比如使用JDBC for Reading 模式,直接通过JDBC读取数据。
4. EJB常见设计问题。
(1)未缓存JNDI查找结果。
(2)未使用本地接口。
JavaEEDesign_013:数据层(持久化层)面临的四大问题之三:事务问题(摘录+整理)
使用EJB 容器可以简化事务问题的处理,也就是说使用EJB来实现DAO。
关于EJB 容器的事务管理请参考相关文章。
关于EJB 容器的事务管理请参考相关文章。
JavaEEDesign_012:数据层(持久化层)面临的四大问题之二:并发性问题(摘录+整理)
并发性问题指的是多个用户要更新同一记录,用户1提交修改后,用户2也提交修改,用户2覆盖了用户1的修改。
要避免这个问题,可以采取锁的机制。
1. 悲观锁策略 (pessimistic locking strategy)
用户1读取记录后,其他用户都不能访问这个记录,即使只是读取记录。
悲观锁策略是最安全的事务隔离级别,但在事务量较大的应用中,会使性能大大下降。
2. 乐观锁策略 (pessimistic locking strategy)
记录中带有版本信息,可以允许多个用户同时读取,但更新时,会比较读取的版本信息和数据库中的版本信息,如果两者一致,则允许更新,否则不允许更新。
乐观锁策略特别适合在事务量较大的应用中读取和迅速更新少量数据。乐观锁策略的实现方法有:
(1)在表中增加一个字段 row_version。
UPDATE title SET title_name=?, row_version=? WHERE title_id=? AND row_version=?
(2)在表中增加一个上次更新的时间戳字段。
建议使用第一种,比较清楚。
乐观锁代码应该放在DAO模式中,不要利用数据库触发器来完成这个工作,因为会有移植性问题。
要避免这个问题,可以采取锁的机制。
1. 悲观锁策略 (pessimistic locking strategy)
用户1读取记录后,其他用户都不能访问这个记录,即使只是读取记录。
悲观锁策略是最安全的事务隔离级别,但在事务量较大的应用中,会使性能大大下降。
2. 乐观锁策略 (pessimistic locking strategy)
记录中带有版本信息,可以允许多个用户同时读取,但更新时,会比较读取的版本信息和数据库中的版本信息,如果两者一致,则允许更新,否则不允许更新。
乐观锁策略特别适合在事务量较大的应用中读取和迅速更新少量数据。乐观锁策略的实现方法有:
(1)在表中增加一个字段 row_version。
UPDATE title SET title_name=?, row_version=? WHERE title_id=? AND row_version=?
(2)在表中增加一个上次更新的时间戳字段。
建议使用第一种,比较清楚。
乐观锁代码应该放在DAO模式中,不要利用数据库触发器来完成这个工作,因为会有移植性问题。
JavaEEDesign_011:数据层(持久化层)面临的四大问题之一:主键的生成(摘录+整理)
1. 主键生成策略有哪些?
(1)使用数据库触发器自动产生主键。
(2)使用自动递增列自动产生主键,适用于MySQL、SQL Server。
(3)使用顺序产生器自动产生主键,然后插入表中,适用于Oracle。
(4)使用Java类或EJB,维护顺序号,缓存这些顺序号,使用者按顺序取得顺序号,使用完毕后更新表中的计数值。
2. 优劣比较
(1)(2)无法返回生成的主键,需要再使用一条语句查询。当然,使用 JDBC Statement 的特性可以提前返回生成的主键,使用方法如下:
pstmt=conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS );
ResultSet rsKey=pstmt.getGeneratedKeys();
rsKey.next();
int rootid=rsKey.getInt(1);
(3)可以返回生成的主键,但(1)(2)(3)共同的缺点是可移植性差,改换数据库后,要改动很多地方。(4)独立于数据库,但使用时也有要注意的地方:
(1)由单一的服务点提供主键的生成。(2)主键的使用者与主键的生成机制分离。
(3)如果做不到独立于数据库,至少要将数据库特性隐藏起来,这样即使要改主键生成机制,至少不用改动主键的使用者:DAO。
(1)使用数据库触发器自动产生主键。
(2)使用自动递增列自动产生主键,适用于MySQL、SQL Server。
(3)使用顺序产生器自动产生主键,然后插入表中,适用于Oracle。
(4)使用Java类或EJB,维护顺序号,缓存这些顺序号,使用者按顺序取得顺序号,使用完毕后更新表中的计数值。
2. 优劣比较
(1)(2)无法返回生成的主键,需要再使用一条语句查询。当然,使用 JDBC Statement 的特性可以提前返回生成的主键,使用方法如下:
pstmt=conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS );
ResultSet rsKey=pstmt.getGeneratedKeys();
rsKey.next();
int rootid=rsKey.getInt(1);
(3)可以返回生成的主键,但(1)(2)(3)共同的缺点是可移植性差,改换数据库后,要改动很多地方。(4)独立于数据库,但使用时也有要注意的地方:
- 集群环境中如何保持主键的唯一性。
- 如果Server突然down掉,会造成缓存的主键丢失,重新启动后,会有一段主键是“空白的”。这种情况虽然不是大毛病,但数据库管理员也许不会接受。
- 其它直接访问数据库(不通过方法(4))的程序,会造成主键顺序混乱。
(1)由单一的服务点提供主键的生成。(2)主键的使用者与主键的生成机制分离。
(3)如果做不到独立于数据库,至少要将数据库特性隐藏起来,这样即使要改主键生成机制,至少不用改动主键的使用者:DAO。
JavaEEDesign_009:与数据层(持久化层)有关的设计模式(摘录+整理)
数据层框架完全抽象了访问数据方法的细节,把业务层与数据层分离。
数据层框架主要使用的设计模式有:
1. 数据访问对象 Data Access Object(1)抽象数据源:Oracle、SQL Server、LDAP......
(2)抽象数据操作CRUD
(3)提供一致的异常 DataAccessException,供DAO使用者捕获。其它特定的异常有NoDataFoundException、OptimisticLockException、ServiceLocatorException,它们都继承自DataAccessException。(4)提供基本的数据操作方法:
2. 值对象 Value Object值对象模式的产生的初衷是为了最大限度地减少(减少到一次)对实体EJB的远程调用。值对象的特性如下:
(1)作为数据的逻辑视图(表示实体之间一对一或一对多的关系)。
(2)作为唯一能够在表示层和数据层之间来回传递的数据(因此值对象必须是可序列化的)。
(3)值对象提供如下状态属性:
(6)值对象的数量要适当,不要有过多“毛细值对象”。
3. 服务定位器 Service Locator
服务定位器通过缓存EJBHome接口和DataSource对象,从而减少JNDI查找次数。
服务定位器模式实现一般采用单例模式。
数据层框架主要使用的设计模式有:
1. 数据访问对象 Data Access Object(1)抽象数据源:Oracle、SQL Server、LDAP......
(2)抽象数据操作CRUD
(3)提供一致的异常 DataAccessException,供DAO使用者捕获。其它特定的异常有NoDataFoundException、OptimisticLockException、ServiceLocatorException,它们都继承自DataAccessException。(4)提供基本的数据操作方法:
- findByPrimaryKey (Object pPrimaryKey)
- insert (ValueObject pValueObject)
- createValueObject ()
- update (ValueObject pValueObject)
- delete (ValueObject pValueObject)
- 普通Java类:好处就是实现比较简单。
- EJB:好处是可以利用EJB 容器的特性:事务管理、声明式访问控制、EJB资源池。
2. 值对象 Value Object值对象模式的产生的初衷是为了最大限度地减少(减少到一次)对实体EJB的远程调用。值对象的特性如下:
(1)作为数据的逻辑视图(表示实体之间一对一或一对多的关系)。
(2)作为唯一能够在表示层和数据层之间来回传递的数据(因此值对象必须是可序列化的)。
(3)值对象提供如下状态属性:
- insertFlag
- updateFlag
- deleteFlag
- rowVersion (乐观锁机制,见后文介绍)
(6)值对象的数量要适当,不要有过多“毛细值对象”。
3. 服务定位器 Service Locator
服务定位器通过缓存EJBHome接口和DataSource对象,从而减少JNDI查找次数。
服务定位器模式实现一般采用单例模式。
JavaEEDesign_008:Web开发面临的五大问题之五:安全问题(摘录+整理)
安全问题是Web开发中不可忽视的问题,常见的安全模式有:
1. 唯一访问入口 Single Access Point
确定有且只有一个入口可以进入Web系统,任何访问都必须要先经过这个入口,不能回避任何身份验证。
实现方式:登录页面。
验证方式:基本验证、表单验证、客户端证书。
2. 设置多个检查点 Check Point
3. 基于角色的授权机制 RBAC Role-Based Access Control
1. 唯一访问入口 Single Access Point
确定有且只有一个入口可以进入Web系统,任何访问都必须要先经过这个入口,不能回避任何身份验证。
实现方式:登录页面。
验证方式:基本验证、表单验证、客户端证书。
2. 设置多个检查点 Check Point
3. 基于角色的授权机制 RBAC Role-Based Access Control
JavaEEDesign_007:Web开发面临的五大问题之四:验证(摘录+整理)
表示层验证有两种:客户端验证和服务器验证。
服务器验证可以使用视图帮助器和截获过滤器来实现。
如果验证逻辑比较复杂,可以专门为此设计一个Validator类以及相关的工厂类来创建不同的Validator。
服务器验证可以使用视图帮助器和截获过滤器来实现。
如果验证逻辑比较复杂,可以专门为此设计一个Validator类以及相关的工厂类来创建不同的Validator。
JavaEEDesign_005:Web开发面临的五大问题之二:会话管理(摘录+整理)
客户机会话的保存方式有:HTML、Coookies、URL、表单的隐藏字段。
可以使用会话帮助器或截获过滤器创建新会话和验证会话。
1. 截获过滤器设计模式 Intercepting Filter
截获过滤器模式可以在进入控制器之前截获请求并对其采用一组过滤条件,然后退回请求或让其传递到目标。
过滤器一般使用javax.servlet.Filter创建。
可以使用会话帮助器或截获过滤器创建新会话和验证会话。
1. 截获过滤器设计模式 Intercepting Filter
截获过滤器模式可以在进入控制器之前截获请求并对其采用一组过滤条件,然后退回请求或让其传递到目标。
过滤器一般使用javax.servlet.Filter创建。
JavaEEDesign_004:Web开发面临的五大问题之一:请求处理(摘录+整理)
以前的Web请求处理都是交给每个页面自己去处理,使得代码很难维护和扩展。
现在的Web的请求处理都交给了控制器来处理,即前端控制器模式(Front Controller)。
1. 前端控制器模式(Front Controller)前端控制器对请求处理集中控制,避免处理逻辑掺杂在视图中,同时使得导航逻辑和表示逻辑分离。前端控制器模式一般使用Servlet实现。前端控制器模式一般与命令模式一起使用,对数据的不同操作如增删改查,都可以包装成不同的命令。在命令模式中,会使用业务代理模式,通过调用业务代理,调用后台的业务逻辑。
为了动态地调用不同的命令(根据用户的操作,确定使用哪个命令),可以引入抽象工厂模式。
为了更好地串联命令模式和抽象工厂模式,需要使用视图帮助器模式。这样,视图只需要与视图帮助器打交道,不需要与中
2. 视图帮助器模式 (View Helper)视图帮助器帮助视图完成与视图不直接关联的任务。
这些任务可以是(1)分析请求参数(2)做必要地转换 (3)使用抽象工厂模式
视图帮助器可以使用Java Bean(jsp:useBean)或定制标志实现。
现在的Web的请求处理都交给了控制器来处理,即前端控制器模式(Front Controller)。
1. 前端控制器模式(Front Controller)前端控制器对请求处理集中控制,避免处理逻辑掺杂在视图中,同时使得导航逻辑和表示逻辑分离。前端控制器模式一般使用Servlet实现。前端控制器模式一般与命令模式一起使用,对数据的不同操作如增删改查,都可以包装成不同的命令。在命令模式中,会使用业务代理模式,通过调用业务代理,调用后台的业务逻辑。
为了动态地调用不同的命令(根据用户的操作,确定使用哪个命令),可以引入抽象工厂模式。
为了更好地串联命令模式和抽象工厂模式,需要使用视图帮助器模式。这样,视图只需要与视图帮助器打交道,不需要与中
2. 视图帮助器模式 (View Helper)视图帮助器帮助视图完成与视图不直接关联的任务。
这些任务可以是(1)分析请求参数(2)做必要地转换 (3)使用抽象工厂模式
视图帮助器可以使用Java Bean(jsp:useBean)或定制标志实现。
2009年5月2日星期六
JavaEEDesign_003:模型-视图-控制器 MVC 模式介绍(摘录+整理)
MVC设计模式把应用分为三个大的层次:
1. 模型层:负责与后台数据源交互,运行业务逻辑。
2. 视图层:负责用户界面的展现。
3. 控制器:负责管理模型层和视图层之间的交互行为。
MVC设计模式简化了维护性,提高了复用性,每个层各司其职,互有联系又互不干涉。
1. 视图反映模型的状态。
2. 模型发生改变时,视图得到通知并更新自己(在Web上,较难做到)。
3. 如果视图发生改变,无须修改模型。
三个层各自独立发展,彼此之间是松耦合的关系,其实这就是面向服务架构SOA的基础和雏形。
1. 模型层:负责与后台数据源交互,运行业务逻辑。
2. 视图层:负责用户界面的展现。
3. 控制器:负责管理模型层和视图层之间的交互行为。
MVC设计模式简化了维护性,提高了复用性,每个层各司其职,互有联系又互不干涉。
1. 视图反映模型的状态。
2. 模型发生改变时,视图得到通知并更新自己(在Web上,较难做到)。
3. 如果视图发生改变,无须修改模型。
三个层各自独立发展,彼此之间是松耦合的关系,其实这就是面向服务架构SOA的基础和雏形。
2009年5月1日星期五
JavaEEDesign_002:Java EE 设计模式概览(摘录+整理)
目前,公认的Java EE 设计模式一共有13个,分成三个大类。
1. 表示层模式:如何创建结构合理的表示层,明确每个组件的角色使命(1)截获过滤器 Intercepting Filter(2)前端控制器 Front Controller:处理请求的初始点,集中处理请求,用派遣器委托到下一视图。用帮助器分解不同功能(验证、授权)到不同模块。
(3)视图帮助器 View Helper
(4)复合视图 Composite View
(5)服务/工人 Servie-to-Worker:派遣器用帮助器将数据推到视图中(先获取数据,再显示视图)。控制器的责任更大些。
(6)派遣视图 Dispatcher View:派遣器用帮助器将数据拉到视图中(先显示视图,再获取数据)。
2. 业务层模式:如何使用EJB 实现业务逻辑
(1)业务代理 Business Delegate
JNDI是Java EE应用中常用的资源定位机制,客户机需要知道要使用和查找的资源,还是有些麻烦。
使用业务代理模式后,客户机不再直接跟JNDI打交道,而是交给业务代理打点一切,客户机完全感觉不到是在做复杂地远程调用。
(2)值对象 Value Object
(3)会话门面 Session Facade一个Facade代表一组相关的用例,一个粗粒度的方法映射一个用例。
客户机(一般为业务代理)对Facade的调用虽然为远程调用,但Facade对其它EJB的调用可以使用EJB容器优化,如本地接口。消息门面 Message Facade也是一种Facade模式,只不过是用消息驱动Bean来实现的,可以异步执行。
(4)值对象装配器 Value Object Assembler
(5)值列表处理器 Value List Handler
(6)服务定位器 Service Locator。
3. 数据层模式:如何抽象不同数据源
(1)数据访问对象 Data Access Object
接下来,我们就逐个介绍每个模式,建议首先阅读《Java 设计模式》,有助于理解Java常见的设计模式。
1. 表示层模式:如何创建结构合理的表示层,明确每个组件的角色使命(1)截获过滤器 Intercepting Filter(2)前端控制器 Front Controller:处理请求的初始点,集中处理请求,用派遣器委托到下一视图。用帮助器分解不同功能(验证、授权)到不同模块。
(3)视图帮助器 View Helper
(4)复合视图 Composite View
(5)服务/工人 Servie-to-Worker:派遣器用帮助器将数据推到视图中(先获取数据,再显示视图)。控制器的责任更大些。
(6)派遣视图 Dispatcher View:派遣器用帮助器将数据拉到视图中(先显示视图,再获取数据)。
2. 业务层模式:如何使用EJB 实现业务逻辑
(1)业务代理 Business Delegate
JNDI是Java EE应用中常用的资源定位机制,客户机需要知道要使用和查找的资源,还是有些麻烦。
使用业务代理模式后,客户机不再直接跟JNDI打交道,而是交给业务代理打点一切,客户机完全感觉不到是在做复杂地远程调用。
(2)值对象 Value Object
(3)会话门面 Session Facade一个Facade代表一组相关的用例,一个粗粒度的方法映射一个用例。
客户机(一般为业务代理)对Facade的调用虽然为远程调用,但Facade对其它EJB的调用可以使用EJB容器优化,如本地接口。消息门面 Message Facade也是一种Facade模式,只不过是用消息驱动Bean来实现的,可以异步执行。
(4)值对象装配器 Value Object Assembler
(5)值列表处理器 Value List Handler
(6)服务定位器 Service Locator。
3. 数据层模式:如何抽象不同数据源
(1)数据访问对象 Data Access Object
接下来,我们就逐个介绍每个模式,建议首先阅读《Java 设计模式》,有助于理解Java常见的设计模式。
JavaEEDesign_001:何谓设计模式?(摘录+整理)
1. 定义
设计模式是在一定情境下的具有普遍性的问题的重复性的解决方案。
2. 四要素
(1)模式名称
(2)所针对的问题
(3)解决方案
(4)结果评估
3. Java EE技术与Java EE设计模式之间的关系
Java EE包含很多技术标准:参见《JavaEE_001: JavaEE5.0是个啥东东?》。掌握这些技术并不容易,但仅仅学习这些技术并不能够设计出优秀的Java EE应用,因为这些技术只回答了如何使用的问题,而没有回答何时使用和为何使用。
学好Java EE技术是开发Java EE应用的基础,但要想成为一名优秀的设计人员,还必须知道:
(1)哪个问题使用哪个技术。
(2)每种技术的最佳用法。
而Java EE设计模式能够告诉你这两个问题的答案。
Java EE设计模式按适用范围可以分为域特定模式、语言和平台特定模式、通用模式。
参考文献:
1. 《实用J2EE设计模式编程指南》
2. 《J2EE核心模式》
设计模式是在一定情境下的具有普遍性的问题的重复性的解决方案。
2. 四要素
(1)模式名称
(2)所针对的问题
(3)解决方案
(4)结果评估
3. Java EE技术与Java EE设计模式之间的关系
Java EE包含很多技术标准:参见《JavaEE_001: JavaEE5.0是个啥东东?》。掌握这些技术并不容易,但仅仅学习这些技术并不能够设计出优秀的Java EE应用,因为这些技术只回答了如何使用的问题,而没有回答何时使用和为何使用。
学好Java EE技术是开发Java EE应用的基础,但要想成为一名优秀的设计人员,还必须知道:
(1)哪个问题使用哪个技术。
(2)每种技术的最佳用法。
而Java EE设计模式能够告诉你这两个问题的答案。
Java EE设计模式按适用范围可以分为域特定模式、语言和平台特定模式、通用模式。
参考文献:
1. 《实用J2EE设计模式编程指南》
2. 《J2EE核心模式》
订阅:
博文 (Atom)