衔尾蛇(Ouroboros),一个存在于多种文明、宗教和神话故事中的符号,一条吞食自己尾巴的蛇,形象要么是一个圆环,要么是一个类似莫比乌斯环的闭合纽带,后者非常接近数学中的无穷大符号「∞」。
软件开发技术是原子性的,与具体的业务需求无关。实际问题的解决依赖技术,但往往并不直接依赖技术,所以催生出各式各样的架构模式以适应具体的业务需求。软件开发并不仅受技术架构单方面的影响,人的因素同样不容忽略,以规范、有序、高效为目标的工程旨在使用技术手段降低人可能导致的负面影响,而且必然是在项目的既有技术架构的基础之上实施的。
反过来看,工程生态的繁盛为技术进一步发展提供了必要的基础。
技术推进架构演进,架构支撑工程实施,工程为技术发展提供生态土壤,三者之间首尾相连同步演进的关系与衔尾蛇的形象颇为相似。
RockfordLhotka 在 Expert C# Business Objects 一书中提出分层软件架构模型,不论是数据、服务还是表现层,均依托于当时的技术背景。分层软件架构模型如下图所示。
分层软件架构是实现关注点分离的必要途径,层级之间的划分是一种架构设计上的约定而非职能上的切割。各个层级之间往往没有绝对明确的分界线。不同类型、场景、规模的项目在层级上的划分可能会存在很大差异。
软件开发技术的发展不断地推进着架构的演进。在 Expert C# Business Objects 一书出版十几年后的今天,五层架构模型虽然并未完全过时,但其中个别细节相较于十几年前已经有了很大的变动。比如,以当前技术背景为依托的前后端分离架构,在业务逻辑层和客户端之间可能需要一个中间渲染层承担SSR(服务器端渲染)能力,如下图所示。
软件工程(SoftwareEngineering)一词正式得名有多种来源,认可度相对较高的一种说法是来自于NATO在1968年举办的首届软件工程会议。工程的核心是结合实际情况建立科学的、规范的设计和生产流程,降低生产成本。将这一理念带入软件开发领域便形成了软件工程。
作为一门与计算机科学技术平行的一级学科,软件工程的核心思想是以工程的理念进行软件开发和管理,目的是解决软件危机。典型的软件危机包括:
:black_medium_small_square:成本超标,包括硬件成本、人员成本、时间成本等。
:black_medium_small_square:性能不理想且功能不稳定。
:black_medium_small_square:开发过程混乱无序难以管理。
:black_medium_small_square:代码不规范,维护成本高。
从经济学的角度来看,软件危机的问题是昂贵的成本没有换来对应的收益,这也是工程学与学术研究之间最大的不同。
而软件工程的基础必然无法脱离学术研究所产出的可用技术以及在技术可行性前提下建立的软件架构。
代码和流程是软件工程的核心关注点。从代码的角度考虑,工程的目标是保证软件的高可用性、可扩展性、可伸缩性、性能以及安全,这些要素共同组成了软件的技术架构。在架构之外,工程从更宏观的角度完善开发和维护流程的管控,强调项目迭代的规范性、 有序性、可控性和高效性,并根据架构特征提供额外的辅助功能。也就是说,架构是工程的子集,两者的关系可以简单地概括为如下图所示的内容。
将以上理论带入前端范畴便得出了前端工程化的完整定义:
前端工程化=前端技术架构+前端工程服务体系
在以上理论基础上,前端工程化的工作便可以分为技术架构和工程效率两部分。
技术架构面向代码,分治与聚合是架构的两个基本要素。分,即将问题化整为零,各个击破;合,即将各个模块化零为整,融会贯通。这种理念不仅仅是软件架构的根本,也同样适用于其他的工作领域。具体到实际开发工作,在进行软件架构设计之前往往需要充分的预备工作,比如编程语言的选择、技术规范的制定以及根据业务类型进行合理的技术选型等。
:black_medium_small_square:编程语言:对于编程语言选型单一的前端来说,编程语言的意义并不仅仅是一种工具,而且是一种思维模式。在充分了解语言特性的前提下制定适用于业务类型的开发规范和技术栈,是前端架构师的必备能力。
:black_medium_small_square:技术规范:技术规范的优劣并没有绝对的评判标准,其唯一的原则是一致性。统一的技术规范能够显著提高团队协作和项目迭代的效率,这种优势随着团队规模和项目量级的增长被逐步放大。
:black_medium_small_square:组件化:组件化是代码复用的一种经典实施模式。前端组件的定义不仅停留在 UI 层面,而且融入了一些面向对象的理念,比如封装性、扩展性、可组合性、可复用性等。
:black_medium_small_square:前后端分离:前后端分离的宗旨是将前端开发与后端开发解耦,进而实现开发、维护、部署甚至发布的相对独立性,实现高开发效率和快速响应问题。
:black_medium_small_square:性能:性能是评估应用程序高可用性最重要的指标之一,对于用户群体广泛、设备多样、场景复杂的互联网产品来说,性能也是抢占市场的核心竞争力之一。
工程效率面向流程,基本的原则是在保证产品功能的前提下尽可能地减少迭代所消耗的成本。具体到实际工作中,成本又可以细分为人力成本和沟通成本。以这两者为突破点,工程效率的目标便很明确了:
:black_medium_small_square:降低开发本身所消耗的人力成本。
:black_medium_small_square:降低跨团队协作消耗的沟通成本。
业务的需求、功能的量级,甚至不同的开发阶段都有可能影响协作开发的具体模式。根据协作模式的不同可以将开发工作分为个人独立开发、团队内协作开发和跨团队协作开发。基于此,开发阶段的效率提升集中在以下3点:
:black_medium_small_square:减少重复性体力劳动。
:black_medium_small_square:建立规范的代码版本管理规范。
:black_medium_small_square:辅助跨团队并行开发。
在前端领域,构建是一个比较新的词汇,随着前端技术的演进,对于构建功能的需求和相关工具也在不断进化。时至今日,构建已经成为现代前端开发不可或缺的一部分,也是前端工程服务体系中最重要的环节之一。前端构建的针对点有以下方面。
:black_medium_small_square:编程语言:构建针对编程语言的相关功能可以理解为编译(Compile),即将源代码转变为客户端可执行代码的过程。除了原生的JavaScript和CSS以外,CSS预编译、特定开发框架的编译均属于此类。
:black_medium_small_square:性能优化:比如压缩混淆、自动生成 CSS Sprite、动态模块按需加载等。
:black_medium_small_square:部署策略:比如给静态资源URL加入Hash指纹和CDN路径等。
:black_medium_small_square:开发效率:比如文档生成、动态构建等。
:black_medium_small_square:审查评估:比如规范审查、性能评估等。
既定的技术选型和编码规范是测试的必要前提,React、Vue等框架的发展令UI测试可以在一定程度上映射为字符串测试。此外,端到端测试和集成测试的环境仿真也是必不可少的前置工作。
部署最核心的地方并不是对不同类型资源的处理,而是在于对流程的控制。这项原则对于任何职能部门来说都是适用的。此外,作为应用发布前的重要环节,部署需要做到稳定和精准。
开发、构建、测试和部署组成了一个完整的迭代流程,工程化的第一步是合理地使用工具以提高各个环节独立的工作效率;第二步是搭建自动化流程来提高跨团队协作的效率,削减迭代整体所消耗的时间成本;最终的目的是持续化。
监控和统计可以辅助开发团队快速定位问题的症结,从而缩短修复问题的时间,间接地提升了产品的竞争力。除此之外,监控和统计也是持续化工程体系不可或缺的一部分。
Serverless不是一种具体的技术或框架,而是一种软件架构理念,一种基于云的解决方案。CNCF将其定义为:为实现构建和运行不需要服务器管理的应用程序的解决方案。Serverless将支撑后端业务逻辑的基础设施和与环境相关的工作交付给云计算平台,开发者的关注核心聚焦于前端交互逻辑和后端业务逻辑。在Node.js打破前后端编程语言壁垒之后,Serverless更进一步地弱化甚至消除了前后端领域的知识边界,在其支撑下,传统的技术研发职能体系被重新洗牌,前后端职能单一化不仅利于架构的多样化和扩展性,同时从工程角度也更具效率。目前业务不乏基于Serverless的优质解决方案,比如Google的Firebase、腾讯的云开发等。虽然现在Serverless仍未完全占据软件研发的主流市场,但其未来可期。
本文节选自博文视点新书《前端技术架构与工程》
本书所有内容遵循一个基本出发点:业务是架构和工程的核心。一切编码方案均是为了解决业务的功能需求,在此基础之上以分治和聚合为基本原则设计合理的软件架构,最后进一步规范工作流程和产品发布策略,这便是工程化的理论模型。总结为一句话:以业务为出发点,架构聚焦于代码,工程聚焦于流程。