从 0 到 1 工程实践 (1)

叁叁肆2018-11-13 11:02

欢迎访问网易云社区,了解更多网易技术产品运营经验。


做一个互联网产品,首先就要把项目的基础框架搭好,方便后续的开发。很多产品开 始开发的时候,都不太注意规范化,待产品需求越来越复杂,人员越来越多时,整个项目 会变得很难维护,甚至会影响产品的持续迭代。没有规范化的构建发布流程,容易导致出 错,特别是工程结构越来越复杂时,这个问题会更加明显。所以如果项目一开始,就以工 程化的思想去组织代码,以规范化的流程去做构建发布,会给后续的发展打下坚实的基础。

随着项目的发布,至少存在线下、线上两个不同的环境:线下环境用于开发测试,线 上环境用于给客户提供服务。两个环境对运行时的依赖(操作系统及其版本、依赖软件及 版本等)需求是一致的。在传统发布模式下,需要由类似运维人员这样的角色来维护环境 的运行时依赖,各种因素可能会导致虽然需求一致,但实际环境不同,从而为项目的稳定 运行带来风险。


本章首先将介绍一些工程化的实践经验,比如如何组织代码、如何对代码进行版本管 理及如何规范化地进行构建和发布。然后说明环境不一致会导致的问题,以及如何基于容 器技术解决环境不一致问题,并对容器相关的生态系统进行简单介绍。最后结合一个简单 的实战示例,给予完整展现。


2.1 工程化


在产品快速迭代、快速发布的情况下,好的工程实践会引导项目向好的方向发展,不 至于越来越难维护及扩展。对于产品来说,良好的开发习惯、规范化的测试发布流程可以 保证产品的可维护性及质量。


2.1.1 工程模板


要开发一个服务(或者产品),首先就要创建一个工程(或者项目),如何快速生成一个规范化的项目模板,并且按一定规则组织代码,对于项目后续的维护及演进至关重要。 如果一开始不注意规范化,代码组织混乱,就会影响后续的代码维护。


1. 生成代码框架


如果在创建工程的时候,通过工具生成一个简单的代码框架,对开发人员来说就很方 便,后续只需要按照框架的规范去填充代码就行。本节以 Java 生态中一个很重要的工具 Maven 来简单说明如何基于 Maven 生成代码框架。


Archetype 简介

Maven 的目标是提供一个简单并且标准化的构建系统,以业界的最佳实践为开发人员 的开发构建过程提供参考,并为在不同项目间共享依赖包提供一种标准化的流程和规范。 而 Maven Archetype 是 Maven 提供的一个模板工具,通过它可以快速创建一个规范化的项 目框架。Archetype 将某一类工程所共有的模式抽象成一个模板,而且会包含实际项目的一 些实践经验或者规范,可以帮助开发者快速创建工程框架,并保持良好的风格。


Maven Archetype 提供了很多模板,可以通过 mvn archetype:generate 来查看模板列表。 基础的模板如表 2-1 所示。


表 2-1 Maven Archetype 基础模板

基于 Archetype 生成框架

我们来看一下如何基于 Archetype 提供的模板生成一个简单的 Maven Web 工程。
mvn archetype:generate \ -DarchetypeGroupId=org.apache.maven.archetypes \ -DarchetypeArtifactId=maven-archetype-webapp \ -DgroupId=com.netease.example.shopping \ -DartifactId=web \ -DinteractiveMode=false
基于上述命令,我们就可以生成一个简单的 Web 工程框架,生成的工程目标结构如下。



可以看到,工程根目录下有一个 pom.xml 文件。POM(Project Object Module,项目对 象模型)文件是 Maven 的核心配置文件,它会定义工程的基本属性,如工程名称、版本等, 也会定义工程所依赖的组件,构建所需要的一些插件及配置信息等。


webapp 目录下会存放一些与 Web 页面相关的内容,如 JSP 文件、静态文件(HTML、 JS、CSS 等) 、模块文件(FTL 等)等。而 resources 目录下会存放一些与配置有关的文件, 如数据库配置文件、缓存配置文件、Web 框架配置文件(Spring 的配置文件)等。


2. 代码分层


通过 Archetype 生成一个基础项目框架后,就需要我们去填充代码。在实际的开发过 程中,有一些基本的规范去组织代码。
MVC(Model-View-Controller,模型-视图-控制器)是一种设计模式,在开发中,我 们也会以此为原则把代码分成 controller(控制器)层、service(业务逻辑)层、dao(数 据访问)层和 meta(模型)。


接口与实现分离也是日常开发中需要注意的,这个规则背后是面向接口编程的思想。通 过接口向外暴露服务,而隐藏实现细节,使用方只通过接口来使用服务,这样既可以保证在 某个接口实现变动时,不影响使用方,也可以在需要的时候通过替换接口实现来改变系统 行为。比如之前的 Web 工程,按照上述分层原则,添加一些与用户操作相关的代码如下。



我们在其中的 resources 目录下放置了数据库访问的配置文件。


3. 单元测试


单元测试是指对软件系统中最小的集合例如方法或函数级别进行测试和验证。单元测试 是最低级别的测试活动,这个阶段重点在于验证一个函数的输入输出是否符合设计,而不是 验证功能或特性,也不是测试服务提供的接口。单元测试一般都由开发自己完成。


单元测试的目的是在项目早期排查业务代码中比较初级的问题,并且维持系统一个健 康的生态圈,在后续不断修改代码的过程中保证最基础的产品质量(例如开发人员不小心 修改了前人开发的逻辑导致单元测试失败,就需要排查是真正的设计需要还是不小心引入 了问题)。相比有单元测试的项目来说,无单元测试的项目更像是在裸奔,毫无安全感。在 单元测试中一般会将测试代码直接集成到业务代码库的方式来维护和运行,使用 Java 语言并且使用 Maven 工程的业务代码都会有现成的结构以供开发者直接添加,如下所示。



单元测试一般使用一些用例管理框架来组织自己的测试代码,例如 JUnit、TestNG 等。 一般单元测试运行的时候不会真正启动服务,假如业务代码依赖其他模块或者服务,则可 以使用 Mock 的方式,尽量做到单元测试执行的时候不依赖其他模块或函数。Mock 的方式 有很多,在 Java 中可以用 PowerMock、Mockito 等工具来完成。


文章节选自《云原生应用架构实践》 网易云基础服务架构团队 著 


网易云计算基础服务深度整合了 IaaSPaaS 及容器技术,提供弹性计算、DevOps 工具链及微服务基础设施等服务,帮助企业解决 IT、架构及运维等问题,使企业更聚焦于业务,是新一代的云计算平台。点击可免费试用