기술

한 관계의 주체에 타입 두 개를 허용했더니, 조직 구조가 자연스럽게 들어왔습니다

2026.05.1211분 읽기

조직 구조와 기술 구조의 계층이 맞지 않았습니다

운영 중인 지식그래프에 도메인(기술 단위) 노드들이 있었습니다. 결제 시스템의 도메인은 결제 도메인, 정산 시스템의 도메인은 정산 도메인 같은 식입니다. 처음에는 도메인 단위로 데이터를 분류하고 담당자를 매핑하면 충분해 보였습니다.

운영하다 보니 어색한 부분이 드러났습니다. 조직 팀과 기술 도메인의 계층이 1:1이 아니었습니다.

운영A팀 — 도메인 A 담당 (1:1)
운영B팀 — 도메인 B + 도메인 C 담당 (1:N)

운영B팀은 두 개의 기술 도메인을 함께 담당하고 있었습니다. 이메일 임포트 UI에서 "도메인 B"를 선택하면 내부적으로는 운영B팀이 임포트한 메일인데, 그게 화면에 드러나지 않았습니다. 사용자가 "이거 누가 임포트한 거지?"를 추적하기 어려웠습니다.

문제를 정리하면 두 가지였습니다.

그래프에 팀 개념 자체가 없음. 도메인만 있고, 도메인이 곧 운영 단위처럼 취급됨

"이 팀이 담당하는 도메인이 무엇인가"를 그래프로 표현할 수 없음. 결과적으로 팀별 장애 통계·담당자 조회 같은 분석이 불가능

해결은 두 단계였습니다. 첫째, Team 노드를 추가해서 조직 단위를 그래프에 표현. 둘째, Team이 Domain을 관리한다는 관계를 어떻게 표현할지 결정.


첫 번째 시도: Team 전용 관계를 새로 만들면 어떨까

처음 떠올린 방식은 단순했습니다. Person이 Domain을 관리하는 관계는 이미 (Person)-[:MANAGES]->(Domain) 으로 있으니까, Team 전용으로 새 관계를 하나 더 만드는 거였습니다.

(Person)-[:MANAGES]->(Domain)        # 기존
(Team)-[:OWNS]->(Domain)              # 신규 - 별도 관계

이름은 OWNS든 MANAGES_TEAM이든 다를 수 있어요. 핵심은 관계 타입을 분리하는 발상입니다.

이 방식의 문제는 운영 시점에서 보였습니다.

"도메인 A의 담당자가 누구인가?" 쿼리를 짤 때 두 관계를 다 따라가야 함

한 관계의 의미가 두 곳에 흩어지니, 어느 쪽을 갱신해야 할지 헷갈림

새 주체 타입(예: 외부 컨설팅 회사)이 추가되면 또 새 관계를 만들어야 함

같은 의미("이 자원을 관리한다")가 관계 이름만 다르게 여러 개로 존재하는 게 본질적으로 어색했습니다.


두 번째 시도: 관계 한 개에 여러 주체 타입을 허용

다른 방식은 MANAGES 관계 하나는 그대로 두되, from 쪽이 받을 수 있는 노드 타입을 여러 개로 확장하는 것이었습니다.

# 변경 전
MANAGES: { from: Person, to: [Host, Domain, System, Process] }

# 변경 후
MANAGES: { from: [Person, Team], to: [Host, Domain, System, Process] }

from: [Person, Team]이 핵심입니다. 한 관계가 Person이 주체인 경우도 받고, Team이 주체인 경우도 받게 됩니다. 이 패턴이 폴리모픽 관계입니다.

비슷한 발상은 객체지향에서도 보입니다. 하나의 메서드가 여러 타입의 매개변수를 받는 다형성. "두 타입이 같은 동작을 한다"는 게 본질이고, 그걸 한 인터페이스로 묶는 거예요.

1.jpeg


폴리모픽으로 가니 운영 쿼리가 단순해졌습니다

이 방식의 진짜 장점은 운영 시점에 드러났습니다. "이 도메인의 담당자가 누구인가?" 같은 쿼리가 한 관계만 보면 끝났습니다.

MATCH (?)-[:MANAGES]->(d:Domain {name: "도메인 B"})
RETURN ?

? 자리에는 Person이 올 수도 있고, Team이 올 수도 있습니다. 둘 다 같은 MANAGES 관계로 연결되어 있으니까요. 응답 결과에 두 타입이 함께 나와도 자연스럽습니다. "이 도메인은 운영B팀이 관리하고, 그 안의 개인 담당자는 X씨입니다" 같은 식으로 읽을 수 있습니다.

쿼리 외에 운영에서 이점이 또 있었어요.

확장에 열려 있음: 나중에 외부 컨설팅 회사 같은 새 주체가 추가되면 from: [Person, Team, ExternalOrg]로 한 줄만 늘리면 됨

의미가 한 곳에 모임: "MANAGES는 자원을 관리한다"는 의미가 분산되지 않음

분석 일관성: 팀별 장애 통계, 도메인별 담당 조직 같은 분석이 같은 쿼리 패턴으로 가능


BELONGS_TO도 같이 확장했습니다

MANAGES만 폴리모픽으로 바꾸니 BELONGS_TO 쪽도 같은 이슈가 보였습니다.

# 변경 전
BELONGS_TO: { from: Person, to: Organization }

# 변경 후
BELONGS_TO: { from: Person, to: [Organization, Team] }

이번에는 from이 아니라 to 쪽이 폴리모픽입니다. Person이 외부 조직(Organization)에 속한다는 의미는 이미 있었고, Person이 내부 팀(Team)에 속한다는 의미가 추가됐습니다. 둘 다 "어딘가에 소속됨"이라는 같은 의미이기 때문에 같은 관계로 묶었습니다.

(직원 A) -[:BELONGS_TO]-> (운영B팀)        # 내부 팀 소속
(직원 A) -[:BELONGS_TO]-> (외부 협력사 X)  # 외부 조직 소속 — 둘 다 가능

한 사람이 여러 BELONGS_TO를 가질 수도 있습니다. 팀에 속하면서 동시에 외부 조직과도 협업하는 케이스가 자연스럽게 표현됩니다.

2.jpeg


UI도 자연스럽게 따라왔습니다

그래프 구조가 바뀌니 운영 UI도 따라갔습니다. 이메일 임포트 화면에서 가장 큰 변화가 있었어요.

기존 UI

도메인 드롭다운: 도메인 A / 도메인 B / 도메인 C

"도메인 B"를 선택해도 그게 어느 팀의 책임 영역인지 화면에서 드러나지 않았습니다.

변경 UI

팀 드롭다운: 운영A팀 / 운영B팀

내부적으로는 선택된 팀이 관리하는 도메인 목록을 메타데이터로 함께 저장합니다.

UI 선택

내부 저장

운영A팀

team=운영A팀, domains=[A]

운영B팀

team=운영B팀, domains=[B, C]

흥미로운 점은 UI 변경이 그래프 구조 변경의 결과로 자연스럽게 나왔다는 거예요. 그래프에 팀 노드가 생기고 팀-도메인 MANAGES 관계가 있으니, UI에서는 "팀을 선택하면 자동으로 도메인 목록이 채워짐"이라는 동작이 그래프 쿼리 한 번으로 구현됩니다.

MATCH (t:Team {name: "운영B팀"})-[:MANAGES]->(d:Domain)
RETURN d.name

이런 식으로 그래프 구조가 잘 잡혀 있으면 UI 로직이 가벼워집니다. 화면 코드에 비즈니스 룰을 하드코딩할 필요가 없어요.


Case 리뷰 파이프라인에서도 같은 패턴이 이어집니다

이번 변경의 또 다른 효과는 케이스 분석에서 나타났습니다. 장애 보고서가 그래프에 들어갈 때 "이 장애가 영향을 준 시스템의 담당자는 누구인가?"를 자동으로 추적할 수 있게 됐습니다.

MATCH (incident:Incident)-[:AFFECTS]->(s:System)<-[:MANAGES]-(owner)
RETURN incident, s, owner

여기서 owner는 Person일 수도 있고 Team일 수도 있습니다. 폴리모픽 MANAGES 덕분에 한 쿼리로 둘 다 잡힙니다. 개인 담당자가 있으면 개인이 나오고, 팀 수준에서만 관리되는 자원이면 팀이 나옵니다. 분석 코드가 분기하지 않아도 됩니다.

팀별 장애 통계, MTTR 분석, 도메인별 담당 조직 매트릭스 같은 후속 분석도 이 구조 위에서 자연스럽게 가능해졌습니다.


트레이드오프 — 폴리모픽이 항상 정답은 아닙니다

폴리모픽 관계가 깔끔하긴 하지만, 항상 좋은 건 아니에요. 트레이드오프가 있습니다.

의미가 정말 같을 때만 폴리모픽으로 묶어야 합니다. MANAGES는 "이 자원을 관리한다"는 의미가 Person과 Team 모두에서 동일하니까 묶을 수 있었습니다. 만약 Person은 "직접 운영"이고 Team은 "공식 소관"으로 의미가 다르다면, 폴리모픽이 아니라 별도 관계로 가야 합니다. 같은 관계로 묶고 나면 두 의미를 구분할 수단이 사라지거든요.

쿼리에서 타입 확인이 필요한 경우도 있습니다. "팀이 관리하는 도메인만 알고 싶다"면 결국 MATCH (t:Team)-[:MANAGES]->(d) 처럼 타입을 명시해야 합니다. 모든 쿼리가 폴리모픽 그대로 가는 건 아니에요.

이 두 가지를 감수할 만한 가치가 있을 때 폴리모픽이 유리합니다. 일반적으로는 "의미가 같은 동작인데 주체 타입만 다르다"는 신호가 보일 때가 적용 시점이에요.


마무리

지식그래프에 Team 노드를 추가하면서, MANAGES 관계의 주체를 Person 단독에서 [Person, Team]으로 확장했습니다. 별도 관계를 새로 만드는 대신 같은 관계가 여러 타입의 주체를 받게 한 것이 폴리모픽 관계 설계입니다. BELONGS_TO도 같은 방식으로 대상 쪽을 [Organization, Team]으로 확장했습니다.

이 구조 덕분에 "이 자원의 담당자가 누구인가" 같은 쿼리가 한 관계만 따라가면 끝나고, 새 주체 타입이 추가되어도 한 줄 변경으로 확장 가능한 형태가 됐습니다. 운영 UI도 그래프 구조를 그대로 따라가서 비즈니스 룰이 화면 코드에 흩어지지 않게 정리됐습니다.

비슷한 결의 두 주체가 같은 동작을 하는 상황이 있다면, 관계를 두 개로 나누기 전에 폴리모픽으로 묶을 수 있는지 한 번 검토해보시길 추천합니다. 의미가 같은 동작은 같은 관계로 표현하는 게 그래프 구조를 단순하게 유지하는 핵심입니다.

#온톨로지#폴리모픽관계#Neo4j#지식그래프#스키마설계#팀모델링#AI전환기