4

一次关于架构的“嘴炮”

 2 years ago
source link: https://juejin.cn/post/7078249602410889247
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

文章标题很随意,些微有一些骗点击的“贼意”;但内容却是充满了诚意,想必你已经感受到了。

这是一次源于头条 Android 客户端软件架构问题的探讨,之所以冠上“嘴炮”之名,是因为它有一些务虚;同时又夹杂了一些方法论,不仅适用于客户端软件架构,也适用于其他工作场景,希望对大家有所帮助。

为了拉满读者的带入感,且以“我们”为主语,来看架构的挑战、判断和打法

我们的挑战

优秀的公司对架构都有着很高的期许,都希望有一个良好的顶层设计,从上到下有统一的认知,遵循共同的规范,写出让人舒适的代码,甚至有那么一丢偷懒,有没有“一劳永逸”的架构设计可保基业长青?

然而高期望意味着高落差,面对落差,我们容易焦虑:

  • 代码什么时候能写的看上去本就应该是那个样子;而现在怎么就像是在攀登“屎山”呢?
  • 文档什么时候能写的既简明又详细;而现在怎么就简明的看不懂,详细的很多余呢?
  • 工具什么时候能更好用更强大一点;而现在怎么就动不动掉链子,没有想要的功能常年等排期呢?
  • “我”什么时候能从架构工作中找到成就感,而不是搞一搞就想着跑路呢?

大量问题的最终归因都是代码问题:设计不合理、使用不规范、逻辑太晦涩、编码“坑”太多。

没有一个单一的团队能承担这些问题的责任,我们收到过很多“吐槽”:

  • 这尼玛谁写的,简直不堪入目,看小爷我推倒重来展现一把真正的实力
  • XX 在这里埋了颗雷,但 XX 已经不管了,事到如今,我也只能兜底搞一把
  • 这压根就不应该这么用,本来的设计又不是为了这个场景,乱搞怪我咯?
  • 卧槽,这特么是隐藏技能啊,编译时悄悄改了老子的代码,找瞎了都没找到在哪过环节渗透进来的

一方面,口嗨一时爽,我们“吐槽”历史代码得到了一时的舒缓;另一方面,也意味着责任也传递到了我们:处理得好,我们的产出可能还是一样会被当作糟粕,但如果处理不好,我们就断送了业务发展的前程。

架构面临的从来不是单一的业务问题,而是多个业务多人协作的交叉问题,负重前行是常态。

  • 业务历久弥新,历史包袱叠加新的场景,随便动动刀子就拔出萝卜带出泥。譬如:头条 2021 年 10 月的版本有 XXXX 组件,相比一年前已经翻倍;类个数 XXXXX;插件 XX 个;仓库数量 XX 个;ttmain 仓库权限 XXX 人。(XX 代表数量级,隐去了具体数字,^_^)
  • 技术栈层出不穷,一方面要保持成熟稳定,一方面要积极探索落地。架构的同学要熟悉多种技术栈,譬如:跨端技术在客户端业务中通常都是多种共存(H5/Hybrid/小程序/Lynx/Flutter),一个业务到底选用哪种技术栈进行承载,需要耗费多少成本?选定技术栈后存在什么局限,是否存在不可逾越的障碍?

我们经常说代码复杂度高,并把降复杂度作为架构方向的重点工作之一;但影响复杂度的因子众多,从外部来看,有主观感受、客观指标、行业对标三个角度;从内部来看,有工程组织、代码实现和技术栈三个角度。即便我们很好的优化了工程结构这个因子,短时间内也很难感受到复杂度有一个明显的下降。

图片

我们常说治理,其实是设计一种机制,在这种机制下运转直到治愈。

就像老中医开方子,开的不是特效药,而是应对病症的方法,是不是有用的方子,终究还是需要通过实践和时间的检验。希望我们不要成为庸医,瞎抓几把药一炖,就吹嘘药到病除。

我们的判断

架构问题老生常谈

谁来复盘架构问题,都免不了炒一炒“冷饭”;谁来规划架构方向,都逃不出了“减负”、“重构”、“复用”、“规范”这些关键词。难点在于把冷饭炒热,把方向落实。

图片

架构方向一直存在

架构并不只局限于一个产品的初始阶段,而是伴随着产品的整个生命周期。架构也不是一成不变的,它只适合于特定的场景,过去的架构不一定适合现在,当下的架构不一定能预测未来,架构是随着业务不断演进的,不会出现架构方向做到头了、没有事情可搞了的情况,架构永远生机勃勃。

图片

图片

  • 强制遵循规范:  通常会要求业务公共的组件逐渐下沉到基础组件层,但随着时间的推移,这个规范很容易被打破
  • 需要成熟的团队:  领域专家(对业务细节非常熟悉的角色)和开发团队需紧密协作,构建出核心领域模型是关键。但盲目尝试 DDD 往往容易低估领域驱动设计这套方法论的实践成本,譬如将简单问题复杂化、陷入过分强调技术模型的陷阱

迄今为止,用于商业应用程序的最流行的软件架构设计模式是大泥球(Big Ball of Mud, BBoM),BBoM 是“......一片随意构造、杂乱无章、凌乱、任意拼贴、毫无头绪的代码丛林。”

泥球模式将扼杀开发,即便重构令人担忧,但也被认为是理所应当。然而,如果还是缺乏对领域知识应有的关注和考量,新项目最终也会走向泥球。没有开发人员愿意处理大泥球,对于企业而言,陷入大泥球就会丧失快速实现商业价值的能力。

——《领域驱动设计模式、原理与实践》Scott Millett & Nick Tune

复杂系统熵增不断

只要业务继续发展,越来越复杂就是必然趋势,这贴合热力学的熵增定律。

可以从两个维度来看复杂度熵增的过程:理解成本变高预测难度变大

图片

理解成本:规模和结构是影响理解成本的两个因素

  • 宏大的规模是不好理解的,譬如:在城市路网中容易迷路,但在乡村中就那么几条道
  • 复杂的结构是不好理解的,譬如:一个钟表要比一条内裤难以理解

当需求增多时,软件系统的规模也会增大,且这种增长趋势并非线性增长,会更加陡峭。倘若需求还产生了事先未曾预料到的变化,我们又没有足够的风险应对措施,在时间紧迫的情况下,难免会对设计做出妥协,头疼医头、脚疼医脚,在系统的各个地方打上补丁,从而欠下技术债(Technical Debt)。当技术债务越欠越多,累积到某个临界点时,就会由量变引起质变,整个软件系统的复杂度达到巅峰,步入衰亡的老年期,成为“可怕”的遗留系统。

正如饲养场的“奶牛规则”:奶牛逐渐衰老,最终无奶可挤;然而与此同时,饲养成本却在上升。

——《实现领域驱动设计 - 深入理解软件的复杂度》张逸

预测难度:当下的筹码不足以应对未来的变化

  • 业务变化不可预测,譬如:头条一开始只是一个单端的咨询流产品,5 年前谁也不会预先设计 Lite 版、抖音、懂车帝等,多端以及新的业务场景带来的变化是无法预测的。很多时候,我们只需要在当下做到“恰当”的架构设计,但需要尽可能保持“有序”,一旦脱离了“有序”,那必将走向混乱,变得愈加不可预测
  • 技术变化不可预测,譬如:作为一个 Java 开发人员,Lambda 表达式的简洁、函数式编程的快感、声明式/响应式 UI 的体验,都是“真香”的技术变化,而陈旧的 Java 版本以及配套的依赖都需要升级,一旦升级,伴随着的就是多版本共存、依赖地狱(传递升级)等令人胆颤的问题。很多时候,我们不需要也没办法做出未来技术的架构设计,但需要让架构保持“清晰”,这样我们能更快的拥抱技术的变化

既然注定是逆风局,那跑到最后就算赢。

过多的流程规范反倒会让大家觉得是自己是牵线木偶,牵线木偶注定会随风而逝。

我们应该更多“强调”一些原则,譬如:分而治之、控制规模、保持结构的清晰与一致,而不是要求大家一定要按照某一份指南进行架构设计,那既降低不了复杂度,又跟不上变化。“强调”并不直接解决问题,而是把重要的问题凸显出来,让大家在一定的原则下自己找到问题的解决办法。

我们的打法

我们的套路是:定义问题 → 确定架构 → 方案落地 → 结果复盘。越是前面的步骤,就越是重要和抽象,也越是困难,越能体现架构师的功力。所以,我们打法的第一步就是要认清问题所在。

架构的问题是盘根错节的,将所有问题放在一起,就有轻重缓急之分,就有类别之分。区分问题的类别,就能在一定的边界内,匹配上对应的人来解决问题。

工程架构:

业务架构:

基础能力:

挑战、问题、手段这些经常混为一谈,哪些是挑战?哪些是问题?那些是手段?其实这些都是一回事,就是矛盾,只是不同场景下,矛盾所在的层级不同,举一个例子:

我们判断当前的研发体验不能满足业务日渐延伸的需要,这是一个矛盾,既是当下的挑战,也是当下的一级问题。要处理好这个矛盾,我们得拆解它,于是就有了二级问题:我们的代码逻辑是否已经足够优化?研发流程是否已经足够便捷?文档工具是否已经足够完备?二级问题也是矛盾,解决好二级问题就是我们处理一级矛盾的手段。这样层层递进下去,我们就能把握住当前我们要重点优化和建设的一些基础能力:插件化、热更新、跨端能力。

在具体实践过程中,基础技术能力还需要继续拆解,譬如:热更新能力有很多(Java 层的 Robust/Qzone 超级补丁/Tinker 等,Native 层的 Sophix/ByteFix 等),不同热更方案各有优劣,适用场景也不尽相同。我们要结合现状做出判断,从众多方案汲取长处,要么做出更大的技术突破创新,要么整合已有的技术方案进行组合创新。

勤于思考问题背后的问题

亨利福特说,如果我问客户需要什么,他们会告诉我,他们需要一匹更快的马。从亨利福特的这句话,我们可以提炼出一个最直接的问题:客户需要一匹更快的马。立足这个问题本身去找解决方案,可能永远交不出满意的答卷:寻找更好的品种,更科学的训马方式。

思考问题背后的问题,为什么客户需要一匹更快的马? 可能客户想要更快的日常交通方式,上升了一个层次后,我们立刻找到了更好的解决方案:造车。

我们不能只局限于问题本身,还需要看到问题背后的问题,然后才能更容易找到更多的解决方案。

认知金字塔

引用认知金字塔这个模型,谨以此共勉,让我们能从最原始数据中,提炼出解决问题的智慧。

DATA:  金字塔的最底层是数据。数据代表各种事件和现象。数据本身没有组织和结构,也没有意义。数据只能告诉你发生了什么,并不能让你理解为什么会发生。

INFORMATION:  数据的上一层是信息。信息是结构化的数据。信息是很有用的,可以用来做分析和解读。

KNOWLEDGE:  信息再往上一层是知识。知识能把信息组织起来,告诉我们事件之间的逻辑联系。有云导致下雨,因为下雨所以天气变得凉快,这都是知识。成语典故和思维套路都是知识。模型,则可以说是一种高级知识,能解释一些事情,还能做预测。

WISDOM:  认知金字塔的最上一层,是智慧。智慧是识别和选择相关知识的能力。你可能掌握很多模型,但是具体到这个问题到底该用哪个模型,敢不敢用这个模型,就是智慧。

这就是“DIKW 模型”。

架构的问题不能等,也不能急。一个大型应用软件,并非要求所有部分都是完美设计,针对一部分低复杂性的区域或者不太可能花精力投入的区域,满足可用的条件即可,不需要投入高质量的构建成本。

以治理头条复杂度为例:

  • 长期的架构目标:更广(多端复用)、更快(单端开发速度)、更好(问题清理和前置拦截)
  • 当下的突出问题:业务之间耦合太重、缺少标准规范、代码冗余晦涩

图片

细节已打码,请读者不要在意。重点在于厘清问题之后,螺旋式上升,做到长期有方向,短期有反馈。

一顿输出之后,千万不能忘却了人文关怀,毕竟谋事在人。架构狮得供起来,他们高瞻远瞩,运筹帷幄;但架构人,却是更需要被点亮的,他们可能常年在“铲屎”,他们期望得到认可,他们有的还没有对象...干着干着,架构的故事还在,但人却仿佛早已翻篇。

我们是今日头条客户端 Android 团队,我们的业务方向包括:

  • 架构优化(深圳/北京):负责头条系 APP 的客户端架构、插件、热修等基础能力建设优化等;
  • 增长业务(深圳):负责头条系 APP 的金币、活动、联动等增长相关业务,海量数据挖掘业务增长;
  • 安全合规(广州/深圳):负责头条系 APP 的安全、隐私保护、监管合规等工作;

大量 HC 正在热招,投递简历或问题咨询,可发送邮件到:[email protected]

了解更多岗位详情👇

tjock.github.io/bytedance/?…


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK