개발(0)/회사 기록

[20240517~20240528]

까만밀가루 2024. 5. 28. 20:15

하나의 Service를 마무리하고.

작년 이 맘 때 개발했던 코드를 올해 보니 , 코드가 단순 무식한 거 같아 성능, 가독성, 유지보수 등을 고려하였을 때 변경 할 필요가 있다고 생각하였다. 아래는 내가 기간 동안 간단하지만, 제대로 확인하지 못해 에러를 받은 것들과 나의 코드를 변경할 때 내가 왜 그렇게 변경하였는지 적은 기록이다.


 

 

application.yml

  1. DB 아이디/비밀번호 확인
  2. DB 설정 확인 → Tibero인데 MariaDB로 되어 있음, 번외로 dev, local, prod 확인

 

Tibero

  1. NUMBER 단위 → 자바 코드 단에서 int 변환 코드 필요
BigDecimal pageCntDecimal = (BigDecimal) dataMap.get("PAGE_CNT");
int pageCnt = (totCntDecimal != null) ? pageCntDecimal.intValue() : 0;

 

 

selectKey

: 국비 프로젝트 때 썼던 selectKey인데, 두 개의 테이블에 한 번에 insert시 동일한 Key값을 넣어야하는 경우 이용

이때 가져온 값을 params.get("Seq"); 로 바로 값을 가져와 다음 넣어야 하는 테이블에 넣을 수 있다.

<selectKey keyProperty="Seq" resultType="int" order="BEFORE">
  SELECT SEQ.NEXTVAL FROM DUAL
</selectKey>

 

 

@Transactional 처리

: 처리가 되기 위해선 catch절에서 throw e; 처리를 해야한다. 이때 예외를 별도 커스텀을 하거나 일반적인 예외를 사용해도 된다. 두 테이블에 연결되어 insert하기 때문에 제대로 insert 안되었을 경우 롤백 처리를 위함이었으나, 많은 data를 insert시 단일 건, 혹은 다 건에 대해 에러가 생긴다면 DB 자체에 fail 기록을 남겨야 하기 때문에 따로 @Transactional 처리가 필요하지 않는다고 판단하였다.

  catch절에서 fail로 insert 처리

 

 

Junit 테스트

@SpringBootTest 통합테스트
Spring 컨텍스트를 로드하여 실제 빈 주입을 받아 테스트한다.
여러번 상호작용 & DB  통신 중 통합테스트이기 때문에 최종적으로 테스트 할 때 사용

[내가 사용한 테스트]
→ 빈 주입에만 의존하여, 빈 주입 후 단순 쿼리 메서드 확인 
다음 개발이 완료되었을 때 통합 테스트로 이용해보자.
Mockito 단위테스트
외부리소스에 의존하지 않는다.
격리된 테스트이기 때문에 빠른 테스트가 가능하며, 개발 초기에 하는 테스트

[내가 사용한 테스트]
→ 메서드가 값을 설정하였을 때 맞게 호출 되었는가

 

 

 

전체적인 Service 코드

: 기존에 만든 Service를 전체적으로 변경하였다.

자바코드를 순서대로 나열한 대신, 가독성/유지보수에 집중하고 Math의 메서드를 이용하여 단순화 할 수 있는 것은 단순화 처리하였다. 또한, 각각 상태코드를 update 처리 할 때 중복되는 코드는 하나의 메서드로 빼서 한 줄로  쓸 수 있도록 변경하였다.

 

1.ExecutorService의 사용

기존 : while문 안에서 생성 한 후 for 문 안에서 쓰레드 이용 후 닫고 재생성

변경 : while문 전에 고정된 수의 ExecutorService 생성 후 for문 쓰레드 이용 완료 후 shutdown() 처리

각 반복마다 새로운 ExecutorService 생성 장점
  • 각 반복이 독립적이어서 특정 반복에서 발생한 오류나 지연이 다른 반복에 영향을 미치지 않음
  • 관리가 용이하고 각 반복이 명확히 구분
단점
  • 스레드 풀을 반복적으로 생성하고 소멸시키는 것은 많은 오버헤드를 초래
  • 스레드 생성과 소멸에 따른 성능 저하가 발생 가능성
  • 메모리 사용량이 증가 가능성
하나의 ExecutorService 사용 장점
  • 스레드 풀을 한 번만 생성하고 재사용하므로 자원 사용이 효율적
  • 스레드 생성과 소멸에 따른 오버헤드가 없음
  • 성능이 향상되고, 메모리 사용이 최적화
 단점
  • 모든 작업이 동일한 스레드 풀에서 실행되므로, 특정 작업이 지연되거나 실패할 경우 전체 실행에 영향을 미칠 수 있음
  • 스레드 풀의 크기를 적절히 설정하지 않으면 과도한 작업이 쌓여 성능이 저하

 

→나의 현재 프로젝트는 1번 ~ 10,000번의 호출이 필요하다.

고정된 스레드를 생성하여 과도한 스레드 생성의 메모리 사용을 줄이고, 성능저하나 오버헤드를 고려하였을 때 하나의  ExecutorService  사용이 적합하다고 판단하여 변경

 

2. Callable과 Runnable 사용

: 두 인터페이스의 큰 차이점은 Callable은 응답값을 받을 경우, Runnable은 응답값이 없이 간단한 작업 때 쓰인다.

나의 프로젝트의 경우 단순 call 후 그 값을 DB에 update만 하면 되기 때문에 Runnable이 적합하다고 생각하여 변경

 

3. Runnable 사용 시 고려사항

: Runnable은 Spring이 관리하지 않기 때문에(컨테이너 밖 생성) @Component가 적합하지 않는다.

때문에 의존성 주입 중 생성자 주입을 이용해야 한다.

사용하는 Runnable이 외부 클래스가 되어 있었지만, 다른 클래스와 공유하지 않고 독립적으로 하나의 Service내에서만 사용되기 때문에 내부 클래스로 변경하였다.

 

4.의존성 주입

:생각없이 Spring에서 의존성 주입할 때 @Autowired를 이용한거같다.

이 필드 주입은 간편하지만 이것만 사용하다보니 다른데서 안될 때 머릿속이 멈추는 거 같다.

실제로 Runnable에서 생각없이 @Component후 @Autowired가 안되어서 하루종일 인텔리제이 자동완성으로 이것저것 해본 거 같다. 

이번 기회 의존성 주입에 대해 다시 공부해보면서 특히 생성자 주입은 불변성 유지와 테스트 용이성에 의해 자주 사용한다고하니 자주 쓰도록 해야겠다.