Django单体应用模块隔离方案有效性及过度设计疑问
我们公司现有规模尚小的Django单体应用,已出现模块间隔离问题。架构采用通用User模型、UserProfile模型及用于用户分组的Company模型,这些模型集中在companies模块,其他模块通过外键耦合,我们将其视为只读依赖以遵守业务边界。
当前问题在于模块间的跨模块服务调用:例如moduleB需访问moduleA的资源,直接导入moduleA的GetResourceInterface会打破边界;若不使用DTO,隔离性进一步受损。
我们考虑通过各模块的REST API实现跨模块调用,现有两种代码方案:
原有耦合方案
# The GetResourceInterface is defined in module A! from moduleA import GetResourceInterface class AServiceInModuleB: # We use dependency injection def __init__(service: GetResourceInterface): pass
接口隔离替代方案
# The name could be different (not sure which for now) from dependencies import ModuleAConnectorInterface class AServiceInModuleB: def __init__(connector: ModuleAConnectorInterface): pass
该替代方案优势在于依赖关系更明确,但存在HTTP请求开销(采用JWT认证,请求多为本地调用),暂未担心闲聊式架构问题。
现咨询:此方案是否可行?是否属于过度设计?我们曾经历无边界的混乱单体应用,当前重构后团队扩张,采用单仓模式,各团队负责部分模块,需避免依赖冲突、代码破坏及重构阻塞。注:我们采用DDD,明确限界上下文与独立领域数据结构。
方案完全可行,且不属于过度设计
结合你们的背景(曾经历无边界混乱、团队扩张、单仓多模块维护、DDD限界上下文落地),这个接口隔离+REST API调用的方案完全适配需求,理由如下:
严格守住限界上下文边界
替代方案通过ModuleAConnectorInterface抽象依赖,彻底切断了moduleB对moduleA内部接口的直接依赖,完全符合DDD中限界上下文独立的要求。每个模块只对外暴露标准化的API契约,内部实现变更不会直接影响其他模块,从根源上避免了之前的无边界混乱问题。适配团队协作需求
单仓模式下多团队维护不同模块,这种方案能明确各模块的依赖契约:- 各团队只需维护自身模块的API接口定义和Connector实现,不会因为跨模块导入导致代码冲突或误改其他模块代码;
- 重构时只要保持API契约不变,内部逻辑可以自由调整,不会阻塞其他团队的开发进度。
HTTP开销的可优化空间
针对本地调用的HTTP开销问题,有两种低成本优化方式:- 实现双模式Connector:同一个
ModuleAConnectorInterface提供两个实现类,本地环境使用直接调用内部逻辑的实现(跳过HTTP和JWT认证),生产环境使用HTTP调用实现; - 使用轻量内部通信方案替代HTTP:比如基于Django的信号系统、内部消息队列,或者直接使用进程内的RPC调用,既保留接口隔离的优势,又消除HTTP开销。
- 实现双模式Connector:同一个
额外建议
- 一定要标准化API契约:使用OpenAPI/Swagger定义每个模块的API接口,确保Connector的实现和API定义完全一致,避免契约不一致导致的问题;
- 保留DTO的使用:即使通过API调用,也要用DTO在模块间传输数据,避免直接暴露内部模型结构,进一步强化边界隔离。
内容的提问来源于stack exchange,提问作者Antonio Gamiz Delgado

