Topic
백엔드 엔지니어링
유지보수 가능한 백엔드 시스템을 위한 애플리케이션 서비스, 프레임워크와 구현 패턴을 다룹니다.
순환 참조를 고치기 전에 도메인 경계부터 바로잡기
인터페이스나 의존성 역전으로 순환 참조처럼 보이는 문제를 다루기 전에 모호한 소유권과 개념 경계를 먼저 정리한다.
널인가 0인가: 코틀린 JPA 엔티티 ID 전략
코틀린 JPA 엔티티의 숫자 ID를 nullable 또는 0으로 둘 때 신규 판별, 모호성, 검증 방법을 비교한다.
한 프로젝트 안에서 실행 역할별 배포 경계 만들기
공개 API, 어드민, 배치, 운영 작업을 실행 앱으로 분리하되 코드가 충분히 성숙하기 전부터 별도 프로젝트로 쪼개지 않는 방법을 설명합니다.
Reader, Finder, Searcher를 행위로 구분하는 법
Reader, Finder, Searcher를 조회 건수가 아니라 직접 읽기, 추가 필터링, 복합 검색이라는 행위로 구분하는 기준을 설명한다.
'마이' 도메인 없이 마이페이지 데이터를 조합하는 법
사용자, 주문, 상품의 책임은 각 도메인에 유지하면서 전용 조합 계층으로 마이페이지 요약 데이터를 만드는 방법을 설명합니다.
'마이'는 왜 도메인이 아닌가
마이페이지는 클라이언트가 보는 화면이지 비즈니스 도메인이 아닙니다. 주문, 상품, 쿠폰은 원래 주인에게 두고 경계에서 조합합니다.
UI 모양을 넘어서는 도메인 모델 설계
트리 모양의 API가 트리 모양의 도메인을 요구하지는 않습니다. 클라이언트 계약은 프레젠테이션 경계에 두고 내부 개념을 조합해 응답합니다.
첫 테스트는 서툴러도 된다, 나중에 리팩터링하라
지키고 싶은 행위를 검증하는 테스트부터 만들고, 실행에 필요한 만큼 목을 쓰며, 반복과 리뷰를 통해 테스트 설계를 개선하는 방법입니다.
API 요청 모델을 핵심 도메인에서 분리하라
프레젠테이션 경계에서 외부 요청을 비즈니스가 소유한 값으로 바꿔 API는 안쪽을 의존하고 코어는 바깥을 모르도록 만드는 방법입니다.
외래키는 규칙이 아니라 운영상의 선택이다
무결성 요구, 장애 대응, 배포 절차, 운영 DB의 주체를 기준으로 외래키와 인덱스, ORM 연관관계를 각각 선택하는 방법입니다.
도메인 간 행위는 책임의 주인에게 맡겨라
호출자 쪽 인터페이스를 모듈 사이에 두기 전에 행위의 주인을 정하고, 호출자가 그 도메인의 기능을 의존하게 만드는 기준을 설명합니다.
열거형의 주인은 누구인가: 도메인 모듈 의존성 설계
비즈니스 열거형은 도메인이 소유하고 스토리지는 안쪽을 의존하게 하며, 경계가 익는 동안에만 작은 공유 열거형 모듈을 두는 방법입니다.
플랫폼 API에서 제공자 식별과 인증 경계를 나누는 법
작은 플랫폼 API가 제공자 키를 도메인 식별자로 바꾸고 데이터를 구분하며, 규모에 맞는 인증 경계를 선택하는 과정을 다룹니다.
도메인 모델을 먼저 보는 보수적인 JPA 연관관계 설계
ID에서 시작하고 생명주기가 실제로 맞을 때만 연관관계를 추가하며, 비즈니스 개념은 엔티티와 독립적으로 표현하는 방법을 다룹니다.
실제 트래픽이 없어도 대용량 시스템 대응은 연습할 수 있습니다
작은 서비스를 직접 운영하고 의도적으로 부하를 만들어 병목을 찾고 고친 과정을 보여주세요. 다만 부하 테스트를 운영 경험이라고 과장해서는 안 됩니다.
공유 테스트 DB 없이 신뢰할 수 있는 데이터베이스 테스트 만들기
잡아야 할 실패에 따라 목, 인메모리 DB, Testcontainers, 실제 DB를 고르고 일반 테스트는 공유 인프라에서 격리합니다.
계층마다 DTO를 습관처럼 만들지 마세요
데이터가 서로 다른 계약을 가진 경계를 넘을 때 DTO를 사용합니다. 매핑에도 비용이 들지만 외부 요청 형태가 서비스 내부를 지배하게 두는 데도 비용이 듭니다.
서킷브레이커는 실패하는 I/O 가까이에 두세요
서킷브레이커, 타임아웃, 캐시 폴백 같은 외부 호출 정책은 I/O 구현체 가까이에 두고, 도메인 코드는 그 결과가 비즈니스에서 무엇을 뜻하는지 결정합니다.
타임아웃은 클라이언트 설정이 아니라 제품의 결정입니다
모든 실패에 같은 재시도 규칙을 붙이지 말고, 사용자가 기다릴 수 있는 시간과 실패 뒤에 알 수 있는 사실을 기준으로 타임아웃과 복구 정책을 설계합니다.
도메인이 성숙하기 전에 모듈부터 나누지 마세요
도메인 성숙도는 정책과 행동, 운영 현실을 얼마나 이해했는지에서 나옵니다. 추측을 일찍 굳히지 말고 운영에서 드러난 책임으로 모듈 경계를 정해야 합니다.
의존성 격차가 프로젝트가 되기 전에 버전 올리기
우선순위에 따라 의존성을 자주 올리면 변경을 작게 유지하고 호환성 문제를 일찍 발견하며 운영 서비스에 부채가 조용히 쌓이는 일을 막을 수 있습니다.
AI 에이전트가 같은 도구를 두 번 호출한다면
분산 시스템과 AI 워크플로에서 재시도는 정상입니다. DB 제약, 멱등 키, 제한된 재시도로 도구 호출의 중복 부작용을 막는 방법을 정리합니다.
그래들 의존성 범위로 아키텍처 경계 세우기
Gradle의 implementation, api, runtimeOnly, compileOnly를 의도적으로 사용해 모듈 접근을 제한하고 우발적인 결합을 막는 방법을 설명합니다.
어드민을 서비스 도메인에서 격리하기
어드민 API는 조회, 수정, 릴리스 위험이 다릅니다. 운영 편의가 핵심 서비스를 바꾸지 않도록 모듈이나 저장소로 격리합니다.
리더와 라이터 컴포넌트로 비즈니스 흐름 드러내기
리더와 라이터는 저장소 세부사항과 변경 범위를 감추고 비즈니스 계층에 정책을 남깁니다. 다만 서비스 수명이 그 비용을 정당화해야 합니다.
분산 서비스 끝까지 하나의 트레이스 아이디 전달하기
민감한 정보를 노출하거나 저장소를 로그로 넘치게 하지 않으면서 HTTP 호출과 비동기 이벤트를 하나의 요청 맥락으로 추적합니다.
유즈케이스 아래 계층에서 코드를 재사용하기
유즈케이스끼리 재사용하면 비즈니스 변경이 번지고 순환 참조가 생깁니다. 위에서 조합하거나 아래의 구현 컴포넌트를 추출합니다.
거대한 서비스 클래스를 책임과 계층으로 분리하는 법
생성자 의존성과 import로 비대해진 서비스를 진단하고, 새로운 아키텍처 이름을 붙이기 전에 응집된 책임부터 분리합니다.
요구사항과 객체 관계로 정규화와 반정규화를 선택하기
정규화 수준을 점수처럼 높이기보다 값의 변경 의미, 조회 비용, 데이터가 보존해야 할 객체 관계를 기준으로 테이블을 설계합니다.