Github Actions, Jib와 캐싱을 통해 CI 최적화하기 CI/CD 파이프라인에서 도커 이미지 빌드는 종종 전체 배포 시간의 상당 부분을 차지합니다. 빠른 피드백을 원하는 개발자들에게 이러한 상황은 별로 달갑지않죠. 특히 규모가 큰 프로젝트나 잦은 배포가 필요한 환경에서는 이 비용을 최소화하고 싶을 겁니다. 이번 포스팅에서는 기존 CI/CD 파이프라인을 최적화하는 과정에서, 구글의 Jib를 적용하며 겪었던 고민과 문제 해결 과정을 공유하려고 합니다.도커 빌드의 문제점과 Jib 소개기존 워크플로우의 한계와 고민점기존에 사용하던 GitHub Actions 워크플로우는 다음과 같은 절차로 구성되어 있었습니다.Gradle로 Java 애플리케이션 빌드Docker를 사용해 이미지 빌드Docker Hub에 이미지 푸시원격 서버에 배포이 과정에서 다음과 같은 고민들이 있었습.. Mockito 사용 중 @Spy로 실제 객체 동작 활용하기 배경소프트웨어 개발에서 리팩토링은 필수지만, 리팩토링으로 인해 기존 테스트 코드가 깨지는 경우가 많습니다. 최근 프로젝트를 리팩토링하다 비슷한 문제를 마주쳐서, 이번 시간에는 그 내용을 공유해보려 합니다.저희 팀은 ScheduleService 클래스에서 유효성 검증 로직을 분리하여 별도의 ScheduleCreateUpdateValidator 클래스로 추출하는 리팩토링을 진행했습니다. 이 과정에서 기존 테스트 코드가 실패하게 되었고, 해결 과정에서 Mockito의 @Spy를 사용하며 편리함을 깨달았습니다. 리팩토링 전후 코드 비교리팩토링 전 (ScheduleService 클래스 내부에 유효성 검증 로직 포함):@Service@RequiredArgsConstructorpublic class ScheduleS.. SQL에서 재귀 쿼리(CTE) 사용법 및 NOT IN vs NOT EXISTS 비교 최근 프로그래머스 SQL 고득점 Kit에서 4~5레벨 위주로 몇 문제를 풀고있습니다.https://school.programmers.co.kr/learn/courses/30/lessons/301651오늘 푼 문제 중 하나가 재귀 CTE를 이용하는 쿼리여서 이 참에 정리해보려고 합니다.데이터베이스에서 계층 구조와 같은 복잡한 데이터를 다룰 때 재귀 쿼리를 사용하면 도움이 될 수 있습니다. 이번 글에서는 SQL의 재귀 쿼리 활용법과 동작 원리, 그리고 NOT IN과 NOT EXISTS를 성능 측면에서 비교해 보겠습니다. 재귀 쿼리란?재귀 쿼리는 자기 자신을 참조하는 쿼리로, SQL에서는 CTE(Common Table Expression)를 사용하여 작성할 수 있습니다. 주로 다음과 같은 상황에서 유용하게 사.. JPQL은 쉽게 깨질 수 있다. 패키지 구조를 변경하며 패키지 구조를 개선하는 리팩토링 과정에서 JPQL로 작성된 부분들에 문제가 발생했습니다.바로, JPQL 쿼리에서 DTO 클래스 경로 참조가 깨지는 현상인데, 뭐 문자열이니까 어찌보면 당연한 결과기도 합니다. 짧게 설명해보겠습니다. 문제 상황계층형 패키지 구조에서 도메인 중심 패키지 구조로 전환하면서 아래와 같은 JPQL 쿼리가 동작하지 않았습니다:@Query("SELECT new com.appcenter.timepiece.dto.project.ProjectThumbnailResponse(p, c.thumbnailUrl) " + "FROM Project p " + "INNER JOIN MemberProject mp ON mp.projectId = p.id " + "LE.. JPA 연관관계 매핑을 끊고 식별자 참조 방식으로 전환하면서 배경기존 타임피스 프로젝트의 소스코드에는 JPA의 연관관계 매핑(@OneToMany, @ManyToOne 등)이 과도하게 사용되고 있었습니다. 이와 함께 외래키 제약조건도 활성화되어 있었죠. 다행히도 @ManyToMany는 사용하지 않고 있었지만, 개발이 진행될수록 두 가지 측면에서 문제가 발생했습니다1) 과도한 연관관계 매핑으로 인한 코드 결합도 증가와 2) FK 제약조건으로 인한 운영 제약입니다.프로젝트가 성장하면서 이러한 문제점들이 실제 운영 및 개발에 걸림돌이 되기 시작했고, 근본적인 해결책으로 식별자 참조 방식으로의 전환을 결정했습니다. JPA 연관관계 매핑과 FK 제약조건의 구분먼저, JPA의 연관관계 매핑과 데이터베이스의 FK 제약조건은 별개의 개념이라는 걸 짚고 넘어가겠습니다.JPA 연관관.. Spring Security를 포함한 테스트 작성하기 개요@WebMvcTest를 이용하면 웹 계층의 슬라이싱 테스트를 수행할 수 있습니다. 이는 웹 계층 요청과 관련된 필터, 인터셉터 등의 컨텍스트를 포함하여 테스트하게 된다는 의미입니다. 여기에는 당연히 Spring Security 필터 체인도 포함되는데, Spring Security 필터 체인이 DelegateFilterProxy로 동작한다는 것을 기억해야 합니다.Spring Security를 포함하여 WebMvcTest를 수행할 때는 몇 가지 주의해야 할 점들이 있습니다. 이 글에서는 디버깅 과정을 통해 이를 해결하는 방법을 알아보겠습니다.테스트 코드먼저 테스트할 클래스는 다음과 같습니다:@WebMvcTest(AuthController.class)public class AuthControllerTest.. WebMvcTest 도중 Jpa 메타모델과 관련한 오류를 마주한다면? 문제 상황: WebMvcTest에서 JPA 관련 오류 발생타임피스 프로젝트에 컨트롤러 테스트 코드를 추가하던 중 의외의 문제에 부딪혔습니다. @WebMvcTest를 사용했는데 JPA 메타모델과 JpaAuditing 관련 에러가 발생했습니다.@WebMvcTest는 웹 계층과 관련된 컨텍스트만 로드하는 것이 목적인데(필터, 컨버터, 인터셉터, 시큐리티 필터체인 등), 왜 JPA 관련 모듈 에러가 발생한 것일까요?원인 분석그 답은 Spring Boot 공식 문서에서 그 답을 찾을 수 있었습니다:If you use a test annotation to test a more specific slice of your application, you should avoid adding configuration sett.. Money 클래스 구현 시 마주친 두 가지 함정: BigDecimal equals와 정적 필드 초기화 순서 문제 상황 소개최근 내가 운영하고 있는 GDG 독서클럽에서 조영호님의 책 ‘오브젝트’를 읽고 함께 토론하고 있다.책에 삽입된 코드를 따라 작성하고 거기에 테스트 코드를 추가하는 형식으로 실습을 준비하고 있다.그러던 도중 예제에서 통화를 표현하기 위해 사용한 Money 클래스의 구현때문에 테스트가 통과하지 못하는 것을 발견했다. Money의 구현은 다음과 같다.public class Money { public static final Money ZERO = Money.wons(0); private final BigDecimal amount; public static Money wons(long amount) { return new Money(BigDecimal.valueOf(am.. Gradle 빌드 실패, NoClassDefFoundError 올해 초부터 GDG on Campus 활동의 일환으로 백엔드 북클럽을 운영하고 있다.북클럽 시즌2 활동으로 조영호님의 책 '오브젝트'를 읽어가며 예제코드를 작성하고, 테스트 코드를 추가하는 일을 하고있다. 프로젝트 생성 및 예제코드 작성 후테스트 코드 작성을 위해 AssertJ 의존성을 추가하고 Gradle build를 돌리자 다음과 같은 빨간 문장들을 만나뵙게 된다.ClassNotFoundException.. 왜 못 찾는걸까Gardle build를 위한 initializing 과정에서 gradle 라이브러리를 못 읽어온다는 것 같은데 어째선지는 힌트가 없다.로그 전문을 보아도 따로 더 이상의 힌트를 찾을수는 없다. (~/Library/Logs/Jetbrains/.../idea.log에서 찾을 수 있다... docker-compose로 Spark, Hadoop 클러스터를 띄우자. - 생성하지 않은 도커 볼륨이 생기는 이유 생성하지 않은 도커 볼륨이 생기는 이유위처럼 docker-compose.yml 파일에서 정의하지 않은 도커 볼륨이 생긴다.심지어 아래 항목을 로컬에서 먼저 만들어줘도 그렇다! hadoop-master-data: hadoop-slave1-data: hadoop-slave2-data:파일 수정 이후, 볼륨을 초기화하며 최초 상황에서부터 시작하기를 기대했는데, 아니나 다를까 네임노드가 초기화되지 않았다.의도대로라면 볼륨을 삭제하고 다시 연결하면 네임노드가 포맷되어야 한다!위의 문제와 연관지어 생각해보니, 현재 컨테이너에 연결되어 있는 볼륨이 hadoop-master-date가 아닌,spark-analysis_hadoop-master-data 임을 깨달았다.claude는 이렇게 말한다즉, 현재 docker.. Monitor와 ReentrantLock MonitorJava의 모든 객체는 하나의 락과 연결되어 있다. 메서드가 synchronized로 선언된 경우 메서드를 호출하려면 그 객체와 연결된 락을 획득해야 한다.다른 스레드가 이미 락을 소유한 경우 synchronized 메서드를 호출한 스레드는 봉쇄되어 객체의 락에 설정된 진입 집합(entry set)에 추가된다.진입 집합은 락이 가용해지기를 기다리는 스레드의 집합을 나타낸다락을 획득한 스레드가 (synchronized)메서드를 종료하면 락이 해제된다.락이 해제될 때 락에 대한 진입 집합이 비어있지 않으면 JVM은 이 집합에서 락 소유자가 될 스레드를 임의로 선택한다.JVM 명세에서 정의하지 않는다. == 구현따라 다르다.락 외에도 모든 객체는 스레드 지합으로 구성된 대기 집합과 연결된다.대기 .. Wait과 Notify, Spurious Wakeup Java 기준으로 설명https://www.baeldung.com/java-wait-notifyWait과 Notify자바에서 모든 객체는 모니터를 갖는다.그리고 스레드가 synchronized에 들어설 때, 해당 스레드가 객체의 **모니터**를 소유한다.주어진 객체에 대해 synchrnoized instance 메서드를 실행했을 때주어진 객체에서 synchrnoized block이 실행될 때synchronized static 메서드를 실행할 때 ✅synchrnoized (feat. claude)https://www.baeldung.com/cs/monitorsynchronized의 작동 방식모든 Java 객체는 고유한 모니터(monitor)를 가지고 있습니다. 이 모니터는 잠금 장치처럼 작동합니다.스레드가.. 이전 1 2 3 4 다음