Now in Android:它不是最佳实践,而是大型 Android 工程实践的展示
核心观点
Now in Android(NIA)经常被批评为"过度设计",但这种评价只有在忽略其目标的情况下才成立。
NIA 的价值并不在于提供一个适用于所有 Android 项目的模板,而在于展示 Google 对大型 Android 应用工程化的理解。因此,对 NIA 的评价必须结合项目规模和团队背景。
NIA 解决的问题是什么?
阅读 NIA 的官方文档后可以发现,它关注的是以下几个目标:
- 支持多人并行开发;
- 降低大型项目的构建成本;
- 提高代码的可测试性;
- 演示 Jetpack 官方推荐实践;
- 提供性能优化与持续集成的示例。
这些目标都不是"小型应用如何快速开发"。
因此,NIA 的设计天然偏向大型团队和长期维护的场景。
为什么会被认为"过度设计"?
1. 模块拆分过细
NIA 将应用拆分为大量模块,例如:
- feature:me
- core:ui
- core:data
- core:database
- core:datastore等。
对于只有几名开发者的项目而言,这种拆分会带来额外成本:
- Gradle 配置复杂;
- 新成员上手困难;
- 查找代码成本增加;
- 重构需要跨多个模块协调。
模块化本身并不是问题,问题在于模块化程度是否与项目规模匹配。
2. 小功能采用完整架构链路
在 NIA 中,即使是简单的数据修改,也可能经过:
#mermaid-svg-vTEzBQ7dDVrnVFfT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vTEzBQ7dDVrnVFfT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vTEzBQ7dDVrnVFfT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vTEzBQ7dDVrnVFfT .error-icon{fill:#552222;}#mermaid-svg-vTEzBQ7dDVrnVFfT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vTEzBQ7dDVrnVFfT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vTEzBQ7dDVrnVFfT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vTEzBQ7dDVrnVFfT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vTEzBQ7dDVrnVFfT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vTEzBQ7dDVrnVFfT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vTEzBQ7dDVrnVFfT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vTEzBQ7dDVrnVFfT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vTEzBQ7dDVrnVFfT .marker.cross{stroke:#333333;}#mermaid-svg-vTEzBQ7dDVrnVFfT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vTEzBQ7dDVrnVFfT p{margin:0;}#mermaid-svg-vTEzBQ7dDVrnVFfT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vTEzBQ7dDVrnVFfT .cluster-label text{fill:#333;}#mermaid-svg-vTEzBQ7dDVrnVFfT .cluster-label span{color:#333;}#mermaid-svg-vTEzBQ7dDVrnVFfT .cluster-label span p{background-color:transparent;}#mermaid-svg-vTEzBQ7dDVrnVFfT .label text,#mermaid-svg-vTEzBQ7dDVrnVFfT span{fill:#333;color:#333;}#mermaid-svg-vTEzBQ7dDVrnVFfT .node rect,#mermaid-svg-vTEzBQ7dDVrnVFfT .node circle,#mermaid-svg-vTEzBQ7dDVrnVFfT .node ellipse,#mermaid-svg-vTEzBQ7dDVrnVFfT .node polygon,#mermaid-svg-vTEzBQ7dDVrnVFfT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vTEzBQ7dDVrnVFfT .rough-node .label text,#mermaid-svg-vTEzBQ7dDVrnVFfT .node .label text,#mermaid-svg-vTEzBQ7dDVrnVFfT .image-shape .label,#mermaid-svg-vTEzBQ7dDVrnVFfT .icon-shape .label{text-anchor:middle;}#mermaid-svg-vTEzBQ7dDVrnVFfT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vTEzBQ7dDVrnVFfT .rough-node .label,#mermaid-svg-vTEzBQ7dDVrnVFfT .node .label,#mermaid-svg-vTEzBQ7dDVrnVFfT .image-shape .label,#mermaid-svg-vTEzBQ7dDVrnVFfT .icon-shape .label{text-align:center;}#mermaid-svg-vTEzBQ7dDVrnVFfT .node.clickable{cursor:pointer;}#mermaid-svg-vTEzBQ7dDVrnVFfT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vTEzBQ7dDVrnVFfT .arrowheadPath{fill:#333333;}#mermaid-svg-vTEzBQ7dDVrnVFfT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vTEzBQ7dDVrnVFfT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vTEzBQ7dDVrnVFfT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vTEzBQ7dDVrnVFfT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vTEzBQ7dDVrnVFfT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vTEzBQ7dDVrnVFfT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vTEzBQ7dDVrnVFfT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vTEzBQ7dDVrnVFfT .cluster text{fill:#333;}#mermaid-svg-vTEzBQ7dDVrnVFfT .cluster span{color:#333;}#mermaid-svg-vTEzBQ7dDVrnVFfT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vTEzBQ7dDVrnVFfT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vTEzBQ7dDVrnVFfT rect.text{fill:none;stroke-width:0;}#mermaid-svg-vTEzBQ7dDVrnVFfT .icon-shape,#mermaid-svg-vTEzBQ7dDVrnVFfT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vTEzBQ7dDVrnVFfT .icon-shape p,#mermaid-svg-vTEzBQ7dDVrnVFfT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vTEzBQ7dDVrnVFfT .icon-shape .label rect,#mermaid-svg-vTEzBQ7dDVrnVFfT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vTEzBQ7dDVrnVFfT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vTEzBQ7dDVrnVFfT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vTEzBQ7dDVrnVFfT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} UI
ViewModel
Repository
Local DataSource
Remote DataSource
Database
API
Repository 的价值并不在于"多了一层",而在于屏蔽数据来源的变化;但如果项目永远只有一种数据来源,这层抽象就可能成为过度设计。
这种设计强调职责分离和可测试性,但对于需求变化频繁、生命周期较短的项目而言,会增加实现成本。
因此,很多开发者会产生一种感受:
"为了实现一个简单功能,却引入了远超需求的复杂度。"
3. 性能与测试设施齐全
NIA 包含:
- Macrobenchmark;
- Baseline Profile;
- 自动化测试;
- CI 流程;
- Benchmark 模块。
对于大多数中小团队来说,这些设施并不是当前阶段的瓶颈。
但对于拥有数百万用户的大型应用而言,启动时间减少 100ms 就可能带来显著收益。
NIA 的真正定位
NIA 更像是一个"参考架构",而不是"项目脚手架"。
它回答的问题是:
"如果从零开始构建一个现代 Android 大型应用,Google 会如何组织它?"
而不是:
"如果我要在两个月内交付一个 App,我应该怎么写?"
将这两类问题混淆,是很多争论产生的原因。
对 NIA 的评价应该基于项目规模
小型项目(1~5人)
适合借鉴:
- Compose;
- ViewModel;
- Repository;
- Hilt;
- 少量模块化。
不适合照搬:
- 复杂模块拆分;
- Benchmark 基础设施;
- 完整测试矩阵。
中大型项目(10人以上)
NIA 的很多设计开始体现价值:
- 降低多人协作冲突;
- 支持独立模块开发;
- 提高测试能力;
- 控制构建时间;
- 保障长期可维护性。
一个有用的类比
NIA 与 Kubernetes 有相似之处。
对于个人博客而言,Kubernetes 是过度设计。
对于拥有数百个微服务的企业系统而言,Kubernetes 是必要基础设施。
NIA 也是如此:
- 对 Todo App 来说,它可能太重;
- 对维护五年的大型 Android 应用来说,它可能正合适。
复杂度本身不是问题。
不匹配的复杂度才是问题。
我的结论
Now in Android 不是 Android 开发的"标准答案"。
它更像是一份展示大型工程实践的样板间。
学习 NIA 的正确方式不是复制,而是理解:
- 哪些复杂度是在解决真实问题;
- 哪些复杂度在当前阶段并不需要;
- 哪些设计可以随着项目成长逐步引入。
好的架构不是"最先进"的架构,而是"刚好足够"的架构。
因此,与其问:
"Now in Android 是否过度设计?"
不如问:
"我的项目是否已经遇到了 NIA 想要解决的问题?"
如果答案是否定的,那么简化就是一种更好的设计。