0%

250429-可维护性

题目

1、预计:项目信息
2、软件维护的主要内容,提高可维护性的常见方法
3、预计:结合项目说明具体实施过程/遇到的问题及解决方案

简介

近些年,新能源汽车蓬勃发展,我司开发了一个针对新能源汽车的平台,主要包括了:媒体、社区、车型库等模块。我在该项目中担任技术经理,负责系统方案设计及技术指导工作。本文描述了该项目中维护性方面的设计与实施过程,主要包括应用端、服务端、部署运行三个部分。应用端采用 Nodejs 同构框架 NestJS,使用 Typescript 进行代码编写,提高了可阅读性、可修改性。服务端采用分层设计,并使用 REST 风格与应用端通信,并生成标准的 OpenAPI 文档,有效提高了可修改性、可阅读性。部署与运行阶段,采用 CI/CD 工具,实现了代码测试、打包、部署等功能,并使用 Serverless,提高了项目的可靠性、可移植性。

背景

2022 年,新能源汽车蓬勃发展,国家出台了相应的政策支持,此时市面上还没有专门针对新能源汽车的应用平台,用户在检索新能源车型信息的时候,无法快速准确的找到对应信息。为响应国家号召,满足用户需求,我司开发一个针对新能源汽车的一体化平台。

该项目于 2022 年 6 月开始,团队成员共 17 人,我在该项目中担任技术经理,主要负责系统方案定制及技术指导工作。该项目主要包括媒体、社区、车型库等主要模块,其中媒体模块主要为用户提供最新的新能源汽车新闻,主要功能有:简讯、文章、视频、最新车型等功能。社区模块为用户提供了讨论新能源车型的渠道,主要包括了:车友圈、热点话题、发帖、车型口碑等功能。车型库模块是该系统的核心,我们吸收传统汽车平台的经验,并在此基础上增加了一些新能源汽车特有的功能,比如三电系统、智能座舱、辅助驾驶等,并针对这些功能进行评测,建立了对应的评测系统。并由此延伸出选车、评测榜单等功能模块。

问题回应

软件的生命周期中,软件维护是提高系统寿命的一个主要手段,主要分四种维护类型,第一种是正确性维护,主要是修复系统中的 bug;适应性维护,系统状态或者系统数据变更后,系统需要进行更新或者迁移。完善性维护,当系统增加新功能或进行性能方面的优化属于该方面维护。预防性维护,适应未来的一种维护,比如专用的功能改成通用的功能。提高可维护性的常见方法有,提高可阅读性,完善的文档与规范的代码属于此类;提高可修改性,低耦合、高内聚的架构设计可以有效的提高可修改性;提高可测试性,测试是软件开发过程中不可或缺的环节,良好的系统可以更容易的进行测试;提升可靠性,一个稳定的软件,可以有效的降低维护成本。提升可移植性,应用软件的部署环境可能会发生变化,当环境变化时,如果我们采用环境无关的技术,比如 java 的虚拟机或者容器技术,可以有效的降低移植成本。

过度

一个良好的软件,应该是更容易维护的,以下就该系统的应用端、服务端、部署运行三个方面进行论述该项目的具体实施过程与解决方案。

正文

应用端

该项目是针对 C 端的汽车一体化应用平台,考虑到推广的便利性与开发成本,决定使用 B/S 架构。传统 B/S 架构中,一般会使用服务端渲染,但是这种方式,html 与后端的代码是放在一起的,可阅读性较差。这个时候,如果有功能需要进行维护,那么需要前端人员与后端人员同时在一个地方修改,因为前后端分工不同,这种方式明显降低了可修改性。所以我们决定使用前后端分离的方式,前端负责界面与功能交互,后端负责提供数据,降低耦合,提高可修改性。纯前端的应用,需要在浏览器使用 AJAX 技术去动态的获取后端数据,同时使用 Javascript 去渲染页面,最终通过拼接字符串或者模板的方式去生成 html 。这种方式因为没有 IDE 支持,可阅读性差,且修改也容易引起错误,可修改性差,且 javascript 是一种脚本语言,没有类型系统,当项目复杂后,阅读与修改都比较困难。所以我们决定使用基于 React 的全栈同构框架 NextJS,并使用微软出品的语言 Typescript 进行代码编写,并编译成 Javascript 在浏览器与 Nodejs 环境运行。这种方式可以使用服务端渲染,满足推广要求。使用 NextJS 框架 react 技术栈,有 IDE 支持,对开发人员友好,可以方便的生成 html,同时又使用 Typesctipt 语言进行类型控制,极大提高了可阅读性与可修改性。

服务端

服务端采用分层架构,共 6 层,主要包括:中间件层、守卫层、管道层、路由层、服务层、数据层,使用层次化风格的架构,可以有效的降低耦合度,提高可修改性。在与前端的通信上,我们选择 REST 风格的架构,该风格以资源为中心,使用 HTTP 协议进行构建,用不同的请求方式表示对资源的操作,主要有 GET,表示对资源的获取,POST 表示对资源的创建,PUT 表示对资源的全量更新,PATCH 表示对资源的部分更新,DELETE 表示删除资源。这种方式降低了前后端开发人员的沟通成本,同时因为资源定义明确,可以有效的提高可阅读性。我们在使用 REST 风格的时候,也生成了接口文档,在路由层使用装饰器风格的注解,标注每个资源的路由、入参、出参等详细描述,并使用 OpenAPI 标准生成了对应的文档,使用 swagger 工具在开发环境展示,有效提高了可阅读性。同时因为有了对应的标准接口文档,我们可以使用自动化接口测试工具对其进行测试,提高了可测试性。

部署与运行

该项目在设计阶段采用的是云原生架构,我们搭建了 DevOps 相关工具,代码版本管理工具使用 Git,并制定了代码的提交、质量规范,提交前进行预检,预检通过后,提交到 Gitlab 远程仓库,同时对应的负责人进行 Code Review,审核通过后合并对应分支,提升代码质量、可阅读性。当代码提交到指定分支后,自动运行代码检测工具,包括代码格式检测、单元测试等,提高了代码的可阅读性,降低了维护成本。检测通过后,使用容器化技术,将应用打包为 Docker 镜像,并提交到镜像仓库,提高了可移植性。打完完毕后,我们使用云厂商的服务,将应用镜像部署在 Serverless 上,即用即付,有效降低了运行成本,同时使用资源冗余的方式,多实例运行,自动伸缩,提高了应用的可靠性。同时在数据库层面上,我们使用的一主多从的方式进行部署,当某台数据库宕机后,可以自动切换其他节点,提高了可靠性。

结语

该项目于 2023 年 10 月上线,整体运行良好,未出现重大事故。后续我们做了一些完善性的维护,比如在服务端的数据层增加了缓存模块,由于该项目可修改性、可测试性良好,少量改动后便顺利上线。二期工程增加了移动端应用,因为采用 REST 风格架构,文档完善,可阅读性较好,后续也顺利上线。在项目的运行过程中,也遇到了一些问题,比如 Serverless 的冷启动问题,假如服务第一次启动,那么需要云厂商构建 VPC 网络,同时要下载镜像,同时启动镜像成功后,服务才会返回对应的数据,该过程耗时多达数秒,用户体验较差。 因为 serverless 其中一部分功能由云厂商控制,部分环节我们无法参与,所以我们只能对其中一部分功能做优化,比如裁剪镜像体积,降低云厂商拉取镜像的时间。根据不同时段的流量进行预留启动实例,降低冷启动概率。目前冷启动时间与概率已有所降低,镜像裁剪还有优化空间。