본문 바로가기

트러블슈팅과 고민/고민15

DI, IoC, AOP에 관한 고민 책이나 인터넷 강의에서는 DI, IoC, AOP에 대해서 잘 알려주지만 많이 들어도 역시나 모호한 면이 있다.그것은 직접 코드가 물리적으로 돌아가는 것을 보지 못해서인것같다.그동안 고민도 많이하고 자바로 스프링도 조금씩 만들고 있는데 내 나름대로의 결론이다. 아직까지 부족한 면이 있을것이다. DI 1. IoC를 구현하는 방법중하나2. 프록시빈을 주입할 수 있어 AOP를 가능하게한다.3. 개발자가 하나하나 팩토리를 작성할 필요 없음4. 외부에서의 구현체 주입으로 구현체 변경에도 수정이 일어나지 않아 결합도 하락 (구현체가 여러개일때 프라이머리) IoC1. 객체의 생성, 생명주기, 메소드의 실행 흐름등을 외부로 위임2. 객체를 생성하지 않아 결합도 하락 (new 연산자의 외부 이동) (DI가 없으면 구현체 .. 2026. 3. 15.
실시간 인기글의 캐시 갱신시 빈 페이지 반환에 대한 개선 (스케줄러, 캐시어사이드 동시 사용) 캐시전략은 백그라운드 갱신, 라이트 어라운드, 캐시 무효화이다.실시간은 더해서 캐시 어사이드도 사용한다.게시글 수정과 삭제시 캐시를 삭제한다.캐시 무효화를 쓴 이유는 수정이 되었을 때 글 내용이 달라지는 것은 비즈니스에 타격을 준다고 생각했기 때문이다. 백그라운드 갱신을 한 이유는 빈페이지 반환을 막기 위해서다. 조회시마다 캐시 갱신을 하면 대용량 트래픽의 디비 접근을 막기 위해서 빈페이지를 반환할 수 밖에 없다. 핫 키를 계산하여 미리 갱신할 수 있지만 어쨌거나 핫 하지 않은 키는 빈페이지를 받는다. 키가 많으면 레디스의 보호를 위해 락이 있어도 핫 키를 계산해야하지만 키가 몇개 없어서 핫 키계산은 현재 사용안한다. 실시간 인기글의 스케줄러 갱신의 어려움하지만 실시간인기글은 이 방법을 사용할 수 없다.. 2026. 1. 27.
소셜 로그인/회원가입 반환 프로토콜 재설계 문제 발견시작은 단순했다. “기존 회원과 신규 회원의 로그인 반환값을 어떻게 구분할까?”당시 구조에서는 MemberDetail이라는 DTO가 모든 책임을 떠안고 있었다. 로그인 과정에서 Member 도메인이 MemberDetail을 생성해 Auth 도메인으로 넘기고, Auth는 그 DTO를 기반으로 JWT와 쿠키를 발급했다.하지만 곧 두 가지 문제가 눈에 들어왔다.첫째, 기존 회원과 신규 회원의 흐름이 모두 하나의 DTO에 묶여 있어 분기 로직이 어색했다. 기존 회원의 경우 실제 Member 엔티티가 필요한데, DTO로 변환되는 순간 더티 체킹이나 추가 갱신이 불가능했다. 반대로 신규 회원은 DTO만 넘겨둔 채 Redis에 임시 저장을 맡기다 보니 “회원가입을 완료하지 않은 사용자”의 상태를 추적하기가 .. 2025. 10. 3.
헥사고날 아키텍처에서 신고(Report) 엔티티의 도메인 위치 딜레마 1. 상황 비밀로그(BimilLog) 프로젝트를 헥사고날 아키텍처로 설계하면서 신고 기능을 구현하게 되었다. 현재 시스템은 7개의 주요 도메인(admin, auth, comment, notification, paper, post, user, common)으로 구성되어 있으며, 각 도메인은 명확한 책임과 경계를 가지고 있다. 신고 기능의 요구사항은 다음과 같았다: - 글 신고: 부적절한 게시글 신고 - 댓글 신고: 부적절한 댓글 신고 - 건의사항: 사용자가 시스템에 대한 건의사항 제출 - 신고 관리: 관리자가 신고 내역을 조회하고 처리 자연스럽게 각 기능은 관련 도메인에 배치되었다: - 신고 하기→ user 도메인의 in 어댑터 (UserCommandController) - 신고 조회 →.. 2025. 9. 5.
DTO와 의존성, 계층의 분리에 대한 고민 모놀리식아키텍처는 컨트롤러 비즈니스 레포지터리의 계층을 나누고 계층간의 이동은 DTO로 변환해서 관리한다.이것은 엔티티는 영속성에 종속되어있고 이것을 계층간에 전달하게 되면 강한결합을 유발하기 때문이다. 순수한 비즈니스로직을 영속성에 오염시킬 수 있고 보안 문제의 예방도 있다. 종합하자면 단일원칙책임을 준수하기위해서 DTO를 활용한다고 볼 수 있다.하지만 헥사고날아키텍처에서는 외부세계 (어댑터)밖으로 나가기 직전에 DTO로 변환시키고 그 이전엔 엔티티를 활용한다.이것은 도메인 모델과 영속성 분리의 완벽한 분리를 추구하기 때문이다. 엔티티는 JPA나 외부기술의 영향을 받지않는 가장 순수한 계층이다. 헥사고날에서의 DTO는 도메인과 외부 세계를 연결하는 계약의 역할을 한다.이때! 엔티티는 가장 순수하다고 했.. 2025. 8. 15.
모놀리식 -> 헥사고날 전환 도메인 경계 문제 해결 문제발생비밀로그 프로젝트를 헥사고날 아키텍처로 정리하는 과정에서 가장 먼저 눈에 들어온 문제는 도메인 경계의 침범이었다. 회원가입과 로그인 흐름을 담당하는 auth 도메인의 AuthDataAdapter가 알림 도메인의 구현체인 FcmTokenRepository와 FcmToken 엔티티를 직접 사용하고 있었고, 이로 인해 FCM 토큰의 저장과 삭제까지 auth가 떠맡고 있었다. 더 나아가 포트 설계도 이 결합을 부추겼다. ManageAuthDataPort가 본래 인증 데이터만 다뤄야 함에도 String fcmToken을 파라미터로 받으며 책임이 섞여 있었다. 심지어 JWT에도 fcmTokenId를 클레임으로 넣고, JwtFilter에서 이를 꺼내 재발급에 사용하면서 인증과 알림이 구조적으로 강결합된 상태였.. 2025. 8. 12.
아키텍처 관점에서 Repository 계층의 접근 범위에 대한 고민 (2025년 6월 15일) 2025년 6월 15일의 고민 노션에서 옮겨오고 있습니다. 고민 최근 데이터엑세스 코드를 수정하면서 레포지토리 계층에서 DTO나 인터페이스에 접근하는 것이 아키텍처에 어긋나는지 고민에 빠졌다. 일반적으론 Repository에서 바로 비즈니스 로직을 거치지않고 바로 DTO에 접근하는 것은 맞지 않다고 느껴진다. 하지만 그건 JPA의 관점이 아닌가? 마이바티스는 일반적으로 바로 DTO에 접근하는데? JPA의 더티체킹에 익숙해져서 서비스 -> 엔티티 -> 레포지토리 구조에 빠져버린건가? 특히 QueryDSL의 프로젝션 기능을 사용하면 복잡한 조회 쿼리도 깔끔하게 DTO로 매핑할 수 있는데, 이런 경우에도 아키텍처 원칙 때문에 포기해야 하나 하는 고민이 들었다. 같은 애플리케이션에서 기술에 따라 다른 패턴을 사.. 2025. 8. 7.
알림 읽음 처리에 대한 고민 (2025년 4월 29일) 2025년 4월 29일의 고민 노션에서 옮겨오고 있습니다 고민 알림을 읽을 때 마다 DB에서 update 쿼리를 요청하면 불 필요한 부하가 생긴다.불 필요한 부하라기엔 필요한 로직일 수도 있지만 알림을 읽는다는 역할의 중요성을 생각해 보았을 때 차후에 만약 사용자가 많아진다면 대안을 생각하는 것이 필요한 부분이라고 생각한다.당장은 사용자가 적어 문제가 되지 않지만 만약 사용자가 많아진다면? 스케일 아웃이나 스케일 업은 피할 수 없는 선택지가 되겠지만 그 선택을 하기전까진 대안과 최적화로 할 수 있는만큼은 기존 서버만으로 트래픽을 받고 싶다. 해결알림 읽음과 삭제 상태를 프론트의 로컬 스토리지에서 관리하고 5분마다 서버로 전송하여 DB에 반영하는 방식을 선택했다.그리고 사용자가 5분도 이용하지 않고 떠났을.. 2025. 8. 7.
추가적인 보안 관련 고민 (2025년 4월 26일) 2025년 4월 26일의 고민 노션에서 옮겨오고 있습니다. 고민1차 테스트 서버에서 모의 해킹결과 GET요청에 민감 데이터를 넣어서 프론트에서 민감데이터 처리를 하는 바람에 서버로 직접 요청해서 응답을 탈취하는 경우가 있었음. HTTPONLY쿠키 SAMESITE STRICT SECURE 설정 다 했기 때문에 CSRF나 쿠키탈취 가능성은 적음 그리고 서버 시큐리티에서 권한 검사 함 다만 서버에 직접 요청이 가능한 점 프론트를 통해서만 서버에 접근 가능하는 것도 생각해보았지만 ELB에서는 루트를 분기하는 기능만 있고 서버에 접근해도 신원검사와 보안을 해놓았기 때문에 신원을 검사하지 않는 GET요청의 민감 데이터를 내려주지 않으면 될 듯 함해결 민감데이터 처리는 프론트에서 하지말고 서버에서 해야함 그리고 서버.. 2025. 8. 7.
실시간 알림 시스템 기술 선택 관한 고민 (2025년 4월 13일) 2025년 4월 13일의 고민 노션에서 옮겨오고 있습니다. 고민 비밀로그는 젊은 층을 저격한 SNS의 특성상 유행이 빠르게 일어나고 빠르게 사라질 특성을 가진 서비스유행 탄 초반에는 순간적으로 대량의 알림이 일어날 수 있음 롤링페이퍼에 메시지가 달릴때 알림이 발생 친구가 메시지 보낼 때 친구의 친구가 메시지를 보낼 수도 있기 때문에 동시성이 보장되어야 함. 알림은 최대 30개까지 저장되며 개인이 삭제하지 않는 이상 다시 읽을 수 있어야 함. 모바일 유저는 백그라운드에서 알림을 받을 수 있어야 함. 목표:1. 1분에 500개의 알림을 처리할 수 있는 성능2. 동시성 보장3. 실시간성 보장4. 유실 방지5. 모바일 유저만을 위한 전용 알림 기능과정 제외 기술폴링, 롱 폴링 : 계속 Get요청을 보내는 것이 .. 2025. 8. 7.
단일책임원칙에 대한 고민 단일책임원칙은 '클래스는 변경이 일어나야하는 이유가 하나여야 한다'고 말한다. 단일책임원칙을 적용하면 유지보수성이 증가하고 테스트도 쉬워지고 후에 CQRS를 적용할때도 용이하다다만 비밀로그의 퍼블릭 메서드는 최소 100개 이상이다 150~200개 까지 될 수도 있다. 그럼 클래스도 100개 이상 생긴다그런데 모조리 단일책임원칙을 적용하는게 맞을까?어느정도 분리하는건 좋지만 모조리 적용하면 클래스가 너무 많아질 것 같다.클래스란.. 속성과 동작을 정의하며 객체를 생성하기 위한 틀이다. 자바 공식문서에서는 '클래스를 특정 종류의 객체를 구현하는 데 필요한 타입을 정의한다'라고 설명하고있다특정 객체.. 하나의 성격.. 그 성격에 맞는 타입들클래스의 관점에서봐도 단일책임 원칙이 맞아보인다 하지만 현실적으로 클래.. 2025. 8. 6.
DB를 거치지 않은 JWT을 통한 사용자 식별에 관해 (2025년 4월 7일) 2025년 4월 7일의 고민 노션에서 옮겨오고 있습니다. 고민 만약 토큰에 식별자만 넣으면 JWT필터에서 인증객체를 만들기 위해 DB를 조회해야하지 않나?프론트에서는 페이지마다 /userinfo API로 서버에 유저정보를 요청할것이고 서버는 응답으로 유저정보를 반환한다. 그리고 필터는 모든 API요청마다 작동한다.그럼 모든 요청마다 DB를 조회해야하나? 그럼 토큰을 사용하는 의미가 없다.시큐리티컨텍스트홀더를 활용해서 최초한번만 DB를 조회하게하는 방법은 없나?해결 1. 우선 필터에서 DB를 조회하면 안된다. 필터는 서버를 들어오는 요청을 사전에 확인하는 거름망으로 Tomcat 서버의 필터레벨에 스프링 시큐리티의 필터체인이 삽입된다. 스프링의 필터체인에는 JWT필터도 있고 아직 웹 서버에 도착하지 않은 상.. 2025. 8. 3.