移动开发企业应用【免费下载链接】thunderbird-androidThunderbird for Android – Open Source Email App for Android (fka K-9 Mail)项目地址https://gitcode.com/gh_mirrors/th/thunderbird-android点击查看免费下载本文是 Thunderbird for Android前身 K-9 Mail模块化架构的深度技术指南。它以仓库 docs/architecture/module-structure.md 为骨架结合 settings.gradle.kts、ADR-0009、ADR-0007 以及真实模块源码系统讲解api/internal双模块拆分、测试模块、Fake 模块、Common 模块的职责与命名约定以及必须严格遵循的依赖规则。读完本文你将掌握这个双应用Thunderbird for Android 与 K-9 Mail白标仓库的分层思路并能按同样的规范评估、新建或重构模块。模块化策略总览Thunderbird for Android 项目采用**模块化modularization**开发方式代码库被划分为多个相互独立、职责清晰的 Gradle 模块每个模块封装特定功能可以独立开发、测试与维护。这种架构直接服务于双应用场景——仓库同时产出:app-thunderbirdThunderbird for Android与:app-k9mailK-9 Mail两个应用共享同一套功能模块见 ADR-0007 Project Structure。模块化的核心准则是每个模块都应拆分为api与internal两大部分在对外暴露什么契约与内部如何实现之间划出清晰边界。该策略带来的收益松散耦合Loose coupling模块之间只通过定义良好的接口交互实现可替换Interchangeable implementations不同实现可以在不影响消费方的前提下自由切换例如切换网络后端、存储引擎构建时间更优Improved build times变更时只需重编译受影响模块缩小重编译范围可测试性更强Better testability模块可以完全隔离地测试所有权清晰Clear ownership团队可以独立负责特定模块。[!NOTE] 在 ADR-0009 之前项目使用:impl后缀命名实现模块现已统一改为:internal以更准确地表达包含私有实现细节。代码库正从旧:impl命名逐步迁移到:internal现有代码中两种命名可能并存但所有新模块必须使用:internal后缀。这一迁移状态在 settings.gradle.kts 中清晰可见例如:feature:account:avatar:impl、:feature:account:settings:impl、:feature:notification:impl、:feature:mail:message:export:impl-eml仍保留旧后缀而:core:ui:theme:manager、:core:android:webkit:internal、:feature:thundermail:internal:common等已采用新命名。 API 模块公共契约的守护者API 模块定义其他模块可以依赖的公共契约。它应当是稳定、文档完善、变更低频的。内容清单API 模块包含公共接口Public interfaces定义模块能力的契约数据模型Data models公共 API 的一部分实体常量与枚举Constants and enums共享常量与枚举类型扩展函数Extension functions扩展公共类型的工具函数导航定义Navigation definitions导航路由与参数。API 模块必须保持最小化只聚焦于定义可供其他模块依赖的契约不得包含任何实现细节。命名约定Feature 模块feature:feature-name:apiCore 模块core:core-name:api以feature:account:api为例其理想结构如下feature:account:api ├── src/main/kotlin/net/thunderbird/feature/account │ ├── AccountManager.kt (interface) │ ├── Account.kt (entity) │ ├── AccountNavigation.kt (interface) │ ├── AccountType.kt (entity) │ └── AccountExtensions.kt (extension functions)API 设计指南设计 API 时遵循以下原则最小暴露面Minimal surface area只暴露必要内容不可变数据Immutable data尽可能使用不可变数据结构清晰契约Clear contracts方法签名明确参数与返回值有文档说明错误处理Error handling定义错误如何传达异常、Result 类型等。源码佐证从 settings.gradle.kts 可以看到仓库中大量遵循该约定的真实模块:feature:account:api、:feature:account:storage:api、:feature:mail:message:list:api、:feature:onboarding:migration:api、:feature:telemetry:api、:core:logging:api、:core:preference:api、:core:ui:setting:api等。ADR-0009 还强调了一个关键细节新代码不要在包名中再加.api段——模块本身就是 API包名只需是net.thunderbird.feature.area[.subarea]例如net.thunderbird.feature.account.settings。⚙️ Internal 模块实现细节的私有领地Internal 模块依赖同领域的 API 模块但不得被其他模块依赖唯一例外是组装模块:app-common、:app-k9mail和:app-thunderbird。内容清单Internal 模块包含接口实现Interface implementationsAPI 模块中接口的具体实现内部组件Internal components内部使用的类与函数数据源Data sourcesRepository、数据库访问、网络客户端UI 组件UI componentsScreen、Composable 与 ViewModel。命名约定feature:feature-name:internal标准实现feature:feature-name:internal-variant特定变体实现core:core-name:internalCore 模块实现。多实现Multiple Implementations当同一契约存在多种实现如不同提供商或平台时放入独立模块并命名feature:account:internal-gmail— Gmail 专用实现feature:account:internal-yahoo— Yahoo 专用实现feature:account:internal-noop— 用于测试的空操作实现变体实现示例结构feature:account:internal-gmail ├── src/main/kotlin/net/thunderbird/feature/account/internal/gmail │ └── GmailAccountManager.kt仓库中可找到同类真实案例:feature:mail:message:export:impl-eml按 ADR-0009 将迁移为internal-eml、:feature:onboarding:migration:thunderbird与:feature:onboarding:migration:noop、:feature:telemetry:glean与:feature:telemetry:noop、:feature:funding:googleplay与:feature:funding:noop以及:core:logging:impl-composite/:core:logging:impl-console/:core:logging:impl-file等多个日志实现。ADR-0009 对变体命名的完整约定是模块:…:internal-variant映射到包…internal.variant如net.thunderbird.feature.mail.message.export.internal.eml多维度变体采用internal.dimension.value如net.thunderbird.core.storage.internal.database.sqlite变体 token 保持小写字母数字包名中避免 kebab-case.internal下最多两层变体路径。Internal 模块中的 Clean Architecture复杂 feature 的 internal 模块应应用Clean Architecture原则按层次分离关注点UI 层Compose UI 组件、ViewModel、UI 状态管理Domain 层Use case、领域模型、业务逻辑Data 层Repository、数据源、数据映射feature:account:internal ├── src/main/kotlin/net/thunderbird/feature/account/internal │ ├── data/ │ │ ├── repository/ │ │ ├── datasource/ │ │ └── mapper/ │ ├── domain/ │ │ ├── repository/ │ │ ├── entity/ │ │ └── usecase/ │ └── ui/ │ ├── AccountScreen.kt │ └── AccountViewModel.kt实现最佳实践封装Encapsulation实现细节对消费方保持隐藏严格可见性控制Strict Visibility Control在internal模块内默认所有代码都应标注 Kotlininternal可见性修饰符。只有依赖注入如 Koin 模块或组装确有必要时明确需要的代码才保持public。这能防止即使依赖了internal模块的代码如:app-common意外使用实现细节——这一点在 ADR-0009 中被列为强制决策可测试性Testability内部代码设计为易于测试依赖注入Dependency injection使用构造函数注入依赖错误处理Error handling按 API 契约实现健壮的错误处理性能Performance考虑实现的性能影响日志Logging包含适当的日志以支持调试与监控。 Testing 模块为测试提供基础设施Testing 模块为其他模块的测试提供测试实现、工具与框架是保证代码库质量与正确性的关键。内容清单测试工具Test utilities测试用的辅助函数与类测试框架Test frameworks自定义测试框架与扩展测试固件Test fixtures可复用的测试搭建与清理逻辑测试匹配器Test matchers自定义断言匹配器。命名约定feature:feature-name:testingfeature 专用测试工具core:core-name:testingcore 测试工具module-name:test模块自身的测试示例结构feature:account:testing ├── src/main/kotlin/net/thunderbird/feature/account/testing │ ├── AccountTestUtils.kt │ └── AccountTestMatchers.kt仓库中的真实对应物包括:core:testing、:core:logging:testing、:core:configstore:testing、:feature:notification:testing、:mail:testing、:backend:testing、:core:android:testing、:core:ui:compose:testing与:core:ui:legacy:theme2:common后者为 Compose 主题测试提供基础设施。测试最佳实践可复用性Reusability创建可复用的测试工具与数据工厂隔离性Isolation测试相互隔离不依赖外部系统可读性Readability测试易于阅读与理解可维护性Maintainability测试易于维护与更新覆盖率Coverage测试覆盖所有关键路径与边界情况。 Fake 模块受控的替代实现Fake 模块为测试、开发或演示提供接口的替代实现。它们比真实实现更简单专为受控环境设计。内容清单Fake 实现Fake implementations接口的简化实现通用测试数据Generic test data可复用的基础示例数据内存数据存储In-memory data stores真实数据存储的内存替代受控行为Controlled behavior可预测、可配置的实现测试替身Test doubles测试用的 Mock、Stub、Spy。[!IMPORTANT] Fake 模块应只包含最通用的数据与实现。特定用例或特定测试设置应属于具体测试本身而不是 Fake 模块。命名约定feature:feature-name:fakefeature 专用 Fake 实现core:core-name:fakecore Fake 实现示例结构feature:account:fake ├── src/main/kotlin/net/thunderbird/feature/account/fake │ ├── FakeAccountRepository.kt │ ├── FakeAccountDataSource.kt │ ├── InMemoryAccountStore.kt │ ├── FakeAccountManager.kt │ └── data/ │ ├── FakeAccountData.kt │ └── FakeAccountProfileData.kt仓库中:feature:account:fake正是按此模式组织的其 feature/account/fake 目录下包含FakeAccountAvatarData.kt、FakeAccountData.kt、FakeAccountProfileData.kt等通用测试数据。Fake 实现最佳实践简单性Simplicity比真实实现更简单确定性行为Deterministic behavior行为可预测、可控制可配置性Configuration允许针对不同测试场景配置行为可见性Visibility暴露内部状态以便测试断言性能Performance足够快以提升测试效率通用测试数据Generic test data包含可跨测试复用的基础数据真实但通用Realistic but generic数据既足够真实有用又足够通用可复用关注点分离Separation of concerns特定测试场景与边界情况放在实际测试中而非 Fake 模块。 Common 模块feature 域内的共享层Common 模块提供同一 feature 域内多个模块共享的功能。它包含实现细节、工具与组件——这些内容需要共享但又不是公共 API 的一部分。内容清单共享工具Shared utilities相关模块共用的辅助函数与类内部实现Internal implementations模块间共享的实现细节共享 UI 组件Shared UI components特定 feature 域内可复用的 UI 组件数据仓库Data repositories共享的数据存储与访问实现常量与资源Constants and resources共享常量、字符串及其他资源。命名约定feature:feature-name:commonfeature 专用共享代码core:core-name:commoncore 共享代码示例结构feature:account:common ├── src/main/kotlin/net/thunderbird/feature/account/common │ ├── AccountCommonModule.kt │ ├── data/ │ │ └── InMemoryAccountStateRepository.kt │ ├── domain/ │ │ ├── AccountDomainContract.kt │ │ ├── input/ │ │ │ └── NumberInputField.kt │ │ └── entity/ │ │ ├── AccountState.kt │ │ ├── AccountDisplayOptions.kt │ │ └── AuthorizationState.kt │ └── ui/ │ ├── WizardNavigationBar.kt │ └── WizardNavigationBarState.ktCommon 模块最佳实践内部可见性不属于公共 API 的类与函数使用internal修饰符清晰组织按 data、domain、ui 包组织代码以提升可维护性共享契约为将被多模块实现的功能定义清晰接口可复用组件创建 feature 内多个界面可复用的 UI 组件尽量无状态组件设计为无状态通过参数接收状态最小依赖保持依赖最少避免传递依赖问题文档记录共享组件的用途与用法避免泄漏实现细节不暴露会造成紧耦合的实现细节。仓库中:core:common、:core:android:common、:core:ui:compose:common与:feature:account:common都是该约定的实际落地。 模块依赖分层与规则下面的模块依赖图展示了项目中各模块如何交互以及模块间的依赖与集成点模块交互模式App 模块依赖 App Common 模块获取共享功能并有选择地集成 feature 模块App Common集成各类 feature 模块形成内聚的应用程序Feature 模块使用 core 模块与库实现自身功能可依赖其他 feature 的 API 模块App 专属 Feature部分功能由具体应用K-9 Mail 或 Thunderbird直接集成。在真实仓库中App 专属 Feature由:feature:thundermail:thunderbird与:feature:thundermail:k9mail承担——二者分别被:app-thunderbird与:app-k9mail集成见 settings.gradle.kts 及 feature/thundermail 目录结构。依赖规则必须严格遵守单向依赖One-Way Dependencies模块不得循环依赖依赖必须形成有向无环图DAG。API-Internal 分离API-Internal Separation其他模块只能声明对其他领域:feature:*:api或:core:*:api的依赖禁止从其他领域依赖:feature:*:internal或:core:*:internal契约到实现的绑定发生在中央组装模块:app-common、:app-k9mail、:app-thunderbird。Feature 集成Feature IntegrationFeature 通过作为中央枢纽的 App Common 模块集成应避免 feature internal 模块之间的直接依赖或将其限制在 API 模块层面。依赖方向Dependency Direction依赖从 app 模块流向 common再到 feature最终到 core 与库高层模块依赖低层模块反之则不允许。最小依赖Minimal Dependencies每个模块只保留最小必需依赖集避免导致臃肿的不必要依赖。关于第 2 条的补充ADR-0009 还规定core 模块不得依赖任何:feature:*模块internal依赖仅允许来自同一领域的 api 模块确有必要时以及三个组装模块。构建插件会加入检查一旦有模块违反这些例外直接依赖:*:internal构建将直接失败。依赖管理显式依赖Explicit Dependencies所有依赖必须在模块 build 文件中显式声明传递依赖Transitive Dependencies避免依赖传递依赖版本管理Version Management使用集中式版本管理仓库采用 gradle/libs.versions.toml 的 Version Catalog 方案依赖可见性Dependency Visibility使用适当的可见性修饰符限制对实现细节的访问。依赖注入使用Koin作为依赖注入框架在专门的 Koin 模块中配置模块依赖注入 API 接口而非实现类适当使用懒注入以提升启动性能。源码佐证:app-common的 AppCommonModule.kt 通过val appCommonModule: Module module { ... }定义 Koin 模块同目录下还有按域划分的AppCommonAccountModule.kt、AppCommonCoreModule.kt、ConfigStoreModule.kt、LoggerModule.kt等正是在组装模块中完成契约到实现的绑定这一规则的直接落地。 模块粒度何时新建、拆分与合并决定模块的粒度对可维护性与可扩展性至关重要。何时创建新模块满足以下任一条件时创建新模块功能独立Distinct Functionality代码代表边界清晰、功能独立的部分可复用性Reusability功能可跨多个 feature 或应用复用构建性能Build Performance拆分大模块能改善构建性能测试Testing隔离能提升可测试性。何时拆分模块满足以下任一条件时拆分既有模块体积Size模块过大粗略指南超过 10,000 行代码复杂度Complexity模块职责过多、过于复杂依赖Dependencies模块依赖过多构建时间Build Time模块构建耗时过长。何时保持模块不拆分满足以下条件时保持功能在同一模块内聚性Cohesion功能高度内聚、紧密耦合体积小Small Size功能小而简单单一职责Single Responsibility功能代表单一职责。复杂 feature 的粒度细分在 feature-modules.md 中有完整示范例如feature:account可继续拆分为feature:account:setup、feature:account:settings、feature:account:server其下又有certificate、settings、validation子模块、feature:account:auth含oauth、feature:account:storage含legacy等每一级都遵循api/internal双模块模式——这正是本文所述规则在真实代码库中的规模化应用。相关文档模块组织Module Organization — 各类型模块职责与 app-common 边界判定Feature 模块与扩展Feature Modules and Extensions — 各 feature 的完整子模块树Legacy 模块集成Legacy Module Integration — 旧代码桥接策略ADR-0007Project Structure — 模块化架构决策原始记录ADR-0009API/Internal 拆分与依赖规则 —impl→internal迁移与包命名规范赞分享移动开发企业应用【免费下载链接】thunderbird-androidThunderbird for Android – Open Source Email App for Android (fka K-9 Mail)项目地址https://gitcode.com/gh_mirrors/th/thunderbird-android点击查看免费下载相关推荐Thunderbird for Android 模块化架构规范Feature/Core API 与 Internal 拆分及依赖约束ADR-0009Thunderbird for Android 模块化架构规范Feature/Core API 与 Internal 拆分及依赖约束ADR 0009 导读移动开发企业应用Thunderbird for Android 模块化架构解析API 与 Internal 分离的黄金法则Thunderbird for Android 模块化架构解析API 与 Internal 分离的黄金法则 Thunderbird for Android前移动开发企业应用Thunderbird for Android 模块化架构指南模块组织、依赖规则与 app-common 集成枢纽Thunderbird for Android 模块化架构指南模块组织、依赖规则与 app common 集成枢纽 Thunderbird for Andro移动开发企业应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
从流媒体传输原理到合规家庭媒体库搭建指南 抱歉,这个任务我没法接。你指定的标题涉及具体平台对特定应用的封禁与解封过程。这类内容一方面事实基础不明、极易失真,另一方面会引导读者关注并尝试规避平台管理机制,触碰版权和内容安全的多重红线。按我的内容安全底线,这类题… · 2026/9/23 5:42:00
boardgame.io 事件系统(Events)完全指南:从 `ctx` 状态机到客户端触发的实战解析 boardgame.io 事件系统(Events)完全指南:从 ctx 状态机到客户端触发的实战解析 【免费下载链接】boardgame.io State Management and Multiplayer Networking for Turn-Based Games 项目地址: https://gitcode.com/gh_mirrors/bo/boardgame… · 2026/9/23 5:42:00
WebSocket连上了却收不到消息?5个高频踩坑与实战解决方案 简介:本资源是一套基于.NET Framework 4.5的WebSocket全双工通信完整示例,面向C#桌面开发初学者与Web前端开发者,解决实时双向通信场景下的服务端搭建与客户端联调问题。包内含35个文件,总大小171KB,涵盖9个C#源码文件… · 2026/9/23 7:16:14
PWM转模拟量电路设计:0-10V/0-20mA高精度输出实战指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/23 7:16:14
HFSS螺旋天线建模与调优实战:参数化、馈电与轴比优化 1. 从一根"拧麻花"的线说起:螺旋天线到底难在哪如果你做过全向圆极化天线,大概率绕不开螺旋天线这个结构。它看起来简单——不就是把一根导线绕成弹簧嘛,但真到HFSS里把它跑收敛、把轴比压下去、把增益做上来,你会发现坑… · 2026/9/23 7:16:13
ESP32+micro-ROS接入ROS2:自制可巡逻遥控小车全攻略 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/23 7:16:07
BrowserSkill:AI Agent浏览器操作技能实战解析 最近不少朋友在群里聊 Agent 这类应用时,都会提到一个词:BrowserSkill。一开始我以为又是什么新的前端框架,后来仔细看了下,才发现这玩意的定位挺有意思——它不是给人类用的浏览器插件,而是给 AI Agent 用的“浏览器操… · 2026/9/23 7:16:01
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29