개발 지식 공부

김동영·2022년 4월 29일
0

1. Throwable Suppressed

  • 예외 발생 후, 해당 예외를 캐치하여 처리하다 다른 예외가 발생하는 경우 이전 예외는 무시되고 마지막 예외만 표시된다.
  • 이를 해결하기 위해 이전 예외들을 Throwable 클래스 내 List<Throwable> 구조인 Suppressed 에 저장한 뒤, 이를 출력하여 발생한 모든 예외를 순서에 맞춰 보여주도록 설정할 수 있다.
    Suppressed Exception 참고 블로그

2. JUnit5

org.springframework.boot:spring-boot-starter-test 디펜던시에 
Mockito, AssertJ, Junit5 가 포함된다.  

2-1. Assertions.assertAll()

  • 메소드 내 여러 개의 assertion 을 사용하는 경우, 모든 assertion 을 실행시키도록 설정하는 기능
  • assertions 하위 클래스의 경우, assertion 하지 않은 케이스가 생기는 경우 메소드 내 남은 케이스는 동작하지 않고 종료된다.
  • 이를 해결하기 위해 assertAll(Functional Interface) 을 통해 실패여부와 상관없이 모든 assertion 을 실행시킬 수 있다.
    Assertion 메소드 참고 글

2-2. Mockito

  • Mock 객체를 쉽게 만들고 관리/검증할 수 있도록 도와주는 테스트 프레임워크

    1. 특정 클래스를 테스트할 경우, DI 가 없어서 의존 관계를 가지는 클래스를 직접 임포트하거나, @SpringBootTest 를 통해 의존관계를 주입해야 한다.

    2. 이 경우, 스프링부트 서버를 기동시키기 때문에 하나의 클래스를 테스트함에도 많은 시간이 소요된다.

    3. 또한 의존 관계를 가지는 클래스에 영향을 받기 때문에 목표 클래스를 온전히 테스트하기가 힘들다.

    4. 이를 해결하기 위해 의존 관계를 가지는 클래스를 원하는 동작만 하도록 만든 것이 Mock 객체이다.

      // given
      when(roomService.findRooms(owner.getId(), null)).thenReturn(rooms);
      
      // when
      var responseDto = roomController.findRooms(owner.getId(), null);
      
      // then
      Assertions.assertThat(responseDto.getResultCode()).isEqualTo("S001");
      Assertions.assertThat(responseDto.getResponse().size()).isEqualTo(3);

      Mockito 참고글

2-3. Mockito Vs BDDMockito

  • BDD 기준으로 테스트 코드를 작성할 때, 시나리오에 맞게 테스트 코드가 읽힐 수 있도록 도와주는 (이름을 변경한) 프레임워크이다.

  • 기존 Mockito 를 사용하는 경우와 달리 given 순서에 when 대신 given 코드가 사용된다.

    // given
    given(fcmV2Service.sendMessage(anyLong(), any())).willReturn(true);
    
    // when
    var apiResult = fcmController.sendMessage(userId, fcmSendMessageReqDto);
    
    // then
    assertThat(apiResult.getResultCode()).isEqualTo("S001");
    assertTrue(apiResult.getResponse());
  • BDD : 행위 주도 개발(Behavior-Driven Development) 로 테스트 대상의 상태 변화 를 테스트하는 것이 목표이다.

  • Given, When, Then 구조의 시나리오 기반 테스트를 권장한다.
    Mockito Vs BDDMockito 비교글
    TDD, BDD 참고글

3. JPA

3-1. N+1

  • 연관관계가 있는 데이터 조회 시, 연관관계 데이터 전체 조회 후 원하는 데이터를 한번 더 조회하는 현상
  • 연관관계 데이터(N) + 그 중 원하는 데이터(+1) 로 조회된다.
  • 이로 인해 연관관계가 많을 경우, N*N + 1 등 모든 데이터 경우의 수 + 1 만큼 쿼리 조회가 발생한다.
  • 발생 시점
    1) FetchType EAGER 로 즉시로딩하는 경우,
    2) FetchType LAZY 로 로딩 후, 연관관계 테이블 내 데이터를 조회하는 경우
  • 조회 시 시작 테이블만 조회 후, 하위 테이블을 다시 조회하는 구조이기 때문에 발생하는 문제
    JPQL 은 기본적으로 글로벌 Fetch 전략을 무시하고 JPQL로 SQL 을 생성하기 때문에 이러한 문제가 발생한다.
    N+1 문제 참고 블로그

4. Java

4-1. Arrays.sort()

4-2. 타입추론 var

  • Java 10 부터 도입된 타입추론 키워드
  • 컴파일러가 타입을 추론한다. (Kotlin 의 타입추론과 비슷함)
  • 컴파일 시 자료형이 같이 바이트 코드로 변환되기 때문에, 런타임 과정에서 추가 연산하지 않아 성능에 영향을 주지 않는다.
  • 컴파일러가 타입을 추론할 수 있어야 하기 때문에 아래와 같은 조건에서만 사용가능
    1) 지역 변수에만 사용가능
    2) 초기화 필요
    3) null 초기화 불가
    4) 배열에 사용 불가
    5) 람다식에 사용 불가
    참고 블로그
    OpenJdk var docs

4-3. Block method in java

1) 설명

2) SimpleDateFormat

3) StringBuffer vs StringBuilder

5. DB

5-1. Isolation Level 트랜잭션 격리수준

여러 트랜잭션이 처리될 때, 트랜잭션끼리 얼마나 고립되어있는지 나타내는 레벨
특정 트랜잭션이 다른 트랜잭션에 변경한 데이터를 볼 수 있도록 허용하는 정도를 나타낸다.

  • Read Uncommited
    • Commit 이나 Rollback 되지 않은 트랜잭션의 변경 내용을 다른 트랜잭션에서 참조할 수 있는 격리 수준
  • Read Commited
    • 트랜잭션 변경 내용이 Commit 되어야만 다른 트랜잭션에서 조회할 수 있는 격리수준
    • Oracle 의 기본 설정
  • Repeatable read
    • 트랜잭션이 시작되기 전 커밋된 내용에 대해서만 조회할 수 있는 격리수준
    • MySQL 의 기본 설정
  • Serializable
    • 트랜잭션이 변경하는 레코드를 공유 잠금하여 Commit/Rollback 전까지 다른 트랜잭션에서 접근하지 못하도록 하는 격리 수준
    • InnoDB 기준 SELECT 의 경우 잠금 없이 조회되지만, 해당 격리 수준을 적용하면 SELECT 작업 시에도 공유 잠금되어 성능 저하가 발생된다.
  • 격리 수준에 따른 문제
     1) Dirty read
         트랜잭션 내 다른 트랜잭션의 변경 내용을 Commit 전 읽은 뒤, Rollback 후 다시 읽었을 때 다른 결과가 나오는 현상
      2) Non repeatable read
         트랜잭션 내 같은 쿼리 두 번 실행 시, 대상 레코드를 다른 트랜잭션에서 수정/삭제하는 경우 동일 쿼리임에도 결과가 다르게 나타나는 비 일관성이 발생하는 현상
      3) Phantom read
         트랜잭션 내 같은 쿼리 두번 실행 시, 첫 번째에 검색되지 않던 레코드가 두 번째 쿼리 실행 시 나타나는 현상
         다른 트랜잭션에서 Insert 하는 경우에만 발생한다.
    격리 수준DIRTY READNON-REPEATABLE READPHANTOM READ
    READ UNCOMMITTEDOOO
    READ COMMITTED-OO
    REPEATABLE READ--O(InnoDB는 발생 X)
    SERIALIZABLE---
    참고) InnoDB 기준 트랜잭션은 시퀀셜한 트랜잭션 번호를 가지고 있다.
          undo 영역에 백업된 모든 레코드는 변경을 발생시킨 트랜잭션의 번호가 포함되어 있다.
          PostgreSQL 에서는 READ UNCOMMITTED 레벨을 지원하지 않는다.
    트랜잭션 격리수준 블로그 참고 글
    트랜잭션 격리수준 참고 블로그2-상세한 설명

5-2. MariaDB Maxscale Readwritesplit

1. 라우팅 기준

1) master

  • write statements
  • transaction 내 모든 statements
  • stored procedure calls
  • user-defined function calls
  • DDL statements(DROP, CREATE, ALTER TABLE)
  • EXECUTE (prepared) statements that modify the database
  • all statements using temporary tables

2) slave

  • read-only database queries
  • read-only queries to system, or user-defined variables
  • SHOW statements
  • system function calls

출처) MariaDB Maxscale ReadWritesSplit docs

6. Spring Boot

6-1. io.spring.dependency-management

  • Spring Boot Gradle Plugin 중 스프링 부트의 의존성들을 관리해주는 플러그인

  • 프로젝트에 적용된 Spring Boot 버전에 맞춰 의존성을 자동으로 관리해준다.

    plugins {
        id 'org.springframework.boot' version '2.6.5'
        id 'java'
    }
    
    apply plugin: 'io.spring.dependency-management'
    ...
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    참고) Spring boot gradle plugin 은 Gradle 4.4 이상부터 지원된다.

6-2. Default Logger

6-3. Default Transaction 처리방식 -> CGLib

7. SRE(Site Reliability Engineering)

7-1. 설명

  • 소프트웨어를 툴로 활용하여 시스템 관리 및 애플리케이션 모니터링 등 IT 인프라 작업을 자동화하는 관행
  • 소프트웨어, 자동화를 사용해 문제를 해결하고 운영 애플리케이션을 관리한다.
  • 예) 인하우스 시스템 관리자
    예) 백오피스 시스템, 운영이관절차 수립 등 원활한 개발을 보조
    • 백오피스 시스템 관리 => 이슈 대응을 위한 시스템 자동화, 녹스 결재 연동을 통한 결재 자동화, 시스템을 활용하여 머니 지급/회원 탈회 등 구현
    • 배포 자동화 => CI/CD 도입
  • 운영 및 개발 작업 간 균형을 유지하는 것이 SRE의 핵심이다.

7-2. DevOps 와 차이

  • DevOps는 개발 파이프라인을 효율적으로 거치는데 중점을 둔다.
  • SRE는 새로운 기능 개발과 사이트 신뢰성 간 균형을 맞추는데 중점을 둔다.

99. 기타 임시 저장

  1. 인덱스 페이지 활용
    • 인덱스에서 시작할 경우 도메인 기준 상대경로로 이동가능하기 때문에 프론트에서 관리가 비교적 용이하다.

8. Java8 vs 11 차이

  1. GC 차이
  1. 컨테이너 최적화 차이
  • docker 는 cgroup 으로 리소스를 제한함
  • Java SE 8u131 , JDK 9 이전버전의 경우 아래와 같은 이슈로 OOM(OutOfMemory) 가 발생할 수 있다.
    1) Host OS 8G 에서 도커 컨테이너 4G 로 구동
    2) -Xmx 설정 없이 구동할 경우 JVM 에서 Host OS 기준 8G 를 최대 힙메모리로 설정
    3) 힙메모리 포함 컨테이너 메모리가 4G 이상이 될 경우 OOM 발생
    JDK 버전에 따른 Docker Container Memory 이슈 관련 블로그
profile
프레임워크와 함께하는 백엔드 개발자입니다.

0개의 댓글