전체 글

호기심 가득한 밤을 하나씩 밝히는 밝은별입니다.
백엔드/Spring

레이어간 의존 관계 문제

아래 사진은 레이어드 아키텍처다 의존하는 방향을 주목해보자. 항상 상위 레이어가 하위 레이어를 의존하는 형태를 가져간다.근데 인프라 레이어의 코드가 도메인에도 있고 애플리케이션 레이어에도 존재한다면 어떻게 될까?DB를 바꿔야 하는 상황에 닥쳤다고 생각해보자.운영상 RDBMS에서 NoSQL로 바꿔야한다는 니즈가 생겨버렸다.그럼 인프라의 변경으로 인해 도메인 레이어의 코드도 수정해야하고, 애플리케이션 레이어의 코드도 수정을 해야한다.수정만이 문제가 아니다. 이전과 동일하게 동작하는지 테스트 코드도 수정해야하고 엄청나게 많은 리소스를 쏟아 부어야한다. 바꿀 수가 없을 정도의 리소스와 리스크를 안고 가야할 수도 있다.그럼 누군가가 이렇게 말할 수도 있다."DB를 바꿔야 하는 건 소프트웨어 설계부터 잘못된거 아니..

백엔드/Java

[Java] Collection API 개선

컬렉션 팩토리 Java 9에서는 작은 컬렉션 객체를 쉽게 만들 수 있는 몇 가지 방법을 제공한다. List friends = new ArrayList(); friends.add("Raphael"); friends.add("Olivia"); friends.add("Thibaut"); 세 문자열을 저장하는데도 많은 코드가 필요하다 Arrays.asList() 메서드를 이용하면 코드를 간단하게 줄일 수 있다. List friends = Arrays.asList("Rapheal", "Olivia", "Thibaut"); 고정 크기의 리스트를 만들었으므로 요소를 갱신할 순 있지만 새 요소를 추가하거나 요소를 삭제할 순 없다. List friends = Arrays.asList("Raphael", "Olivia")..

백엔드/Java

[Java] 병렬 스트림 (parallel stream)

병렬 스트림이란? 병렬 스트림이란 각각의 스레드에서 처리할 수 있도록 스트림 요소를 여러 청크로 분할한 스트림이다. 따라서 병렬 스트림을 이용하면 모든 멀티코어 프로세서가 각각의 청크를 처리하도록 할당할 수 있다. 예를 들어, 숫자 n을 인수로 받아서 1부터 n까지의 모든 숫자의 합계를 반환하는 메서드를 구현한다했을 때, public long sequentialSum(long n) { return Stream.iterate(1L, i -> i + 1) // 무한 자연수 스티림 생성 .limit(n) // n개 이하로 제한 .reduce(0L, Long::sum); // 모든 숫자를 더하는 스트림 리듀싱 연산 } 위와 같은 코드에 n이 커진다면 이 연산을 병렬로 처리하는 것이 좋을 것이다. 병렬 스트림을 ..

프로젝트/Petogram

[Petogram] Oauth Login refactoring 여행기 - 2

들어가며 이전에 Oauth 로그인을 전략 패턴을 활용해서 로직을 분리했다. (https://brightstarit.tistory.com/58) 결과적으로 공통 로직과 provider별 다른 로직을 분리해 낼 수 있었고, 추가적으로 내가 제어할 수 없는 로직을 분리했다. 이제 테스트를 진행하려는데 맞닥들인 문제가 있었다. Mockmvc 테스트를 진행하면서 내가 제어할 수 없는 부분은 어떻게 처리해야 할까? Map으로 동적으로 사용할 빈을 결정하는 경우 Stub을 어떻게 해야 할까? 이 두 문제를 해결함으로써 좀 더 테스트를 진행할 때 문제에 더 유연하게 대처가 가능해질 것 같다. 내가 제어할 수 없는 코드 테스트 다음은 우리 서비스의 /api/login을 호출했을 때의 코드이다. @Override publ..

프로젝트/Petogram

[Petogram] Oauth Login refactoring 여행기 - 1

들어가며 이전에 Qhoto에서 구현했던 Oauth2.0을 구현하면서 아쉬웠던 점이 있었다. Qhoto에서는 모든 로직을 GoogleLoginService, KakaoLoginService 함수 안에 중복된 로직이 존재했고 다른 Provider를 추가한다면 계속해서 중복된 로직을 작성해야 된다는 단점이 있었다. 사실 Oauth2.0을 구현하다 보면 Google, Kakao, Naver 등과 같은 Provider의 인증과정이 비슷하다는 것을 알 수 있다. 그리고 인증에 성공했을 때, 처리해야 하는 과정은 모든 Provider가 일치한다. 그럼 모든 공통된 로직과 Provider의 구현 전략들을 분리해 낼 수 있겠다는 결론에 도달했다. 디자인 패턴 중 어떤 디자인을 패턴을 적용해야 할까? 생각이 난 것은 템플..

백엔드/데이터베이스

[데이터베이스] Redis 캐시(Cache) 설계 전략

Redis 캐시 전략 이전 Redis의 글에서 레디스의 캐시 활용에 대해서 알아봤는데, 이번에는 캐시 배치 전략 종류에 대해서 더 상세히 알아보고, redis에서 캐쉬를 다룰 때 어떤 점을 유의해서 설계해야 되는지 적절한 캐싱 전략 선택 지침 이론을 정리해 본다. 캐시는 일반적으로 메모리(RAM)를 사용하기 때문에 데이터베이스 보다 훨씬 빠르게 데이터를 응답할 수 있어 이용자에게 빠르게 서비스를 제공할 수 있다. 하지만 기본적으로 RAM의 용량은 커봐야 16~32GB 정도라, 데이터를 모두 캐시에 저장해 버리면 용량 부족 현상이 일어나 시스템이 다운될 수 있다. 따라서 어느 종류의 데이터를 캐시에 저장할지, 얼마큼 데이터를 캐시에 저장할지, 얼마동안 오래된 데이터를 캐시에서 제거하는지에 대한 '지침 전략..

백엔드/데이터베이스

[데이터베이스] 레디스(Redis)

Redis(Remote Dictionary Server)란? Redis는 Remote(원격)에 위치하고 프로세스로 존재하는 In-Memory 기반의 Dictionary(key-value) 구조 데이터 관리 Server 시스템이다. Redis는 mysql 같은 관계형 데이터가 아닌 비 관계형 구조로서 데이터를 그저 '키-값' 형태로 단순하게 저장한다. 그래서 관계형 데이터베이스와 같이 쿼리 연산을 지원하지 않지만, 대신 데이터의 고속 읽기와 쓰기에 최적화되어 있다. 그래서 Redis는 일종의 NoSQL로 분류되기도 한다. 또한 Redis는 인 메모리(In-Mememory) 솔루션으로도 분류되기도 하는데, 다양한 데이터 구조체를 지원함으로써 DB, Cache, Message Queue, Shared Memo..

백엔드/JPA

[JPA] 즉시 로딩과 지연 로딩

객체는 객체 그래프로 연관된 객체들을 탐색한다. 그런데 객체가 데이터베이스에 저장되어 있으므로 연관된 객체를 마음껏 탐색하기는 어렵다. JPA 구현체들은 이 문제를 해결하려고 프록시라는 기술을 사용한다. 프록시를 사용하면 연관된 객체를 처음부터 데이터베이스에서 조회하는 것이 아니라, 실제 사용하는 시점에 데이터베이스에서 조회할 수 있다. 하지만 자주 함께 사용하는 객체들은 조인을 사용해서 함께 조회하는 것이 효과적이다. JPA는 즉시 로딩과 지연 로딩이라는 방법으로 둘을 모두 지원한다. 즉시 로딩과 지연 로딩 프록시 객체는 주로 연관된 엔티티를 지연 로딩할 때 사용한다. JPA는 개발자가 연관된 엔티티의 조회 시점을 선택할 수 있도록 다음 두 가지 방법을 제공한다. 즉시 로딩(EAGER LOADING) ..

밝은별 개발자
밝은별 개발 블로그