From c95898504c964220bfd12089f19cf06017888543 Mon Sep 17 00:00:00 2001 From: Sumin Hwang <163857590+tnals0924@users.noreply.github.com> Date: Mon, 19 Oct 2026 18:59:53 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=EC=A1=B0=ED=9A=8C=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20readOnly=20=ED=8A=B8=EB=9E=9C=EC=9E=AD=EC=85=98=20?= =?UTF-8?q?=EC=BB=A8=EB=B2=A4=EC=85=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/conventions/coding-style.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/conventions/coding-style.md b/docs/conventions/coding-style.md index 6278a2e7..5afd0e6b 100644 --- a/docs/conventions/coding-style.md +++ b/docs/conventions/coding-style.md @@ -281,7 +281,7 @@ Map countAppliedByEventIds(List eventIds); - `{Domain}Service`는 공개 인터페이스(`service`), `{Domain}ServiceImpl`는 구현체(`service.impl`). `service.impl` 안의 클래스는 구현체·협력 객체 모두 **package-private**으로 선언한다(package-private `@Service`도 빈 등록됨). ArchUnit(`DomainImplAccessTests`)이 public 클래스와 외부 참조를 잡는다. - **`{Domain}ServiceImpl`가 `{Domain}Repository`를 직접 참조**한다. - 비즈니스 규칙 검증은 `{Domain}ServiceImpl`(또는 `service.impl` 협력 객체)에서 하고 `BusinessException`을 던진다. -- 트랜잭션 경계는 Service 메서드에. 조회 전용은 `@Transactional(readOnly = true)`, 교차 도메인 UseCase가 감쌀 수 있게 **기본 전파(REQUIRED)** 를 쓴다(`architecture.md` 6-1절). +- 트랜잭션 경계는 쓰기 Service 메서드에. 교차 도메인 UseCase가 감쌀 수 있게 **기본 전파(REQUIRED)** 를 쓴다(`architecture.md` 6-1절). 조회 메서드에는 `@Transactional(readOnly = true)`를 붙이지 않는다(트랜잭션 설정 SQL만 늘어난다). ```java // core:domain:member — domain/member/service (공개) @@ -311,7 +311,6 @@ class MemberServiceImpl implements MemberService { } @Override - @Transactional(readOnly = true) public Member getById(Long id) { return memberRepository.findById(id) .orElseThrow(() -> new BusinessException(MemberErrorCode.MEMBER_NOT_FOUND)); @@ -369,7 +368,7 @@ public class AppMemberController implements AppMemberApi { - **서로 다른 도메인의 `{Domain}Service` 2개 이상**을 조합할 때만 만든다. `api:{client}-api`에 두고 공개 `{Domain}Service`만 조합한다. - **`{도메인}` 아래 `usecase` 하위 패키지에 둔다**(`{basePackage}.api.{client}.{팀}.{도메인}.usecase`, `request`/`response`와 동일 계층, `architecture.md` 2-2절). 컨트롤러는 `{도메인}` 패키지 바로 아래 있으므로 UseCase와 계층이 분리된다. -- 트랜잭션은 원자성이 필요한 흐름에만. 조회 조합은 걸지 않거나 `readOnly`, 원자적 쓰기에만 `@Transactional`(`architecture.md` 6-1절). +- 트랜잭션은 원자성이 필요한 흐름에만. 조회 조합에는 걸지 않고, 원자적 쓰기에만 `@Transactional`(`architecture.md` 6-1절). ```java // api:admin-api — 조회 조합 (운영진 대시보드) @@ -381,7 +380,6 @@ public class AdminDashboardUseCase { private final EventService eventService; private final NoticeService noticeService; - @Transactional(readOnly = true) public AdminDashboardResponse getDashboard() { long memberCount = memberService.countActive(); List upcoming = eventService.findUpcoming();