前端系统设计:入门基础

一、前言

当提到"前端系统设计" ,我想大部分小伙伴都有类似的疑问:前端系统设计?有必要吗?有啥好设计的?

今天基于这些疑问,本人结合自身的一些实践案例、思考总结,给大家做一次分享。希望能够帮助大家,具象对前端系统设计的想象、建立前端系统设计的基本认识、识别出前端工作中的设计内容。

分享内容共分为四个章节:

  1. 系统设计的基本概念
  2. 前端系统设计的必要性
  3. 前端系统设计包含的内容
  4. 如何提高系统设计能力

二、系统设计的基本概念

本章节以"系统设计"展开,描述系统设计是什么,并梳理其中的相关概念与名词

1.1 系统设计是什么

系统设计是根据系统分析的结果,运用系统科学的思想和方法,设计出能最大限度满足所要求的目标 (或目的) 的新系统的过程。系统设计内容,包括确定系统功能、设计方针和方法,产生理想系统并作出草案,通过收集信息对草案作出修正产生可选设计方案,将系统分解为若干子系统,进行子系统和总系统的详细设计并进行评价,对系统方案进行论证并作出性能效果预测。

上面是百科中对"系统设计"的定义,拆解出语句骨干:系统设计就是设计出 满足需求目标的新系统过程

这个过程一般处于研发流程中的"需求分析"之后与"编码"之前,交付物是《系统概要设计说明书》。只是说我们前端较少参与该过程,对它还比较陌生。

1.2 系统设计的分类

咱们开发人员,不可避免的会经常会听到各种xx设计的名词,初次听到可能会让人疑惑、傻傻分不清楚,其实它们是对系统设计不同层次、不同维度的表达。这里提纲挈领的对这些名词做一个归类,以快速的帮助我们建立对系统设计的整体认识。

  • 按设计的阶段分为:概要设计、详细设计
  • 按设计的层次分为:总体/架构设计、程序结构设计
  • 按设计的领域分为:后端设计、前端设计
  • 按设计的内容分为:接口设计、数据库设计、部署设计、组件设计

下面我们就其中有关联、较模糊或存在争议的概念名词,做一些比较、澄清。

1.3 架构设计与程序结构设计

1.3.1 架构设计

架构设计是指在软件开发过程中,对系统的顶层结构进行规划和决策的过程。比如:

  • 架构模式的抉择:单体架构还是微前端架构、单页应用还是多页应用、服务端渲染还是客户端渲染

  • 系统架构图的绘制:从全局视角描述平台的系统构成、外部依赖和各个子系统的职责边界以及它们之间的关系。

1.3.2 程序结构设计

程序结构设计更侧重于软件的内部结构,即代码层面的组织和布局。比如:

  • 关键业务流程
  • 组件的划分与封装

1.3.3 二者的区别

二者在系统设计中的范围和层次不同

  • 范围:架构设计关注于系统的宏观结构,而程序结构设计关注于代码层面的微观结构。
  • 层次:架构设计通常在程序结构设计之前进行,为程序结构提供指导和约束。

总之,架构设计和程序结构设计是两个在软件开发过程中至关重要的环节,它们相互配合、相互支持,只是各自有不同的目标和关注点。架构设计为程序设计提供了宏观的指导和框架 ,侧重于从整体上把握系统的功能和结构,而程序设计则是实现系统设计的具体方法和手段,更关注程序内部的实现细节。

1.4 前端与后端系统设计

常规的web应用一般会由客户端和服务端两部分组成。前端系统设计,指的是其中客户端应用的系统设计,相应的服务端的设计就是后端系统设计。

这里着重介绍一下二者的区别,帮助我们顺着后端设计的"藤"摸摸前端设计的"瓜"。

1.4.1 关注的对象不同

后端:接口设计、数据库设计、部署设计

前端:组件设计、页面设计

1.4.2 面对的问题不同

后端:大流量、高并发、数据同步、数据安全、服务治理

前端:多端运行、浏览器兼容性、屏幕适配、主题定制、页面性能、国际化

1.4.3 设计侧重点不同

它们遵循一致的设计原则,但侧重点略有不同

后端:

  • 可扩展性:多节点部署的设计,支持把系统的不同组件或服务部署在多个服务器或计算节点上,允许在需求增长时通过增加资源来提升性能和容量。
  • 容错性:负载均衡的设计,会把用户请求均匀地分配到各个节点上,防止单个节点过载。

前端:

  • 可访问性:离线访问、对残障用户友好的无障碍设计
  • 一致性:在UI设计中保持一致性,颜色、字体、按钮等元素的一致性
  • 复用性:组件化开发

PS:这些差异,时刻提醒我们设计时不能生搬硬套,应该因地制宜、具体情况具体分析。

三、前端系统设计的必要性

2.1 前端到底需不需要设计

在过去的很长一段时间,或者现有的绝大部分系统,都是没有前端设计的。这一点从你看过的《系统概要设计说明书》中可以窥探一二,里面的内容大多是系统整体设计(架构图)、接口设计、数模设计、关键业务流程,压根没有前端应用的位置和内容体现。

不可避免的,有不少人(比如曾经的我)就会基于过往经验,发出"前端压根就不需要设计"这样的声音,因为没有它,我们依然做了很多的项目,且没见出现有很大的问题。那么前端到底需要需要设计呢?

现在的我的答案是:需要,但要不要以文档的形式体现,这取决于"复杂度"以及"是否需要协作"。

原因是,在前端应用相对简单的过去,它作为子系统不展开描述是合理的,但时代变了。随着技术的演进,我们能明显的感受到,前端应用在不断的承载、容纳更多、更复杂的功能。

那些软件危机上演过的问题,在前端应用中日益凸显。即便在我们已经默认选用组件化框架,在MVVM模式加持的情况下。

  • 系统规模庞大,内部耦合严重,开发效率低;
  • 系统耦合严重,牵一发动全身,后续修改和扩展困难;
  • 系统逻辑复杂,容易出问题,出问题后很难排查和修复。

基于良好的设计,开展编码工作,能够帮助我们有效规避或延缓上述问题

2.2 设计的价值和作用

前端开发人员受限于编程语言的特性 和专业出现较晚,普遍没有设计的习惯和意识。我们非常有必要构建对前端系统设计必要性的统一认识,这有助于我们更积极的开展设计活动(这在后端通常是不需要的,他们习以为常)。

关于前端系统设计的价值和作用,我总结了三点:

  1. 帮助开发人员提前构思,避免边想边干

    有太多的从业者,在代码编写基本完成后,才发现设计思路是有问题的。他们在很多项目上花费很少(甚至没有花费)时间进行系统设计,对于在设计中所隐藏的问题并没有仔细思考和求证。基于这样的设计投入和设计质量,项目出现设计失误也是很难避免的。而面对一个已经完成了基本编码的项目,如果要"动大手术"来修改它,相信每个有过类似经历的人都一定深知那种感受一越改越乱,越改越着急。

    编码之前的设计,可以让我们在开发之前,将技术上不确定的点确定好,以减少后续开发出现风险和问题的可能性。

  2. 阐明设计思路和方案,方便组内成员了解你的设计,以便帮助你判断设计方案的优劣、分析你方案中潜在的需求和影响

  3. 可以帮助其他成员或者自己了解你的系统,有利于将来的持续迭代,或者问题的快速定位和解决

    系统设计特别是架构层面的信息很难从具体的代码中获取,单独的表述有利于团队成员快速了解你的系统。把复杂处理逻辑图形化描述,也有利于将来问题的快速定位和解决。

四、前端系统设计包含的内容

3.1 架构设计

3.1.1 整体架构

在这个章节,一方面我们需要结合业务实际问题和需要,抉择系统的顶层设计。比如 单体架构还是微前端、单页应用还是多页应用、服务端渲染还是客户端渲染。

另一方面我们还需要画一些架构图,从全局视角描述平台的系统构成、外部依赖和各个子系统的职责边界以及它们之间的关系。

3.1.2 应用架构

在这一章节,前端一般会以分层架构的形式,表达应用中包含的技术组件,基础组件、业务组件、公共方法等

3.1.3 不要局限于此

架构没有银弹,除了通用的架构抉择外,我们往往需要根据产品实际面临的问题,做出改进。

3.2 技术选型

在架构设计之后,我们就需要考虑使用何种技术实现架构目标。比如微前端架构,选择qiankun还是micor-app;组件化/数据驱动开发框架,选择vue还是react; 跨端开发框架,选择uni-app还是reactNative。这就是在技术选型。

只是在大多数情况下,我们基于项目要求或者个人惯性,被动的默认了某一种。

且大多时候选定的技术框架都会或多或少的包含一揽子架构决策,比如我们使用vue框架开发,被动的就是组件化软件开发方法、MVVM软件设计模式。架构层面,我们自主技术选型的机会并不多。

更多的时候,我们是基于某项具体问题或需求,选择使用何种插件,比如富文本编辑器、比如node应用中的中间件等。这里就不过多举例了。

3.3 关键技术方案

这一章节我们需要基于产品特定需求,制定关键技术方案。

前端常见的关键技术方案有:权限控制流程、屏幕适配方案、离线访问方案等。

这里结合自身经验,分享两个浅显易懂的案例。

3.3.1 例子一:差异化配置

之前给银行打工的时候做过一个产品,它在不同的渠道/端(手机银行、微信银行和浏览器)存在定制、差异化需求。比如不同的渠道,购买是否需要交易密码、是否需要短信验证码、是否能直接展示余额、是否允许支取等都是不一样的。

基于此我们做了 "基础功能可配置"的设计

arduino 复制代码
// 抽象出的差异功能
{
  needPassWord: true, // 购买是否需要交易密码
  needSendCode: false, // 购买是否需要短信验证
  canDirectShowAmount: true, // 是否可以直接显示月
  allowDraw: true, // 是否允许支取
  canEditBenefit: false // 是否可以维护结息账户
}

这样的好处是我们在业务处理时,只需关注功能的开关,而无需关注是哪个渠道,实现了"业务功能和渠道的解耦"。

kotlin 复制代码
onPwdInputOver (password) {
  this.password = password
--      // 基于渠道判断
--      if (isWx||isAPP) {
++      // 基于功能开关判断
++      if (this.$config.needSendCode) {
  
          this.isShowMsgCode = true
        } else {
          this.submit()
        }
    }

两种代码的在可读性和可维护性上有明显的差异,特别是当渠道、差异越来越多的时候。

3.4 组件设计

在前端vue一把梭的当下,组件化几乎成为了我们前端开发的本能。在拿到UI设计稿之后,我们会下意识识别里面有哪些可复用的组件,并做简单的划分。这就是组件设计。

我这里把组件设计的过程拆分为两个环节:①组件的识别与划分;②组件的定义与API设计。

3.4.1组件的识别与划分

组件的拆分无外乎两种目的:一种是复用、一种是降低复杂度。我们基于这两项目标,就能快速、直观的识别出前端应用中需要的组件。

拿一个常见的搜索框组件举例

应用范围:首页、页面A、页面B、页面C、...

功能说明:吸顶;支持62/38px两种高度;支持自定义palceholder;派发点击搜索事件。

项目中多个页面都需要使用,这种就是显然就是基于复用的考量,而划分的组件。

3.4.2 组件的定义与API设计

组件设计的内容无非是定义组件的功能、约定组件的职责边界,以及API说明。沿用上面搜索组件的例子,设计如下:

Props、event、插槽,都是我们耳熟能详的东西,这里就不多赘述了。

3.4.3 一些经验教训

分享、探讨一些个人遇到的问题和总结的经验教训。

  1. 不要过度拆分

    下沉/封装的组件不是越多越好,每一次的封装、每一层的下沉,都是有代价、有副作用的。

    如果嵌套层级过多,势必会带来组件间跨层级传参、通信困难的问题,也势必会增加开发人员理解和维护代码的成本。

    当我们拆分带来的复杂度,大于拆分降低的复杂度时,就得不偿失了。

    个人建议是组件不要抽象、嵌套超过三层。

  2. 不要忽略使用便捷性的考虑

3.5 页面设计

页面设计关注的内容一般有页面构成、关键业务处理逻辑等。

我个人没有很典型的案例可以分享,这里仅列一些通用的内容,大家借鉴一二。

  1. 页面中使用的组件
  2. 页面中要调用的接口
  3. 页面内复杂业务处理流程

3.6 非功能需求

本章节我们需要对系统中哪些非功能需求做对应的设计和实现方案,比如浏览器兼容性、页面性能、构建与部署等。

在实际工作中较少涉及,这里简单提一下。提醒我们在做系统设计时一定要多维度、全面的思考,在关注功能性需求之余,不能忽略非功能层面的思考和设计。

3.7 一些个人见解

  1. 不是所有的系统、应用都需要设计

    判断是否需要设计的唯一准则是:复杂度。比如在逻辑不大发生变化的地 方,没有必要去做过多的设计,应用各种花俏的设计模式等浪费时间。

    当业务的复杂度提升到必须由更复杂的技术架构承载时,对架构的研究才有意义。

  2. 不设计不意味着快

    成本并没有消失,边想边干推翻重来只会让你更慢。

  3. 设计没有标准答案,只有"探索与权衡",合适就是最好的

    合适原则:避免过度设计,适合自己的才是最好的。

  4. 不要坚持只有一种可能的解决方案

    好的问题通常有几种可能的解决方案,每种解决方案是否合适取决于具体情况。即使其他解决方案明显不好,也要提及并简要解释为什么不好。

  5. 系统设计不应该只包含结果

    仅仅在系统设计中留下最后的结果是不够的,如何推导出这个结果,其"过程"也同样重要。当前的系统设计并不是终点,未来也会有优化或重构。对于未来从事这些工作的同事来说,系统设计中所留下的"设计思路"是非常有价值的。我们有时也会看到很多系统在重构后,并没有比以前的 更好,甚至在很多地方重蹈了之前的错误,这和系统设计文档 中"设计思路"的缺失有很大关系。

  6. 当你采用一项设计去降低复杂度的时候,必然会带来新的复杂度

    不管是软件工程还是架构师设计 其底层逻辑都是 "分而治之"。但拆分势必带来系统复杂度的提升,集成、通信成本。

  7. 尽量避免一人设计一人开发

    特别是详细设计,每个人的思维逻辑与编程习惯天差地别,它会带来昂贵的沟通、理解成本。

五、如何提高系统设计能力

听一场培训、看一篇文章,绝对不可能让我们凭空获取某项能力, 系统设计能力的获取或提升,需要下功夫,以下是我对此的一些建议。

5.1 多学

学习基础知识、学习设计原则、学习架构模式、学习设计模式......

和"你永远无法赚到你认知之外的钱"一个道理,你也做不出认知之外的设计。只有充分了解、深刻理解浏览器渲染原理、编程语言特性、HTTP这些基础知识的前提下,才能制定出适用于前端并且与Web整体架构相契合的设计方案。

在基本功足够扎实的前提下,推荐一些学习资源

整洁代码:《代码的艺术》、《代码整洁之道》、《重构:改善既有代码的设计》

设计模式:《JavaScript设计模式与开发实践》、《架构整洁之道》

架构设计:《前端架构从入门到微前端》、前端基础建设与架构30讲、《从零开始学架构》

5.2 多看

阅读优秀代码:研究优秀的开源项目,理解它们的设计决策,参看它们的API设计。

如果我们一上来就去啃源码,难度极高。建议从开源作者分享的系列文章起手,然后再结合源码分析的文章啃啃vue之类的知名框架,这样由易到难的顺序可以有效避免被劝退。

墙裂推荐vue-element-admin作者的《手摸手,带你用vue撸后台系列》文章,还有 Mall-Cook作者的《从零开始搭建低代码平台》系列文章。

此外,利用好GitHub Copilot、通义灵码、MarsCode等AI编程助手的代码解释功能,能够降低理解学习难度。

5.3 多练

学而不思则罔,思而不学则殆。知识的获取,是学习+实践反复揉搓的过程。我们需要把握日常工作中的每一次设计需要,去思考、去实践。

需要提醒的是,不是需要写入设计文档的才算设计,我们接到的每一个需求,开发的每一个功能,都可以进行设计上的思考。分析已有的实现是怎样的、计划做怎样的变更、变更的影响有哪些、有没有更好的处理方式,等我们养成先想再做、先设计再开发的习惯后,你的设计能力会在不知不觉间水涨船高。

六、结语

很多前端开发(包括我自己)很难迈出第一步的原因在于,思维上还不习惯区分设计和编码。

现在、就在此时此刻,在你心里把设计和编码的那道线画出来,打开系统设计的大门,准备好迎接挑战,享受创造的过程吧!

相关推荐
编程零零七1 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
(⊙o⊙)~哦3 小时前
JavaScript substring() 方法
前端
无心使然云中漫步4 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript
Bug缔造者4 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
xnian_4 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js
麒麟而非淇淋5 小时前
AJAX 入门 day1
前端·javascript·ajax
2401_858120535 小时前
深入理解MATLAB中的事件处理机制
前端·javascript·matlab
阿树梢5 小时前
【Vue】VueRouter路由
前端·javascript·vue.js
随笔写7 小时前
vue使用关于speak-tss插件的详细介绍
前端·javascript·vue.js
史努比.7 小时前
redis群集三种模式:主从复制、哨兵、集群
前端·bootstrap·html