作者:文艺码农天文
软件架构是成功开发软件产品的基础,精心设计的软件架构可以大大提高系统的质量。它还有助于降低出错风险,并使将来添加新特性和功能变得更加容易。
本文将分享前端架构岗的一些通用知识、高频面试题和学习资料。
什么是前端架构?
只要是概念性的术语,一般都会有很多版本的定义,在聊前端架构前,我们先聊聊软件架构。
软件架构
软件架构对于软件开发是非常重要的,是整个软件的大脑,它是指软件系统的设计方案,决定了软件系统中各个组件之间的关系、功能分配和架构方式。
软件架构根据不同的场景,可以分为系统软件架构、后端架构、前端架构和算法架构等,架构的根本价值在于能够降低未来功能开发的成本。软件架构通常涵盖三个部分:
架构模型:定义了系统组件是如何组织和拼装的,明确系统的组件模块,划分各自边界以及如何组合在一起,一般有分层架构、微服务架构和插件式架构。
通信接口:定义了系统组件之间是如何进行通信的,通常指的是组件/模块之间的通信方式、接口定义、API。
质量要求:定义了非功能性的系统要求,例如扩展性、稳定性、高可用性、高并发、高性能、安全等等。
不同阶段构成架构的因素是不同的,基于这个思路,架构设计可以分为四个层级:
系统级,即应用在整个系统内的关系,如与后台服务如何通信,与第三方系统如何集成。
应用级,即应用外部的整体架构,如多个应用之间如何共享组件、如何通信等。
模块级,即应用内部的模块架构,如代码的模块化、数据和状态的管理等。
代码级,即从基础设施来保障架构实施。
前端架构和后端架构(技术大厂内推,前后端测试捞人)
前端架构和后端架构都是软件系统中最关键的架构层,负责处理不同方面的任务和逻辑,两者之间是存在一些区别和联系的。
前端架构主要关注用户界面和用户体验,负责处理用户与应用程序交互的所有事项,包括页面渲染、用户输入响应、前端逻辑和交互设计等。
后端架构主要处理应用程序的业务逻辑、数据存储、安全性、性能优化等方面,后端通常包括数据存储、服务器端逻辑、API 设计等。
前端架构主要使用 HTML、CSS、JavaScript 等技术构建用户界面,常见的前端框架有 React、Vue 等。
后端架构主要使用各种编程语言,如 Java、Python、Go 等,使用流行框架来处理服务器端逻辑,数据库技术、服务器软件等也是后端的核心组成部分。
前端架构简史
架构并不是被发明出来的,而是持续演进的结果。
随着前后端分工划分越来越明确,前后端系统也逐步分离。前端系统变成了静态前端资源,部署HTML、JS、CSS文件,后端服务提供API(通常是REST API),前后端通过API进行通信。
前后端分离解决了前后端分工的问题,但是随着移动互联网到来,前端变成多端状态(PC、iOS、Android),前端应用越来越复杂,开始需要通过架构来提升研发质效。
常见的前端架构包括以下几种:
单页面应用(Single Page Application, SPA)
优点:用户体验流畅,页面无需重新加载;前后端分离,便于维护和扩展。缺点:初次加载时间长;SEO优化相对困难;对服务器压力较大。应用场景:适用于需要高度交互性的应用,如社交网络、在线办公套件等。
微前端架构
优点:允许独立开发和部署不同的前端部分;提高了系统的灵活性和可维护性。缺点:架构复杂性增加;需要解决不同微前端之间的通信和样式冲突问题。应用场景:适合大型复杂应用,尤其是由多个团队共同维护的项目。
分层架构
优点:通过代码职责的拆分可以有效的将系统进行解耦,从而让各自部分能够很好的分工并且协同。缺点:随着页面逻辑复杂度提升,数据更改容易混乱,还好出现了Redux、Mobx等数据流控制的框架,将数据管理进行了统一。应用场景:只要不是静态网页,现代的web 应用,都会使用分层的架构。
每种架构都有其特定的优势和局限性,选择哪种架构取决于项目的具体需求、团队的技能水平以及预期的维护成本。在实际开发中,通常会根据实际情况对这些架构进行适当的调整和混合使用。
相关的高频面试题
谈谈你对软件架构的认识?
软件架构是软件系统的高级组织结构,它定义了系统的组件、组件之间的交互方式以及整个系统的结构和设计原则。
有多种架构风格可供选择,例如分层架构、微服务架构和事件驱动架构等,每种风格都有其独特的优势和适用场景。良好的软件架构能够确保系统的可扩展性、可维护性和灵活性,同时降低系统的复杂性和构建风险。
在我的项目中,我曾经面临过需要在保证快速迭代的同时,实现高可用性的挑战。我们通过采用分层架构来解决这一问题,这个过程让我深刻体会到,软件架构设计是一个需要综合考虑多方面因素的决策过程。
总的来说,我认为软件架构是连接业务需求和软件实现的桥梁,是确保软件系统长期成功和可持续发展的关键。
代码开发和架构设计的区别?
代码开发和架构设计在软件工程中扮演着不同的角色,代码开发关注的是如何编写高质量的代码来实现特定的功能,它涉及具体的编程任务,如编码、调试和测试。
相比之下,架构设计则是一个更高层次的抽象,它关注的是整个系统的结构、组件之间的关系以及系统如何满足业务需求。
简而言之,代码开发更侧重于‘怎么做’,而架构设计则侧重于‘做什么’以及‘为什么这么做’。代码开发和架构设计在软件开发过程中扮演着不同的角色,它们相互依存、相辅相成。
代码开发是架构设计的实现基础,而架构设计为代码开发提供指导和约束,优秀的工程师需要在代码开发和架构设计之间找到恰当的平衡。
react和vue技术栈的对比
这两个框架都是很优秀的前端框架,而且在各大 IT 社区每年的统计和调查中都会被赋予最流行、最受欢迎、最常用的 Web 框架的称号。
它们都支持服务端渲染,都有虚拟DOM,数据驱动,组件化开发,响应式,组件通信,生命周期,Diff,都有状态管理Vuex/Pinia、Redux/Mobx,等。
React一开始定位的就是 UI 开发的新思路,这种思想说白了就是要改变开发者,我制定规则,你们都照我的来,因为背靠大公司(facebook),所以不缺用户,而Vue是尽可能降低前端开发的门槛来适应不同的开发者,让开发者怎么爽怎么来。
从加载速度,运行时性能来说,我觉得这两个框架综合各种场景应该是没什么质的差别的。硬要说的话,Vue在更新时性能优化方面,需要的心智负担可能会少那么一点,特别是Vue3,而React如果不注意,容易导致一些组件无用的Diff。
一些不大的系统或者H5就用Vue,因为不管是上手还是开发难度上都很简单,开发效率也高,而且它有更小的打包体积。
一些中后台系统,或者一些大点的项目,会越做越大的,多人协作开发的,就用React,因为它的函数式编程有更加灵活的结构和可扩展性,丰富的生态圈和工具链,解决方案多,后期也更方便迭代与维护。
对 hooks 的理解
2019年年初,react在16.8.x版本正式具备了hooks能力,同年6月,尤雨溪提出了关于vue3 Component API的提案。在后续的react和vue3相关版本中,相关hooks能力都开始被更多人所接受。
React和Vue中的Hooks都是为了提供更灵活、更易于维护的组件开发方式,它们允许开发者将组件逻辑提取到可复用的函数中,从而减少了代码重复,提高了代码的可读性和可维护性。
React提供了以下几个内置的Hooks:
useState: 用于在函数组件中添加state。
useEffect: 用于处理具有副作用的操作,比如数据获取、订阅或者手动修改DOM。
useContext: 用于访问React context。
useReducer: 用于管理复杂的组件状态。
useCallback: 返回一个记忆化版本的回调函数。
useMemo: 返回一个记忆化版本的计算值。
useRef: 创建一个可变的引用对象。
useImperativeHandle: 允许你在组件渲染后自定义该组件的行为。
useLayoutEffect: 与useEffect类似,但它会在DOM更新之后同步执行副作用函数。
useDebugValue: 用于调试自定义Hooks。
此外,开发者还可以创建自定义Hooks,以便在不同组件之间复用状态逻辑。
虽然Vue不直接使用"Hooks"这个术语,但是setup函数和其他Composition API提供了类似的功能,允许开发者在组件内组织和复用逻辑。
setup: 是Composition API的入口点,它接收props作为参数,并暴露一个返回对象,该对象包含组件响应式数据和方法。
reactive/ref: 用于创建响应式数据。
computed: 创建计算属性。
watch/watchEffect: 用于观察响应式数据的变化并执行副作用。
onMounted/onUnmounted等生命周期钩子函数,用于在组件的不同生命周期阶段执行代码。
Vue的Composition API还包括其他API,如provide/inject、emits等,用于更高级的状态管理和父子组件通信。
React hook是根据调用顺序来确定下一次重新渲染时的state是来源于哪个,所以有一些限制,而Vue3 hook是基于响应式实现的,它是声明在setup里,一次组件实例化只调用一次setup,而React每次重新渲染都要重新调用,性能上自然不言而喻,Vue自动实现了依赖收集,而React需要手动传入依赖等。
聊聊vue 或 react 的数据响应
Vue2响应式的特点就是依赖收集,数据可变,自动派发更新,初始化时通过Object.defineProperty递归劫持data所有属性添加getter/setter,触发getter的时候进行依赖收集,修改时触发setter自动派发更新找到引用组件重新渲染
Vue3响应式使用原生Proxy重构了响应式,一是proxy不存在Vue2响应式存在的缺陷,二是性能更好,不仅支持更多的数据结构,而且不再一开始递归劫持对象属性,而是代理第一层对象本身。运行时才递归,用到才代理,用effect副作用来代替Vue2里的watcher,用一个依赖管理中心trackMap来统一管理依赖代替Vue2中的Dep,这样也不需要维护特别多的依赖关系,性能上取得很大进步。
相比Vue的自动化,React则是基于状态,单向数据流,数据不可变,需要手动setState来更新,而且当数据改变时会以组件根为目录,默认全部重新渲染整个组件树,只能额外用pureComponent/shouldComponentUpdate/useMemo/useCallback等方法来进行控制,更新粒度更粗一些。
聊聊 diff 算法
Vue2是同层比较新老vnode,新的不存在老的存在就删除,新的存在老的不存在就创建,子节点采用双指针头对尾两端对比的方式,全量diff,然后移动节点时通过splice进行数组操作
Vue3是采用Map数据结构以及动静结合的方式,在编译阶段提前标记静态节点,Diff过程中直接跳过有静态标记的节点,并且子节点对比会使用一个source数组来记录节点位置及最长递增子序列算法优化了对比流程,快速Diff,需要处理的边际条件会更少
React是递归同层比较,标识差异点保存到Diff队列保存,得到patch树,再统一操作批量更新DOM。Diff总共就是移动、删除、增加三个操作,如果结构发生改变就直接卸载重新创建,如果没有则将节点在新集合中的位置和老集合中的lastIndex进行比较是否需要移动,如果遍历过程中发现新集合没有,但老集合有就删除。
谈谈前端的打包构建工具
前端打包构建工具是现代前端开发工作流程中不可或缺的一部分。它们帮助开发者自动化地处理资源文件(如HTML、CSS、JavaScript)的转换、优化、打包等任务。
流行的前端打包构建工具有:
Webpack:一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。它将诸如 HTML、CSS、JavaScript 等文件视为模块,并打包成一个或多个 bundle。具有强大的插件系统,支持代码分割、懒加载、热替换(HMR)等功能。
Parcel:一个零配置的Web应用程序打包器,它利用多核处理来提供极快的打包速度。自动安装依赖,支持多种文件类型,无需复杂的配置。
Rollup:一个模块打包器,专注于 ES6 模块的打包。适用于库和框架的开发,提供了 Tree Shaking 功能,可以有效地减少最终打包文件的体积。
Gulp:一个基于流的自动化构建工具,通过一系列的任务来转换和优化文件。易于使用,插件生态系统丰富,可以轻松地集成到开发流程中。
Grunt:一个基于配置的任务运行器,可以自动化处理重复性的任务,如压缩、编译、单元测试等。高度可配置,拥有大量的插件。
Snowpack:一个现代前端工具链,通过利用原生 ES 模块来提高开发速度。无需打包,直接启动快速的开发服务器,支持增量构建。
Vite:一个由原生 ESM 驱动的现代前端开发与构建工具。利用浏览器的模块加载能力,提供快速的开发体验,支持热更新。
选择哪个工具取决于项目的需求、团队的熟悉度以及期望的开发体验。例如,Webpack 和 Parcel 在大型项目中很流行,而 Gulp 和 Grunt 更适合需要高度自定义的任务流程。
一些学习资料
作为架构师,持续学习和适应新技术是必备的职业素养。而这个素养提升的一个重要的方式就会读书、读好书,以下是一份精选的书单:
《领域驱动设计:软件核心复杂性应对之道》:不仅介绍了领域模型的概念,还详细阐述了如何通过战略和战术设计来构建复杂的业务系统。
《实现领域驱动设计》:探讨了限界上下文、实体、聚合、领域服务等概念,并提供了丰富的实现细节。
《分析模式:可复用的对象模型》:提出了一系列常用的业务领域模式,帮助架构师快速识别和应用已有的最佳实践。
《凤凰架构:构建可靠的大型分布式系统》:不仅讨论了设计原则和模式,还涉及了系统运维和监控等关键问题。
《软件架构:架构模式、特征及实践指南》:全面介绍了软件架构的各个方面,包括架构模式、质量属性和设计原则。
《代码整洁之道》:涵盖了从命名规则到代码布局的多个方面,旨在帮助开发者提升编程技能。
《架构整洁之道》:讨论了架构设计中的常见问题,并提供了解决方案。
《匠艺整洁之道》:涵盖了软件开发的整个生命周期,从个人责任到团队协作,从设计到交付。
通过阅读这些书籍,我们将获得深入理解复杂系统、设计高质量软件架构、编写整洁代码的能力和洞察力。不断学习,不断进步,让我们在架构师的道路上越走越远。
总结
前端架构是前端开发中非常重要的一个方面,它涉及到如何组织代码、处理数据流、管理状态以及设计组件等方面。
每种架构都有其优缺点,选择哪种架构通常取决于项目的需求、团队的熟悉度以及期望的维护和扩展性。随着技术的发展,前端架构也在不断进化,以适应不断变化的开发需求和环境。
选择合适的前端架构模式对于提高开发效率和创建高质量的Web应用程序至关重要,不同的架构模式适用于不同的项目需求,开发团队应该根据项目的具体情况和团队的技术栈来选择最合适的架构模式。