写点什么

Nuxt Apps 中的领域驱动设计实践

  • 2020-12-08
  • 本文字数:2479 字

    阅读完需:约 8 分钟

Nuxt Apps中的领域驱动设计实践

我在Vue StorefrontVue Storefront Next中实验 Vue apps 的领域驱动方法有一段时间了。使用这种方法能显著改善你的代码库的可维护性和复杂度。在这个系列,我想分享一些在 Vue Storefront 中对我们有效,且容易应用到任何 Vue 应用程序中的模式。


我将展示如何在 Nuxt 和“普通”Vue 项目中如何应用这些模式。本文中,我们将聚焦理论和 Nuxt 实现。


什么是领域驱动设计?


领域驱动设计(Domain-Driven Design,DDD)概念是,将业务概念优先于代码库的其它分类类型(例如,按文件类型分组)。这意味着,你应该基于你主要的业务领域(“问题”)及其子领域(问题的细分部分)来组织你的代码。例如,在电子商务领域,我们有产品目录、客户、订单、库存等子领域。


虽然 DDD 概念来自面向对象编程,依赖于类及其关系,但其核心理念可以很容易地应用到其它范式。


为什么领域驱动设计很棒?


领域驱动设计越来越受欢迎最简单的解释是,它是一种非常简单的模式,在大多数情况下,它都会在编程最困难和最痛苦的领域之一——代码维护性上带来显著改善。


我记得,我在思考组织代码库的最佳方式时度过的无眠之夜和漫长的淋浴。如果你曾经尝试过,你就会明白这项任务非常困难,而且结果永远不会完美,因为你必须考虑到你的项目在将来可能演变的所有可能的方式。随着时间的推移,我们对试图解决问题的理解不断增长,这会带来更有效的解决问题的方法,从而改变我们最初的方案。


我们都经历过并且知道,改变最初的架构会付出多大的成本。


这就是领域驱动设计的亮点。基于业务需求对系统进行建模要容易得多,因为这个方案不受技术限制和困难的影响。我们改变核心业务需求的频率比改变底层技术的频率要少得多。


此外,领域驱动设计推崇在编写代码时考虑实际的业务需求,这意味着我们根据业务功能(例如客户)而不是技术术语(组件、存储、服务),来组织我们的代码和文件结构。这种管理代码的方式让代码更容易维护。


下图显示了一个“标准的”Vue 文件结构 vs 基于业务领域的文件结构:




如果与某个功能相关的所有东西都放在一个地方,就会很容易理解它是如何工作的,因为不存在忽略某些部分的风险。完全删除某个功能也同样非常简单,因为这个功能相关的代码不会分布在整个代码库中。


另一个好处是,我们只需查看应用程序的文件夹结构,就能很容易地推断出其业务和功能。这也很容易找到一个开始上手的地方,因为我们的任务大部分时候是用业务语言编写的。我能够给出很多其它例子,但是我确信你已经明白为什么这个方案现在被认为是更容易维护的了。


领域驱动设计和根据功能组织代码的最大好处之一,就是限制了不同模块之间的关联数量。通常,我们在应用程序中有一组扩展点被所有模块使用。理想情况下,所有的连接都应该通过一个单独的地方进行,例如一个共享模块或事件总线。使用这种方法更容易维护这些模块,因为连接不同功能的部分通常是导致应用程序复杂性增加最多的地方。如果我们设法避免不必要的复杂性并简化连接,那么让你的代码库保持简单也就非常容易了。


弄清楚如何使你的模块独立并封装,是另外一篇文章(或者是一系列文章)的主题,因此现在如果你想要深入了解这一点,我建议你阅读hexagonal architecture,并应用这种方法中的大部分有用的理念。


那么,我们该如何在 Vue 中应用领域驱动设计理念呢?


Nuxt 中的领域驱动设计


我们从 Nuxt 开始介绍,它有了一个很好的内置机制,使得应用这个理念非常容易——模块。


Nuxt 模块通常用于在你的应用程序中包含第三方功能,例如授权或 i18n。虽然编写第三方代码是最常用的利用它们的方法,但是 Nuxt 模块也可以很好地在我们的内部架构中发挥作用。


因为 Nuxt 模块可以挂接到应用程序的不同部分,例如路由或 Vuex store,所以我们能很容易地使它成为一个特定子领域与我们的应用程序连接的唯一地方!


看看这个简单的 Nuxt 模块:

// index.jsmodule.exports = function ProductCatalogModule (moduleOptions) {  this.extendRoutes((routes) => {    routes.unshift({      name: 'product',      path: '/p/:slug/',      component: path.resolve(themeDir, 'pages/Product.vue')    });  );  // we can't register stores through Nuxt modules so we have to make a plugin  this.addPlugin(path.resolve(__dirname, 'plugins/add-stores.js'))}
复制代码


// plugins/add-stores.jsimport CategoryStore from '../stores/category.js'import ProductStore from '../stores/product.js'
export default async ({ store }) => { store.registerModule(CategoryStore) store.registerModule(ProductStore)};
复制代码


…有如下文件:


.├── pages|   |── Category.vue │   └── Product.vue├── components|   |── ProductTile.vue│   └── ProductGallery.vue├── plugins│   └── add-stores.js├── store|   |── category.js│   └── product.js└── index.js
复制代码

我们这里就是一个小的 Nuxt.js 应用程序,专注于我们的应用程序的某一个子领域。现在,当我们想要在应用程序中包含所有目录相关的功能时,我们只需要一行代码就可以做到这一点!


// nuxt.config.jsexport default {  modules: [    '~/modules/product-catalog/index.js',  ]}
复制代码


现在,每当我们在 Jira 中看到产品目录相关的问题时,我们就会立即知道从哪里开始改。而且,使用这种模块化方案,新来的人也能很快知道我们应用程序中有什么功能,因此可以更快地理解业务和技术背景!


.├── pages│   └── index.vue├── modules|   |── product-catalog|   |── orders|   |── payment|   |── shipping|   |── inventory│   └── customers└── index.js
复制代码


总结与展望


基于业务领域及其子领域来组织代码,是使应用程序更易于维护的最简单有效的方法之一。尽管还有一些已知的挑战,例如不同模块之间的通信,了解基础知识就足以为代码库带来巨大的好处。应用本文中的模式不需要高级编程技巧,这让所有层次的开发人员都可以使用它。


原文链接:


https://vueschool.io/articles/vuejs-tutorials/domain-driven-design-in-nuxt-apps/

2020-12-08 14:511854
用户头像

发布了 165 篇内容, 共 80.9 次阅读, 收获喜欢 343 次。

关注

评论

发布
暂无评论
发现更多内容

MySQL only_full_group_by 1055 报错的三种解决方案,临时关闭有影响吗?

蒋川

MySQL 报错 MySQL 数据库

python 爬虫爱好者必须掌握的知识点“ 协程爬虫”,看一下如何用 gevent 采集女生用头像

梦想橡皮擦

12月日更

Go语言学习查缺补漏ing Day1

恒生LIGHT云社区

编程语言 Go 语言

运维监控场景下,如何从OpenTSDB迁移到TDengine

TDengine

数据库 tdengine

【云小课】CDN第5课 CDN入门之—我的网站可以用CDN加速吗?

华为云开发者联盟

网站 CDN 网络 CDN加速 华为云CDN

Springboot & RabbitMQ 延时队列的使用

编程江湖

大数据 消息中间件

华云大咖说 | 安超信创桌面云金融行业解决方案

华云数据

刚提测就改需求,我是渣男吗?

小傅哥

Java 加班 小傅哥 需求迭代 产品功能

迈向云原生:名企FreeWheel应用架构演进

博文视点Broadview

如何使用GoldWave软件将文字转换为语音

懒得勤快

推开“微前端”的门

百度Geek说

微服务 大前端

【12月11日】真香现场,带你玩转 EKS!

亚马逊云科技 (Amazon Web Services)

人工智能 Meetup EKS

Hutool中那些常用的工具类和方法

编程江湖

JAVA开发 java工具包

Rust 元宇宙 11 —— Websocket

Miracle

rust websocket 元宇宙

最受欢迎的5个React动画库

编程江湖

React

Spark SQL之RDD转换DataFrame的方法

@零度

大数据 RDD DataFrame spark SQL

Rust 元宇宙 从零开始构建

Miracle

rust 元宇宙

极光笔记|百亿级KV存储在极光的运维实践之路

极光GPTBots-极光推送

JDK 动态代理与 CGLIB 动态代理,它俩真的不一样

华为云开发者联盟

jdk 动态代理 spring aop JDK 动态代理 CGLIB 动态代理

大咖联袂发布!《慧技术·惠金融——2022金融科技趋势研究报告》开放下载

恒生LIGHT云社区

金融科技 行业趋势 行业大会

工具 | PG 集群复制管理工具 repmgr

RadonDB

数据库 postgresql RadonDB

web技术分享| AudioContext 实现音频可视化

anyRTC开发者

Web 音视频 WebRTC 音频可视化 AudioContext

数字化转型鸿沟如何消除?ROMA Connect融合集成,联接企业应用现在与未来

华为云开发者联盟

多云服务 应用 集成 集成平台 ROMA Connect

Redis玩转Message Queue之Stream详述

李子捌

redis 28天写作 Redis Stream 12月日更

Java开发之如何连接Redis

@零度

redis JAVA开发

前端开发面试题分享,看一下是不是你需要的

@零度

大前端 面试题

六个数字化意识和习惯

明道云

Linux学习方法《Linux一学就会》:重定向和文件的查找

侠盗安全

Apache APISIX 2.11.0 正式发布,蓄力两月带来更多新功能!

API7.ai 技术团队

开源 云原生 网关 API网关 Apache APISIX

Apache APISIX 社区双周报 | 11.15-11.30 功能亮点更新进行中

API7.ai 技术团队

开源 云原生 网关 api 网关 Apache APISIX

恒源云(GPUSHARE)_分享一个技巧!CV训练时容易忽视的数据标签问题

恒源云

深度学习 算法 CV

Nuxt Apps中的领域驱动设计实践_文化 & 方法_Filip Rakowski_InfoQ精选文章