前端技术架构与工程

3,741 阅读18分钟

《前端技术架构与工程》 读后感。此文写于2020年10月,2022年2月对外发布。

工程化

架构可以渗透到任何一个细微之处,即使再简单不过的一个静态网页也存在架构,只不过过于简单,没有讨论价值。当业务的复杂度提升到必须有更复杂的技术架构承载时,对架构的研究才有意义。

工程化同样如此,任何针对架构和工程的讨论和研究必须以业务为根本点出发。

前端的定义

目前前端工程师的工作重点逐渐偏向复杂的交互逻辑和架构,技能和发展方向也发生了改变。当前较普遍的有两个方向:

  • 大前端:服务端 + Web 前端
  • 泛前端:App前端 + Web 前端

“泛前端” 已经脱离了传统意义上的前端范畴,这种模式目前仍处于探索阶段

有一种声音提倡所谓的 “全栈开发”,即前端工程师负责开发客户端逻辑的同时,将 Web 服务端、数据库管理等工作一并包揽。这是一个美好的愿景,但实际上一个人很难做到从前到后面面俱到。当然如个人博客等小体量网站(体量小、架构简单且对稳定性要求不高)除外,对于大型 Web 应用程序来说,每一个环节都必须做到尽善尽美。术业有专攻,专业的事情最好交给专业的人去做。

另一种声音认为前端工程师可以负责一部分 Web 服务端工作,但仅限于渲染。例如,首页 Node.js 架设中间渲染层,将前后端模板统一,如淘宝的 Midway Framework。这种模式是是实现前后端分离的一种探索,且已得到业界一定的认可和普及。

目前 “大前端” 模式已经成为主流。

业务逻辑和交互逻辑

“大前端” 将与渲染功能相关的 Controller 归属于前端的工作范畴,定义为中间渲染层

大前端分层架构.png

各个层级之间没有明确的分界线,仅是架构设计上的划分。对于大型项目而言,分层架构是实现关注点分离的必要途径。业务逻辑层、数据访问层和数据存储层三者之间的划分相对比较清晰,相关技术和生态也相对成熟,并且不论是传统的前端还是“大前端”均不会纵深到业务逻辑层以下。所以对于前端工程师来说,数据访问层和数据存储层并不是深入研究的对象。

前端和服务端的开发工作分别对应交互模块和业务模块。

交互逻辑层和业务逻辑层定义:

  • 业务逻辑是现实业务规则的编码实现,决定了数据被创建、存储和修改的规则
  • 交互逻辑指的是将数据展示给用户的方式

前端的边界

前端工程师这一岗位被独立分化出来的初衷是负责客户端相关的开发工作。

在分层架构的演进过程中,每一次的分层都贯彻了关注点分离原则,将各个层级进行分离、解耦,从而搭建高性能、高可用、高扩展、可伸缩的应用层序架构,同时提高开发团队的迭代和维护效率。

业务逻辑层作为 Web 网站业务的核心,最主要的原则之一是平台无关性。比如,一个大点的平台有 Web、App、微信小程序等客户端平台,所有平台的核心业务逻辑必须保持一致

架构的分层是一种设计理念,意在解耦,而不是承载各层级的技术“能力”为界限。这里的“前端的边界”并非指的是“前端工程师的能力边界”,而是前端在 Web 分层架构中的位置。业务逻辑层不属于前端范畴并不代表前端工程师不能接触业务逻辑,职称只是一个代号。实际工作应根据团队组织架构和产品需求而定。

历史不断推进,技术和生态也不断进化,分层架构也只是目前时间节点的一种相对较优的实践方案,具有时代的局限性。当前的时代背景下,这种层级的划分是比较合理的,前端仍然是围绕交互逻辑展开的

架构与工程

现实中并不一定要求项目具备足够的复杂度才会涉及架构,即使一个最简单的静态网页也存在架构,只是太过于简单缺乏深入研究和讨论的价值。任何项目都会涉及到开发、测试、发布和维护,这些流程均属于工程领域。 除了项目本身的复杂度以外,业务的类型、场景、平台、用户群体等特征同样是架构的决定性因素。

任何架构的设计和实施必然以业务特征为根本点出发,否则毫无意义。而支撑项目的正常运行仅仅是衡量架构合理性最基础的标准。除此之外,架构的设计往往需要考虑高可用性、可扩展性、可伸缩性、性能以及安全,要保证项目在多变的生产环境下能够高效且稳定地运行,这些都是同样从工程角度考虑的要点。

软件工程出总是解决软件危机,如:

  • 成本超标,包含硬件成本、人员成本、时间成本等
  • 性能不理想且功能不稳定
  • 开发过程混乱无序难以管理
  • 代码不规范,维护成本高

工程学方法的核心是结合实际情况建立可续的、规范的设计和生产流程,降低生产成本。

代码和流程是软件工程的核心关注点。从代码角度考虑,软件的目标是保证软件的高可用性、可扩展性、可伸缩性、性能以及安全,这些要素共同组成了软件的技术架构。

在架构之外,工程从更宏观的角度完善开发和维护流程的管控,强调项目迭代的规范性、有序性、可控性和高效性,并根据架构特征提供额外的辅助功能。

架构与工程的关系

若将前端工程化于架构之外的部分称为前端工程服务体系,则前端工程化的定义为:

前端工程化 = 前端技术架构 + 前端工程服务体系

由于前端技术架构的零散性以及模糊的工程边界,传统的软件工程方法与架构设计理念并不完全适用于前端。

零散的前端架构

如果将浏览器作为前后端的界定线(事实上,早期甚至目前很大一部分前端工程师确实只负责浏览器网页端的工作),AJAX 诞生前的“源码目录结构”的前端架构 可称为“第一代前端架构模式”。AJAX 诞生后有了性能优化环节,前端工程师开始思考合理的组件化模块化;数据复杂度和体量的增长催生了 MV* 框架,前端架构中新增了数据管理模块,形成了“第二代前端架构模式”,相比前一代新增了:

  • 性能优化
  • 组件化、模块化
  • 数据管理

Node.js 的普及令前端开始接触 Web 服务层,前端工程师开始思考架构的进一步细化解耦,即前后端分离。确切地说,前后端分离应该理解为一种分工协作的模式。至此,“第三代前端架构模式”成形。完整的前端架构包括:

  • 源码组织规范
  • 组件化、模块化
  • 数据管理
  • 性能优化
  • 前后端分离

以上各个环节是任何一个大中型 Web 前端项目必然具备的,我们可以称之为前端架构的共通点,或者说其是与业务类型无关的。

HTML5 为前端带来了多媒体(Video/Audio)、绘图(WebGL/WebGPU)、即时通信(WebRTC)等技术,前端的业务类型也开始扩展。不同业务类型的技术架构往往包含了一些与业务紧密相关的特殊性,如视频播放器分段视频的无缝播放、复杂图形的交互流畅度、多人协作平台等。这些独特的业务类型均在一定程度上造成了前端技术技术架构的零散性,当然项目的体量也同样影响了前端技术架构的设计。

模糊的前端工程边界

“大前端”也好,“泛前端”也罢,不同的分工模式说明目前市场对于前端工程是没有明确的定位,前端工程师的工作范畴并不清晰。这种局面不仅造成了前端与其他职能岗位之间模糊的分工,同时也影响了前端工程师服务体系的界定原则。 分工模式的差异会直接影响前端工程服务体系的差异,如有无 SEO 需求,可决定是否是 SPA、SSR 还是同构。

前端与测试

单元测试和集成测试通常由开发人员在将应用程序交付测试之前进行。

前端单元测试的目标是在既定接口规范的前提下保证交互逻辑的正确性。

服务端单元测试的目标是正确响应由前端发起的网络请求。

端到端测试指的是将所有组件和模块组装成完整的应用程序后进行的技术性测试,测试范畴包括功能、性能、健壮性、稳定性等。

验收测试可以简单理解为站在用户的角度去评估应用程序是否满足了需求,由需求方或者 PO 负责

前端与运维

前端与其他职能团队之间的分歧主要在于某些功能如何实现,前端与运维的分歧集中在某些功能应该交给谁来做。

大部分企业对于技术团队的组织结构划分秉承着研发与运维分离的原则,寄将负责业务开发、测试、设计等职能的岗位汇总在一起组成“应用研发团队”,将运维岗位独立为“线上保障团队”。

传统的研发与运维职能分配.png

将研发与运维分离的主要目的是保障线上的稳定性(减少人为导致的低级错误、建立固定的上线周期),但影响了迭代的自由度。近几年于此架构相反的 DevOps 模式开始崛起,目标是实现软件开发、测试和发布的敏捷性和持续化,也正是解决了一部分痛点,DevOps 逐渐成为了主流,特别是和敏捷模式搭配。

最近 BizDevOps 开始冒头,不知道能否像愿景一样打通业务( Biz)、开发(Dev)和运维(Ops),让他们成为一个高效运作的整体,建设 BizDevOps 实践体系,赋能数字化时代的组织,加速业务发展和创新。

开发与运维的协作关系直接影响了工程体系在部署环节的具体形态。传统模式下(开发与运维分离),开发人员基本不关心持续化的问题;DevOps 下,持续优化与每个人都息息相关。

前端架构师的职责

前端架构师的职责可以概况为两个方面:

  • 根据业务特征设计合理的前端技术架构
  • 根据架构特征搭建高效的前端工程服务体系

技术架构

人活着就是在对抗熵增定律,生命以负熵为生。架构也是如此。

架构难以满足日益增长的功能需求,若任其野蛮生长,碎片化会越来越严重、越来越无序,最终达到那个难以维护和扩展的阈值,变回得到一个极端的结果:彻底重构。架构师的职责便是通过及时、有效的干预,令软件产生负熵,以保持系统的有序。

所谓及时干预可以理解为连续的、微小的重构行为,实现渐进式演进。

软件架构有两个基本要素:分治聚合。分,即将问题化整为零,各个击破;合,即将各个模块化整为零,融会贯通。具体到实际开发工作,在进行软件架构设计之前往往需要充分的准备工作,比如对编程语言的选择、对技术规范的制定以及根据业务类型进行合理的技术选型等。

语言

无论何种业务类型和架构,前端都无法摆脱 HTML、CSS、JavaScript 这三个核心技术。

前端开发者通常不会直接编写 HTML 和 CSS,而是借助一些工具和框架,目的是令源码具有可编程性,以便于维护和迭代。前端架构师的工作之一便是选择适用于业务类型、同时可提高开发和维护效率的工具和框架,并且制定相应的开发规范

JavaScript 是一种非常灵活的编程语言,这是优势,也是隐患。如其弱类型、异步编程等。TypeScript、ES6+ 已解决此问题。

简言之,架构师在编程语言方面的工作并非集中于语言本身,而是在充分了解语言特性的前提下制定适用于业务类型的开发规范和技术栈

技术规范

成熟的团队通常会设立代码审查制度,一方面可以发现代码逻辑的缺陷以及算法对性能的不良影响;另一方面是为了纠正开发者不规范的编码方式。

技术规范的优劣并没有绝对的评判标准,其唯一的原则是一致性。统一的技术规范能够显著提高团队协作和项目迭代的效率,这种优势随着团队规模和项目量级的增长被逐渐放大。

技术规范包含编码规范、项目源码的组织结构、依赖管理以及第三方技术选型等。

组件化

组件化是代码复用的一种经典实施模式。前端对于组件的定义不仅包含在 UI 层面,而且还融入了一些面向对象的理念,比如封装性、扩展性、可组合性、可复用性等

前后端分离

前后端分离的宗旨是将前端与后端开发解耦,实现开发、维护、部署甚至发布的相对独立性,提高开发效率和快速响应问题。

性能

性能是评估应用程序高可用性最重要的指标之一,也是抢占市场的核心竞争者之一。

对用户来说,Web 网站的性能表现为首屏加载时间、操作响应速度等。

对开发来说,Web 应用整体架构的任何环节(包括软件和硬件)都能影响网站的性能,比如服务器分布式架构、负载均衡、数据缓存等。

对前端来说,性能优化的具体措施更多的是从软件层面出发的,可以归结为两类:加载性能执行性能。提升加载性能的主要目标是尽可能快的将网站呈现给用户;提升执行性能的主要目标是快速响应用户的操作。

快并非性能优化的唯一指标,需要在性能和功能之间进行权衡,不要一味追求性能而影响产品功能。

前端架构师需要深刻理解浏览器渲染原理、编程语言特性、HTTP 等知识的前提下制定适用于前端并且与 Web 整体架构相契合的性能优化策略。

工程服务体系

成本控制是工程的核心关注点,即所谓的“降本增效”

再流弊的架构也只能在局部范围内实现熵减架构,实际工作中让人恼火的还是沟通成本,特别是跨团队协作。跨团队协作的沟通成本是非常昂贵的,降低成本不能只依靠人与人之间的书面语言沟通,还需要使用技术手段建立合理协作规范工具平台。所以前端工程服务体系的目标为:

  • 降低开发本身所消耗的人力成本
  • 降低跨团队协作消耗的沟通成本
  1. 开发

    前端工程服务体系针对开发阶段的目标为:

    • 减少重复性体力劳动

    • 建立规范的代码版本管理规范

    • 辅助跨团队并行开发

    内部资产 -> Bit

    协作方式 - 规范 - 执行

  2. 构建

    除了常规的编译、打包外(目前已被各个脚手架所包含),还可以加入安全、性能评估等

  3. 测试

    端到端测试和集成测试阶段需要尽可能地消除测试环境和生产环境的差异,避免无效的测试样例。

  4. 部署

    部署最核心的地方并不是对不同类型资源的处理,而是对流程的控制。部署需要做到稳定精准

    稳定、精准可对应灰度、增量发布,归为低风险发布。

  5. 持续化

    工程化的第一步是合理地使用工具提高各个环节独立的工作效率;第二步是搭建自动化流程来提高跨团队协作开发的效率,降低迭代整体所消耗的时间成本;最终的目的是持续化

  6. 监控和统计

    监控和统计是持续化工程体系不可或缺的一部分。目前很多前端团队没有将监控和统计作为必须的环节考虑,一方面是由于大部分前端涉及的统计数据是与产品相关(如 PV、UV 等)的,并非是技术团队组要关注的数据;另一方面则是考虑到部署前端监控和统计系统的性价比问题。

    通常,Web 应用与技术相关的指标包括性能表现和稳定性。性能,真实的用户数据模拟不出来;稳定性针对的是交互逻辑,更多的是对数据接口,也就是服务端的稳定性。问题的原因是什么,是通过各个团队层层转发还是直接定位到问题,从而缩短修复时间,从而间接的提升产品竞争力这些都是实施的权衡点。

一个团队的能力不仅仅体现在编码这种硬实力上,还有很多软实力,如各项流程制度、团队协作等。具体可以从一个完整的研发流程去考虑,一般涉及到:

  1. 业务需求
  2. 需求导入
  3. 开发准备
    • 规范制度:编码、工程、流程、协作等;
    • 常用的文档资产:业务方案、设计资源、技术方案、沉淀等
  4. 开发阶段
    • 框架
    • 组件
    • 工程化
    • 协作
  5. 质量
    • 自动化测试:UI、E2E等;
    • 合规性检测:lint、sonar、兼容性、api检测等;
    • 性能:基线、优化建议、自动化评测;
    • 埋点:监控接入
  6. 构建部署
    • 构建部署:打包、灰度、一件回滚等;
    • 配置中心/跨项目复用
  7. 投产后监控和数据分析
    • 异常、行为、性能
    • 数据可视化、分析、预测等
  8. 根据数据/用户反馈迭代优化设计
  9. 需求导入

实现一个流程形成闭环

工程化总结

前端一直在变,变的是技术的不断进步和权重的不断增长,但不变的是始终围绕分层架构中的交互逻辑层展开的。爆发式的技术发展给前端带来了很多问题,不论是从前端应用架构本身还是迭代流程考虑,前端急需系统性的开发和管理方案。

作为软件工程的子集,前端工程化仍然围绕编码、方法、工具三个要素展开。

从前端应用的技术架构本身出发,关注点聚焦于模块解耦、数据管理架构模式、性能以及前后端分离,目标是实现架构的高可用、可扩展、可伸缩性,同时提高独立开发和跨团队协作开发的效率;

从架构之外的角度出发,关注点聚焦于前端应用的开发、构建、测试、部署以及持续化工程体系,目标是建立规范、有序、高效的迭代流程,降低产品迭代所消耗的人力和沟通成本。