百度 App Feed 流业务架构变迁思考和升级实践
如果无法正常显示,请先停止浏览器的去广告插件。
1. 百度 App Feed 流业务架构
变迁思考和升级实践
李哲浩
Baidu Feed Android Architect
2.
3. • 过去的架构漫步
• 大环境的冲击
• 采用的架构思想和原则
• 若干场景的架构示例
• 架构维护控制
4. 从仓促开始
频道A
展现层V
频道B
展现层V”
Android
三方库
控制层C
业务逻辑层M
网络
日志 框架
Android
RN
三方库
控制层C”
基础设施
DB
频道C
业务逻辑层M”
基础设施
DB” 网络
日志 框架
整体组件化
频道D
Feed业务组件
Feed SDK
Hybrid
Copy
用例不多,不够重视
迭代不多,不够复杂
团队视野受限,经验不足
重构就是物理搬移、单例满天飞
征战状态,时间紧 工程化平台不够完善 核心业务深入迭代,产品需求不断叠加
还没做好,别人就要用 遗留代码基大,
架构老旧不敢改 模型复杂,系统僵化、脆弱、晦涩
5. • 过去的架构漫步
• 大环境的冲击
• 采用的架构思想和原则
• 若干场景的架构示例
• 架构维护控制
6. 行业众软件架构模式
MVC
MVP
PAC
(HMVC)
MVVM
MVI
model-view-controller model-view-presenter presentation–abstraction–contro
l model-view-viewmodel model-view-intent
ECB ECS OBR MOA SOA
DCI
data-context-interaction
CQRS
entity-control-boundary entity-component-system object-request-broker message-oriented-arch service-oriented-arch Command-Query Responsibility
Segregation
Hexagonal Onion DDD Clean Redux Flux
N-tier Event-driven Plugin-based Component-based Microservices Reactive Systems
VIPER VueX MobX Database-centric Micro-frontends Middleware-based
7. 公司平台和环境
Easybox
工程构建
Scheme
协议路由
NPS
插件化
Talos
Hybrid
Pyramid
IoC/服务
组件化
动态化
webview
增强
Crius
BdBus
OEM
mapping
容器化
事件总线
技术中台
RN
中台化
跨端
小程序
数据中台
业务中台
客户端重点技术方向
商业 产品线
内容分发 Feed 搜索
研发
测试
基础技术平台
内容消费
多团队
研发多、测试少
Flutter
KMM
Jetpack
Compose
内容生产
全民小视频 好看视频
百度App
百度贴吧
百家号 音啵 Flow 新流 小度 音磁 看多多 柠檬爱美
百度云 招财猫 慧拍 西番 秒懂 游所为 有驾
多产品线输出 (快速孵化、动态裁剪)
8. • 过去的架构漫步
• 大环境的冲击
• 采用的架构思想和原则
• 若干场景的架构示例
• 架构维护控制
9. 架构影响因素
环境
行业特征
开发方式
业务
价值
组织结构
干系人构成
功能
服务
流程
商业模式
团队成熟度
高
保持满意 关键参与
最小投入 保持知会
权力级别
技术约束
低
低
ROI
数据
利益级别
高
10. 投入成本比
需求
发布
名义粗估
6天
排期
5天(倒排) 开发
4天 测试
1天 发版上线 Bugfix
1.5天
预计加班
1天 含上版本
bugfix 1
天 借调
人力
0.5天 需求
发布 正在开发
下一个需
求
实际粗估
4.5天
研发效率的提升收益如何度量?
• 这个需求需要记录几天?6
vs 5 vs(4 – 1)+ (1 + 0.5)x 30% + 1.5
• 我们敏捷迭代平台记录了什么?名义粗估、排期
• 假设架构重构需要1个人1个Q投入,名义粗估不会提升,还投资吗?
重塑度量积累数据
• 假设实际效率有平台度量,确有5到3人天的提升,重构需要投入1年,
若环境变化中断,导致架构四不像,怎么办?
架构重构是否有足够power
需求
回顾
研发质量的提升收益如何度量?
架构升级 架构复辟
脆弱和遗漏带来的bug减少 复用带来的bug减少
真实复用 copy复用
中间件变多带来认知复杂度 并行开发冲突
抽象带来的性能劣化 巨型类加载的性能劣化
11. 团队成熟度
黑箱复用
白箱复用
基本需求/初始代码
扩展需求/继承
新需求/要求复用
原型阶段
重构/分解
通用化
扩展阶段
•
•
•
争取业务,
野蛮增长,
重复轮子
表现打分
● 宁可花时间研究fresco,不愿花时间研究打磨现有的项目“复杂”组件;
● 宁可花时间研究花哨的外家功夫,不愿花时间打磨自己的基本内功;
● 不是自己写的代码基本不改,完全无视带来的重复,架构设计的背离;
● 没有制定设计规范,或者存在多套设计规范,互相无法说服,没有顶层架构设计;
● 对单测、代码评审等保障体系建设有抵触,认为给自己带来无意义的麻烦;
● 能copy工作就行,对新技术、团队指标、任何宣贯都漠不关心
● 团队成员互相不愿意沟通协调解决协作、边界处理等问题
● 擅长 0-1 Copy,对1-n没有自己的想法,处处依赖上面的指定
框架化
标准化
萎缩阶段
巩固阶段
•
•
争抢标准,争抢输出
你造汽车,我造航母
•
ROI至上,强调先验
俄罗斯方块类比
重视地基
重视拼接正确性
有code review比没有code review强,
没有code review比有code review强,
同样适用于测试,即没有勇气,只想遵循规则而不是坚持原则
12. 业务复杂度
•
做一个转换器插件,将RGBA的颜色数组转化成YV12格式的颜色数组
技术复杂度可以很高,业务复杂度低
•
做一个简易弹窗提醒(弹窗无要求),有上百种情况,不同情况组合(协同、互斥、相互作用)
下,弹窗的文案不同
技术复杂度低,业务复杂度可能很高(熵很高)
•
文件写入也可能有多种异常情况要处理啊?
文件处理是您的主要业务吗?
难以理解,难以整合,难以预测
13. 团队成熟度和业务复杂度
复杂业务
简单业务
强制或重组 过度设计 领域模型设计
放任 样板间设计 简单设计
自由人 工具人
敏捷人
14. 什么应该是模型
{
"is_vip":"1"
"data": { … }
"pass_through": { … }
vipTitleColor="#FF0000"
title="<b>" + data.title.substring(0, 1) + "</b>"
subtitle=data.title.substring(1)
}
展现模型
isVip=true
云控模型
if (isVip) {
// 解锁
// 更新ui
}
业务模型
id
|
xxxxxx |
{ … } }
json
{ "is_vip":"1","data":
存储模型
关注业务模型
模型应该能用于不同角色的交流
模型是业务需求分析的设计表达,
使业务规则显明化
聚焦业务合法性
启动加载8条数据
填满首屏
其他数据延后加载
回填
技术模型
15. KMM的启示
架构层级 是否推荐共享
业务逻辑 是
平台访问 可选,接口化行为(此部分共享),使用平台API
前端交互(输入交互,后端通信) 可选,依赖架构模式
UI展示 否
业务逻辑不依赖基础设施
16. 前端状态管理方案的启示
单向数据流
模型响应式状态化 (而非接口化)
展示层设计
•
•
•
MVI
Redux
Flux
UI被动渲染
UI不能更改状态
UI传递抽象意图
VueX
MobX
Bloc
一个意图或事件可能多次切换状态
UI只是观察状态变化触发render方法
17. 后端前沿架构的启示
依赖方向
Query
接口
驱动/主适配器
基础设施
被驱动/次适配器
Command
Controller
Entity
actor/UI
Moment Interval
Presenter
Value Object
Context
Gateways
Interactor
Entity
Control
Adapter
Data
•
框架/基础设施
Entity
Converter
Port
event
Adapter
其他上下文
四色原型
DCI
Clean
•
•
bridge
Adapter
Command
DDD
•
•
核心
单测/脚本
•
网络库/Server
Methodful Role
Boundary
•
Description
Methodless Role
•
•
Remote
source
Domain Event
•
•
IO
Adapter
Party Place Thing
Use Case
Local
source
Domain Service
Aggregate
Role
存储/Database
Repository
领域层
Application Service
IO
Port
应用层
特点
ECB/EBI
•
•
依赖反转,端口适配
里层不依赖外层
不再依赖基础设施
不再嫁给框架
边界清晰
领域模型为核心
业务逻辑不泄露
关注点分离
富血模型
用例整洁
业务维度隔离
易于单测
易于维护
18. 快速开发的思考
Feed的同学
比较深入,难度大
核心业务实现
已具备
外部团队同学来Feed
无法实现快速开发
独立模块
独立扩展
可裁剪
可以实现快速开发
大业务认知
概念统一有助于实现此目标
已具备
新入职同学来Feed
重点扩大
这里的辐射范围
“标准化”
“边界清晰”
技术栈
工程能力
工具链
新人必备的能力
目前已必备
19. 组件化
壳工程
业务组件A
业务组件B
接口层
模块
业务组件C
下沉通用部分
共用依赖
基础组件X
基础组件Y
基础组件Z
核心
实现层
模块
扩展
实现层
模块
初步组件化
依赖情况
组件A
接口层
模块
接口层
模块
接口层
模块
实现层
模块 实现层
模块 实现层
模块
组件A 组件B 组件C
接口层提取
接口层
模块
接口层
模块
layout
xml
实现层
模块
业务基础
组件
实现层
模块
核心组件
B
实现层
模块
扩展组件B‘
实现层
模块
组件C
贫血
模型
data
实现层
模块
业务组件
业务组件膨胀情况
物理接口层有助于减少依赖环,随迭代膨胀后,产出一些隐式经验规则:
A. 适合核心组件和扩展都在一个团队
B. 适合多团队外部扩展,独立发布、组合使用
C. 历史遗留情况
划分组件类型
减少贫血模型,尽可能接口化
减少布局文件,尽可能code as ui(声明式DSL)
20. 组件化
能力集成方式
业务中台组件
泛化(继承/实现) 基础框架组件 包含(聚合/组合) UI组件
Data组件 业务基础组件
基础技术组件 业务支撑组件
调用(依赖/关联)
线程池库、网络库、
图片库等
业务无关
feed容器等
点赞、关注等
业务组件
通用业务
特定业务
组件能力模型
•
•
•
•
•
分离通用和业务,进行业务抽象,分离不变和易变
•
•
接口层提取容易程度
账号、打点等
组件分类
•
服务化程度
依赖的服务(下游)
提供的服务(上游)
身份
通信机制
生命周期
概念完整性
关系管理(优先级、互斥、协同、容器父子)
动态性(编译期识别/运行时发现,热更新,异常鲁棒性)
业务相关性
21. 边界问题
Id=x
• 原则1:组件独立、互不依赖
列表条目数据json
• 原则2:谁的PM提需,胶水、脏活这一方适配开发
首页胶水
tid=1
图文落地页
首页列表页
tid=2
push 内容
搜索落地页
sid=1_1
视频落地页
vid=11
我有一套通用
的当前展示内
容的通知机制
搜索落地页
条目2
来自push
电商
重复逻辑
条目3
Back返回
vid=12
我不想调用你
的方法,你提
前注册我
电商胶水
来源是否
锚点条目
sid=1_2
视频落地页
API层
条目1
点击熊掌按钮返回
来自push
首页
视频的通知格式
Back 返回
图文落地页
来源是否
我有一套通用
的锚点插入机
制
没有时机?那
application里
注册?
不想耦合你的通
知的数据结构信
息
业务
组件
胶水/适配
组件
胶水/适配
组件
业务
组件
22. 多产品线方案选型
矩阵产品+创新孵化产品+不同应用市场渠道
差异部分
组件1
新分支
组件1
组件2
组件3
分支方案:跟随者/独立自主
为什么以分支方案为主
差异部分
组件1
接口化
插件扩展
1
组件2
组件3
插件方案:客户和供应商/开放服务
差异部分
组件1
main
两个团队发版节奏不同,时
间不容易match
构建方案版本管理成本大
两个分支差异有工具可以
merge
整体也能得到足够复用
主线定期以矩阵用例回溯改
进接口
common
lite
组件2
组件3
构建方案:共享内核
23. 架构升级假设
业务单元
拆解
功能单元
功能单元
调度/分发
功能单元
调度/分发
服务中心
通信
通信
能力单元 能力单元 能力单元 能力单元 能力单元 能力单元 能力单元 能力单元 能力单元
事务脚本 领域模型 表模块 四色原型 DDD战术充血 响应式状态 插件下发 hybrid RN
梯田式架构
不同的子域根据不同的业务复杂度和质量约束,
采用不同的编程范式,建模方式,方法论,
开发构建部署形式
概念完整度、业务模型边界清晰度、
测试覆盖度、团队成熟度、单元细颗粒度
是架构可以自然升级的保障
升级
业务用户量上涨
单测
调度/分发
事件中心
升级
单测
不单测
交互定制
易维护性
快速开发
NA
业务变复杂
领域模型
MVC
MVP
Compose
能力单元由于粒度细,可以边重构,边进行产品需求开发,重构周期短,有单测验证保障
VS 标准化架构模型:大炮打蚊子,但认知迁移负担小
24. 迁移和升级准备
简单列表
简单列表
简单列表
业务自增逻辑层
弥补三级列表中台能力不足
复杂列表
三级列表中台组件
带通用业务策略的列表
可刷新的通用列表
• 最小级
• 通用业务级
• 饱满业务级
基础列表
架构现状
架构割裂,四不像,维护成本高
复杂列表业务痕迹严重,难复用,中台难落地
三级列表中台能力薄弱,其上业务重复造轮严重
提前做培训
升级问题
权力变更、无法持续投资
设计之初未分析好重点对象,另起灶炉、天马行空
没有做好培训引导、推广
不接受四不像,重塑?
25. • 过去的架构漫步
• 大环境的冲击
• 采用的架构思想和原则
• 若干场景的架构示例
• 架构维护控制
26. 定义结构和语义
组件
Processor
业务逻辑组件
连接件
Page
UI抽象组件管理者
消息
Action
连接核心业务逻辑和
基础设施、父容器、异构容器
约束 (部分摘录)
Ability
Extension
基础设施抽象组件(UI)
Process
Context
业务逻辑组件管理者
生命周期管理者
服务发现者
事件派发者
业务扩展组件
Plugin Assistant
可动态下发的
一类业务扩展
集合 对外服务接口
Extension
Point
连接核心业务逻辑和
扩展业务逻辑
• Processor中仅能接受以Ability身份封装的基础设施的交互,不能出现具体的视图类、数据存储类等
• Processor间不能互相直接交互,可以以Assistant的身份交互,或者基于Action消息交互(适合单向单工)
• Ability是基础设施的被动封装,谦卑对象, Ability间的交互只能发生在Page、Repository、 DataSource、UnitOfWork等连接件中
• Processor、Ability都可以进行复合使用,但ID标识符应虚拟,并设置为可查找内部组件
• Processor是基于“主营”业务设置的,通用时机应设计Action消息,非通用时机需要设计为Extension Point,供外部注入Extension,
禁止非“主营”特定业务以分支(if-else)的方式污染Processor
•
各种组件应附着在对应生命周期容器的Process Context里,禁止自建不必要的ID标识符Map、单例等分散的全局引用
27. 事件-组件-系统
Action
Action
Processor
UI
回调1
…
回调N
UI
业务a
业务b
业务a
Action1
Processor b
…
Processor a
Processor
Processor
Event
ActionN
事件
转换
器
Action
Action
Processor
Processor c
Action
业务c
Processor
Processor
Action
Event Sourcing
Redux动机/收益
CQRS
单向数据流,预测性好
UI只基于状态更新,Data驱动UI
无缝衔接类React思想组件
全局app级state树实现内存数据库
单一数据源置信
State不可修改,无副作用
从测UI变成测状态,易于单测
树状reducer集实现模块化
纯函数,增强组合能力
28. 上下文框架
getProcessContext()#query(AssistantA.class)
Create View
ID
外部组件事件
提供的Assistant服务
Touch
依赖的Assistant服务
Extension Point 1
Extension Point 2
Extension Point N
load
Extension Manager
Assistant Manager
服务注册和发现
Dependency Manager
Process Context
Processor
Scroll
ID规则管理和组件查找
Processor Container
Extension N
Assistant N
页面状态 监控
刷新 数据同步
模板 网络状态
运营 …
映射Action的ID
派发Action流
查找能处理的Processor集
提取组件对外接口
回调组件注册观察者
按依赖拓扑排序
业务维度划分的Processor集
Ability N
编排引擎
Page
Repository
框架提供的Process Context能力
Action Dispatcher State Map
parent 自定义的Process Context属性
Process Context
Plugin/Bundle
三方框架回调
29. 复杂业务-DDD战术设计
模型
Message
1
Params
3
1
1
Params
2
1
3
7
4
5
6 1
0
8 9
1
2
1
4
1
6
1
5
最终显示
① 读取缓存数据
一次feed流
数据源
还原历史
② 请求网络数据(下拉)
③ 请求网络数据(上滑)
④ 解析数据
去重
⑤ 装配数据
⑥ 执行云控策略
Action
⑦ 置顶数据去重
Command
重复上滑
冲突
⑧ 普通数据去重
⑨ 清理过期数据
刷新时间
间隔
频道信息
一次feed流
刷新协调
DomainEvent
基础设施层
Infrastructure Layer
⑩ 处理黑名单数据
⑪ 加载更多历史数据
⑫ 缓存数据
⑬ 回填数据
⑭ 插入数据到列表头部
⑮ 插入数据到列表尾部
⑯ 通知列表刷新
30. 展示层设计
无视图控制图层
播放器组件
视频播放区
手势图层
消息
中心
loading/fail/empty状态图层
WebView组
件
运营槽位
作者信息槽位
RN组件
运营视图图层
控制UI图层
列表组件
推荐区
点赞组件
操作
槽位
背景图层
评论组件
评论区
页面图层化
页面槽位分区化
关注组件
收藏组件
31. 展示层设计
Page
业务组装工厂层
推荐 Factory
心潮 Factory
热榜 Factory
… Factory
Layout Ability
页面实现层
能力实现层
ListView Page
JetpackCompose Page
Update RecyclerView实现 Update Compose实现
Navigate实现 Refresh实现
… Page
RecyclerView Page
列表
图层
items
页面接口层
能力接口层
other abilities
能力可注册 能力可查找
能力可发现 能力可替换
Adapter Ability
Footer Ability
可点击Footer实现 Popup实现
加载型Footer实现 … 实现
Empty View Ability
Refresh Ability
item
UI
Page
槽位分区
items
Page
items
other
items
Page
data
Update Ability
Popup Ability
Navigate Ability
页面能力接口化
… Ability
Data
processors
适配融合(父子)
32. • 过去的架构漫步
• 大环境的冲击
• 采用的架构思想和原则
• 若干场景的架构示例
• 架构维护控制
33. 架构评价和特征度量
演进式架构是支持跨多个维度进行引导性增量变更的架构,而架构的适应度函数为这些架
构特征提供了客观的完整性评估
--《演进式架构》
ATAM/SAAM
GSM-QUANTS
稳定性/抽象性度量
McCabe圈复杂度
认知复杂度
霍尔斯特德复杂度
DSQI
MOOD
34. 架构能力评估模型
团队成员
• 是否有经验丰富的架构师
• 成员多大程度有一致的目标和价值观
开发过程
• 过程是否已定义、或已量化管理
• 有无采用敏捷开发模型、快速开发模型或有效的项目管理
• 成员中有大中型重构设计经验的比例
组件、工具、平台
• 是否有组件库并有足够的组件、以及检索能力
• DevOps平台能够多大程度智能阻止不规范
成本
• 是否建立了有效的效率、质量、需求满足度、业务收益等的度量机制
• 架构防劣化可持续性、决策可逆性这些的难度
• 自动化工具占全开发工作的占比
决策
• 常规问题决策是否有路径规范可循
• 决策者是否有足够的权力和责任,不受干扰
• 决策的质量和效用能否量化、有无反馈考核机制
规范制度、最佳实践
• 规范、最佳实践的数量和质量
• 规范、最佳实践的普及、奖惩、遵守情况
35. 劣化度量监控
•
Emacs编辑器可以煮咖啡?
理念:离开发者手边越近的东西就越有价值。不离开IDE就能提供帮助的优于离开IDE
•
单例的最好写法是静态内部类方式还是契约规范?
理念:钩子(或切面、插桩)铺开的越多,越规范,就越可控,统计价值越大,架构决策越有效,也越能够自动化。
36. 度量-IDE插件
37. 度量-平台建设
管理平台
考试平台
规范文档平台
组件质量度量平台
DevOps
38. 架构过程回顾
• 架构需求分析
• 质量属性甄别
• 架构风格选型和改造设计
• 架构评审
• 架构准备、架构实现和组件库建设
• 架构维护和监控平台建设
并行开发、快速启动业务和支援、业务动态下发、尽可能免测、减少质量问题
可维护性、可复用性、可扩展性、可测试性
梯田方式,以低迁移成本改造为Redux + Hexagonal + DDD等
简易ATAM(架构权衡分析方法)
架构能力评估、培训、迭代速率度量、权力和完整性、标签建设
6+适应度函数、IDE和DevOps并重、测试体系和个人贡献挂钩
39. 架构升级实践收益
测试体系保障 开发效率
所有NA频道相关业务已全面迁移复用 核心业务单测覆盖率从0变成60%+; 可归因的效率提升10-20%;
接入架构组件来快速孵化相关业务, 自动化白盒测试覆盖了刷新主要场景 主要来自免测、非单点开发者
并行开发、动态裁剪 决策和设计自由度 平台和能力提升
业务模型边界清晰,依赖关系整
洁,扩展性好,标准化程度高 业务维度隔离,各业务可以更好的根据
自己的特点进行维护和质量权衡点决策 基础配套设施更全更智能,
输出复用收益
聚焦、认知成本降低
架构升级经验和框架沉淀,
团队sense提高、工作强度降低
40.
41.
42.
43.