前端虽然日新月异,但大部分人都还是“All in Component”(组件一把梭),“面向页面编程”的做法(少数人会有一些contianer的概念),造成项目缺乏可维护性,很多项目每隔几年就不得不推到重来。归根揭底是因为前端缺乏合理的架构支撑,前端由于其复杂性(既有业务数据又有ui数据,既有业务逻辑又有交互逻辑,多平台适配问题),其实是更需要架构的地方。但社区更多在纠结vue还是react,我认为在任何架构里,view都应该是最不重要的部分,本架构的示例项目将不使用任何库和框架。
本系列文章将以领域驱动和整洁架构为主要参照,设计出一个适合前端的通用架构。最终的效果是代码即产品,产品即代码,代码做为产品的一部分,最终的代码是业务专家和产品经理可浏览的。因此它是面向业务的,技术无关,框架无关,可以应用在当今任何技术栈里,并且可以随时低成本的随时切换到任何框架和技术栈。
代码是没有价值的,代码的唯一价值在于其所承载的业务。目前前端的架构总是基于技术的(mvc/mvvm,redux/flux等)。技术架构的缺点是业务逻辑是隐含的,领域知识没有得到很好的体现,新人难以理解。如果某个用例跨越多个页面,那么无论“面向页面编程”还是“面向store编程”,都很难弄清这么多的代码到底完成了怎样一件事。另外,技术总在更新换代,新技术也会层出不穷,切换的成本比较高。
简介
点击查看【processon】
该架构非常简洁,首先划分出子域,一个子域作为一个独立的模块。每个模块有三层:领域层(model),应用层(app), 适配器层(adapter)。领域层放领域逻辑,适配层做io,应用层编排它们完成具体用例。最后,ui作为应用层方法和适配器(store)层数据的消费者。上面是单个子域的架构图。
你可能要先浏览一些领域驱动和整洁架构的相关介绍,不过本架构非常简单,只用了它们中最基础的部分并且有一个step by step的示例项目。
用例层
应用层就是产品用例图的体现,其中每一个方法/模块都是一个个用例(方法的命名和用例图保持一致)。应用层的要义在于用例完整,这个“完整”体现在一是所有用例都被实现,二是每个用例都完整体现了该用例的时序图。
领域层
领域层内是一个个实体和值对象,不必对概念过于纠结,在前端这一层比较简单,你可以先简单视为系统的组成元素,如电商系统的商品,订单,购物车,领域层来存放它们自身的业务逻辑。领域层应该是纯的,没有技术倾向,也没有副作用,这保证它可以独立被测试。
适配器层
前端store,后端api等其他具体技术有关的都用适配器模式实现,它们的作用是隔离具体的技术和副作用。最终,它们在用例层被编排和领域层共同完成领域逻辑:
async function 某个用例() {const data = await 入方向的适配器.get()const entity = 领域层方法.create(data)出方向的适配器.set(entity)}
ui
ui应该尽可能简单,不要有具体逻辑和状态,只是简单作为应用层方法和store层数据的消费者,它甚至不需要用vue或react之类的框架。
import app from 'some-domain/app'import store from 'some-domain/adts/store'export default () => <Ui data={store} onClick={app.某条用例} />
示例
接下来将会一步步搭建一个todo-mvc应用来体现该架构的方方面面。先简单描述产品功能:
这是一个供用户管理自己待办的地方,需要注册登录。有两种身份的用户,普通用户可以创建,标记完成或删除自己的待办,只有管理员可以删除其他人的待办。
为了体现架构的技术无关性(以及view层的不重要),这个项目将不使用任何库与框架。源码地址是:https://github.com/happy-little-one/clean-ddd-archtecture
