当前位置: 首页 > 科技观察

分层架构的演化:从单体插件演进的思考

时间:2023-03-14 00:39:35 科技观察

最近在为Coco优化分层架构时,陷入了各种决策困境。所以我一直拖延决定找出什么更适合现有系统。也就是说,徘徊在危险的边缘,希望得到最大的利益。在设计一个新的架构时,我们总是依靠我们以前的经验,结合当前业务情况的需要,让我们的设计立足于未来的需求。即:过去的经历。现在需求。未来的方向。在各种因素的影响下,注定我们无法设计出满足所有历史时期的制度。未来变成现在,现在变成过去。Coco架构设计:从过去到未来,Coca的各种设计问题,Golang对多平台的支持等诸多因素。迫使Inherd开源团队在Coco初期就考虑为Coco设计一个插件系统。直到最近,我们实现了插件系统后,才发现原来设计的分层架构已经不能满足今天的需求了。虽然,我已经知道新的分层架构应该如何设计,但我不想往那个方向走。我绕一圈,看看有没有更有趣的设计。原始形态:MonolithicArchitecture在设计初期,我在Coco:app中引入了类似CleanArchitecture(不含Cargo模块)的分层架构设计,对应用例(usecases)。bin,对应控制器。在Rust构建系统中,会在bin目录下构建可执行文件基础设施,对应基础设施,比如调用Git的接口,访问文件系统等。领域,即业务实体和领域模型,包括系统的业务设计。在domain目录下,根据我们的四个基本业务,做了一个二级划分:clocgitframeworkarchitecture......虽然,我一直在说我用的是类似于CleanArchitecture的分层架构。但实际上,一些重要的设计并没有被采纳,比如依靠反演来控制流向的问题。个人观点:带来了一定的架构复杂度,需要不断迁移相关的架构知识。能否在开源项目中推广,还有待商榷。后续的转换可以通过重构来完成。我不是很资深的架构师,所以入手学习比较方便。作为一个单体应用程序,这种分层结构还可以:它不太复杂,而且它让开发人员知道将代码放在哪里。可以按需演进到清洁架构。模块可以按业务进一步拆分。故事的开头还不错。可复用形式的模块化为了在多个不同的系统/应用之间复用代码(即Coco项目的代码提供给其他应用),在系统中产生一些独立的模块,如psa、framework等。这也是很常见的模块化场景。模块化在不同的语言中有一定的相似性。例如:有两种使用方式:本地使用和远程发布。在本地使用时,不需要关注语义版本等一系列的事情,只关注代码本身。一旦时机成熟,它可以演变成一个可以远程发布的模块。从整体中出现的一种典型的模块化形式是代码库中与源代码处于同一级别的目录。如下:├──framework├──psa├──src│├──app│├──bin│├──domain│├──infrastructure│└──lib.rs其中framework和psa是独立的一个模块,一旦脱离了对其他模块的依赖,就可以作为独立的应用程序分发。Copyoverreuse顺带一提,对于模块化的代码复用,如果代码量不大,可以尝试复制一份代码,而不是当成代码来复用。这样我们就可以通过this来解耦依赖。插件架构的演进同时,为了灵活扩展系统的功能,我们设计了插件系统。(其实从更多的角度来说,我们只是想减小包的大小,方便在GitHub上下载)所以,我们单独创建了一个plugins目录,并在里面创建了相应的模块,如下coco_xxxx即插件。同时,我们使用plugin_manager作为插件管理器(其实后来证明这个管理器不应该作为一个模块独立存在):├──framework├──plugin_manager├──plugins│├──coco_container│├──coco_pipeline│├──coco_struct│└──coco_swagger├──psa├──src│├──app│├──bin│├──domain│├──infrastructure│└──lib.rs来自design和evolution来看,问题不大,可以用。进化:未来的未来是美好的,但是由于我们缺乏经验,我们面临着之前没有考虑到的问题。提取核心模型从设计思路上来说,我们应该在原有的架构模型中提供一个核心模块。而在这个核心模块中,是用来为插件和应用程序提供一些核心代码的。于是,我们很快创建了一个core_model出来。我的本意只是提供一个核心模型。我不认为在一些插件项目中,核心中提供了很多非核心代码。只是,随着第一个模型复用需求的出现,很快就会有第二部分和第三部分。另一种选择:基础设施层的改造。除了模型的复用,插件之间还会有基础设施的复用。而这些代码,我并不想放在core里面,所以我需要抽取一个infra模块来共享infrastructure的代码。那么问题来了,我们应该如何选择呢?将原始基础设施提取到主目录并作为单独的模块存在。双层基础架构,即只将共享代码提取出来,作为一个独立的模块放在主目录下。从架构设计的角度来看,我支持两层基础设施的存在。过多无意中复制这些通用代码会导致包体积进一步膨胀。一个典型的例子就是在一个叫做commonpackage的jar包中,我们看到一个common子包,里面有一个common目录,即xxx-common.common.common。总结:架构不断演进的故事到此结束。即使是一个小项目,其架构模型也会随着系统的发展而不断演进。如果任其发展,系统可能会推动控制。而进化本身也不会一帆风顺。但是,我正在思考一个新事物,关于“分层架构适应度函数”。Yiki:分层架构适应度函数无论是在Coco还是Coca中,我们都在尝试对系统的分层进行评级。这个评级的依据之一是通过依赖关系确认模块之间的引用关系,从而判断系统的层次结构是否满足要求。通过分析模块之间的引用关系,可以有效帮助我们理清系统模块之间的合理性。本文转载自微信公众号「phodal」,可关注下方二维码。转载本文请联系phodal公众号。