엔터프라이즈 백엔드 아키텍처에서 IoC(제어의 역전)와 DI(의존성 주입)가 도입된 가장 큰 이유가 무엇이었습니까? **"하위 계층의 컴포넌트가 상위의 서비스를 일일이 파라미터로 넘겨받지 않고, DI 컨테이너에 등록된 의존성을 필요할 때 직접 주입(Injection)받아 결합도를 끊어내는 것"**이었습니다.
Vue 3는 이 의존성 주입 메커니즘을 프레임워크 코어 레벨에서 완벽하게 지원합니다. 바로 **provide와 inject**입니다.
provide: 최상위 BoardApp.vue가 하위 트리 전체를 향해 댓글 비즈니스 서비스를 방송(제공)합니다.
inject: 아무리 깊은 곳에 있는 대대댓글이라도 중간 단계의 관여 없이 상위 서비스를 다이렉트로 주입받아 호출합니다.
Chapter 06. 계층형 댓글 트리와 Provide / Inject (DI)
6.1
BoardApp.vue에 계층형 댓글 기능 추가하기 사내 기술 Q&A 게시판에서 가장 중요한 소통 창구는 질문 아래 달리는 **댓글과 그 댓글에 달리는 답글(대댓글, 대대댓글)**입니다.
트리(Tree) 구조 데이터는 깊이(Depth)가 고정되어 있지 않고 무한히 내려갈 수 있습니다.
우리는 템플릿 안에서 자기 자신을 스스로 호출하는 **재귀 컴포넌트(
CommentItem.vue)**를 만들어BoardApp.vue의 상세 뷰에 붙였습니다.새로운 컴포넌트 파일을 생성합니다:
frontend/src/components/CommentItem.vue[코드 6-1] 재귀 컴포넌트의 뼈대 (
frontend/src/components/CommentItem.vue) 6.2 Props Drilling과 이벤트 릴레이 지옥
여기서 엄청난 설계적 고통이 찾아옵니다.
저 4단계 깊숙한 곳에 있는
대대댓글 1-1-1에서 사용자가 [삭제] 버튼을 눌렀다고 가정해 봅시다.실제 서버 DELETE API를 호출하고 전체 댓글 트리를 갱신해야 하는 주체는 최상위
BoardApp.vue입니다.전통적인
props와emit방식을 고집하면:Depth 0,Depth 1컴포넌트들은 댓글 삭제에 아무런 관심도 없으면서, 오직 자식의 이벤트를 부모에게 전달하기 위해 불필요한@delete="$emit('delete', $event)"보일러플레이트를 모든 재귀 호출마다 도배해야 합니다.6.3 엔터프라이즈 IoC/DI를 프론트엔드에 투영하다
엔터프라이즈 백엔드 아키텍처에서 IoC(제어의 역전)와 DI(의존성 주입)가 도입된 가장 큰 이유가 무엇이었습니까?
**"하위 계층의 컴포넌트가 상위의 서비스를 일일이 파라미터로 넘겨받지 않고, DI 컨테이너에 등록된 의존성을 필요할 때 직접 주입(Injection)받아 결합도를 끊어내는 것"**이었습니다.
Vue 3는 이 의존성 주입 메커니즘을 프레임워크 코어 레벨에서 완벽하게 지원합니다.
바로 **
provide와inject**입니다.provide: 최상위BoardApp.vue가 하위 트리 전체를 향해 댓글 비즈니스 서비스를 방송(제공)합니다.inject: 아무리 깊은 곳에 있는 대대댓글이라도 중간 단계의 관여 없이 상위 서비스를 다이렉트로 주입받아 호출합니다.6.4
InjectionKey<T>를 통한 100% 타입 안전한 DI 문자열 키(
provide('service', ...))를 쓰면 오타가 날 수 있으므로, TypeScript의InjectionKey<T>심볼을 사용합니다.[코드 6-2] DI 계약서 정의 (
src/types/comment-di.ts) [코드 6-3]
BoardApp.vue에서 서비스 Provide [코드 6-4] 깊은 자식
CommentItem.vue에서 다이렉트 Inject 6.5 무엇이 개선되었는가?
재귀적으로 수없이 호출되는 중간 컴포넌트들은 이제 부모와 자식 간의 이벤트 중계 책임을 완전히 벗어던지고, 오직 화면 렌더링에만 집중하게 되었습니다.
댓글의 삭제 및 등록 비즈니스 로직이
BoardApp.vue에 집중되어, 어느 깊이에서 삭제를 누르든 일관된 상태 갱신이 보장됩니다.6.6 다음 챕터로 이어지는 질문
이제
BoardApp.vue는 페이징, 검색, 폼 검증, 그리고 계층형 대댓글까지 갖춘 제법 훌륭한 애플리케이션이 되었습니다.하지만 소스 코드를 가만히 들여다보면, 아직도 치명적인 구멍이 남아있습니다:
PostDto클래스로 엄격한 데이터 타입을 정의하고 있는데, 우리 프론트엔드 코드 곳곳에는 여전히any나 느슨한 필드명이 섞여 있습니다.?)로 처리되어 있어 런타임 에러의 불씨가 살아있습니다.이어지는 Chapter 07에서는 Spring Boot DTO와 1:1로 맞물리는 **엄격한 TypeScript 도메인 계약(Contract)과 판별된 유니온(Discriminated Unions)**을
BoardApp.vue에 전면 적용해 보겠습니다.