英文:
Gap between updated domain model and previously saved data
问题
Assumption:
- 使用领域驱动设计方法。
- 领域模型类包含业务逻辑。
- 领域模型数据保存在存储库中。
- 当尝试从应用层获取数据时,首先检索数据库数据,然后使用它实例化领域模型类,然后将实例返回给应用层。
Example:
- 用户领域模型类有一个属性 'name',该属性有一个规则:长度应大于3且不超过100。
- 使用 'name' 属性的长度为99来实例化该类,并将实例保存在存储库中。用户的姓名确保符合规则。
- 当应用层需要用户数据时,它调用存储库方法,该方法返回用户领域类的实例。
现在我想知道规则必须更改的情况:最大长度为80。
然后存储库方法开始抛出错误(数据库中保存的用户姓名长度为99,尽管规则现在要求最多为80)。
这个 'name' 示例可以扩展为一个更通用的情况:当领域规则更改为更严格的规则时,我们如何从应用层获取数据?
我已经研究过这个主题,但未能从领域驱动设计的角度找到最佳实践。
是否有人有解决方案或经验来处理这个问题?
英文:
Assumption:
- Using domain driven design approach.
- Domain Model class holds business logic.
- Domain Model data is saved in repository.
- When tring to get the data from application layer, db data is first retrieved and the domain model class is instantiated with it, then the instance is returned to application layer.
Example:
- User domain model class has a property 'name' which has a rule: the length should be more than 3 and within 100.
- The class is instantiated with the 'name' property's length being 99 and the instance is saved in repository. The user's name is assured to comply with the rule.
- When application layer demands the user's data, it calls the repository method which returns the user domain class instance.
Now I'm wondering the case where the rule has to be changed: max length is 80.
Then the repository method starts to throw an error(length of the user's name saved in db is 99, though the rule now says it should be 80 at maximum)
This 'name' example can expand to a more generic case: How can we get data from application layer when the domain rule is changed to a more strict one?
I've researched this topic but failed to find a best practice from a DDD point of view.
Does anyone have a solution or experience with this problem?
答案1
得分: 1
问题的根本在于域规则不能改变过去(它可以改变过去的解释方式,但那是不同的事情),因为在现实世界中(希望这是你尝试模拟的内容),你不能改变过去。
这意味着你不能拒绝在早期规则下持久化的实体:你最多只能模拟它们不再符合当前规则。这可能会暗示需要进行自动协调,以使它们符合规则,但也可能意味着将它们标记为旧版本,并手动决定如何处理。
这可能意味着在编程语言中以类型级别建模域规则可能不可取,除非,也许,你采用类型的版本化方案(例如 AggregateV1
、AggregateV2
等,它们被视为同一类型的不同表现形式(如果你的语言支持,你可以使用接口继承,否则适配器(对于你们后台的静态FP人员,通常也可行)通常可行):“使非法无法表示” 在持久性和法律变化方面效果不佳。
在名称属性的最大长度从99变为80的情况下,你可能会将其实现为“无法修改名称属性以使其长度超过80个字符”,但不更改域类的编码类型(也不更改DB模式...)。你可以在保存时实现截断(或其他某种启发式方法),以便加载99字符名称时,它以80个字符保存;或者你可以有一个属性指示它已被允许存在,并且应采取某些措施。
如果采用事件溯源,你有一些更多的选项:带有旧名称的事件是永久的,但可以根据新规则重新解释它们,或者你可以使用快照和/或校正事件来进行技巧性处理。
英文:
The root of the problem is that a domain rule can't change the past (it can change how the past is interpreted, but that's something different), because in the real world (which is hopefully what you're trying to model), you can't change the past.
This means that you can't reject entities which were persisted under earlier rules: the most you can do is model that they no longer comply with the current rules. This might in turn imply that there's an automatic reconciliation which could be done to bring them in compliance, but it could also just mean mark them as an older version and manually figure out what to do.
This may mean that modeling domain rules at a type level in your programming language is undesirable, unless, perhaps, you adopt a versioning scheme in the types (e.g. AggregateV1
, AggregateV2
, etc. which are considered different manifestations of the same type (you might use interface inheritance for this if your language supports it, otherwise adapters ("type classes" for you static FP folks in the back) are generally viable for this): "making the illegal unrepresentable" doesn't work well with persistence and changing laws.
In the case where the maximum length of the name property changes from 99 to 80, you might instead implement that as "it's impossible to modify the name property such that it's resulting length is more than 80 characters", but not change the type in your encoding of the domain class (nor change the DB schema...). You might implement truncate (or some other heuristic) on save so that when a 99-character name is loaded, it gets saved with 80 characters; alternatively you might have a property indicating that it's been grandfathered and some action should be taken.
If event-sourcing, you have some more options: the events with the old name are forever, but they can be reinterpreted in light of the new rule, or you can do tricks with snapshots and/or corrective events.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论