Skip to main content

[微前端] 前端架构历史简介与设计原则

前端架构历史简介​

初始无架构​

前端代码内嵌到后端应用中

后端 mvc 架构​

将视图层, 数据层, 控制层做分离

缺点: 重度依赖开发环境, 代码混淆严重. 比如前端调试时, 需要启动和安装后端所有依赖, 从本地调试. 非常复杂. 很多依赖通过后端服务注入.

mvc

前后端分离架构​

将前端代码从后端环境中提炼出来(ajax 促进了前后端分离架构的发展)多页面架构

缺点:

  • 前端缺乏独立部署能力, 整体流程依赖后端环境

发展:

Nodejs 发展诞生了多元化前端开发方式, 使得前端开发可以脱离整体后端环境

单页面架构​

打包: gulp, rollup, webpack, vite..

框架: react/vue/angular..

ui 库: antd/iview/elementui/mintui...

优势:

切换页面无刷新浏览器, 用户体验好

组件化开发方式

缺点:

不利于 SEO, 首次渲染可能会较长时间白屏

大前端​

后端框架: express, koa

包管理: npm, yarn

node 版本管理: nvm

微前端​

  • 技术栈无关

  • 独立开发独立部署

  • 支持增量升级

  • 微前端是一种非常好的实施渐进式重构的手段和策略

  • 微应用仓库独立, 前后端可独立开发, 主框架自动完成同步更新

缺点:

接入难度高

应用场景: 移动端少, 多在 PC 端管理后台上应用

总结​

过于灵活的实现也导致了前端应用拆分过多, 维护困难

往往一个功能或需求会跨两三个项目进行开发

软件设计原则 SOLID​

单一职责原则​

  • 概念: 永远不应该有多于一个原因来改变某个类

  • 理解: 对于一个类而言, 应该仅有一个引起它变化的原因

  • 应用: 如果一个类拥有了两种职责, 那就可以将这个类分成两个类

例子

登录页面: 有两个验证功能, 1. 验证用户名 2. 验证密码

如果两个功能放在同一个方法里, 不仅不利于查找错误原因, 而且一个方法里会有很多的逻辑判断, 加重开发负担与维护困难

所以可以将两个验证功能拆分为两个方法去实现

开放封闭原则​

  • 概念: 软件实体扩展应该是开放的, 但对于修改应该是封闭的

  • 理解: 开发过程中, 对扩展开放, 对修改封闭. 可以去扩展类, 但不要去修改类

  • 应用: 当需求有改动, 尽量用继承或组合的方式来扩展类的功能, 而不是直接修改类的代码

例子

登录页面: 有两个验证功能, 1. 验证用户名 2. 验证密码

现在要增加一个验证码功能, 只有通过图片验证码之后, 才可以验证密码.

此时如果直接取修改验证密码函数的功能, 那么要做出大量修改, 而且需要测试, 并且也会对原有功能产生影响.

可以通过增加一个函数, 通过这个函数返回 true 或 false 的结果判断是否进行接下来的流程. 这样仅会影响图片验证码功能

里氏替换原则​

  • 概念: 父类一定能够被子类替换

  • 理解: 在使用父类的方法的时候, 如果将父类的引用换为子类的引用, 那么对于整体的程序设计来说是没有任何影响的. 里氏替换原则在使用面向对象的时候不会着重的注意到. 但是现在在使用函数式编程的时候可能关注度并没有很高

最少知识原则​

  • 概念: 只与你最直接的对象交流

  • 理解: 低耦合, 高内聚

  • 应用: 做系统设计时, 尽量减小依赖关系

例子

上个图片验证码的功能与验证用户名和密码功能是强依赖相关的. 因为需要知道验证码通过与否来判断是否验证用户名和密码. 那么针对其他依赖项, 只有图片验证码功能是强相关, 所以只需要知道验证码结果就可以进行用户名和密码校验

接口隔离原则​

  • 概念: 一个类与另一个类之间的依赖性, 应该依赖于尽可能小的接口

  • 理解: 一个接口不要对外暴露没有实际意义的接口. 用户不应该依赖它不需要的接口

  • 应用: 当需要对外暴露接口时, 如果是非必要对外提供, 尽量删除

例子

如果说登录验证用户名和密码接口是必须的, 但是跟用户所处的地域环境, 比如说 ip 没有关联. 那么就不需要对这样一个接口做依赖, 而只暴露验证用户名和密码接口即可

接口: 这里的接口并不是日常获取数据的接口, 而是在程序设计中通过接口去预设一部分类型, 来限定一个类是怎样实现的这个接口

依赖倒置原则​

  • 概念: 高层模块不应该依赖于底层模块, 他们应该依赖于抽象, 抽象不应该依赖于细节, 细节应该依赖于抽象

  • 理解: 应该面向接口编程, 不应该面向实现类编程. 并不是说, 所有的类都要有一个对应的接口, 而是说, 如果有接口, 那就尽量使用接口来编程吧

总结​

将以上六大原则的英文首字母拼在一起就是 SOLID, 所以也称为 SOLID 原则

补充设计原则​

组合/聚合复用原则​

  • 当要扩展类的功能时, 优先考虑使用组合, 而不是继承

  • 该原则在 23 种经典设计模式中频繁使用. 如代理模式, 装饰模式, 适配器模式等

无环依赖原则​

  • 当 A 模块依赖于 B 模块, B 模块依赖于 C 模块, C 依赖于 A 模块, 此时将出现循环依赖. 在设计中要避免该问题. 可通过引入中介者模式解决

共同封装原则​

应该将易变的类放在同一个包里, 将变化隔离出来. 该原则是开放-封闭原则的诞生

共同重用原则​

如果重用了包中的一个类, 那么也就相当于重用了包中的所有类, 我们要尽可能减小包的大小

好莱坞原则​

Dont call me, i will call you

控制反转, 或称为依赖注入

不需要主动创建对象, 而是由容器帮我们来创建并管理这些对象

不要重复你自己​

不要让重复的代码到处都是, 要让他们足够的重用, 所以要尽可能的封装

保持他简单与傻瓜​

保持系统界面简洁, 功能实用, 操作方便

高内聚与低耦合​

模块内部需要做到内聚度高, 模块之间需要做到耦合度低

关注点分离​

将一个复杂的问题分离为多个简单的问题, 然后逐个解决

你不需要它​

不要一开始就把系统设计的非常复杂, 不要陷入过度设计的深渊, 让系统足够简单, 而又不失扩展性

软件设计分层​

架构种类: 系统级架构, 应用级架构, 模块级架构, 代码级架构

系统级架构​

  • 应用在整个系统内, 如与后台服务如何通信, 与第三方系统如何集成

  • 设计前端首要条件: 了解前端系统与其他系统之间的关系

  • 关系包括: 业务关系和协作机制

  • 设计后端: 只需要规定与后台数据传递的机制.

  • 包括: api 设计原则, 访问授权的一个开放标准(Oauth)跳转 token 的验证, 数据传递 cookie 等

  • 前端与后端的关系考虑的主要因素是: 前后端分离的架构设计

  • 前后端分离架构其实是如何实施技术决策, 用户鉴权, API 接口管理和设计, API 文档管理, Mock 的使用, BFF(服务于前端的后端, nodejs), 是否需要服务端渲染, 应用间分层, 性能优化, 代码拆分, 项目管理等等这些内容

关于微前端的补充​

在一个系统内微前端是应用间的架构方案. 也就是说微前端整体的子应用是应用在一个系统之内的, 但是对于整体的应用, 多个应用而言, 微前端则是一种系统间等架构方案. 微前端负责的是调度所有的子应用. 不管是每个子应用的渲染, 数据依赖和更新获取, 子应用的激活与卸载等等所有内容都是由微前端框架去完成的. 总体而言, 微前端是将多个前端应用以某种形式结合在一起进行应用

微前端解决的实际问题

旨在解决单体应用在一个相对长的时间跨度下, 由于参与的人员, 团队的增多变迁, 从一个普通应用演变成一个巨石应用(Frontend Monolith)后, 随之而来的应用不可维护的问题

微前端的实现形式

单实例形式: 即同一时刻, 只有一个子应用被展示, 子应用具备一个完整的应用生命周期. 其他子应用处于未激活状态

多实例形式: 同一时刻可展示多个子应用.通常基于 url 的变化来做子应用的切换. 通常使用 Web Components 方案来做子应用封装, 子应用更像是一个业务组件而不是应用

应用级架构​

  • 应用级架构可以看做是整体系统级架构的细化

  • 单个应用于其他外部应用的关系, 微服务架构下多个应用的协作, 数据交换等

  • 应用级架构涉及几种形式: 应用间脚手架, 模式库, 设计系统

模块级架构​

这部分内容使我们开始业务编码之前进行设计, 我们称为迭代

代码级架构​

  • 规范与原则, 开发流程, 代码质量以及改善, 规范而非默契

如何保证架构质量​

系统的稳定性​

  • 定义: 当一个实际的系统处于一个平衡的状态时, 如果受到外来作用的影响时, 系统经过一个过渡过程仍然能回到原来的平衡状态, 我们称这个系统就是稳定的, 否则不稳定

  • 架构设计的基石, 可以更好的实现自我修复

系统的健壮性​

  • 定义: 计算机软件在输入错误, 磁盘故障, 网络过载或有意攻击情况下, 能否不死机, 不崩溃, 就是该软件健壮性的具体表现.

  • 解释: 一个系统容错能力强, 运行不易被干扰, 安全性好

  • 度量标准: 一个软件可以从错误的输入推断出正确合理的输入, 一个软件可以正确的运行在不同环境下, 一个软件能够检测自己内部的设计或者编码错误, 并得到正确的结果

架构质量的衡量​

拓展性, 可管理, 维护性, 高可用(故障修复, 容灾, 降级, 熔断)

日常开发过程中的架构质量指标​

理解难度, 接入依赖的成本, 崩溃率和错误率的指标, 开发效率, 错误上报和信息收集等功能