- 移动开发
- 企业应用
【免费下载链接】thunderbird-android
Thunderbird for Android – Open Source Email App for Android (fka K-9 Mail)
Thunderbird for Android(前身 K-9 Mail)将整个应用拆分为多个特性模块(Feature Modules),每个模块封装一项独立功能,并通过稳定的 API 契约相互协作。本文以 docs/architecture/feature-modules.md 为主线,结合 ADR-0009、模块结构文档 以及仓库中的真实源码与 settings.gradle.kts,系统讲解特性模块的划分方式、命名约定、依赖规则,以及如何按照既有模式扩展全新功能模块。读完本文,你将掌握 Thunderbird for Android 的模块化组织思路,并能在实际开发中正确创建、拆分与集成新特性模块。
一、特性模块架构总览
Thunderbird for Android 项目的核心设计目标是:多个 feature 模块各司其职,通过明确定义的 API 相互调用,最终由顶层应用模块组装成完整应用。项目根目录下的 feature 目录即特性模块的物理载体,与之并列的还有core(基础能力)、legacy(遗留代码)、mail(邮件协议)、backend(后端协议实现)、library(可复用库)等模块层级。
下图为项目文档给出的特性模块总览(对应 docs/architecture/feature-modules.md 中的架构图):
从图中可以看出,应用层功能被划分为两类核心特性:
- 账户与邮件主链路:Account(账户管理)、Mail(邮件处理与展示)、Navigation(应用导航 UI)、Onboarding(新用户引导);
- 配置与辅助能力:Settings(应用配置)、Notification(推送与提醒)、Search(内容检索)、Widget(桌面组件)。
这 8 个模块并非扁平铺开,而是各自再向下拆分为更细粒度的子模块(subfeatures),从而在"特性域"内部实现更小的构建单元与更清晰的职责边界。
特性模块开发最佳实践
原文档给出了 10 条开发新特性模块(或扩展现有模块)时必须遵守的最佳实践,它们是整个模块体系的"宪法":
- API-First Design(API 优先设计):先定义清晰的公共接口,再进行实现;
- Single Responsibility(单一职责):每个特性模块只承担一个定义明确的职责;
- Minimal Dependencies(最小依赖):尽量压缩特性模块之间的依赖;
- Proper Layering(合理分层):每个特性内部遵循 Clean Architecture 原则;
- Testability(可测试性):设计上保证特性可以独立、隔离地测试;
- Documentation(文档化):记录每个特性模块的用途与用法;
- Consistent Naming(命名一致):遵循既定的命名约定(见下文);
- Feature Flags(特性开关):使用特性开关实现渐进式发布与 A/B 测试;
- Accessibility(无障碍):确保所有特性对所有用户可访问;
- Internationalization(国际化):设计阶段就考虑多语言支持。
这些原则共同保证:在功能持续扩张的同时,Thunderbird for Android 仍能保持整洁、模块化的架构。
二、模块组织规则:API / Internal 拆分与命名约定
特性模块能"拆得开、合得上"的关键,在于一套强制性的模块组织规则。这部分是 docs/architecture/module-structure.md 与 ADR-0009 的核心内容,也是理解本文所有模块树的前提。
API 模块:对外契约
api模块定义其他模块可以依赖的公共契约。它应当保持稳定、文档完善、极少变更,且不含任何实现细节。API 模块通常包含:
- 公共接口:定义模块能力的契约(Repository、Use Case、Service 接口等);
- 数据模型:属于公共 API 的实体(DTO / 值对象);
- 常量与枚举:跨模块共享的常量与枚举类型;
- 扩展函数:扩展公共类型的工具函数;
- 导航定义:导航路由与参数。
命名约定为:特性模块用feature:<feature-name>:api,核心模块用core:<core-name>:api。例如 feature/account/api 就是一个典型的最小化 API 模块,其 README(feature/account/api/README.md)明确说明它"刻意不包含邮件地址等特性化字段",只提供强类型账户标识AccountId、极简Account接口(仅含身份)以及聚合视图用的UnifiedAccountId哨兵值:
val id = AccountIdFactory.create() // 生成新的随机 AccountId val parsed = AccountIdFactory.of(rawString) // 从持久化值解析 if (id.isUnified) { // 路由到统一视图/聚合服务,而非具体仓库 } id.requireReal() // 在写路径上调用,若为 unified ID 则抛出 IllegalStateException从源码结构看,Mail、Calendar、Sync 等模块应当各自定义以AccountId为键的能力模型,而不是把字段塞进 Account API——这正是"API 模块保持最小面"的实践样本。
Internal 模块:私有实现
internal模块(旧称impl)依赖同域的api模块,但不允许被其他模块依赖(唯一例外是组装模块:app-common、:app-k9mail、:app-thunderbird)。它承载:
- 接口的具体实现(Repository、DataSource、Mapper、UseCase 实现);
- 特性内部的 UI 实现、ViewModel、UI 状态模型;
- 特性域内的依赖注入(DI)装配与工厂;
- 实验性、易变的实现细节。
命名约定为feature:<feature-name>:internal/core:<core-name>:internal;存在多个实现变体时,用限定后缀区分,如feature:<feature-name>:internal-<variant>(原文档示例:feature:account:internal-gmail、feature:account:internal-noop)。
[!NOTE] ADR-0009 指出,历史上项目使用
:impl后缀,后统一更名为:internal,以更准确地表达"私有实现细节"这一语义。迁移是渐进式的,因此代码库中impl与internal两种命名会同时存在,但所有新模块都应使用:internal。
包名与可见性规则
- 特性 API 包名:
net.thunderbird.feature.<area>[.<subarea>],例如net.thunderbird.feature.account.settings; - 特性 internal 包名:镜像 API 包结构,并在末尾追加
.internal段,例如net.thunderbird.feature.account.settings.internal.data、…internal.domain; - 多实现变体:模块
:…:internal-<variant>映射到包…internal.<variant>,例如:feature:mail:message:export:internal-eml→net.thunderbird.feature.mail.message.export.internal.eml;多维度变体使用internal.<dimension>.<value>,如net.thunderbird.core.storage.internal.database.sqlite。
严格可见性是 internal 模块最重要的纪律:内部模块中的代码默认全部标记为 Kotlininternal可见性,只有依赖注入(Koin 模块)或组装必需的部分才保持public。这样即使其他模块意外依赖了 internal 模块,也无法直接触碰实现细节。
Internal 模块内部的 Clean Architecture
复杂的特性 internal 模块应遵循 Clean Architecture,按三层组织:
- UI 层:Compose UI 组件、ViewModel、UI 状态管理;
- Domain 层:Use Case、领域模型、业务逻辑;
- Data 层:Repository、DataSource、数据映射(Mapper)。
feature:account:internal ├── src/main/kotlin/net/thunderbird/feature/account/internal │ ├── data/ │ │ ├── repository/ │ │ ├── datasource/ │ │ └── mapper/ │ ├── domain/ │ │ ├── repository/ │ │ ├── entity/ │ │ └── usecase/ │ └── ui/ │ ├── AccountScreen.kt │ └── AccountViewModel.kt这一分层在仓库中随处可见,例如 feature/account/oauth、feature/mail/message/reader 等目录均采用类似的 data / domain / ui 结构。
其他模块类型:Testing、Fake、Common
除 api/internal 外,模块化体系还定义了三种辅助模块类型:
- Testing 模块(
feature:<feature-name>:testing):提供测试工具、框架扩展、fixture 与自定义 matcher,例如 feature/notification/testing、core/android/testing; - Fake 模块(
feature:<feature-name>:fake):提供简化、可控、确定性的替身实现与通用测试数据,用于测试/开发/演示,例如 feature/account/fake。Fake 模块只应包含最通用的数据与实现,特定用例应写在具体测试中; - Common 模块(
feature:<feature-name>:common):共享同域内多个相关模块使用的实现细节、工具与 UI 组件,例如 feature/account/common。Common 模块中的非公共代码同样应使用internal可见性。
三、核心特性模块详解
下面逐一拆解 8 个核心特性模块的职责与子模块结构。所有模块树均直接继承自 docs/architecture/feature-modules.md,并补充了与仓库实际目录的对应关系。
3.1 Account 模块(账户管理)
Account 模块管理电子邮件账户的全部方面:设置、配置与认证。
feature:account ├── feature:account:api ├── feature:account:internal ├── feature:account:setup │ ├── feature:account:setup:api │ └── feature:account:setup:internal ├── feature:account:settings │ ├── feature:account:settings:api │ └── feature:account:settings:internal ├── feature:account:server │ ├── feature:account:server:api │ ├── feature:account:server:internal │ ├── feature:account:server:certificate │ │ ├── feature:account:server:certificate:api │ │ └── feature:account:server:certificate:internal │ ├── feature:account:server:settings │ │ ├── feature:account:server:settings:api │ │ └── feature:account:server:settings:internal │ └── feature:account:server:validation │ ├── feature:account:server:validation:api │ └── feature:account:server:validation:internal ├── feature:account:auth │ ├── feature:account:auth:api │ ├── feature:account:auth:internal │ └── feature:account:auth:oauth │ ├── feature:account:auth:oauth:api │ └── feature:account:auth:oauth:internal └── feature:account:storage ├── feature:account:storage:api ├── feature:account:storage:internal └── feature:account:storage:legacy ├── feature:account:storage:legacy:api └── feature:account:storage:legacy:internal子功能说明:
- API / Internal:账户管理的核心公共接口与内部实现;
- Setup(设置向导):新账户设置向导功能,
api暴露设置流程的公共接口,internal提供具体实现; - Settings(账户设置):账户级设置管理;
- Server(服务器):服务器配置与管理,向下细分为三层——
- Certificate:SSL 证书处理;
- Settings:服务器设置配置;
- Validation:服务器连接校验;
- Auth(认证):认证功能,其中OAuth提供 OAuth 专用认证实现;
- Storage(存储):账户数据持久化,其中Legacy是遗留存储实现。
仓库对照:feature:account域在 feature/account 目录中实际展开为api、avatar、common、core、edit、fake、oauth、profile、server、settings、setup、storage等子模块。其中server下确有三层子模块 certificate、settings、validation,与文档树一一对应;oauth即文档中的auth:oauth演化形态。所有模块均在 settings.gradle.kts 中以:feature:account:*前缀注册。
3.2 Mail 模块(邮件处理)
Mail 模块处理核心邮件功能:消息展示、撰写与文件夹管理。
feature:mail ├── feature:mail:api ├── feature:mail:internal ├── feature:mail:account │ ├── feature:mail:account:api │ └── feature:mail:account:internal ├── feature:mail:folder │ ├── feature:mail:folder:api │ └── feature:mail:folder:internal ├── feature:mail:compose │ ├── feature:mail:compose:api │ └── feature:mail:compose:internal └── feature:mail:message ├── feature:mail:message:api ├── feature:mail:message:internal ├── feature:mail:message:view │ ├── feature:mail:message:view:api │ └── feature:mail:message:view:internal └── feature:mail:message:list ├── feature:mail:message:list:api └── feature:mail:message:list:internal子功能说明:
- API / Internal:邮件功能的公共接口与内部实现;
- Account:邮件域专用的账户接口与实现(邮件账户集成);
- Folder:邮件文件夹管理(
api定义文件夹操作接口,internal提供实现); - Compose:邮件撰写功能;
- Message:消息处理与展示,细分为View(单封邮件查看)与List(消息列表展示与交互)。
仓库对照:在 feature/mail 目录下,实际存在account、folder、message三个子域;feature/mail/message 进一步展开为api、composer、export、list、reader。可以看出,文档树中的compose对应仓库中的composer(撰写器),message:view对应message:reader(阅读器),并且额外演化出message:export(邮件导出,含impl-eml/internal-eml变体,见 settings.gradle.kts 中的:feature:mail:message:export:impl-eml)。这印证了文档树描述的是目标形态,而代码库仍在持续演进。
3.3 Navigation 模块与 Navigation Drawer 模块
Navigation 模块属于核心 UI 层,提供贯穿应用的导航基础设施:
core:ui:navigation其内部包含三部分职责:
- Navigation:核心导航接口与路由;
- Route:类型安全的路由定义;
- NavigationExtension:Compose 专用导航扩展。
在仓库中对应 core/ui/navigation 模块(注册为:core:ui:navigation)。"导航放在 core 而非 feature"这一设计表明:导航是跨特性复用的基础设施,因此归入 core 层,这与"依赖方向从 feature 流向 core"的规则一致。
Navigation Drawer 模块则提供主界面导航抽屉的 UI 组件(含下拉式等变体):
feature:navigation:drawer ├── feature:navigation:drawer:api ├── feature:navigation:drawer:internal └── feature:navigation:drawer:dropdown ├── feature:navigation:drawer:dropdown:api └── feature:navigation:drawer:dropdown:internal子功能说明:
- API / Internal:抽屉核心接口与内部实现;
- Dropdown:下拉式导航实现。
仓库对照:见 feature/navigation/drawer,包含api与dropdown两个子模块,dropdown即文档中的下拉变体。
3.4 Onboarding 模块(新用户引导)
Onboarding 模块引导新用户完成初始设置流程。
feature:onboarding ├── feature:onboarding:api ├── feature:onboarding:internal ├── feature:onboarding:main │ ├── feature:onboarding:main:api │ └── feature:onboarding:main:internal ├── feature:onboarding:welcome │ ├── feature:onboarding:welcome:api │ └── feature:onboarding:welcome:internal ├── feature:onboarding:permissions │ ├── feature:onboarding:permissions:api │ └── feature:onboarding:permissions:internal └── feature:onboarding:migration ├── feature:onboarding:migration:api ├── feature:onboarding:migration:internal ├── feature:onboarding:migration:thunderbird │ ├── feature:onboarding:migration:thunderbird:api │ └── feature:onboarding:migration:thunderbird:internal └── feature:onboarding:migration:noop ├── feature:onboarding:migration:noop:api └── feature:onboarding:migration:noop:internal子功能说明:
- API / Internal:Onboarding 核心公共接口与内部实现;
- Main:主引导流程;
- Welcome:欢迎页与初始用户体验;
- Permissions:权限请求处理;
- Migration:从其他应用迁移数据,细分为Thunderbird(Thunderbird 专属迁移实现)与Noop(供测试用的空操作实现)。
仓库对照:feature/onboarding 目录包含main、migration、permissions、welcome四个子模块,且migration下确有thunderbird与noop两种实现变体,与文档树完全一致。"Noop"(空操作)实现是贯穿整个项目的经典模式——它让同一个 API 契约在测试/占位场景下拥有确定性行为,这也在 feature/funding/noop、feature/telemetry/noop 等模块中反复出现。
3.5 Settings 模块(应用配置)
Settings 模块提供配置应用行为的接口。
feature:settings ├── feature:settings:api ├── feature:settings:internal ├── feature:settings:import │ ├── feature:settings:import:api │ └── feature:settings:import:internal └── feature:settings:ui ├── feature:settings:ui:api └── feature:settings:ui:internal子功能说明:
- API / Internal:设置功能核心公共接口与内部实现;
- Import:设置导入功能(如从旧版本或其他客户端导入配置);
- UI:设置界面组件。
仓库对照:当前 feature/settings 下实现的是import子模块(注册为:feature:settings:import);设置界面的通用组件实际沉淀在 core 层,如 core/ui/setting(含api、component、impl-dialog等),体现了"通用设置 UI 下沉 core、特性化设置在 feature"的布局。
3.6 Notification 模块(通知与提醒)
Notification 模块处理新邮件与事件的推送通知和提醒。
feature:notification ├── feature:notification:api ├── feature:notification:internal ├── feature:notification:email │ ├── feature:notification:email:api │ └── feature:notification:email:internal └── feature:notification:push ├── feature:notification:push:api └── feature:notification:push:internal子功能说明:
- API / Internal:通知核心公共接口与内部实现;
- Email:邮件专用通知处理;
- Push:推送通知处理。
仓库对照:当前 feature/notification 包含api、impl(迁移前的 internal 命名)、testing与docs,且 feature/notification/README.md 详细描述了其"命令模式"架构。该模块是对"API/Internal 分离"原则的绝佳印证:
- Client(客户端):ViewModel 构建
Notification载荷并调用 Invoker; - Invoker:
NotificationSender/DefaultNotificationSender,用工厂创建命令并执行; - Command(命令):封装
Notification+NotificationNotifier,暴露execute(); - Receiver(接收者):平台渲染代码(
SystemNotificationNotifier使用NotificationManager,InAppNotificationNotifier使用BroadcastReceiver)。
整个:feature:notification:api是 KMP 模块,通知类型分为SystemNotification(系统托盘,需要POST_NOTIFICATIONS权限)与InAppNotification(应用内展示,无需权限),每种通知必须声明NotificationSeverity严重级别(Fatal / Critical / Warning / Temporary / Information)以驱动打扰程度与样式。这种"接口稳定、实现可插拔、命令解耦"的设计,正是特性模块 API-First 思想的落地范本。
3.7 Search 模块(搜索)
Search 模块提供邮件与联系人搜索能力。
feature:search ├── feature:search:api ├── feature:search:internal ├── feature:search:email │ ├── feature:search:email:api │ └── feature:search:email:internal ├── feature:search:contact │ ├── feature:search:contact:api │ └── feature:search:contact:internal └── feature:search:ui ├── feature:search:ui:api └── feature:search:ui:internal子功能说明:
- API / Internal:搜索功能核心公共接口与内部实现;
- Email:邮件搜索能力;
- Contact:联系人搜索能力;
- UI:搜索界面组件。
仓库对照:当前 feature/search 下仅有impl-legacy一个实现模块(注册为:feature:search:impl-legacy),说明搜索功能仍处于从遗留实现向新架构迁移的阶段——这与 ADR-0009 描述的渐进式迁移过程一致。文档树中的email、contact、ui子模块可视为规划中的目标拆分形态。
3.8 Widget 模块(桌面组件)
Widget 模块提供主屏幕小组件,用于快速访问邮件功能。
feature:widget ├── feature:widget:api ├── feature:widget:internal ├── feature:widget:message-list │ ├── feature:widget:message-list:api │ └── feature:widget:message-list:internal ├── feature:widget:message-list-glance │ ├── feature:widget:message-list-glance:api │ └── feature:widget:message-list-glance:internal ├── feature:widget:shortcut │ ├── feature:widget:shortcut:api │ └── feature:widget:shortcut:internal └── feature:widget:unread ├── feature:widget:unread:api └── feature:widget:unread:internal子功能说明:
- API / Internal:Widget 核心公共接口与内部实现;
- Message List:邮件列表组件;
- Message List Glance:Glance 风格的可速览消息组件;
- Shortcut:应用快捷方式组件;
- Unread:未读消息计数组件。
仓库对照:feature/widget 目录下四个子模块message-list、message-list-glance、shortcut、unread与文档树一一对应(注册为:feature:widget:*)。以 feature/widget/message-list 为例,其src/main/kotlin/app下包含组件实现,res中提供了各语言环境下的布局与字符串资源,AndroidManifest.xml声明了 AppWidgetProvider 注册信息——一个典型特性模块的完整落盘形态。
四、支撑性特性模块
除核心邮件功能外,项目还包含若干支撑性特性模块,它们通常规模更小、更聚焦,同样遵循 api/internal 拆分(settings.gradle.kts 中均有注册)。
4.1 Autodiscovery(服务器设置自动发现)
Autodiscovery 模块自动检测邮件服务器设置:
| 子模块 | 模块坐标 | 职责 |
|---|---|---|
| API | feature:autodiscovery:api | 公共接口 |
| Autoconfig | feature:autodiscovery:autoconfig | 自动配置逻辑 |
| Service | feature:autodiscovery:service | 服务实现 |
| Demo | feature:autodiscovery:demo | 演示实现 |
仓库对照:feature/autodiscovery 下api、autoconfig、service、demo四个子模块齐备;其中autoconfig还带有独立的测试源集(src/test),说明该模块的核心解析逻辑(如从 ISP 配置、MX 记录等渠道推断服务器参数)受到较完善的单元测试保护。
4.2 Funding(应用内赞助)
Funding 模块处理应用内的资金赞助与捐赠选项:
| 子模块 | 模块坐标 | 职责 |
|---|---|---|
| API | feature:funding:api | 公共接口 |
| Google Play | feature:funding:googleplay | Google Play 计费集成 |
| Link | feature:funding:link | 外部赞助链接处理 |
| Noop | feature:funding:noop | 空操作实现 |
仓库对照:feature/funding 下api、googleplay、link、noop齐备。这是一个"多实现变体"的典型场景:正式版通过 Google Play Billing 或外部链接收款,而 Noop 实现让调试/测试版本无需真实计费逻辑即可编译运行。
4.3 Migration(数据迁移)
Migration 模块处理不同邮件客户端之间的数据迁移:
| 子模块 | 模块坐标 | 职责 |
|---|---|---|
| Provider | feature:migration:provider | 迁移数据提供者 |
| QR Code | feature:migration:qrcode | 基于二维码的迁移 |
| Launcher | feature:migration:launcher | 迁移启动器 |
其中launcher进一步拆分:
- API(
feature:migration:launcher:api):启动器接口; - Noop(
feature:migration:launcher:noop):空操作实现; - Thunderbird(
feature:migration:launcher:thunderbird):Thunderbird 专属实现。
仓库对照:feature/migration 下launcher、provider、qrcode三子模块齐备;qrcode是一个体量较大的模块(feature/migration/qrcode 含大量 UI 资源与实现),承担扫码迁移账户配置的完整流程。
4.4 Telemetry(遥测与分析)
Telemetry 模块处理使用统计与上报:
| 子模块 | 模块坐标 | 职责 |
|---|---|---|
| API | feature:telemetry:api | 公共接口 |
| Noop | feature:telemetry:noop | 空操作实现 |
| Glean | feature:telemetry:glean | Mozilla Glean 集成 |
仓库对照:feature/telemetry 下api、noop、glean三子模块齐备。该模块同样展示"多实现变体"思想:正式构建接入 Mozilla Glean 遥测框架,而 Noop 实现用于关闭遥测的构建变体——两种实现共享同一 API 契约,由组装模块(app 层)决定注入哪一个。这与 settings.gradle.kts 中对:feature:telemetry:*的注册一一对应。
五、模块间依赖关系与依赖规则
特性之间通过定义良好的 API 相互交互。文档给出了核心特性(Account、Mail)与潜在扩展(Calendar、Appointments)之间的关系图:
Gradle 依赖规则(强约束)
ADR-0009 将这些关系落实为可被构建逻辑强制检查的硬性规则:
- 单向依赖:模块之间不得循环依赖,依赖图必须是有向无环图(DAG);
- API-Internal 分离:其他模块只能声明对别的域
:feature:*:api/:core:*:api的依赖;跨域依赖:feature:*:internal或:core:*:internal被禁止; - 契约绑定集中在组装模块:契约与实现的绑定只发生在
:app-common、:app-k9mail、:app-thunderbird三个组合模块中; - 依赖方向:依赖从 app 模块流向
app-common,再流向 feature,最终流向 core 与 library,高层模块不得反向依赖低层模块; - 最小依赖:每个模块只声明其必需的最小依赖集,避免传递依赖与膨胀。
[!IMPORTANT] 项目构建逻辑中内置了检查:若某模块依赖了上述例外之外的
:*:internal模块,构建会直接失败。这保证了架构纪律不依赖开发者的自觉,而是由工具强制兜底。
从源码验证依赖方向
在 settings.gradle.kts 中可以看到依赖方向的完整剖面:
- App 模块:
:app-k9mail、:app-thunderbird作为入口; - 组装模块:
:app-common承载跨应用共享的集成代码; - Feature 模块:
:feature:account:*、:feature:mail:*、:feature:widget:*、:feature:notification:*等全部以:feature:前缀注册; - Core 模块:
:core:ui:navigation、:core:common、:core:featureflag、:core:preference:*等为基础能力; - 更低层:
:mail:*(协议)、:backend:*(后端)、:legacy:*(遗留)、:library:*、:ui-utils:*。
这种分层注册方式与文档中的依赖图完全吻合:特性模块只依赖 core 与其他特性的 api,而绝不向上依赖 app 层。
六、如何扩展新特性:从理论示例到落地实践
模块化架构的核心收益之一就是易于扩展。原文档给出两个"理论示例",展示按既有模式新增特性时应有的模块结构。
示例一:Calendar 特性(日历)
一个 Calendar 特性可将日历功能与邮件集成:
feature:calendar ├── feature:calendar:api ├── feature:calendar:internal ├── feature:calendar:event │ ├── feature:calendar:event:api │ └── feature:calendar:event:internal └── feature:calendar:sync ├── feature:calendar:sync:api └── feature:calendar:sync:internal示例二:Appointments 特性(日程/预约)
一个 Appointments 特性可管理会议与预约:
feature:appointment ├── feature:appointment:api ├── feature:appointment:internal ├── feature:appointment:scheduler │ ├── feature:appointment:scheduler:api │ └── feature:appointment:scheduler:internal └── feature:appointment:notification ├── feature:appointment:notification:api └── feature:appointment:notification:internal新特性的标准落地步骤
结合 module-structure.md 中的粒度指南与 ADR-0009 的迁移计划,从零新增一个特性模块的推荐路径如下:
- 先在
internal起步:不确定是否稳定时,先创建:feature:<name>:internal,等到确实需要对外共享且契约稳定后,再提升到api("When in doubt, prefer starting in internal"); - 按需拆分子模块:当功能域内部出现明显的职责边界(如 Calendar 的 event 与 sync)时,按
:feature:<name>:<subarea>:api|internal拆分; - 在 settings.gradle.kts 注册:仿照现有
include(":feature:xxx:api")写法将新模块加入构建; - 包名遵循
net.thunderbird.feature.<area>[.<subarea>][.internal...]规则,internal 代码默认internal可见性; - 在组装模块完成绑定:在
:app-common或 app 模块中用 Koin 将接口绑定到实现; - 为复杂特性配置测试与 fake 模块:测试替身独立成模块,保持 API 消费者不被实现细节污染。
模块粒度的判断标准
何时新建模块、何时拆分、何时合并,module-structure.md 给出了明确指引:
- 新建模块:功能边界清晰且可能被多个特性/应用复用、拆分可改善构建性能与可测试性时;
- 拆分模块:模块超过约 1 万行、职责过多、依赖过多、构建时间过长时;
- 保持不拆:功能高度内聚、规模小、职责单一时。
七、总结
Thunderbird for Android 的特性模块体系可以用一句话概括:以 api/internal 拆分为骨架,以单向依赖为约束,以组装模块为枢纽,以多实现变体(noop/fake/变体后缀)应对现实差异。原文档 feature-modules.md 给出的 8 个核心特性模块与 4 个支撑模块,在仓库 feature 目录、settings.gradle.kts 与 ADR-0009 中均可逐一对证;文档树与现状之间的细微差异(如impl/internal并存、compose/composer演化),则真实反映了项目渐进式重构的进行时状态。
对开发者而言,这套体系提供的不仅是目录组织方式,更是一套可执行的架构纪律:新特性先写契约、实现藏于 internal、依赖只走 api、绑定交给组装层。遵循这些规则,任何新功能都能以低耦合、可测试、可独立演进的方式融入这个拥有两个应用(Thunderbird 与 K-9 Mail)的代码库。
延伸阅读
- 模块结构总览(Module Structure):api/internal/测试/fake/common 各模块类型的详细规范
- ADR-0009:Feature/Core API/Internal 拆分与依赖规则:模块与包命名、Gradle 依赖强约束的权威来源
- 架构总览(Architecture):模块类型、Clean Architecture 与跨切面关注点
- 通知模块架构说明:一个特性模块内部"命令模式"设计的完整案例
- 账户 API 模块说明:最小化 API 模块的实践样板
- 移动开发
- 企业应用
【免费下载链接】thunderbird-android
Thunderbird for Android – Open Source Email App for Android (fka K-9 Mail)
相关推荐
Thunderbird for Android 模块化架构规范:Feature/Core API 与 Internal 拆分及依赖约束(ADR-0009)
Thunderbird for Android 模块化架构规范:Feature/Core API 与 Internal 拆分及依赖约束(ADR 0009) 导读
移动开发企业应用Thunderbird for Android 模块化架构解析:API 与 Internal 分离的黄金法则
Thunderbird for Android 模块化架构解析:API 与 Internal 分离的黄金法则 Thunderbird for Android(前
移动开发企业应用Thunderbird for Android 特性开关新架构:声明式 Feature Flag Catalog 的设计与实践
Thunderbird for Android 特性开关新架构:声明式 Feature Flag Catalog 的设计与实践 导读 本文基于 Thunderb
移动开发企业应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考