电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

进入Harmony 世界,类库开发最佳实践


发布日期:2024/6/19
 

Apache Harmony 是 月宣布的开放源码 Java SE 实现本文是由 部分组成的 进入 Harmony 世界 系列文章的第四篇这个系列主要介绍 Apache Harmony 项目的内部实现最新发展现状和开源 Java 开发的模式并鼓励和欢迎大家参与到 Harmony 的社区中来

本文较详细地介绍了 Harmony 项目类库(API库)开发过程当中的经验从架构设计和软件工程的角度介绍了类库开发过程当中积累的类库模块的划分测试优先的开发模式结对编程代码审核等等最佳实践

类库模块划分

类库模块的划分是 Harmony 项目类库总体设计上的主要特点通过将庞大的 JSE 类库划分为若干个相对独立而且小规模的功能模块Harmony 的开发者简化了类库实现的过程降低了开发类库的风险类库模块的划分原则和具体划分方式是项目进行和结构设计实践当中不断总结和归纳出来的

Harmony 模块化背景和目标

实现一个完整的兼容的开源 JSE这是一种很棒的开创性的想法但它的实现有着相当的难度有很多的问题需要注意开源软件的开发流程具有一定的自由性和不确定性通常的情况是来自世界各地的开发者在一个组织的统一协调下分工合作不定期的提交一些功能模块然后集成到一个大的平台产品当中这样的开发方式是开源软件的固有特征但是对于 JSE 这样的庞大体系这样的开发模式会增加产品的风险为了减小风险便于平台的升级和维护就要充分考虑以下问题合理的划分平台定义好模块之间的接口以及降低耦合性总结来说有以下几个目标

    符合 JSE 基本结构

    与现有的 JSE 实现功能上兼容的同时在基本的大的组件方面也要做到一致如 JVM类库JIT 组件等等大规模组件必须对应一致这样可以使 Java 类库的开发工作易于管理开源社区的参与者可以集中开发他擅长的模块

    独立开发

    为了开发的便利和风险的降低平台的模块必须实现独立开发各个模块之间尽量减少耦合这样才可以发挥开源项目的优势避免其缺陷

    模块替换

    在 Java 的开源世界里随时都有很多开源软件的出现如果出现了某些优秀的开源 JSE 组件应该允许它们方便的替换进来另外如果发现本身某一个模块实现上的不足也可以方便的替换出去而不影响整个平台

    共享组件

    除开提供完整的 JSE 实现这个项目的另外一个有价值之处就是在于为开源社区提供共享的 JSE 组件这个目标十分重大因为一个完整的 JSE 平台本身就意味着了聚集了很多有价值的组件所以平台的设计必须确保这些组件可以方便的被共享和重用

针对以上目标在 Harmony 项目中采用了模块化的划分方式在 Sun 公司的最初设计里面根本没有考虑过对 Java 模块化也没有开源的想法所以原有的耦合性是比较大而且这个划分既要有全局的划分即把整个 JSE 划分为几个大的组件如 JVMAPI 类库Tools 等等也有对组件内部的划分例如把类库进一步划分成一些模块不同的模块实现不同的功能

类库设计

完整的 JSE 平台的模块化设计首先应该在最抽象的层次按照设计目标划分出整体的模块组件规定好它们的互联规范比如对类库虚拟机间接口的定义然后应该在比较具体的层次在比较大的组件当中再次划分子模块例如类库的进一步划分

类库(Class Library)是 JSE 当中最复杂和最常用的部分它为 Java 开发者提供了丰富的编程接口给 Java 应用程序提供了基础类库Harmony 类库的目标是要实现一个标准 JSE 类库和现有的 Sun 的 JDK 兼容一致虽然不会增加特性但是在完全不涉及 Sun 的源代码的前提下仅仅依靠公开的 Java 文档设计和开发这样的类库依然是一项艰巨的工作

Harmony Class Library 分为三十多个模块如果我们从上下层次上看它们主要上分为以下四个大类主要模块如图所示

图一 类库划分总图

应该注意到这个划分和 Sun 公司的 JSE 结构图并不相同这是因为Harmony 为自己项目的特点对已有的基于包(package)的类库结构按照功能重新分析和归类有的模块是从包中划分出来如 instrument 模块做 Java 虚拟机的类重定义和管理功能它本来是 javalang 包当中的子包但是由于功能的独特所以就被单独分为一块

下面逐一介绍这四大类和主要的模块

    基础模块 (LUNI) 与 NIO

    LUNI 是 LangUtilNetIO 这些模块的首字母总称他们和新的 NIO 模块一起表示类库的基础和核心部分处于类库的底层当然LUNI 当中也有些独立分出模块的子包如 instrumentmanagement 模块这些模块作为虚拟机监测工具类库就不属于 LUNI

    之所以要把 LUNI 和 NIO 同看作为基础模块是因为它们互相之间有着密切的联系在实际实现中它和 IO 和非常多的底层公用两者有紧密的联系如 NIO 当中的 SocketChannel 和 NET 中 Socket 基本上就可以共用同一套底层代码

    Lang 模块就是 javalang 包中的基本模块JVM 中的 ClassString反射和引用等类虽然在 lang 包里面但不属于这个模块(属于VMI) javalanginstrument 和 JMX(Java Management Extension) 中的 javalangmanagement 子包也不属于这个模块Lang 模块主要包括基本的语言方面和类型方面的类如基本类型的包装类(Byte Boolean 等)基础的接口和抽象类(如 Comparable 接口和枚举抽象类 Enum)等等另外 中的用于实现元数据技术的注释模块(javalangannotation)的新模块也属于这个模块

    Util 模块就是 javautil 包当中的基本模块(它并不包括 util 当中的任何子包因为这些子包都各自有独立的功能被分成了其他模块)Util 模块包含了 Java 当中最常用的集合框架(Collection Framework)集合框架当中定义了最常用的集合数据结构的表示接口如 SetMapList 等以及这些数据结构的不同具体实现如 HashSetTreeMapLinkedList 等还有一些集合工具类如 Arrays提供了基本的集合操作算法(插入查找和排序等)这个框架当中的接口和类极为重要不仅被应用程序频繁使用而且许多类库的实现也依赖它们所以说这个框架的性能和功能在一定程度上决定了类库的性能和功能

    Util 模块还包含了一些常用类如时间和区域相关的 CalendarTimeZoneLocale 等类格式输入输出类 FormatterScanner随机数生成类 Random用于全球化的 ResourceBundle 类等等

    Net 模块包括与网络操作相关的模块主要在 包里面Java 语言最开始的一大亮点就是对网络的强大支持在 Net 模块当中网络当中的抽象概念如 URLProxySocket(甚至有缺省的 http/ftp 等协议的实现)等都被方便的提供出来使得开发者不用关心底层网络实现大大提高了网络程序开发的能力

    IO 是基于流的输入输出模块由于性能上的缺憾以及对异步 IO 的要求NIO 作为一个新的 IO 模块加入了 Java 库IO 和 NIO 联系紧密在 NIO 出现以后IO 当中的绝大部分都用 NIO 重新实现了NIO 基于缓沖(Buffer)实现了异步 IO对于文件网络等基本 IO 都做了新的实现和优化

    NIO 是新的 IO 模块的缩写(除了字符集(Charset)以外的模块)它是 Java 提出来的最重要的新特性之一与旧的 IONET 模块相比它支持非阻塞模式(nonblocking)提出了 Buffer 概念来替代数组目的是提高整体的 IO 效率

    通用模块 (Common)

    在 LUNI 的上面是许多相对独立的模块组成的通用功能模块区其中有很多是从 javautil 包当中分离出来的这些模块一般是实现了 Java 某一重要方面的专门功能这些功能适用广泛可以为桌面应用程序和企业级服务程序提供丰富的数据结构和操作功能

    Concurrent 是 JSE 版本提供的新组件这个模块主要提供 Util 模块当中集合框架的线程同步功能是一个帮助开发者简便实现线程安全的容器和集合的模块这个模块虽然主要为集合框架提供支持但是它的工作是多线程方面的为了独立开发的需要被单独分为一个模块

    Archive 模块实现了 zip 压缩文件的算法提供了 jar 文件(使用 Zip 算法的压缩文件)生成读取和管理的功能为 Java 程序的压缩发布和传播提供了便利

    Log 模块(logging)是提供程序日志信息管理的组件这个模块实现了多种形式的日志信息表示方式(文件控制台网络流等)提供了多种日志权限的管理为记录程序的运行状态和 debug 提供了便利

    Prefs 模块是提供用户配置信息管理的组件这个模块比较特殊因为它必须为不用 OS 平台提供不同的 Java 实现

    Regex 模块是提供 Java 正则表达式的组件这个模块实现了类似 Perl 语言的正则表达式支持提供了字符串验证查找等功能这个模块被 Java 类库和应用程序广泛使用提高了软件开发中字符串操作的效率和可靠性

    Charset 模块是 javanio 的子包是提供 Unicode 字符集管理和转换的组件虽然这个模块被定义在 nio 的包当中但是它只是用到了 nio 的数据结构而已功能上比较独立Harmony 在设计时将它单独分开

    Text 模块是一个文本解析组件这个模块实现了文本格式管理和解析功能

    SQL 模块是提供通用数据库 SQL 语言操作和查询的组件这个模块提供了对于数据库查询和操作的一般框架和数据结构

    其他的通用模块还包括数学 Math 库Java Beans 等等

    企业级模块 (Enterprise)

    企业级模块区由一些比较高级的企业级应用模块组成虽然它们被称为企业级模块并不代表只被用于企业级系统开发当中而是指它们一般被 JEE 程序应用涉及一些企业级的特性和功能某些企业级模块在桌面应用当中也会用到甚至于还十分基础和重要如 Security 模块

    这个模块区的划分主要是因为平台实现的原因因为这些模块有一些通用的特性与企业级应用相关如 XMLRMI 等这样符合设计的目标利于独立化开发

    Security 模块既包括 javasecurity也包括 javaxsecurity及其子包它们定义了丰富的安全性概念和操作这个模块当中的某些部分比较底层甚至出现在 JVM 的类库当中但是主要的功能还是用于企业级应用的安全验证例如标准的公开密钥算法授权证书报文摘要等等所以这个模块被分到了企业级模块类

    JNDI 模块存在与 javaxnaming包及其子包当中是一个典型的企业级应用模块用于企业级命名空间管理JMX 模块是一个 版本新引入的模块存在于 javaxmanagement 当中实现了对 Java 平台自身的监控和管理它的出现是 Java 在自身信息管理方面的发展

    SQL 模块提供了标准的 SQL 数据库访问构架JDBC 模块存在于 javaxsql 当中和 SQL 模块不同的是它提供了一种具体的数据库访问功能而非通用的框架等等

    客户端模块 (Client)

    客户端模块主要指的是桌面应用程序用到的模块例如用户界面 swingawt 和 applet 等等这个模块在 Java 语言的早期比较流行但是这些桌面应用因为它们比较慢而且用户界面比较差而不受重视尤其是新的 Java 用户界面库 SWT 的出现以后随着 Java 的进一步发展AWT 和 SWING 也有了进一步的发展最近 JSE它们已经比较完善了而且Harmony 对 JSE 平台兼容性的要求也需要开发者去实现它们

    这些模块包括 applet 模块 awt 界面模块 swing 界面模块print 打印功能模块sound 声音处理模块Swing 和 awt 界面模块占据了整个 JSE 平台 Java 代码量的相当大一部分据称几乎超过 %

测试优先开发模式

有了类库模块的划分开发者就可以针对某一个模块进行具体的开发了在具体的类库开发过程当中开发者必须保证代码的正确性以及代码行为跟已有参考实现 RI(Reference Implementation即现有的商业 JSE 的实现如 Sun 的 JDK)的兼容性这些必须通过详细的单元测试来保证在实践当中Harmony 的开发者采取测试优先的开发模式来保证这一点

测试优先或者称测试驱动(Test Driven)的原则是为了保证软件的质量将软件的测试优先考虑在分析设计实现和集成等等开发步骤当中首先完成相应的测试代码来保证软件产品质量的原则这是 XP (极限编程)实践当中一个很重要的内容

在 Harmony 项目当中由于开源的 JSE 实现必须和现有的商业的 JSE 实现保持兼容所以测试优先原则受到了十分的重视我们根据项目特点在实现 API 库的开发过程中提出了具体的测试优先实践方案用于 API 实现的单元测试开发一个具体的 Java 类时采用以下的流程

    阅读规范

    首先开发者将仔细阅读这个类的 API 公开的规范文档以充分了解这个类的基本情况和功能其中每一个公开函数和公开域的含义和功能必要的数据结构和算法特殊情况的处理方法和异常抛出的规则以及类与类的公开函数间的关系等等有了这样的了解就可以对这个类的实现以及在整个模块中它起的作用有一个详细的认识

    完成单元测试代码

    根据以上了解开发者将使用 JUnit 这个测试工具编写相关的尽可能完备的单元测试代码覆盖文档上所提到的所有可能的输入输出情况和对象状态情况

    一般针对每一个类开发者都要实现一个 JUnit 测试类(test class)针对这个类当中的每一个方法要实现若干个测试方法分别对应于不同的输入输出对象状态要覆盖所有正常和异常情况针对规范中提到的其他特性例如多线程同步和序列化支持等也要给出相应正常和异常的测试而对每一个包(package)都有一个测试包(test suit)

    在 Harmony 的进一步开发过程中也有人提出使用 TestNG 等测试构架用于 Harmony 这种大规模的总的单元测试现在这个还在讨论中

    测试 RI 的实现

    有了这些的测试代码开发者可以开始测试 RI 的具体表现开发者在 RI 的实现下运行测试将不通过的测试进行分析和修改确保测试全部通过当然有些时候开发者可能发现 Sun 的实现并不符合规范要求或者和基本逻辑不符这个时候开发者记录这个差异然后保持测试结果与 API 规范的要求相一致

    这一步的主要目的是在分析和修改这些测试的过程当中开发者可能会发现原有测试代码当中很多不完备和没有考虑到的情况通过测试可以进一步完善测试代码

    编写实现代码

    当测试通过了以后开发者等于已经从规范定义和代码实例两个方面掌握了这个类的行为和特性可以开始正式编写开源的实现代码了当然在编写过程中测试代码也可以进一步的完善

    测试实现代码

    最后开发者将开源的实现代码通过测试在测试中开发者需要不断的修改自己的实现使得开源的实现和 RI 的实现一样同样全部通过测试(当然RI 的 Bug 部分除外)这样开发者最终得到了一份和 RI 的实现兼容的开源实现

    在此同时我们还得到了一份可靠的单元测试代码这份测试代码可以被反复的使用并且实现测试的自动化十分有利于项目的增量开发和持续集成中的回归测试

测试优先的主要流程如图所示

图二 测试优先流程

Harmony 项目当中使用的流程是一个测试优先原则的很好实践在这里测试不是一种附加的技巧不是为了写测试而写测试而是实现实际代码的必经之路在现在一般的软件项目当中虽然测试优先是一个被反复提倡和强调的概念因为开发者如果不写测试工程依然可以被开发出来(尤其是大量时间比较紧的项目)这时的测试就是一个可能被忽略的环节但是这样会出现质量隐患而在 Harmony 项目的特点就是我们开发的软件必须要和现有的实现保持兼容而且公开的文档很难直接指导实现工作有很多的细节必须通过对现有实现的单元测试来得到答案没有测试开发根本无从下手这时的测试就成了不可能被遗忘和忽略的一环而且因为有了现有 RI 的实现测试可以被提前开发出来并且得到了进一步的优化和测试这样这个开源项目就真正实现了测试优先

结对编程

有了以上的开发方式Harmony 的开发者如何在团队协作的环境下来有效的实施这些原则和方法呢?在实践当中开发者总结和归纳出了一套以结对编程为主的团队协作方式

结对编程(Pair Programming)也是 XP 当中的一个重要实践它的基本理论是两个开发者结成开发对子一起开发一个模块一个人编码的时候另外一个人在旁边进行检查和核对随时对编码过程中的错误和疏忽做出纠正这个开发模式似乎是在浪费人力资源让两个开发者干一份工作但是在很多项目的开发当中这种模式可以大大降低程序修改和返工的概率提高质量总的来说反而提高了人力资源的利用因为两个开发者都在干有意义的事情并没有浪费人力

在 Harmony 项目当中基于测试优先的原则开发者提出了自己的结对编程实践方法如图所示两个开发者组成一个开发对子(Development Pair)一起阅读两个类的 API 规范文档 然后两人分别完成一个类的测试代码接着两人交叉换位依据对方完成的测试代码完成另外一个类的实现代码

图三 结对编程

这样虽然两人没有如传统结对编程里面提到的那样直接监督对方编程但是通过测试代码两人实现了相互独立的检查对方的工作使得任何一个类都有两个人来完成增加了交流机会和发现问题的机会提高了产品的质量这个方法基于测试工作的重要地位以及测试优先的工作流程是保证开源项目品质的一个很有效的方法

代码审核

对于这个项目而言代码本身就是产品需要开放出来给全世界的人看所以代码的可读性和书写规范就变得十分重要为此开发者制定了统一而严格的规范(Checklist)使用公认的优秀的编码风格来实现这个平台从变量命名的规范到程序结构的安排这个规范十分清晰而完整

为了保证这个 Checklist 被很好的落实开发人员在 Development Pair 的基础上在某些情况下(如新成员加入对工作尚不熟悉时)添加了一个新的角色代码审核员(QA)

一般地在需要 QA 的 Development Pair 当中有 Level 和 Level 两个 QA 角色Level 的 QA 主要负责检查结构和代码的缺陷和隐患例如可能的 Bug不妥的设计结构等等Level 的 QA 主要负责检查除开 Bug 以外的表面上的问题例如注释的书写问题代码命名规范和容易引人混淆的代码书写等等

这样的安排主要是为了加速培训新成员(对于 QA)以及保证代码质量(对于 Development Pair)在实践当中有着很好的效果为了在一定时期内可以最大程度的调动成员的积极性也为了让每个成员都有机会在不同的角色上面得到锻炼开发人员设计了一个轮换游戏(Rotation Game)以一定周期内的表现来决定下一个周期各位开发人员的角色

这个游戏的规则比较灵活以三个 Development Pair 为例Rotation Game 的规则如下图所示其中蓝色表示代码开发人员黄色表示 Level 的 QA红色表示 Level 的 QA每一个小Pair代表两个人的对子

图四 轮换游戏

在实践当中这样的 QA 代码审查和角色轮换的工作大大提高了代码的质量这样的工作方式和上述单纯的结对编程方式相结合灵活应用很好的保证了 Harmony 项目的代码质量要求

除开人工审核以外自动审核的作用也很有效除了使用 Eclipse 内部的代码格式化功能以外开发者还统一将 Eclipse 内部的代码编译要求提高将所有被忽略的代码规范要求都设置成警告级别使得代码中的很多小问题例如注释的格式不对等等都成为了警告开发者原则上必须消除所有警告如图所示另外开发者还使用和配置代码检查工具 Checkstyle对代码的深层次问题例如可能出现的内存洩漏都做出了检查

图五 代码审核自动化的手段之一

此外开发者还定期召开代码审核会议利用以前积累的经验规则用人工检查的讨论方式来改进代码质量这也是开发者之间促进交流和沟通的一个很好方式

除开静态的检查以外开发者还会使用 Purify 等动态检查工具用实际运行的方式来发现程序的缺陷如内存洩漏问题等

结束语

本文介绍了 Harmony 项目进行当中尤其是在 API 库开发过程当中逐渐积累和总结出来的最佳实践经验这些经验不是不变的而是随着项目的进行逐渐改进

参考资料

学习

阅读 进入 Harmony 世界 系列文章的其它部分

从 Apache Harmony 项目的 官方网站 中获得更多相关信息

了解 Harmony 的类库 API 的覆盖率统计报告 JDK JDK

如何 参与 到 Apache Harmony 项目

定制 bugzilla 进行项目管理(developerWorks Java 月) 介绍了如何在 Apache Harmony 项目中使用流行的缺陷跟蹤系统 — Bugzilla

追求代码质量 专栏来自质量专家 Andrew Glover 关于测试覆盖工具方面的专家意见

让开发自动化 专栏专门探索软件开发过程自动化的实际应用

揭开极端编程的神秘面纱 专栏帮助您理解 XP并解释为什么它这么重要

获得产品和技术

Apache Harmony 的二进制版本 下载

IBM Apache Harmony 开发包(VM Environment) 下载

IBM JDK 下载

作者简介

罗毅 就读于南京大学计算机系研究的领域包括软件过程和工作流您可以通过a联系到他

蔡一超就读于南京大学软件学院 对java和Linux技术有浓厚的兴趣您可以通过联系到他

胡睿目前就职于 IBM 中国开发中心 Harmony 开发团队 主要负责类库开发的技术工作对 JSEJEEC/C++全球化技术软件测试等有浓厚的兴趣另外他对历史电影音乐与羽毛球等也十分热爱您可以通过联系到他

上一篇:Task和Activity相关(zz)

下一篇:使用ActionForm一次获取表单的所有参数