本节目标
- 掌握大型 HarmonyOS 应用的模块拆分策略,理解按业务域、按功能层、按团队边界三种拆分维度的适用场景
- 掌握依赖治理的核心原则,能够使用 ohpm 的 override、resolve_conflict 和依赖分析工具控制依赖数量与版本一致性
- 掌握构建优化的关键配置,能够通过增量编译、并行构建、HSP 共享和编译缓存缩短构建时间
- 掌握团队协作规范,包括代码分层约定、命名规范、提交规范和 Code Review 检查清单
- 掌握多环境配置管理方案,能够通过 product/flavor 机制管理开发、测试、生产环境的差异化配置
- 掌握 CI/CD 流水线的搭建方法,能够将编译、测试、性能门禁和签名打包集成到自动化流程
- 能够为一个中大型应用设计可维护、可扩展、可协作的工程架构
一、模块拆分策略
1.1 按业务域拆分
按业务域拆分是最直观的拆分方式,每个业务域对应一个独立的模块。例如一个电商应用可以拆分为首页模块、商品模块、购物车模块、订单模块、个人中心模块等。每个业务模块内部高内聚,包含该业务域的所有页面、组件、数据模型和业务逻辑。
适用场景:业务边界清晰、团队按业务线划分、需要独立开发和测试的大型应用。
核心原则:模块之间通过明确定义的接口通信,尽量减少直接依赖。业务模块之间不应存在循环依赖,可以通过依赖注入或事件总线解耦。
1.2 按功能层拆分
按功能层拆分是将应用按技术职责分为 UI 层、业务逻辑层、数据访问层和基础设施层。这种拆分方式与架构设计的分层模型一一对应。
适用场景:技术栈统一、需要严格控制分层边界、追求架构一致性的团队。
核心原则:上层依赖下层,下层不感知上层。UI 层只负责展示和交互,业务逻辑层负责规则编排,数据访问层负责持久化与网络,基础设施层提供通用工具和日志。
1.3 按团队边界拆分
按团队边界拆分是康威定律在软件架构中的直接体现——系统架构应与组织结构保持一致。每个团队负责的模块可以独立开发、独立测试、独立发布。
适用场景:多团队协作、需要并行开发、模块间接口稳定的大型项目。
核心原则:模块的所有权明确,接口变更需要经过双方评审。每个模块有独立的负责人和 Code Review 流程。
1.4 三种维度的组合使用
实际项目中,三种拆分维度通常组合使用。推荐的结构是:先按业务域拆分为顶层模块,每个业务域内部再按功能层拆分为子模块,最后根据团队边界确定模块的归属和维护责任。
entry/ # 主入口(HAP) ├── features/ │ ├── home/ # 首页业务域(HAR) │ │ ├── ui/ # UI 层 │ │ ├── viewmodel/ # 业务逻辑层 │ │ └── data/ # 数据访问层 │ ├── product/ # 商品业务域(HAR) │ ├── cart/ # 购物车业务域(HAR) │ └── order/ # 订单业务域(HAR) ├── commons/ │ ├── base/ # 基础工具(HAR) │ ├── network/ # 网络封装(HAR) │ ├── storage/ # 持久化封装(HAR) │ └── ui-components/ # 通用 UI 组件(HAR) └── shared/ └── constants/ # 全局常量(HAR)二、依赖治理
2.1 依赖数量的控制
依赖数量直接影响构建时间和包体积。每个第三方依赖都会增加编译时间、增大包体积、引入潜在的安全风险。建议遵循以下原则:
优先使用系统能力:HarmonyOS 已经提供了丰富的系统 Kit,如网络、存储、媒体、AI 等,优先使用系统能力而非引入第三方库。
评估依赖的必要性:引入一个依赖前,评估它是否真的必要,是否可以用少量代码自行实现,是否有更轻量的替代方案。
定期清理无用依赖:项目迭代过程中,部分依赖可能已经不再使用。定期使用依赖分析工具扫描未使用的依赖并清理。
2.2 依赖版本的统一
多模块项目中最常见的问题是依赖版本不一致。模块 A 依赖了 lodash 1.0,模块 B 依赖了 lodash 2.0,打包时两个版本都会被包含,导致包体积膨胀和潜在的运行时冲突。
使用 ohpm 的override机制强制统一版本:
// oh-package.json5(工程级) { "overrides": { "lodash": "2.0.0", "axios": "1.6.0" } }开启resolve_conflict自动解决冲突:
// .ohpmrc { "resolve_conflict": true }2.3 依赖分析工具
使用ohpm list查看工程的依赖树,识别重复依赖和版本冲突。使用 DevEco Studio 的 Build Analyzer 分析各依赖的体积占比,识别体积大户。
2.4 依赖分层的约束
在大型项目中,需要对依赖关系施加约束,避免模块间随意引用导致的架构腐化。推荐使用以下约束:
业务模块不能反向依赖主入口:features 层的模块不能依赖 entry 模块。
业务模块之间禁止直接依赖:features 层的模块之间如需通信,通过 commons 层的接口或事件总线解耦。
公共模块不能依赖业务模块:commons 层的模块不能依赖 features 层的模块。
三、构建优化
3.1 增量编译与并行构建
HarmonyOS 的模块化编译基于 ES Module 的 Bundleless 编译模式,API 10 及以上版本的 Stage 模型工程默认开启。修改单个模块代码无需整包编译构建,增量编译构建时间极大减少。
hvigor 构建系统默认开启并行构建,可以利用多核 CPU 加速构建。在hvigorfile.ts中可以调整并行度配置。
3.2 编译缓存
DevEco Studio 支持编译缓存,将编译产物缓存到本地,下次构建时复用。缓存生效的前提是源文件未变化。建议在 CI 环境中配置缓存目录,加速重复构建。
3.3 HSP 共享减少重复编译
在多模块项目中,将公共代码和资源抽取为 HSP,消除 HAR 导致的重复拷贝。但需要注意:大量使用 HSP 替代 HAR,会在编译引用这些 HSP 共享包的模块时触发更多的语言编译任务,导致编译耗时和编译内存占用增加。需要综合评估包体积收益和编译时间成本。
3.4 构建配置优化
在build-profile.json5中配置以下选项加速构建:
{ "app": { "products": [ { "name": "default", "signingConfig": "default", "compatibleSdkVersion": "5.0.0(12)", "buildOption": { "strictMode": { "caseSensitiveCheck": true, "useNormalizedOHMUrl": true } } } ] } }useNormalizedOHMUrl开启后可以优化依赖解析效率。
四、团队协作规范
4.1 代码分层约定
明确各层的职责边界,避免职责混淆:
页面层(pages/views):只负责 UI 展示和用户交互,不包含业务逻辑。通过 ViewModel 获取数据,通过事件回调触发业务操作。
ViewModel 层(viewmodel):负责业务逻辑编排、状态管理、数据转换。不直接操作 UI,不直接访问数据库或网络。
数据层(data):负责持久化和网络请求,提供统一的数据访问接口。不包含业务逻辑。
工具层(utils):提供无状态的通用工具函数,不依赖任何业务模块。
4.2 命名规范
文件命名:页面文件以 Page 结尾(如 HomePage.ets),组件文件以组件名命名(如 TodoItem.ets),工具文件以功能命名(如 DateUtil.ets),模型文件以 Model 结尾(如 TodoModel.ets)。
变量命名:使用小驼峰(如 userName),常量使用全大写下划线分隔(如 MAX_RETRY_COUNT),类名使用大驼峰(如 TodoViewModel)。
接口命名:以 I 开头或使用描述性名称(如 UserInfo、TodoRepository)。
4.3 提交规范
推荐使用 Angular 提交规范,格式为type(scope): subject:
type 类型:feat(新功能)、fix(修复)、docs(文档)、style(格式)、refactor(重构)、perf(性能)、test(测试)、chore(构建/工具)。
scope 范围:模块名,如 home、cart、network。
subject 描述:简洁的描述,使用中文或英文,不超过 50 个字符。
示例:feat(home): 添加待办搜索功能、fix(cart): 修复购物车数量计算错误。
4.4 Code Review 检查清单
每次提交前自查以下项目:
- 代码是否符合分层约定,是否存在跨层调用
- 是否有硬编码的字符串、颜色、尺寸
- 是否处理了异常和边界情况
- 是否使用了正确的状态管理装饰器
- 是否有内存泄漏风险(未释放的定时器、未取消的监听)
- 是否遵循了命名规范
- 是否有必要的注释和文档
五、多环境配置管理
5.1 环境差异化的需求
一个应用通常需要在开发、测试、生产三个环境中运行,每个环境的 API 地址、日志级别、功能开关都不同。硬编码环境配置会导致每次切换环境都要修改代码,容易出错。
5.2 使用 product 机制
在build-profile.json5中定义多个 product,每个 product 对应一个环境:
{ "app": { "products": [ { "name": "develop", "signingConfig": "default", "compatibleSdkVersion": "5.0.0(12)", "buildOption": { "arkOptions": { "buildProfileFields": { "API_BASE_URL": "https://dev-api.example.com", "LOG_LEVEL": "debug", "ENABLE_MOCK": true } } } }, { "name": "release", "signingConfig": "release", "compatibleSdkVersion": "5.0.0(12)", "buildOption": { "arkOptions": { "buildProfileFields": { "API_BASE_URL": "https://api.example.com", "LOG_LEVEL": "error", "ENABLE_MOCK": false } } } } ] } }在代码中通过BuildProfile访问:
importBuildProfilefrom'BuildProfile';constAPI_BASE_URL=BuildProfile.API_BASE_URL;constLOG_LEVEL=BuildProfile.LOG_LEVEL;constENABLE_MOCK=BuildProfile.ENABLE_MOCK;5.3 配置文件的组织
将环境相关的配置集中到一个文件,通过 BuildProfile 注入不同值:
// commons/config/AppConfig.etsexportclassAppConfig{staticreadonlyapiBaseUrl:string=BuildProfile.API_BASE_URL;staticreadonlylogLevel:string=BuildProfile.LOG_LEVEL;staticreadonlyenableMock:boolean=BuildProfile.ENABLE_MOCK;staticisDebug():boolean{returnAppConfig.logLevel==='debug';}}六、CI/CD 流水线
6.1 流水线的核心环节
一个完整的 HarmonyOS 应用 CI/CD 流水线包含以下环节:
代码检查:运行 Code Linter 静态检测,检查代码规范和潜在问题。
编译构建:执行hvigorw assembleHap构建 HAP 包,开启 Release 模式获取完整优化。
单元测试:运行 Hypium 单元测试,输出测试报告。
UI 测试:在模拟器或真机上运行 UI 自动化测试。
性能门禁:使用 DevEco Testing 运行场景化性能测试,对比性能基线,低于基线则阻断合入。
签名打包:配置发布签名,构建正式 HAP 包。
上传分发:将 HAP 包上传到 AppGallery Connect 或内部测试平台。
6.2 流水线配置示例
以下是一个基于 Jenkins 或 GitLab CI 的流水线配置示例:
stages:-lint-build-test-performance-packagelint:stage:lintscript:-hvigorw codeLinterbuild:stage:buildscript:-hvigorw assembleHap--mode module-p product=defaultunit_test:stage:testscript:-hvigorw test--mode module-p module=entry@defaultperformance:stage:performancescript:-deveco-testing run--task performance--baseline baseline.jsonpackage:stage:packagescript:-hvigorw assembleApp--mode project-p product=releaseartifacts:paths:-build/outputs/default/*.hap6.3 性能门禁的集成
性能门禁是防止性能退化的关键手段。设定性能基线(如冷启动 ≤3000ms、页面切换 ≤1000ms、帧率 ≥60 帧),每次代码合入前自动运行性能测试,低于基线则阻断合入。
DevEco Testing 的性能基线管理能力可以自动记录内存占用、CPU 负载等关键指标,通过历史数据对比精准定位性能退化问题,在性能退化早期发出预警。
6.4 构建缓存与并行加速
在 CI 环境中配置构建缓存和并行执行,可以显著缩短流水线执行时间:
cache:paths:-.hvigor/cache/-node_modules/-oh_modules/build:stage:buildscript:-hvigorw assembleHap--parallel--daemon七、多元化习题
习题 1(判断题)
题目:在模块拆分中,业务模块之间可以直接相互依赖,不需要通过公共模块解耦。
答案:错误
解读:业务模块之间禁止直接依赖,如需通信应通过 commons 层的接口或事件总线解耦。直接依赖会导致模块间耦合度过高,一个模块的修改会牵连其他模块,破坏模块的独立性和可维护性。
习题 2(单选题)
题目:以下哪种拆分维度是康威定律在软件架构中的直接体现?
A. 按业务域拆分
B. 按功能层拆分
C. 按团队边界拆分
D. 按技术栈拆分
答案:C
解读:按团队边界拆分是康威定律在软件架构中的直接体现——系统架构应与组织结构保持一致。每个团队负责的模块可以独立开发、独立测试、独立发布。
习题 3(多选题)
题目:关于多环境配置管理,以下说法正确的有(多选):
A. 使用 product 机制定义多个环境,每个 product 对应一套配置
B. 通过 BuildProfile 在代码中访问环境配置
C. 环境配置应硬编码在代码中以便于管理
D. 将环境相关的配置集中到 AppConfig 统一管理
答案:A、B、D
解读:使用 product 机制定义多个环境,每个 product 对应一套配置,选项 A 正确。通过 BuildProfile 在代码中访问环境配置,选项 B 正确。环境配置不应硬编码在代码中,硬编码会导致每次切换环境都要修改代码,容易出错,选项 C 错误。将环境相关的配置集中到 AppConfig 统一管理,选项 D 正确。
习题 4(代码填空题)
题目:请补全以下build-profile.json5配置,使用override机制强制统一 lodash 的版本为 2.0.0。
// oh-package.json5(工程级) { "______________": { "lodash": "2.0.0" } }答案:overrides
解读:overrides用于强制统一依赖版本。当多个模块依赖同一库的不同版本时,使用overrides指定统一使用的版本号,避免多版本重复打包导致的包体积膨胀和潜在运行时冲突。
习题 5(代码改错题)
题目:以下代码存在架构分层问题,请指出问题并修正。
// features/home/ui/HomePage.etsimport{RdbHelper}from'../../../commons/storage/RdbHelper';@Entry@Componentstruct HomePage{@Statetodos:Todo[]=[];aboutToAppear():void{// 页面层直接访问数据层this.todos=RdbHelper.queryAll();}build(){List(){ForEach(this.todos,(todo:Todo)=>{ListItem(){Text(todo.title)}})}}}答案:页面层直接访问数据层,违反了分层约定。页面层应通过 ViewModel 获取数据,不直接操作数据库。修正方案:
// features/home/ui/HomePage.etsimport{TodoViewModel}from'../viewmodel/TodoViewModel';@Entry@ComponentV2struct HomePage{@LocalviewModel:TodoViewModel=newTodoViewModel();aboutToAppear():void{this.viewModel.loadTodos();}build(){List(){ForEach(this.viewModel.todos,(todo:Todo)=>{ListItem(){Text(todo.title)}})}}}解读:分层架构的核心价值在于职责分离。页面层只负责 UI 展示和用户交互,业务逻辑由 ViewModel 层处理,数据访问由数据层处理。页面层直接访问数据层会导致职责混淆,难以维护和测试。
习题 6(简答题)
题目:简述大型 HarmonyOS 应用模块拆分的三种维度,以及各自的适用场景。
答案:三种拆分维度包括:按业务域拆分,每个业务域对应一个独立的模块,适用于业务边界清晰、团队按业务线划分的大型应用。按功能层拆分,将应用按技术职责分为 UI 层、业务逻辑层、数据访问层和基础设施层,适用于技术栈统一、需要严格控制分层边界的团队。按团队边界拆分,是康威定律在软件架构中的直接体现,每个团队负责的模块可以独立开发、独立测试、独立发布,适用于多团队协作、需要并行开发的大型项目。实际项目中三种维度通常组合使用:先按业务域拆分为顶层模块,每个业务域内部再按功能层拆分为子模块,最后根据团队边界确定模块的归属和维护责任。
解读:模块拆分的核心目标是高内聚低耦合。拆分不是越细越好,过度拆分会导致模块数量膨胀、接口复杂度上升、维护成本增加。拆分应基于业务边界、技术边界和团队边界,找到合适的平衡点。
习题 7(简答题)
题目:简述 HarmonyOS 应用 CI/CD 流水线的核心环节,以及性能门禁在其中的作用。
答案:CI/CD 流水线的核心环节包括:代码检查(运行 Code Linter 静态检测)、编译构建(执行 hvigorw assembleHap 构建 HAP 包)、单元测试(运行 Hypium 测试)、UI 测试(在模拟器或真机上运行 UI 自动化测试)、性能门禁(运行场景化性能测试,对比性能基线)、签名打包(配置发布签名构建正式 HAP 包)、上传分发(将 HAP 包上传到 AppGallery Connect 或内部测试平台)。性能门禁的作用是防止性能退化,设定性能基线(如冷启动 ≤3000ms、页面切换 ≤1000ms、帧率 ≥60 帧),每次代码合入前自动运行性能测试,低于基线则阻断合入。DevEco Testing 的性能基线管理能力可以自动记录内存占用、CPU 负载等关键指标,通过历史数据对比精准定位性能退化问题,在性能退化早期发出预警。
解读:性能门禁是 CI/CD 流水线中防止性能退化的关键手段。没有性能门禁,代码合入后性能可能悄悄退化,等到用户反馈时已经影响大量用户。将性能测试自动化、常态化,在性能退化早期就发现并修复问题。
八、本节知识点总结
模块拆分策略
三种拆分维度:按业务域拆分(业务边界清晰)、按功能层拆分(技术栈统一)、按团队边界拆分(多团队协作)。实际项目中三种维度组合使用:先按业务域拆顶层,内部再按功能层拆子模块,最后按团队边界确定归属。
依赖治理
优先使用系统能力,评估依赖必要性,定期清理无用依赖。使用overrides强制统一版本,开启resolve_conflict自动解决冲突。业务模块之间禁止直接依赖,公共模块不能依赖业务模块。
构建优化
模块化编译默认开启增量编译,hvigor 支持并行构建。配置构建缓存和useNormalizedOHMUrl优化构建效率。HSP 共享减少重复编译但需评估编译时间成本。
团队协作规范
代码分层约定明确各层职责,页面层不包含业务逻辑,ViewModel 层不操作 UI,数据层不含业务逻辑。命名规范、提交规范(Angular 格式)、Code Review 检查清单保障代码质量。
多环境配置管理
使用 product 机制定义开发、测试、生产环境,通过 BuildProfile 在代码中访问配置。环境配置集中到 AppConfig 统一管理,避免硬编码。
CI/CD 流水线
核心环节:代码检查、编译构建、单元测试、UI 测试、性能门禁、签名打包、上传分发。性能门禁设定性能基线,低于基线则阻断合入,防止性能退化。配置构建缓存和并行执行加速流水线。
下节预告
第11课将进入 ArkUI 应用的安全与合规进阶的学习,涵盖数据加密与安全存储、网络安全传输、权限最小化、隐私合规检测以及应用加固方案。