모든 글

'마이'는 왜 도메인이 아닌가

마이페이지는 클라이언트가 보는 화면이지 비즈니스 도메인이 아닙니다. 주문, 상품, 쿠폰은 원래 주인에게 두고 경계에서 조합합니다.

출처 및 AI 안내: 이 글은 제미니의 개발실무 유튜브를 기반으로 작성되었습니다. gpt-5.6-sol 모델을 사용해 생성·편집했습니다.

/my/orders/me/products 같은 경로는 로그인한 사용자가 보고 싶은 것을 편리하게 표현합니다. 문제는 이 편리한 단어가 프레젠테이션 경계를 넘어 독립된 도메인이 될 때 시작됩니다.

My를 비즈니스 개념으로 취급하면 서로 다른 기능이 그 아래로 모이기 시작합니다. 주문, 상품, 좋아요, 리뷰, 쿠폰이 my 패키지로 들어갑니다. MyController에는 메서드가 계속 늘어나고, MyService는 화면을 조립하는 데 필요한 모든 서비스에 의존합니다. 시스템이 실제로 다루는 개념이 아니라 메뉴 이름을 따라 코드가 구성되는 것입니다.

구분해야 할 지점은 단순합니다. ‘마이’는 API 계약에서 유용할 수 있지만 구현의 소유권까지 가질 필요는 없습니다.

엔드포인트와 도메인을 구분합니다

API 경로는 프레젠테이션 계층에 속합니다. 클라이언트가 데이터를 요청하는 계약의 일부입니다. /my/orders가 클라이언트에게 명확하다면 My가 도메인 개념이 아니라는 이유만으로 이 경로를 거부할 필요는 없습니다.

그러나 애플리케이션 안에서 ‘나의 주문’은 여전히 주문입니다. 현재 사용자의 식별 정보와 권한에 따라 반환할 주문이 정해지기 때문에 ‘나의 것’이 됩니다. ‘나의’는 요청의 관점을 설명할 뿐, 새로운 종류의 주문을 만들지 않습니다.

사용자가 좋아요를 누른 상품, 작성한 리뷰, 받은 쿠폰도 마찬가지입니다. 사용자 맥락은 이 개념들을 필터링하거나 연결합니다. 그렇다고 원래 의미가 사라지거나 모두 하나의 My 모델에 속하게 되는 것은 아닙니다.

그래서 요청이 내부로 들어갈 때 my라는 수식어는 사실상 사라져도 됩니다. 구현은 사용자, 주문, 상품, 리뷰, 쿠폰을 다룹니다. 프레젠테이션 계층은 그 결과를 합쳐 클라이언트가 보는 ‘마이’ 화면을 만들 수 있습니다.

모든 것을 빨아들이는 패키지를 경계합니다

잘못된 구조는 기능이 늘어날 때 드러납니다. 마이페이지가 개인 정보와 주문 목록으로 시작합니다. 이후 상품 활동, 좋아요, 리뷰, 쿠폰과 다른 개인화 조회가 추가됩니다. 화면 이름이 구조를 결정하면 새 기능이 생길 때마다 같은 컨트롤러, 서비스, 패키지에 들어가게 됩니다.

이 구조에는 유용한 멈춤 기준이 없습니다. 커머스 시스템의 행위는 대부분 어떤 방식으로든 사용자와 관련됩니다. 그 관계만 기계적으로 따르면 거의 모든 기능이 my 아래로 들어가거나, 거의 모든 API 앞에 users가 붙을 수 있습니다. 어느 쪽도 행위의 진짜 주인이 누구인지 설명하지 못합니다.

의존 관계도 실제 의미와 어긋납니다. 하나의 화면에 결과를 함께 보여준다는 이유만으로 거대한 MyService가 주문, 상품, 리뷰, 쿠폰 서비스를 모두 가져올 수 있습니다. 프레젠테이션 요구가 중심 도메인 서비스처럼 보이는 구조를 만들지만, 실제 개념들은 여전히 서로 다른 이유로 변경됩니다.

MyController라는 이름의 클래스가 무조건 잘못됐다는 뜻은 아닙니다. 컨트롤러 경계와 엔드포인트 경로는 프레젠테이션 계층에서 선택할 수 있습니다. 같은 이름이 비즈니스 로직까지 구성하고 실제 개념을 원래 영역에서 끌어내기 시작하는지가 경고 신호입니다.

‘마이’를 소유권이 아니라 조합으로 봅니다

마이페이지는 여러 결과를 합치는 역할을 할 때가 많습니다. 사용자 맥락으로 관련 주문, 상품, 리뷰, 쿠폰을 조회한 뒤 하나의 화면으로 표현합니다. 필요한 행위이지만, 결과를 합치는 것과 합쳐지는 모든 개념을 소유하는 것은 다릅니다.

다음처럼 흐름을 나누면 이 구분이 분명해집니다.

현재 사용자 + 주문 조회 ----+
현재 사용자 + 리뷰 조회 ----+--> 마이페이지 응답
현재 사용자 + 쿠폰 조회 ----+

주문은 주문 영역에 남고, 리뷰는 리뷰로 남으며, 쿠폰도 자신의 의미를 유지합니다. 응답을 책임지는 경계에서 이 결과들을 병합할 수 있지만, 각 영역의 규칙과 데이터는 원래 개념이 계속 소유합니다.

이렇게 보면 화면이 전체 모델을 조용히 다시 정의하는 일도 막을 수 있습니다. 주문 규칙이 바뀌면 주문을 보여주는 페이지가 아니라 주문 영역에서 변경해야 합니다. 마이페이지의 구성이 달라져 쿠폰을 더는 보여주지 않더라도 쿠폰 개념까지 함께 옮겨 갈 이유는 없습니다.

로그인한 사용자는 맥락으로 사용합니다

‘나의 주문’을 더 정확히 풀면 현재 사용자와 연결된 주문을 로그인 및 권한 맥락에 따라 반환한다는 뜻입니다. 이 설명은 구현에서 다룰 구체적인 대상을 줍니다. 독립된 My 개념은 그렇지 못합니다.

간단한 확인 방법은 ‘나의’라는 말을 빼고 무엇이 남는지 묻는 것입니다. 주문, 상품, 리뷰, 쿠폰, 사용자가 그대로 남는다면 보존해야 할 개념은 이들입니다. 프레젠테이션 계층에서는 /my/me를 포함해 클라이언트의 언어를 자유롭게 사용할 수 있습니다. 다만 그 편리한 관점이 내부 모델을 모두 흡수하는 그릇이 되게 해서는 안 됩니다.