개발 12

테스트 코드 작성중 데이터 삭제 방식 결정: delete VS truncate

상황펀딩 생성 테스트 코드 작성 중 메서드별 데이터의 독립적인 환경을 보장하기 위해 삭제 로직을 추가했습니다.삭제 방식은 @Sql을 통해 쿼리문을 직접 실행시키는 방법을 선택했습니다.삭제 해야할 데이터는 funding, anniversary_category, consumer, product_option, product 테이블에 있는 정보들 입니다.테이블별 1~2개 정도의 레코드를 삭제해야하고, 현재 외래키 제약 조건이 테이블간 걸려 있습니다. 고민쿼리문 작성 과정에서 delete를 사용할지 truncate를 사용할지 고민했습니다.delete 장점1. 외래키 제약 조건을 풀고, 다시 잠그는 과정이 필요하지 않음.delete 단점1. 삭제시 로그를 남기고, 하나의 데이터씩 삭제하기 때문에 한번에 전체를 삭제..

개발 2025.02.10

헥사고날 아키텍처 적용: 서비스와 도메인의 독립성 확보

헥사고날 아키텍처 도입데이터베이스 변경 리펙토링 과정에서 두가지 문제점을 발견했습니다.DB 엔티티와 도메인 로직의 결합서비스 로직과 데이터베이스 강결합두 문제점을 통해 DDD와 Clean Architecture의 필요성을 느꼈습니다.이를 구현하기 위해 헥사고날 아키텍처를 도입하기로 결정했습니다.레이어드 아키텍처 → 헥사고날 아키텍처기존 패키지 구조- controller- service- entity- repository- dto  헥사고날 아키텍처 적용 범위헥사고날 아키텍처의 핵심은 포트와 어댑터를 통해 각 계층별 의존성을 줄여 변경이나 확장에 유리하도록 하는 것 입니다.따라서 아래와 같은 구조로 설계할 계획을 세웠습니다.패키지 구조- controller - controller.java - dto ..

개발 2025.01.27

친구 목록 동기화 시 기존 데이터를 업데이트하지 않고 새로운 데이터로 저장되는 문제

문제 상황 친구 목록 동기화 과정에서, 이미 존재하는 친구 데이터를 업데이트하고 새 데이터는 추가로 저장해야 한다. 하지만 기존 친구 데이터가 업데이트되지 않고, 새로운 데이터로 중복 저장되는 문제가 발생. 원인 분석 JPA에서 엔티티를 업데이트하려면, 해당 엔티티가 영속성 컨텍스트에서 관리되어야 한다. 문제 지점: FriendEntity로 변환하는 과정에서 id가 누락되어, JPA는 이를 새로운 엔티티로 간주하고 저장. 결론: id 필드가 없는 경우, JPA는 해당 엔티티를 식별할 수 없어 영속성을 판단하지 못하고, 기존 데이터를 업데이트하지 못함. 문제 코드  동기화 로직 // 친구 목록 동기화 로직중 일부friendRepository .findByConsumerIdAndToConsume..

개발 2025.01.17

DDD(Domain-Driven Design)와 Clean Architecture의 원칙을 반영한 이유

이번에 데이터베이스를 변경하면서 DDD와 Clean Architecture의 필요성을 느꼈습니다. 참고: 데이터베이스를 변경한 이유는 아래 포스팅에 있습니다. https://kdozlo.tistory.com/74  친구 정보, Redis에서 MySQL로 옮긴 이유상황현재 사용자의 친구 정보들을 "카카오톡 친구 API"를 통해 받은 뒤, redis에 저장해 놓고 있었다.하지만 "자신의 친구들 중 친한 친구를 표시할 수 있다."라는 기능을 제공하고 있고, 이 정보 또kdozlo.tistory.com 기존 방식의 문제점 1. DB 엔티티와 도메인 로직의 결합 기존 방식에서는 DB 엔티티(Friend)에 도메인 로직(예: toggleFavorite)을 포함하여 구현했습니다. 이로 인해 데이터베이스와 도메인 로직..

개발 2025.01.10

친구 정보, Redis에서 MySQL로 옮긴 이유

친구 정보, Redis에서 MySQL로 옮긴 이유상황현재 사용자의 친구 정보들을 "카카오톡 친구 API"를 통해 받은 뒤, redis에 저장해 놓고 있었다.하지만 "자신의 친구들 중 친한 친구를 표시할 수 있다."라는 기능을 제공하고 있고, 이 정보 또한 redis에 함께 저장하고 있다.문제점1. 인메모리 구조인 redis에서 정보가 사라질 경우, 친구 목록은 "카카오톡 친구 API"를 통해 다시 받으면 되지만, 친한 친구 정보는 복구할 수 있는 방법이 쉽지 않다. 또한 우리 서비스에서 제공하는 기능에 대한 정보를 인메모리 구조인 레디스에서 관리하는 것이 자연스럽지 않다고 판단했다. 2. 친구들의 펀딩 게시글 조회 기능을 구현 할 때 redis를 통해 친구 목록을 받은 후, 이 정보를 바탕으로 mySQL..

개발 2025.01.10

permitAll()로 요청한 api들이 JwtFilter를 거쳐서 가는 문제

문제 상황 S3에 이미지 업로드 테스트 과정에서 해당 요청 api는 생각해보니 현재 jwt 필터를 거치지 않아도 될 api들이 모두 jwt 필터를 거치고 있었다. 권한 확인만 하지 않고 지나갔을 뿐. 문제 원인 이유는 간단하다. permitAll()로 했기 때문이다. permitAll()은 시큐리티 필터를 무시하는게 아니고 그냥 지나쳐 가라는 뜻이였다. 이 경우 시큐리티 필터 자체를 지나가지 않도록 ignore로 처리하면 된다. 하지만 BUT 그러면 spring security 자체를 쓰지 않게 되서 문제가 된다. 해결 방안 따라서 Jwt 필터를 만난경우 필터 로직을 거지치 않도록 Jwt 필터 class에 shouldNotFilter 메서드를 작성해주면 된다.  @Value("${WHITE_LIST..

개발 2024.04.29

예외 처리시 원하는 예외 응답값이 안오는 경우

문제 상황 스프링부트 3.2.5, openjdk 21 s3 이미지 업로드 api 요청 시 컨트롤러에서 해당 요청을 받아서 S3Util의 업로드 메서드를 실행시키는 과정으로 진행된다. 또한 그 과정에서 spring security를 통해 JwtAuthenticationFilter와 JwtExceptionFilter를 만든 상황이고, 현재 s3 이미지 업로드 api는 permitAll()로 되어 있다. S3에 이미지 객체를 업로드 할때, 버킷명을 잘못 적었을 때의 예외처리를 구현했습니다. 해당 예외시 _INTERNAL_SERVER_ERROR_를 발생시켰는데, _INVALID_TOKEN_가 발생했다. S3Util upoad 코드 @Slf4j@Component@RequiredArgsConstructorpubli..

개발 2024.04.29

@ColumnDefault 동작 안함(사실 동작함. 단지 적용이 안됐을 뿐.)

문제 상황 요청 DTO를 받고 이를 통해 객체를 생성하여 save하는 과정에서 @ColumnDefault로 지정한 필드에 값이 들어가지 않는 상황이 발생했다. (요청 DTO에서는 @ColumnDefault로 지정한 필드가 없다) DB에 넣고자 하는 객체 에러 로그 문제 원인 필드가 @Column(nullable = false)으로 지정되어 있고, @ColumnDefault는 사용하지 않도록 테이블을 생성한 상태에서, ddl-auto: update 를 하고 필드에 새로 @ColumnDefault를 해주어도 실제 테이블에는 반영이 되지 않았다. 이로 인해서 @DynamicInsert 를 하여 null인 필드는 insert문에 포함하지 않도록 했고, 이는 해당 필드에 아무런 값도 지정하지 않아서 “dosen’..

개발 2024.04.15

코틀린을 사용한 스프링 프로젝트에서 자바를 사용 할 때 자바 파일을 못 찾는 오류

문제 상황 코틀린을 이용한 스프링 프로젝트에서 BalanceController 를 자바로 작성 했을때, postman으로 api 테스트 시 해당 컨트롤러 내의 url를 찾지 못했다. 오류  @RestController @RequestMapping("/account") public class BalanceController { private final Database db; public BalanceController(Database db) { this.db = db; } @GetMapping("{id}/balance") public Account balance(@PathVariable long id) { return..

개발 2024.02.24

스프링부트 프로젝트를 도커를 이용하여 배포해 보자!

도커란 어플리케이션을 패키징 할 수 있는 툴 컨테이너에 어플리케이션, 시스템 툴, 환경 설정, dependancy들을 하나로 묶어 어디에서나 쉽게 배포하고 안정적인 구동을 할 수 있도록 도와줌 Docker Object Image Docker Container를 만들기 위한 읽기 전용 템플릿 이미지는 몇 가지의 추가적인 사용자 정의와 함께 다른 이미지를 기반으로 한다. 타인이 만들어서 레지스트리에 게시한 이미지를 사용하거나, 직접 이미지를 만들 수 있다. 이미지를 빌드하기 위해서는 Dockerfile를 이용하여 이미지를 만들고 실행하는데 필요한 단계를 정의해야 한다. Dockerfile 이미지에 레이어를 만든다. Dockerfile 변경하고 이미지를 재빌드하면 변경된 레이어만 다시 빌드된다. 이는 다른 가..

개발 2023.12.29