一次关于架构的“嘴炮”

作者:字节跳动技术团队
转载地址:https://juejin.cn/post/7078249602410889247

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

这是一次源于头条 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 模型”。

循序渐进

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

以治理头条复杂度为例:

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

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

最后

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

原文地址:https://blog.csdn.net/weixin_61845324

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


更新Android SDK到3.0版本时,遇到Failed to rename directory E:\android\tools to E:\android\temp\ToolPackage.old01问题,导致无法更新,出现该问题的原因是由于3.0版本与较早的sdk版本之间文件结构有冲突,解决
Android 如何解决dialog弹出时无法捕捉Activity的back事件 在一些情况下,我们需要捕捉back键事件,然后在捕捉到的事件里写入我们需要进行的处理,通常可以采用下面三种办法捕捉到back事件: 1)重写onKeyDown或者onKeyUp方法 2)重写onBackPressed方
Android实现自定义带文字和图片的Button 在Android开发中经常会需要用到带文字和图片的button,下面来讲解一下常用的实现办法。一.用系统自带的Button实现 最简单的一种办法就是利用系统自带的Button来实现,这种方式代码量最小。在Button的属性中有一个是drawable
Android中的"Unable to start activity ComponentInfo"的错误 最近在做一款音乐播放器的时候,然后在调试的过程中发现一直报这个错误"Unable to start activity ComponentInfo",从字面
Android 关于长按back键退出应用程序的实现最近在做一个Android上的应用,碰到一个问题就是如何实现长按back键退出应用程序。在网上查找了很多资料,发现几乎没有这样的实现,大部分在处理时是双击back键来退出应用程序。参考了一下双击back键退出应用程序的代码,网上主流的一种方法是下面
android自带的时间选择器只能精确到分,但是对于某些应用要求选择的时间精确到秒级,此时只有自定义去实现这样的时间选择器了。下面介绍一个可以精确到秒级的时间选择器。 先上效果图: 下面是工程目录: 这个控件我也是用的别人的,好像是一个老外写的,com.wheel中的WheelView是滑动控件的主
Android平台下利用zxing实现二维码开发 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平台上应用比较成熟,而在Android平台上主流还是用zxing库,因此这里主要讲述如何利用zxing
Android ListView的item背景色设置以及item点击无响应等相关问题 在Android开发中,listview控件是非常常用的控件,在大多数情况下,大家都会改掉listview的item默认的外观,下面讲解以下在使用listview时最常见的几个问题。1.如何改变item的背景色和按
如何向Android模拟器中导入含有中文名称的文件在进行Android开发的时候,如果需要向Android模拟器中导入文件进行测试,通过DDMS下手动导入或者在命令行下通过adb push命令是无法导入含有中文文件名的文件的。后来发现借用其他工具可以向模拟器中导入中文名称的文件,这个工具就是Ultr
Windows 下搭建Android开发环境一.下载并安装JDK版本要求JDK1.6+,下载JDK成功后进行安装,安装好后进行环境变量的配置【我的电脑】-——>【属性】——>【高级】 ——>【环境变量】——>【系统变量】中点击【新建】:变量名:CLASSPATH变量值:……
如何利用PopupWindow实现弹出菜单并解决焦点获取以及与软键盘冲突问题 在android中有时候可能要实现一个底部弹出菜单,此时可以考虑用PopupWindow来实现。下面就来介绍一下如何使用PopupWindow实现一个弹出窗。 主Activity代码:public void onCreat
解决Android中的ERROR: the user data image is used by another emulator. aborting的方法 今天调试代码的时候,突然出现这个错误,折腾了很久没有解决。最后在google上找到了大家给出的两种解决方案,下面给出这两种方法的链接博客:ht
AdvserView.java package com.earen.viewflipper; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory;
ImageView的scaleType的属性有好几种,分别是matrix(默认)、center、centerCrop、centerInside、fitCenter、fitEnd、fitStart、fitXY。 |值|说明| |:--:|:--| |center|保持原图的大小,显示在ImageVie
文章浏览阅读8.8k次,点赞9次,收藏20次。本文操作环境:win10/Android studio 3.21.环境配置 在SDK Tools里选择 CMAKE/LLDB/NDK点击OK 安装这些插件. 2.创建CMakeLists.txt文件 在Project 目录下,右键app,点击新建File文件,命名为CMakeLists.txt点击OK,创建完毕! 3.配置文件 在CMa..._link c++ project with gradle
文章浏览阅读1.2w次,点赞15次,收藏69次。实现目的:由mainActivity界面跳转到otherActivity界面1.写好两个layout文件,activity_main.xml和otherxml.xmlactivity_main.xml<?xml version="1.0" encoding="utf-8"?><RelativeLayout ="http://schemas..._android studio 界面跳转
文章浏览阅读3.8w次。前言:最近在找Android上的全局代理软件来用,然后发现了这两款神作,都是外国的软件,而且都是开源的软件,因此把源码下载了下来,给有需要研究代理这方面的童鞋看看。不得不说,国外的开源精神十分浓,大家相互使用当前基础的开源软件,然后组合成一个更大更强的大开源软件。好吧,废话不多说,下面简单介绍一下这两款开源项目。一、ProxyDroid:ProxyDroid功能比较强大,用到的技术也比较多,源码也_proxydroid
文章浏览阅读2.5w次,点赞17次,收藏6次。创建项目后,运行项目时Gradle Build 窗口却显示错误:程序包R不存在通常情况下是不会出现这个错误的。我是怎么遇到这个错误的呢?第一次创建项目,company Domain我使用的是:aven.com,但是创建过程在卡在了Building 'Calculator' Gradle Project info这个过程中,于是我选择了“Cancel”第二次创建项目,我还是使用相同的项目名称和项目路_r不存在
文章浏览阅读8.9w次,点赞4次,收藏43次。前言:在Android上使用系统自带的代理,限制灰常大,仅支持系统自带的浏览器。这样像QQ、飞信、微博等这些单独的App都不能使用系统的代理。如何让所有软件都能正常代理呢?ProxyDroid这个软件能帮你解决!使用方法及步骤如下:一、推荐从Google Play下载ProxyDroid,目前最新版本是v2.6.6。二、对ProxyDroid进行配置(基本配置:) (1) Auto S_proxydroid使用教程
文章浏览阅读1.1w次,点赞4次,收藏17次。Android Studio提供了一个很实用的工具Android设备监视器(Android device monitor),该监视器中最常用的一个工具就是DDMS(Dalvik Debug Monitor Service),是 Android 开发环境中的Dalvik虚拟机调试监控服务。可以进行的操作有:为测试设备截屏,查看特定进程中正在运行的线程以及堆栈信息、Logcat、广播状态信息、模拟电话_安卓摄像头调试工具