您的浏览器禁用了JavaScript(一种计算机语言,用以实现您与网页的交互),请解除该禁用,或者联系我们。[ArchSummit深圳2023|全球架构师峰会]:架构师该如何考虑软件可持续迭代_段和尘 - 发现报告

架构师该如何考虑软件可持续迭代_段和尘

AI智能总结
查看更多
架构师该如何考虑软件可持续迭代_段和尘

讲师自我介绍 毕业于中科院,十二年从事移动端Android研发。百度→创业→魅族→创业→腾讯→字节。目前负责头条的Android客户端架构。 段和尘 又失败了咋办?《在岁月中远行》 几个小问题 1. 你所了解的架构是什么? A.一个完美的设计,能够解决各种软件问题B.没有完美的架构,需要不断对实现做重构 2.你觉得架构师们每天都在干什么? A.每天都根据用户的需求,讨论如何做软件设计B.每天都在填坑,填不完的坑… 01020304架构面临的问题架构常见的手段架构演进的例子成为优秀架构师 01 架构面临的问题 不同产品生命周期的架构问题 不同技术领域的架构问题 公共问题 前端 交叉问题 •编程思想:OOP/AOP/IoC…•问题分解:按业务/按技术…•领域建模:接口设计/DSL/…•服务治理:模块化/容器化…•流程机制:敏捷开发/单测手段…•架构标准:公约文档/数据监测… 客户端 服务端 •语言:Java/Kotlin/Swift/C#...•框架:GMS/Flutter/Cocos…•平台:Android/iOS… •语言:Java/Python/Go...•框架:Spring/Flask/Beego..•平台:CentOS/Windows/… 还有一些其他挑战 只要业务继续发展,越来越复杂就是必然趋势。 理解成本变高•宏大的规模是不好理解的•复杂的结构是不好理解的 预测难度变大•业务变化不可预测•技术变化不可预测 典型的架构设计 – Android OS 应用框架层 Binder IPC App开发者直接使用的接口层,UI的实现、数据的处理、资源的使用,都是利用这一层的API 提供跨进程访问的能力,App可以高效的访问由系统进程暴露的能力。App进程与系统进程之间的通信是典型的C/S模型。 系统服务 提供窗口管理、相机、音视频等重要的系统能力,包含各种子系统,内部逻辑十分庞大,往下调用HAL层封装的硬件能力;往上通过Binder暴露可以远程调用的API 硬件抽象层屏蔽底层不同驱动的差异,使得系统服务层可以快速适配到不同的硬件设备 Linux内核CPU、内存、唤醒服务等重要的驱动实现都是基于该层操作系统的核心实现。 典型的架构设计 – iOS 应用框架层EventKit、GameKit、MapKit、PushKit 图形图像层ULKit、Animation、Graphics、Images 核心服务层Location、Motion、Health、GPS、Telephony、Foundation… 内核层Bluetooth、Security、Accessories… 典型的架构设计 - Flutter UI框架层 提供不同样式的组件和动画,声明式UI。采用了Dart作为编程语言,能够同时支持JIT和AOT,在开发调试和运行阶段都能有不错的效率提升 嵌入层Flutter引擎需嵌入不同的平台:Android/iOS/Windows/Linux等 小结 •架构设计是为了解决特定领域不同发展阶段的业务问题•不同领域的架构有明显的技术差异,但也有很多相似性•架构不仅面临技术挑战,还要应对组织业务膨胀的熵增•移动端需要利用有限的设备资源设计符合小屏幕的架构 02 常见的架构手段 小的架构手段– MVC/MVP/MVVM 小的架构手段– MVVM 小 的 架 构 手 段–D a t aBinding 单向绑定:数据→视图 典型场景 Android使用特征 界面模板,不同区域填充不同数据不同状态显示不同界面,界面局部更新输入框,选择框 @{}Observable,@BindAdapter@={},@InverseBindingAdapter 小的架构手段– IoC 控制反转,是一种模块化的编程思想,有不同的实现方式。 •依赖注入(Denpendency Injection)•Constructor Injection(eg: Spring @Autowired,在构造的时 候,将被依赖的对象注入)•Setter Injection(eg: Spring通过setter方法将依赖的对象注入)•Parameter Injection(eg: Retorfit @Header,@Query,@Path)•Interface/Method injection(eg: Callback) •依赖查询(Dependency Lookup)•Service Locator(eg: Service Provide Interface) •Contextualized Lookup(eg: Android Context)•Template Method(eg: ViewDataBinding...)•Strategy(eg: Scheduler, Event-Driven) 小的架构手段– IoC滥用的案例 大的架构手段 小结 •不同架构手段的共同目标是高内聚低耦合•找到适合业务场景的架构而不是炫技滥用•一个复杂的系统是多种架构模型的组合体 03 架构演进的例子 孕育期 做一个信息流产品,可以无限刷的列表 •首先,需要实现一个列表,支持上下滑动•然后,每次滑动,都需要请求服务端数据•接着,列表的每一项都需要响应点击操作•… 婴儿期 产品功能开始变多,需要拆分模块 •首先,需要支持图文内容的组合混排显示•接着,需要引入账号体系,用户注册登录•然后,用户可以收藏感兴趣的内容并分享•…•继续,场景越来越多,拆分网络和多线程•… 学步期 业务场景变多,需要拆分业务 •首先,支持用户发布文章,并给予奖励•接着,视频这个重要的内容也需要支持•然后,不同业务之间越做越大需要拆分•…•继续,拆分出视频业务,架构自成体系•…•继续,拆分出中台业务,供多业务使用•… 学步期–分层架构 表现层:接收用户输入,获取数据,呈现界面 业务层:处理业务数据,数据流转,安全检查 持久层:提供数据的增删改查能力 存储层:按照特定的格式存储数据 缺点•对层级管控要求严格,灵活性低 优点•结构简单清晰,易于理解和管控 •为了解耦容易拆分出很多中间层 •层级关系适合不同技能人员分工 青春期 不同业务和模块混合,需要解耦 •首先,需要约定模块可以对外提供的能力•接着,模块之间需要遵循相同的调用方式•然后,旧的模块需要按照相同标准来改造•…•继续,使用方不应该直接依赖于实现方•… 青春期–事件驱动架构 事件Event:一个消息,譬如触摸了屏幕、点击了按钮 事件处理器Processor:事件的实际消费者,对关注的消息进行订阅,消息处理的过程很灵活,可以在当前处理器“吞”掉一个消息,也可以继续将消息交由其他消息队列处理(责任链) 事件队列Event Channel:消息队列,事件将以消息的形式发布到队列中,并设计特定的派发机制来处理队列中的消息 缺点•缺少约束,消息处理器容器膨胀 优点•适用广泛,容易扩展出不同变种 •性能较好,支持消息的异步处理 •处理链路容易变长,理解成本高 青春期–事件驱动架构实例 1.事件发布:「You Moved」事件被处理器「Customer」接收处理 2.事件处理:「Customer」将事件转换为「ChangeAddress」,并发布到消息队列 3.事件处理:「Quote」和「Claims」两个事件处理器都订阅了「Change Address」消息,并收到了从消息队列派发出的消息 4.事件处理:「Quote」将消息转换为「RecalcQuote」并将其派发给「Notification」这个处理器;「Claims」将消息转换为「Update Claims」,并将其派发给「Notification」和「Adjustment」 实例 壮年期 业务变得更加内聚,需要灵活插拔 •首先,扫一扫等能力不是所有场景都需要•接着,视频的子能力可以拆解后按需使用•然后,越来越多的业务想动态化发布产物•…•继续,动态化发布引入很多问题需要调优•… 壮年期–微内核架构 宿主容器:Core System,一般不包含具体业务逻辑,而是从中抽象出模型,相当于一个运行环境,供不同业务以插件的形式在其中运行 插件:Plug-in Component,具体的业务实现,通过一定的技术手段挂载到宿主容器中,插件一般可以访问宿主的资源 优点•高扩展性,需要什么就开发什么 缺点•对宿主容器的要求很高,且宿主不易扩展 •插件的注册和通信机制通常比较复杂 •插件隔离,能够简化业务耦合度 稳定期 用户规模和团队稳定,历史包袱重 •首先,经过前期快速发展已经积累了大量历史包袱•接着,需要深入了解业务才能设计出更合理的架构•然后,很多改动牵一发动全局,代码被迫变得更差•…•继续,新旧技术栈共存,版本依赖冲突,冗余代码•… 稳定期–微服务架构 请求接入:服务使用方发起请求,请求以一定的方式(可以直接调用,也可以跨进程调用)发送到服务注册中心,等待请求的处理 服务调度:Broker,将服务请求调度到对应的微服务节点上进行处理 微服务:Service Component,一个高度内聚的模块集合,对外暴露服务接口。每一个微服务都是独立的,分别向服务注册中心注册自身所能提供的服务接口 缺点•容器出现服务数量腹胀难以管控 优点•健壮性好,单个服务不影响全局 •服务隔离,服务之间互不相耦合 •服务发现和通信需要额外的成本 贵族期 期望高 事情难 •业务历久弥新,历史包袱叠加新的场景•随便动动刀子就拔出萝卜带出泥•技术栈层出不穷,老朽学不动了啊•一方面要保持成熟稳定,一方面要积极探索落地 •良好的顶层设计,从上到下有统一的认知•遵循共同的规范,写出让人舒适的代码•有没有“一劳永逸”的设计,可保基业长青•什么时候能从架构工作中找到成就感 疗效慢 责任大 •影响复杂度的因子众多,单个因子优化不足以撼动•没有一年半载,一波治理搞不下来•没有特效药,长期在隐隐作痛中前行•往往也只是开了一个“方子”,想要根治得长期健身 •设计不合理:这谁写的,看小爷我推到重来•使用不规范:这压根就不该这么用•逻辑太晦涩:这尼玛谁看得懂•编码坑太多:这特么是隐藏技能啊,悄无声息改代码 贵族期 对抗架构衰老,从我做起 “这个组件不迭代了,不用改了吧”→“这个组件的API不合理,其他App很难用,得改”“这一坨陈年无用代码反正也不影响功能”→“这对其他App就是累赘,必须删掉”“这个逻辑有点多,改起来容易错,还是新搞一个吧”→“通用逻辑,还是好好重构统一吧”“这个着急合码,先这样吧,后面再改”→“不行啊,此时不改,祸害好几方”“小问题来着,就头条有,先观察一下”→“不仅仅影响到局部了,得谨慎分析一下” 官僚期 代码混乱无序 不同形态的架构 小结 •架构随业务发展由简单变得复杂是规律•没必要最初用复杂架构来解决简单问题•需要用规范持续重构来对抗代码的腐朽 04 成为优秀架构师 越是前面越难 定义问题→确定架构→方案落地→结果复盘 认清问题–分类 架构的问题是盘根错节的,将所有问题放在一起,就有轻重缓急之分,就有类别之分 认清问题–分类 区分问题的类别,就能在一定的边界内,匹配上对应的人来解决问题 认清问题–分级 挑战、问题、手段这些经常混为一谈,哪些是挑战?哪些是问题?那些是手段?其实这些都是一回事,就是矛盾,只是不同场景下,矛盾所在的层级不同 理性看待 - 技术债的产生和应对 Technical Debt,本应采用最佳方案,但妥协了,从而给未来带来了负担。有意的 公开技术债 一开始就与利益相关方权衡技术债的利弊,明确影响和解决方案可以将所有的技术债量化公示,短期和长期技术债可以区分对待大家遵循相同的编码规范 消费技术债 每次迭代确定一定数量的技术债作为消费