Devlime Shared Domain / Inter-MS Domain Reference Design

Devlime Shared Domain / Inter-MS Domain Reference Design

1. Background

A requirement arose to establish a relationship between the two domains in order to display information about Scrum's AgileProject (the execution unit for a sprint) in Devlime's Prism together with Crewit's Project (contract and effort management). In addition, Crewit's effort information had to be displayed on the screen for establishing the relationship between the two domains.

Accordingly, a new layer called the Shared API was added. This layer was used to define relationships between the domains of the two MSs, and one MS's domain was designed as a shared domain so that it could also be used by the other MS.

This document is intended to serve as a reference for future shared-domain design by presenting the principles and methods for designing shared domains and domain references between MSs, organized based on the case described above.

2. Design Decision Criteria

Situations in which domains between MSs need to be mapped are classified into three types below according to the presence of a Shared APIand whether performance issues occur, and each type requires a different design approach. Before beginning the actual design, first determine which case applies.

Scenario

Conditions

Design approach

1

When no Shared API exists and mapping between the two MS domains is required

The referencing MS directly holds the source MS's domain in entity form

2

When a Shared API exists and no significant performance issues occur

The referencing MS holds only the source ID and looks it up by ID through the Shared API when necessary

3

When a Shared API exists and performance issues (N+1, repeated calls, etc.) occur

The referencing MS holds a display-only VO and updates it through batch processing, delayed processing, or business logic

3. Design Principles

Shared-domain design

Domain-reference design between MSs

Example

Shared-domain entity in the Shared API

Reference to a crewit Project held by scrum AgileProject

Location

Inside a separate Shared API service

Inside the domain of the referencing service (scrum)

Nature

A projection of the source MS's domain

An independent object separate from the source, or the source MS domain's ID

3-1. Principles for Shared-Domain Design

A shared domain is a domain among the source MS's domains that exists for the purpose of sharing it with other MSs. It follows the principles below.

1. Have the same lifecycle as the source

When data is stored or modified in the source MS, the shared domain is also updated through an event. In other words, it has the same lifecycle as the source. A trigger is set on the source MS's existing DataEvent → ProjectionHandler hook to apply the changes.

2. Include only the fields required for sharing

Do not duplicate all source fields. Exclude fields used for internal management within the source MS and include only the fields that other MSs actually need.

3. Do not use the source terminology as-is for names

Bringing over the source MS's entity name as-is can make its meaning ambiguous from the perspective of the other MS. Redefine the name to reflect the actual core attributes.

3-2. Principles for Domain References Between MSs

This applies when a domain in one MS needs to express a relationship by referencing information from another MS (or a shared domain). The specific reference method varies by scenario, so the scenarios are explained separately below.

The following two principles apply commonly to all three scenarios.

1. Treat propagated data as an object separate from the source

The information held by the referencing side (an entity or VO) is not a duplicate of the source fields; it is a self-defined object containing only the attributes actually required by the referencing domain.

2. Redefine names from the perspective of the referencing domain

Name it to reflect what this information actually means from the perspective of the referencing domain, rather than using the original term as-is.

3-2-1. Scenario 1 — No Shared API: Direct Entity Ownership

When two MS domains need to be mapped while no shared API is available yet, the referencing MS directly owns the source domain information in its own entity. In effect, the role of the shared domain is held internally by the referencing MS.

1. As with the shared domain, ensure traceability using sourceSystem/sourceKey.

2. If possible, receive the source events and update accordingly; if that is not possible, establish a manual/batch update path.

3. If the number of referencing MSs increases beyond one, each will create and manage a similar copy separately, making management difficult. At that point, create a shared API and structure it for scalability.

3-2-2. Scenario 2 — Shared API Exists, No Performance Issues: ID Reference (Default)

When a shared API exists and no performance issues caused by repeated queries have been identified, the referencing MS stores only the ID and calls the shared API in real time whenever it needs to retrieve the data.

1. Instead of having VO fields, store only one field containing the reference key (ID) of the domain being referenced.

2. Call the shared API in real time at the time of retrieval and obtain the domain mapped through the reference key.

3-2-3. Scenario 3 — Shared API Exists, Performance Issues Occur: VO (Exception)

If performance issues caused by repeated queries are actually confirmed while operating under Scenario 2, the referencing MS stores a display-only VO and populates it through batch resynchronization or lazy updates.

1. Avoid synchronization attempts themselves

Real-time forced synchronization (updating immediately whenever the source changes) is not adopted.

2. Resolve consistency issues through business logic

Use the VO only for display. In logic that requires actual business decisions, do not trust the VO values; instead, re-query the source (or shared domain) using the reference key.

3. Make freshness visible through syncedAt

Expose the time of the last synchronization alongside the data so that its freshness can be verified.

Update Method

Method

Description

Characteristics

Batch Resynchronization

A scheduler periodically re-queries the data (e.g., once a day) to update the VO

Minimizes additional infrastructure; accepts as normal that consistency delays will consistently occur for up to the length of the batch interval

Lazy Update

When scrum handles AgileProject (e.g., during creation or modification), re-query it at that point if syncedAt is outdated

No batch infrastructure is required. However, if the data is not accessed for some time, it may remain outdated indefinitely.

It is not mandatory to use only the two methods above. If there is another business-based method for resolving inconsistency issues, that method may be used.

4. Design Example (Scenario 2)

① Source (crewit's Project)

public class Project extends StageEntity {
    ...
    private String code;                        // 코드
    private LangStrings langNames;               // 이름
    private LangStrings langDescription;         // 설명
    private LangStrings langCustomers;           // 고객사
    private LangStrings langLocations;           // 위치
    private Member manager;                      // PM
    private ProjectStatus projectStatus;         // 프로젝트상태
    private ProjectPeriod projectPeriod;         // 프로젝트기간
    private String skillSet;                     // 기술세트
    private LangStrings langVendors;              // 협력업체
    private LangStrings langRiskNotes;            // 리스크
    private double budget;                        // 예산, ex, 21억5천만원
    private int totalEffort;                      // 총공수, 230 M/M
    private boolean active;
    transient List<ProjectManMonthPlan> projectManMonthPlans;   // 구성원별
    transient List<ProjectMonthPlan> projectMonthPlans;         // 월별
    transient List<ManOutput> manOutputs;
    transient List<ManRatio> manRatios;
    transient List<ManOutputMonthSum> manOutputMonthSums;
    transient List<ManRatioMonthSum> manRatioMonthSums;
    ...
}

② Shared Domain (Staffing Project of the shared API — a Projection of Project)

public class StaffingProject extends StageEntity {
    ...
    private String id;                    // PK
    private String sourceSystem;          // 원본 MS 또는 도메인 추적용
    private String sourceKey;             // crewit Project의 Id
    private String code;                  // 코드
    private LangStrings name;             // 이름
    private LangStrings description;      // 설명
    private LangStrings customerNames;    // 고객사
    private ProjectStatus status;         // 프로젝트상태
    private ProjectPeriod projectPeriod;  // 프로젝트기간
    private Member manager;               // 담당자
    private double budget;                // 예산, ex, 21억5천만원
    private int totalEffort;              // 총공수, 230 M/M
    private boolean active;
    private LocalDateTime syncedAt;       // 마지막 동기화 시각
    ...
}
  • Update through the DataEvent/ProjectionHandler hook + event when the crewit Project is stored or modified (same lifecycle as the source)

  • Exclude internally managed fields such as skillSet/budget/langVendors

  • Named StaffingProject based on the discussion that effort information, rather than contract information, is the core attribute

  • Manage the time of the last synchronization with syncedAt (maintained for tracking purposes because even a shared domain does not guarantee complete real-time reflection)

③ Referencing Service (scrum's AgileProject)

public class AgileProject extends StageEntity {
    ...
    private String staffingProjectId;   // StaffingProject 참조키. ID만 보유.
    ...
}
  • AgileProject does not store crewit/shared-domain information in its fields — it references only one ID.

  • Call the shared API and retrieve the information whenever the screen is displayed.

5. Reference (Scenario 3) — Preparation for Performance Issues

If the query frequency increases in the future and performance issues are confirmed, consider switching to a method that embeds a display-only VO as shown below. It is not adopted at present and is provided for reference only.

public class StaffingProject implements ValueObject {
    ...
    private String staffingProjectId;    // staffing project id
    private LangStrings name;            // 이름
    private LangStrings customerNames;   // 고객사
    private ProjectStatus status;        // 프로젝트상태
    private ProjectPeriod projectPeriod; // 프로젝트기간
    private Member manager;              // 담당자
    private double budget;               // 예산, ex, 21억5천만원
    private int totalEffort;             // 총공수, 230 M/M
    private LocalDateTime syncedAt;      // 마지막 동기화 시각
    ...
}
  • Include it in AgileProject and define the relationship

  • Manage it as a separate, independent object belonging to scrum, not as a copy of crewit

  • Do not reflect the source in real time; populate it through batch resynchronization, lazy updates (or other business logic)

  • Limit the transition point to after performance issues have been confirmed in actual query patterns

Bignow

Site footer