DDD - 聚合上下文、一致性

发布于 2025-01-13 13:49:07 字数 2195 浏览 1 评论 0原文

我正在尝试设计一个项目管理系统的学生。基本上,学生必须在给定的时间内完成项目。一般来说,学生需要每周每天完成该项目,这将以某种方式进行验证。

然而,学生可以享受有限的假期并注册考试,从而在某些日子免去工作。关于如何选择假期时间有一些规则。特别是它还取决于您当天注册的考试。

整个应用程序是一个基于Spring Boot MVC并遵循DDD原则的Web应用程序。

到目前为止,我对系统进行了如下建模:

核心/域由以下类组成:StudentExamVacationExamBooking。考试由导师或学生全局添加到系统中,然后保留在系统中。假期和考试预订属于特定学生,并描述“空闲”时间段:

class Student {
  private String name;
  private int vacationTimeLeft;
  private List<ExamBooking> examBookings;
  private List<Vacation> vacationBookings;
  
  public void addVacation(...) { ... } // performs logic and adds vacation to vacationBookings
  public void addExam(...) { ... } // performs logic and adds exam booking to examBookings

  // ctors, getters, setters, ...
}
class Exam {
  private int examId; // external exam id referencing the exam in the university's own system
  private String moduleName;
  private LocalDate examDate;

  // ctors, getters, setters, ...
}
class Vacation {
  private TimeRange bookedTime;
  private LocalDate day;
  
  // ctors, getters, setters, ...
}
class ExamBooking {
  private Exam exam; // general exam info (module, professor, ...)
  private TimeRange bookedTime;

  // ctors, getters, setters, ...
}

我的问题是学生可以在两种情况下与考试进行交互:

  1. 添加/删除 ExamBooking
  2. 添加 Exam(全局)

在第一种情况下,Student 类是聚合根,而在第二种情况下,Exam 是外层所使用的对象相互影响。 (在本例中是从 StudentController 调用的 StudentService)。

我主要担心两个问题:

总体一致性: 我知道一个人不应该直接引用另一个内部的聚合根,即最好通过 ID 引用考试。但同时,Student 类中的逻辑取决于实际的 ExamBooking(因此也取决于 Exam)对象。但是,ExamBooking用于预订假期/考试,而不用于注册全球考试。

持久化/数据层: 当持久化/保存Student时,我们还需要修改数据库中相应的ExamBookings表。从数据库加载 Student 时,我们需要从多个表构建实际的域对象,因此再次需要引用另一个聚合。

引入冗余是否有意义,即将全局 Exam 中的数据嵌入/复制到 ExamBooking 中(因此无需引用 Exam > 从 ExamBooking 内部),强调我们这里有两个有界上下文的事实?

I am trying to design a project management system students. Basically there is a given period of time in which a project has to be finished by students. Generally, students need to work on the project every day of the week which will be verified in some way.

However, students are allowed to take a limited amount of vacation times and register exams that free them from work on certain days. There are some rules as to how you can choose your vacation times. Especially it is also dependent on the exams you have registered the same day.

The whole application is a web app based on Spring Boot MVC and adheres to DDD principles.

So far I modeled the system like this:

The core/domain consists of the following classes: Student, Exam, Vacation and ExamBooking. Exams are globally added to the system by tutors or students and then remain in the system. Vacations and ExamBookings belong to a specific student and describe the "free of work" time periods:

class Student {
  private String name;
  private int vacationTimeLeft;
  private List<ExamBooking> examBookings;
  private List<Vacation> vacationBookings;
  
  public void addVacation(...) { ... } // performs logic and adds vacation to vacationBookings
  public void addExam(...) { ... } // performs logic and adds exam booking to examBookings

  // ctors, getters, setters, ...
}
class Exam {
  private int examId; // external exam id referencing the exam in the university's own system
  private String moduleName;
  private LocalDate examDate;

  // ctors, getters, setters, ...
}
class Vacation {
  private TimeRange bookedTime;
  private LocalDate day;
  
  // ctors, getters, setters, ...
}
class ExamBooking {
  private Exam exam; // general exam info (module, professor, ...)
  private TimeRange bookedTime;

  // ctors, getters, setters, ...
}

My problem is that a Student can interact in two contexts with exams:

  1. Adding/Removing an ExamBooking
  2. Adding an Exam (globally)

In the first case, the Student class is the Aggregate Root, whereas in the second case the Exam is the object with which the outer layers interact. (in this case a StudentService invoked from the StudentController).

I have two main concerns:

Aggregate consistency:
I know that one should not reference an Aggregate Root inside of another one directly, i.e. it would be better to reference Exams by ID. But at the same time the logic in the Student class depends on actual ExamBookings (and thus also on Exam) objects. However, an ExamBooking is only used in the context of booking vacation/exams, not for registering exams globally.

Persistence/Data layer:
When persisting/saving a Student, we need to also modify the corresponding ExamBookings table in the database. When loading a Student from the database, we need to build the actual domain object from multiple tables, so again needing to reference another Aggregate.

Would it make sense to introduce redundancy, i.e. embed/copy the data from the global Exam into ExamBookings (so there is no need to reference Exam from inside an ExamBooking), to underline the fact that we have two bounded contexts here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

画▽骨i 2025-01-20 13:49:07

引入冗余(即将全局 Exam 中的数据嵌入/复制到 ExamBookings 中(这样就无需从 ExamBooking 内部引用 Exam))是否有意义,以强调我们这里有两个有界上下文这一事实?

可能;在某些情况下,自治组件缓存受其他组件授权的信息副本是有意义的。请参阅不变性改变一切(Pat Helland,2012)

也就是说......您可能需要重新考虑您的聚合设计。

例如:ExamBooking 似乎描述了学生和考试之间的关系,以及时钟/日历/时间表的某些风格。根据数据关系的性质,这四件事中的任何一个都可以合理地成为“聚合”。

需要重点关注的地方(警告:前方意见)是信息随时间变化的方式以及您需要信息在系统中传播的速度。

Would it make sense to introduce redundancy, i.e. embed/copy the data from the global Exam into ExamBookings (so there is no need to reference Exam from inside an ExamBooking), to underline the fact that we have two bounded contexts here?

It might; there are cases where it makes sense for autonomous components to cache a copy of information that is under the authority of some other component. See Immutability Changes Everything (Pat Helland, 2012)

That said... you may want to reconsider your aggregate design.

For example: an ExamBooking appears to describe a relationship between a Student, and Exam, and some flavor of Clock/Calendar/Schedule. Any of those four things could reasonably be "the" aggregate, depending on the nature of the data relationships.

The important place to focus (warning: opinion ahead) is the way information changes over time and how quickly you need information to propagate through your system.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文