业务需求可能不同且在过程中会经常变化,因此创建一个灵活、可扩展和可维护的架构非常重要。确保所有人都能清楚地理解项目,包括团队成员和客户等,这一点也至关重要。为了减少冗长的文档、频繁的会议以及持续的调整,我们采用以下架构方法。本文将探讨流行架构的优点,并帮助您选择最适合您具体需求的解决方案。
很多人认为下面列出的架构只是“文件夹结构”,这种说法虽然有些道理,但并不完全准确。仔细一看,其实背后还有很多重要的细节。
- 模块化协作 : 应用程序中不同模块或组件之间高效通信和互动(使用组件化架构,可重用代码)。
- 改进项目导航 : 以易于导航和维护的方式结构化项目(清晰的文件夹层级结构,命名约定,职责分明)。
- 业务逻辑与UI组件分离 : 将业务逻辑(如数据获取、状态管理)与UI组件分开,以提高可维护性和可重用性(例如,使用服务或Redux、Context API等存储机制)。
- DRY : 不要重复自己
- DAC _: 分而治之(Divide and Conquer)
看下面的图表——我们特别关注图表右下角的部分,这些原则在那里的结合最为有效。
理想的结果是图解
我们希望通过架构来实现这些目标。现在我们来逐一详细分析,并挑选最适合特定情况的那个。
经典建筑设计(看似建筑,实则无)经典架构法——这是你们很多人已经使用的一种方法。我们通常关注基本概念,将项目分为“页面”、“组件”、“辅助模块”等等。然而,问题在于随着应用程序的增长,结构开始松散化,找到正确的组件及其业务逻辑变得越来越困难。让我们通过一个例子来看看这一点:
组件过度使用:示例
在这个例子中,我们有3个显然并没有被过度使用的页面。然而,它们可能包含下面列出的所有组件。如果我们观察这些组件,会看到真正的“混乱” 🤯:每个组件都积极地依赖于其他组件,从而在它们之间创建了依赖关系。这使得它们难以扩展和复用。
这里再举一个使用Redux状态管理器的例子:
分散的应用逻辑:Redux状态管理器示例
在我们的设置里,每个组件都由一个指定的 “reducer” 管理其特定逻辑。然而,一些组件的逻辑被错放到错误的 reducer 中。这可能是因为开发人员不知道有现有的文件,或者由于当时的逻辑需求量较小而没有考虑到创建一个新文件。结果,一些组件的逻辑散落在整个项目中,使得代码变得不那么清晰明了,也更难维护和管理。
我们建议看一下下面的图,它展示了缺失的部分架构。
破坏性的解耦 — 图(例如)
这种方法——或者说更准确地说是没有架构的设计 🥲 —— 经常导致混乱的环境,在这种情况下,依赖关系难以追踪,从而使得项目支持变得困难。如:对于某些特定情况可能很有用,例如:
- 小型团队(1-2名开发者)
- 最小化可行产品(MVP)项目
- 不是长期维护的项目
- 学习项目或参考资料
模块化架构 —— 是一种方法,其中每个模块都是独立的,有自己的逻辑和职责范围,例如 pages
、modules
、components
、UI
等。
模块化架构设计 — 层次结构示例
在这个例子中,你可以看到应用层是按照相同的方向排列的:pages
→ modules
→ components
→ ui
(或者从另一个角度看,可以是 ui
→ components
→ modules
→ pages
)。这意味着层次越高(比如 pages
层),它能使用的下层就越少——组件不能使用模块,但可以使用 ui
层的一切,模块可以使用组件但不能使用页面。而页面只使用模块。
模块化的设计架构 — 独立模块及公开 API(示例说明)
正如我们之前提到的,每个模块都有其特定的职责范围。同样重要的是,每个模块应该拥有自己的公开API(即index.ts
文件),该文件封装了模块的全部内部逻辑,并只对外提供必要的接口。(这与面向对象编程的原则非常相似:当一个类有很多私有方法,这些方法不能从外部调用,但可以在类内部使用时)而对于pages
,理想状态下它们应该是模块和组件的封装,而应用的所有业务逻辑应该放在模块和组件层次上。
(⚠️) 重要:模块不应依赖于其他模块,组件也不应包含复杂的逻辑。如果确实需要逻辑,那么它应该尽可能地简单和易于维护,否则,那它就是模块了。
下面是一张图表,请看:
几乎理想:示意图(示例)
但是……我们仍然有像 components/
和 ui/
这样的全局目录,可能被过度使用。在一些情况下,逻辑会变得复杂,不再总是清楚什么是组件,什么是模块。此外,通常会观察到,随着应用的增长,开发人员开始在模块中使用其他模块,这违背了该架构的原则,并导致了不必要的依赖关系。不过,我们的架构还提供了:
- 单线程性
- 在不同层次间重用组件的能力
- 几乎完美的分层
- 封装性
简介 — https://feature-sliced.design/
功能切片设计(FSD) 架构——与模块化架构有很多相似之处,但避免了我们上面提到的“但是……”的问题。此方法通过功能区域(功能),而不是仅仅通过层来组织项目。这种组织方式有助于避免全局目录的增长(比如模块化架构中的 components
、UI
目录),并为组件、模块和层之间提供了清晰的责任划分。
FSD(全自动驾驶)示例
架构是这样设计的,顶层的 pages
集成了所有子模块和组件的工作,并对它们进行组织。每一层提供更详细和具体的功能和元素。确实,我们也按照同样的规则来操作——层级越高,比如 pages
,它能用到的下一层就越少。
- Pages — 顶层包含在应用中显示的页面。
- Processes — 在此架构中已废弃,所以我们可以在这里跳过它。
- Features/Widgets — 在
_pages_
之下是主要的_features_
块,这些块使它们能够独立管理页面的核心功能。 - Entities — 在功能模块之下是由“_Shared”层中的简单UI组件编译而成的实体。
- Shared — 底层包含了可以在应用程序各部分使用的通用UI组件。
(⚠️) 非常重要:就像在模块化架构中那样,各层不会互相滥用资源。
概述(切片/模块) https://feature-sliced.design/
FSD架构的特点是包含称为“slices”和“segments”的模块化元素。“切片”指的是每一层中的模块(称为“slices”),每个模块代表一个独立的业务实体。而“段”则包括各种结构组件,例如api/
、components/
、config/
、constants/
等,将架构组织成更清晰、更易于管理的板块。
终于如愿以偿了:
理想图,示例图表
这种方法不容易快速地集成到项目里。它至少需要基本的架构知识,并且这可能需要时间。但是掌握FSD的使用可以带来:
- 清晰的结构设计
- 鲜明的层次感
- 灵活的组件设计
- 独立的模块化
- 均衡的复用性
另外,这种设计推广了文件命名中的“烤肉串命名约定”
模块化架构的示例: FSD 架构的使用示例: 结论部分
product-description.vue
/shopping-cart.tsx
/get-base-url.ts
/ 等等文件。
在这篇文章中,我们研究了经典架构、模块化架构和全自动驾驶(FSD)架构之间的区别,并讨论了它们的应用。
如果你对这篇文章感兴趣,不妨参加我们在斯洛伐克的布拉迪斯拉发举办的现场网络开发者大会Webstack,那里将讨论许多其他有趣的主题,而不仅仅局限于 PHP 和 Laravel!
Webstack 2025
共同学习,写下你的评论
评论加载中...
作者其他优质文章