虽然在几乎所有的项目中一些相同的问题不断重复出现,但是我们仍然缺少明确的方法来解决它们。 在软件开发的职业生涯中, 我使用了一些方法来解决这些重复出现的困扰我的大部分开发项目的问题,这些方法真正有助于项目执行效率的提升。本文中,我将与各位分享3项项目执行的最佳实践,其中的某几个方法有充分的资格可以被认定为模式(pattern)。
· 使用模板代码
· 编写高效的开发手册
· 执行自动化代码检查
使用模板代码
开发者可以从参考简单的业务用例和复杂的业务用例的示例代码实现中获得帮助,编写出有效、高效率的代码。考虑下面的一些经常困扰软件开发项目的因素:
· 技术始终在变化,要找到对于新技术具有使用经验的有竞争力的技术人员是很困难的事情(译注: 去做猎头吧!)。另一方面,开发新手可能不具备编写有效正确代码的经验。模板代码为开发者的工作提供了良好的参考,使得学习新技术变的相对简单。
· 学习利用新技术需要时间,而且如果使用不当可能导致一团混乱,因此强迫开发者自己学习新技术不是很好的途径。 作为替代方法,提供模板代码作为开发者编码的参考使得开发者在开发过程中获得了学习新技术的良好起点。
· 许多项目必须由有限的人员在紧迫的期限内完成。项目团队中的每个人都不应该重新造轮子。高级技术人员可能在设计阶段提供帮助,不过项目进行到实现阶段可能就要求程序员自助了。一不留意的小问题,到了发现的时候可能已经造成了混乱。问问自己,使用Javadoc工具的时候,有几次遵循了标准的格式和文档生成指导方针呢?代码是否遵循了定义良好的习惯用法和最佳实践呢?那么如何贯彻这些良好实践呢?此处,可视的模板代码能够提供比技术书籍或者参考手册更有效的帮助,因此,应该使用模板代码。
· 许多软件项目不仅体积庞大,而且分布式地进行开发。有时,项目的执行是同时在世界上的不同地点展开的。作为开发人员你不想看到——当你的项目部分接近完成时,你的代码的客户惊奇的发现你的代码没有满足他们的需求。应该在开始编写代码实现功能前,将示例代码送给你的客户评审,并记录反馈。这些示例代码不应该仅仅是类似”世界,你好”的程序,应该具有代表性,与实际编写的代码很接近。
· 通常开发者都有一堆参考手册、标准、程序框架等资料,可以在项目中通过它们来获得帮助。但是,即使已经完成了设计工作,编码的风格也不是显而易见的,难以遵守。可视的模板代码可以提供这方面的帮助。除非开发者可以看到真实的代码例程,否则他们对当前项目的解释彼此间可能有些许的出入。 一个简单功能由多个开发者来实现,其实现方式可能是不同的,甚至可能没有一个与推荐的模拟最佳实现的方式相同。
模板代码的实现
首先,召集一组专家(技术上的和业务上的)从目标项目的问题域中甄别出简单用例和复杂用例各一个,并在现有设计的基础上分别实现这两个用例。这样,项目组就拥有了自己的模板代码。下面列出了一些编写模板代码的小技巧
· 模板代码中应该包含立即可用的编译和部署脚本。否则,在开发的构建阶段解决这些问题又要浪费不少时间。
· 项目的基本目录结构应该准备完毕,并且包含了欲在项目中使用的各种库。
· 模板代码应该遵循项目中使用的命名规范、代码风格、其它标准以及应用框架的要求。
· 模板代码中应该使用定义良好的Javadoc模板(比如、基于Eclipse的Javadoc模板),以帮助开发人员编写javadoc注释。编写良好的javadoc注释是很重要的,通常这些注释可能是代码维护和再开发团队的唯一可用的文档。
· 程序语言中明确的编码惯用法应该在模板代码中使用,这有助于开发者编写有效的代码。
· 模板代码应该明确定义使用开发框架的标准方法。对于新的开发者来说,在项目的初始构建阶段编写基于特定框架的实现类是很困难的任务。示例代码有助于新的开发者理解框架等概念。即使框架有许多文档,利用框架进行有效率的开发也并不都是很容易。
· 模板代码应该展示如何利用JUnit或其他测试框架编写测试用例(test cases)。
· 客户的技术团队应该评审这些模板代码,这样他们对于在项目构建阶段结束时的代码质量具有更明确的认识,而不会在最后时刻感到意外。
· 模板代码应该从头到尾的涵盖用例,比如从表示层到数据层。
· 对于模板代码的各种细枝末节应该进行一次详尽的介绍,使得开发者熟悉它们。开发者应该理解在架构的每个层次需要做那些工作、使用了(或者可能使用)那些编码惯用法和最佳实践,以及为什么使用它们。
使用模板代码的好处
· 开发者获得开始编写代码的参考
· 客户与开发者就项目预期质量达成一致,因而避免了通常由于理解差异产生的各种问题。
· 开发者拥有了开始编码工作的骨架。
· 开发者更容易掌握并应用项目中使用的开发框架和各种外部API,这有助于提高开发效率。
· 开发者没有重新造轮子。大部分的最佳开发实践和编码惯用法都摆在了他们面前,这也可以提高开发效率。
有效的开发手册 假设我们必须完成一个日常开发人员为30到50人的大项目。不是所有的开发人员都掌握了需要使用的技术以及遵循的标准。一个项目可能需要使用很多技术以及私有的开发框架。这些框架可能在以后的Java企业项目中使用。有效的在项目间,开发者之间进行大量知识的转移是一个大挑战。知识转移也涉及到如下的一些问题:
· 很多大型项目的开发持续很长时间(1到2年)。我们必须正视这样的事实:软件行业具有相当高的离职率,这是基本的现实也是一个挑战。雇用新人可能很容易,但是教授新人项目知识却又是一项艰巨任务,特别的,考虑到项目的进展不能停滞不前。
· 一些开发者可能不具有期望的技术水平。现在,适时的找到掌握技术的开发者是很困难的。当项目期限很急时,新的开发者没有时间去学习厚厚的技术书籍或者参考手册。一部分人可能工作敏锐、高效,这样可以腾出额外时间来学习并应用新的技术,但是不能假定所有人都会如此。
· 维护一个构建完毕的软件项目同样也是大的挑战。在开发周期后的代码维护工作可能是由客户的IT团队执行的。对他们来说,熟悉项目的技术架构并且改动代码以做出改变很困难。如果没有定义明确的方式来传递这些知识,那么在维护阶段的初期,客户IT团队研读项目代码和设计文档的工作可能会是很沮丧的经历。
开发手册应该能够解决上面提到的问题,但是如何编写一个有效的开发手册呢?
编写开发手册
下面是一些如何编写开发手册的提示:
· 开发手册应该包含全部与搭建开发环境相关的必要信息
· 开发手册的语句应该简明易读。如果阅读的人发现手册很难阅读,这不是阅读者、而是手册编写者的失败。
· 开发手册应该包含大量的示例。示例可以有效地表明手册的内容。
· 请求一位不熟悉项目中所使用的技术的开发者检查开发手册。这样,如果手册内包含会造成迷惑或者不明确的内容,可以在其它人使用本手册前修改这些地方,以使手册更清晰明确。
· 开发手册应该在底层设计阶段,作为阶段任务的一部分完成。当构建阶段开始时,开发者可以有效利用本手册。
· 开发手册需要包括多少信息呢?如何在信息的多寡中平衡呢?开发者不喜欢厚重的手册。但是,开发手册中不能遗漏可以为许多不明确之处提供语境的信息。需要考虑开发者的真正需求,而不是仅仅考虑可以提供的全部信息是什么。使用简单的、直截了当的、渐进的方式来编写开发手册。
· 开发手册的信息提供方式应该与阅读者的阅读直觉相符,而不该是在各处零落地散布着这样那样的信息。手册内容的组织方式应该与现实中开发项目时需要阅读信息的先后步骤一致。 比如,对于Java企业项目,首先需要搭建开发环境,然后开始表现层和应用数据层的编码工作。手册信息也应该以同样的顺序组织。
· 需要明确的是:手册不能迷惑开发者。比如,开发者在编写Struts框架下的Action类时需要使用特定的Xdoclet标签,那么开发者应该很清楚项目中使用的各种XDoclet标签的意义和使用方式。为了查找更详尽的信息,开发者总是可以参考开发手册。
下面我们考虑一个在Java企业项目中的使用的真实地开发手册应该是什么样的,它应该包含的信息细节如下:
· 开发环境搭建的细节:当新的开发者加入项目时,必须搭建开发环境,然后才能开始工作。不要认为开发者清楚项目的大小细节。如果项目一起使用了Eclipse和Weblogic开发Web应用,新的开发者可能都不清楚Eclipse或者Weblogic是什么东东。因此,搭建开发环境的细节信息应该是开发手册的第一部分。具有基本Java知识的新开发者应该很容易的按照手册中的这些信息搭建开发环境。
· 表现层的细节:通常,开发者对某个用例的实现从表现层开始。开发手册中应该包含如何创建表现层组件元素的详细步骤。比如,项目的表现层使用Struts框架,手册中应该包含如何编写Action类和Form类的确定步骤。如果项目使用XDoclet来构建Struts配置文件struts-config.xml和其他配置文件,相应的这些步骤也应该包含在内。JSP的相关技术信息也应该如此。应用MVC模式,无论如何不应该在JSP页面中包含任何Java代码来实现业务逻辑。但是在实际开发中如何使用JSTL(JSP标准标签库)标签来实现那样的要求对于初学者或者是中级开发者可能都是很大的难题。开发手册中包含一些展示如何在JSP页面中使用JSTL标签的真实示例可能对这些开发者有些帮助。
· 业务层的细节:业务逻辑可以应用无状态EJB组件、基于Spring的组件、或者简单的原始java对象(plain-old java object)来实现。开发手册中应包含项目中使用的业务组件代码的骨架以及业务逻辑实现的实际例程
· 数据层的细节:依赖于项目使用的持久化机制,开发手册中应该包含JDBC、Hibernate或者任何基于其它框架的DAO(数据访问对象)的信息,包含项目中如何使用此持久化机制的步骤以及最佳实践。
· 其它信息:手册需提供J2EE项目架构各层中使用的各种内部或者外部组件的信息。例如,应该包括日志、邮件、代码检查和安全等组件的信息。同样的,在项目后期,手册中应该包含一些如何扩展业务需求的章节。比如,项目中使用了批处理框架,那么如何为新的批处理需求扩展它呢?
自动化代码检查 代码检查是另外一项需处理的事项。当代码大量生成时,持续的代码检查是必须的工作。即使已经定义了一套代码检查的规则,还是有许多问题没有办法在这些规则中描述并加以限制。基于个人能力和经验,每个人都有自己的代码检查方式。同时,有些问题很微小,无法进行逐行检查。 如果需要检查的代码数量很大,这些微小的问题可能会在一些地方被忽略掉。如果IDE自身产生了错误又怎么办?还好,有些工具可以替代人工代码检查来发现这些问题。
Eclipse IDE的设置
有时, 设置IDE的选项可以提供些帮助。比如,你可以配置Eclipse IDE的选项,当代码中出现问题时显示警告。下图是如何在Eclipse中设置Javadoc配置选项的示例。
图 1. Eclipse Javadoc 设置
选项设置好后,Eclipse会在出现错误时显示警告信息,然后开发者可以修改。如果项目标准很严格,IDE的警告将升级为错误,开发者必须处理这些问题。
Jlint 代码检查工具
类似的,可以在Eclipse中使用Jlint工具以发现代码中的微小问题。下面是在Eclipse中如何使用JLint的方法和步骤:
· 下载jlint的2进制版本以及相应的Eclipse插件,解压缩2进制版本到C:\lint目录,解压缩插件到Eclipse插件目录。
· 运行Eclipse, 选择菜单项Window(窗口)->Preferences(设置)->Java->Jlint,设定jlint.exe的目标位置为C:\jlint\jlint.exe
· 在Eclipse的资源(Resource)视图中右键点击你的项目,然后选择jlint选项即可。当一次完整地工作区编译后,Jlint会在工作区内可能出现问题的地方显示黄色警告标记。
下图 显示了如何在Eclipse中配置Jlint
图2 Eclipse中Jlint插件的配置
Lint4j
如果不使用IDE,那么可以结合ant使用lint4j发现代码中的问题。Ant脚本中需要声明的参数如下:
· lint4j.dist.dir: lint4j的分发包的安装目录
· packages:需要由lint4j检查的java包名称
· ignorePackages: 不需要由lint4j检查的java包名称
下面是使用jlint的ant脚本示例:
lint4j的Ant Build脚本
<?xml version="1.0"?>
<project name="Lint4j" default="lint4j" basedir=".">
<property name="lint4j.dist.dir" value="C:/tools/lint4j-0.8.2"/> <!—lint4j包的路径-->
<property name="lint4j.level" value="5"/> <!—lint4j检查使用的参数-->
<property name="lint4j.exact" value="false"/> <!—lint4j检查使用的参数-->
<taskdef name="lint4j" classname="com.jutils.lint4j.ant.Lint4jAntTask">
<classpath>
<pathelement location="${lint4j.dist.dir}/jars/lint4j.jar" /> <!—lint4j包的信息-->
</classpath>
</taskdef>
<target name="lint4j" description="Run Lint4j on your source">
<!—lint4j 忽略不处理的java包 需要检查的包 其它参数,详见lint4j文档 -->
<lint4j ignorePackages="" packages="com.domain.*" level="${lint4j.level}" exact="${lint4j.exact}">
<sourcepath>
<dirset dir=".">
<include name="**/src" />
</dirset>
</sourcepath>
<classpath>
<pathelement location="C:/bea/weblogic81/server/lib/weblogic.jar" />
<fileset dir=".">
<include name="**/*.jar" />
<include name="**/*.zip" />
</fileset>
<fileset dir="ejblib">
<include name="**/*.jar" />
</fileset>
<fileset dir="lib">
<include name="**/*.jar" />
</fileset>
</classpath>
<formatters>
<formatter type="text" />
<formatter type="text" toFile="./target/lint4j.log"/> <!—lint4j报告文件-->
</formatters>
</lint4j>
</target>
</project>
Checkstyle工具
代码检查的另一个工具是CheckStyle,它会依照java开发专家广泛使用的Java编码规范来检查代码质量。可以结合Ant使用(也有Eclipse插件)。CheckStyle的检查选项是高度可配置的,可以配置成支持任何代码规范的检查。它的下载版本中包含了一个支持Sun编码规范(Sun’s Coding Conventions)检查的规则配置文件。 编写Ant脚本使得代码检查同编译过程一起完成,这样开发者可以注意到代码包含的错误并改正它们。
结论
在软件开发项目中的需要面对的大部分的普通问题是重复出现的。在如今充满竞争的世界里——缩减开发期限、降低项目成本的压力很大,想在每个项目中重新造轮子根本就没有时间。
本文并未对软件开发执行过程中会出现的问题都提供了解决方案,只是踏出了前行的一步,其目的是展示最佳软件开发实践和高效工具的使用。了解了这些以及未来会学习到的最佳实践和模式,你就对软件生命周期中容易出现的任何障碍做好了准备。这些也可以使得项目管理者、架构人员和开发者能够集中精力进行“真正”的开发,而不是疲于应付开发中出现的各种问题。
希望在未来的软件开发中,更多的专家会贡献并记录更多的最佳实践和模式,软件开发实践作为一门艺术的同时也成为具有更多确定性的一门科学。