본문 바로가기

개발관련/TIL

내배캠 12주 3일 차

 오늘의 키워드는 캐시와 DDD와 테스트 코드이다. 그럼 각각 왜 나왔는지에 대해 간단히 적어보겠다. 캐시와 DDD는 각각 튜터님이 학생들 대상으로 진행한 튜터링(강의) 시간에 나왔던 내용이다. 그리고 테스트 코드는 오늘 service 테스트 코드를 작성하다가 단일로 테스트를 돌릴 때는 괜찮은데 여러 개를 한 번에 실행하면 안 되기에 했기 때문에 포함했다. 이번에 작성해 볼 것은 테스트 코드와 캐시에 대해서 간단하게 적어 볼까 한다.

 


 캐시는 영어로 Cache라고 하고 뜻은 고속 기억 장치(네이버 사전)라고 한다. 그럼 캐시를 왜 사용할까? 자주 사용되는 데이터가 있다면 매번 db 또는 저장소에 가서 데이터를 찾아서 가져오고 사용자한테 보여주는 것은 은근히 시간이 걸린다. 그럼 자주 사용되는 데이터를 다른 저장소에 저장하고 필요한 데이터만 저장소에서 찾아서 반환하면 빠르게 데이터 처리를 할 수 있지 않을까? 그래서 이때 사용되는 것이 캐시가 된다. 

 

 캐시는 기본적으로 캐시에서 데이터가 있으면 바로 반환하는 Cache Hit와 데이터가 없을 시 db에서 데이터를 반환하는 Cache Miss가 있다. 뭐 쉽게 말해서 우선적으로 캐시를 확인 후 캐시에서 바로 반환하면 hit db에서 반환하면 miss가 되는 것 같다.

 

 캐시 전략 패턴 5가지가 있는데 어려운 개념은 아니라 그냥 사용하다 보면 쉽게 알 수 있을 거라 생각한다. 읽기 전략과 쓰기 전략 2가지로 나눠서 봐보자  읽기 전략에선 Look Aside와 Read Through 2가지가 있다. 쓰기 전략에선  Write Around와 Write back, Write Through 3가지가 있다.

 

 Look Aside는 캐시에 데이터가 없을 시 db에서 조회하는 것이다. 장점은 캐시에 문제가 있을 경우 db에 요청할 수 있다. 단점은 캐시와 db 간의 직접적인 연결이 없어 정합성 유지가 어렵다. 첫 조회 시 db에 부하가 걸릴 수 있다.

 

 Read Through는 항상 캐시를 통해서 데이터를 읽는 방법이다. 장점은 캐시와 db간의 데이터 정합성을 보장한다. 단점은 캐시가 죽으면 아무것도 못 한다.

 

 Write Around는 캐시를 이용하지 않고 db에 직접 쓴다. 장점 성능이 좋고 빠르다. 단점 캐시와 db의 데이터 정합성이 어렵다.

 

 Write Back은 캐시에 데이터를 모아뒀다가 한번에 db에 쓰기 작업을 한다. 장점은 쓰기 횟수 비용을 줄일 수 있다. 단점은 캐시에서 데이터 유실 문제가 발생할 수 있다.

 

 Write Through는 무조건 캐시를 거쳐서 db에 저장하는 것이다. 장점은 데이터 정합성이 보장된다. 단점은 두 번의 쓰기가 항상 진행되기 때문에 성능을 고려해야 한다.

 


 문제가 테스트 코드는 아래처럼 작성했다. UpdateCategoryName 함수의  흐름은 db에 있는 값을 변경할 때 이미 존재하는 값이라면 변경할 수 없게하는 로직이다. 이 함수를 실행하기 위해서 db에 값을 넣고 1번 값을 2번이랑 같게 변경 시 문제가 발생하는 것을 확인하는 테스트이다.

@Test
fun `카테고리 수정 시 이미 있는 카테고리명 예외 발생`() {
    // Given
    categoryRepository.saveAllAndFlush(listOf((Category(name = "호러")),Category(name = "로맨스")))
    val request = CategoryUpdateRequest(name = "로맨스")

    // When & Then
    shouldThrow<RuntimeException> { categoryService.updateCategoryName(1,request) }
        .let {
            it.message shouldBe "Category name already exists"
        }
}

 

 

 여기서 문제는 updateCategoryName()함수에서 1 부분이 문제였다. 왜인지 확인해 보니 db에 저장돼 있는 id가 1번인걸 찾는데 이 함수만 개별적으로 실행하면 문제가 없지만 여러 테스트를 동시에 실행할 때 다른 테스트에서 db를 이용하면 1번 id가 존재하지 않게 된다는 것이었다. 왜 db에 있는 값이 사라지는지 이유를 찾아보진 못 했지만 이유는 저럴 거라고 추론이 가능했다. 따라서 아래와 같이 코드를 변경하니 개별로 테스트할 때와 전체 테스트 할 때 문제가 없이 잘 실행 됐다.

@Test
fun `카테고리 수정 시 이미 있는 카테고리명 예외 발생`() {
    // Given
    val categories =  categoryRepository.saveAllAndFlush(listOf((Category(name = "호러")),Category(name = "로맨스")))
    val request = CategoryUpdateRequest(name = "로맨스")

    // When & Then
    shouldThrow<RuntimeException> { categoryService.updateCategoryName(categories[0].id!!,request) }
        .let {
            it.message shouldBe "Category name already exists"
        }
}

'개발관련 > TIL' 카테고리의 다른 글

내배캠 12주 5일 차  (0) 2024.07.05
내배캠 12주 4일 차  (0) 2024.07.04
내배캠 12주 2일 차  (0) 2024.07.02
내배캠 11주 5일 차  (0) 2024.06.29
내배캠 11주 4일 차  (0) 2024.06.27