..
주니어 개발자가 개발할 때 더 개선할 여지는 없는 지 고민해보세요
2025.04.17 - [쉬운코드]주니어 개발자가 개발할 때 더 개선할 여지는 없는 지 고민 해보자
예제 1. 1부터 N 까지의 정수 합(Sum)을 구하는 함수를 작성
public static int intSum(int n){
int sum = 0;
while (n >= 1) {
sum += n --;
}
return sum;
}
// 성능 훨 좋다.
public static int intSum3(int n){
return n * (n + 1) / 2;
}
System.out.println(intSum(1_000_000));
System.out.println(intSum(1_000_000));
1784293664
-363189984
// long type 으로 바꿔보자
public static int intSum4(int n){
if (n % 2 == 0) {
return (n / 2) * (n + 1);
}else {
return n * ((n + 1) / 2);
}
}
System.out.println(intSum(1_000_000));
System.out.println(intSum(1_000_000));
1784293664
1784293664
예제 2. 배치작업
상황
- 어떤 기기가 1분 마다 스캔한 데이터를 DB에 저장하고 있는 상황
- 해당 기기가 100대가 있음
- 배치 작업 : 검수를 위해 하루 한번 100대가 하루 동안 스캔한 데이터를 각각의 압축 파일로 만들어서 3rd party API 를 통해 업로드
생각 1. 🤔
- 최초에 배치는 싱글 스레드로 구현 : 총 7시간 정도 소요
- 이걸 스레드 10개로 증가 : 총 3시간 정도로 시간 단축
- 하지만 더 개선할 여지는 없을까??
생각 2. 🤔
왜 스레드 개수를 열개 로 잡았는가 ?? 일단 한번 트라이??
- 하나의 태스크를 조금 더 구체적으로 분석해보자
- 기기 한 대가 하루 동안 스캔한 데이터를 압축
- 압축 파일을 검수 API에 업로드
1번의 경우 CPU bound, 소요 시간은 약 4분 2번의 경우 I/O bound, 소요 시간 약 1분
I/O bound 일 때는 스레드가 적당히 많으면 오히려 병렬성에 좋음 CPU bound 일 때는 스레드가 많으면 ?? 서버 core 수!
- CPU bound → 소요시간 약 4분
- CPU Bound 일 때는 스레드가 많으면?
- 서버 Core 수
- 배치서버는 2core
- 압축하는 동안에 다른 거 할 수 없다.
- CPU Bound 일 때는 스레드가 많으면?
- IO Bound → 소요시간 약 1분
- IO 바운드일 때는 스레드가 적당히 많으면 오히려 병렬성에 좋다.
- 왜 스레드 개수를 열개로 잡았는가???? → 음.. 열개가 최선의 선택은 아닐 수 있다! 더 나은 스레드 개수가 있을 수 있음!, 다섯개로 조정해볼까?
- 최적의 스레드 수를 찾는 게 베스트일까? 오버 엔지니어링 아닐까??
- 기기 100개 이지만, 더 늘어날 수도 있고
- 센싱하는 데이터가 1분마다가 아니라 더 늘어날 수도 있고? …
- 음.. 그러면 앞으로 스레드 수 찾는 게 가변 적일 건데 이게 오버엔지니어링 아닐까?
- 관점의 재점검!! : 스레드 수 조정 외에 다른 접근 은 없을까?(내가 스레드에만 몰입 한 것이 아닐까?)
- scale up! core 수 증가!
- scale out! 더 많은 서버 사용!!
- 이게 최선일까? 현재 서버 스펙에서 더 개선할 여지는 없을까?
- 기기 한대가 하루 동안 스캔한 데이터를 압축 : CPU bound, 약 4분 소요
- 압축 파일을 검수 API 에 업로드 : I/O bound, 약 1분소요
⇒ 기기 100대에 대해서 1번 작업부터 먼저 다하고 이어서 2번 작업을 한번에 하면 어떨까?
- 1번 작업할 때는 2~3개 스레드
-
2번 작업 때 비동기 호출(WebClient, etc…)
- 이게 최선일 까? 더 개선할 여지는 없을까? (추가로 고려해볼 만한 내용)
- 검수 API에 부하를 주진 않을까? (동시에 몇개의 파일을 업로드 할 지 고려)
- DB에서 데이터를 읽어올 때 하루치 스캔 데이터를 한번에 다 읽어보면 서버 메모리는 괜찮을까?
- 1기가 DB에 있다고 가정 → 1기가 전부를 배치 어플에 올려둔다? → 이건 메모리에 부담이다.
- 그러면 한번에 읽지 말고, 스트림 방식으로 가져와서 파일을 떨구는 건 어떨까?
- 스트림 방식으로 압축 파일 생성 방법 검색
- etc) 압축알고리즘은 또 어떤게 있지? (검수 API 쪽에서 허용되는 압축포맷도 확인해봐야하는 부분이고…)
- 1기가 DB에 있다고 가정 → 1기가 전부를 배치 어플에 올려둔다? → 이건 메모리에 부담이다.
예제 3. 캐싱(Caching)
private Cache<Integer, CachedProduct> productCache = Caffeine.newBuilder().build();
CachedProduct product = productCache.getIfPresent(productId);
product.price = (int)Math.ceil(product.price / usdToWonRate); // 달러로 바꿈 <- 문제가 되는 부분
// 달러로 바꾸는 과정은 캐시된 데이터 를 기준으로 바꾸고 있다.!! 힙 메모리를 참조하고 있기 떄문
// 완전망한다. 10000 원화가 -> 5달러로 그대로 바뀐채로 계속 !
public record CachedProduct(int id, String modelName, int price) {
public int id;
public String modelName;
public int price;
}
음.. 그러면 어떻게 개선할 수 있을까?
price 를 바꿀 수 있어서 그런거라고 생각해서 final 을 붙이는 게 최선일까 ? 결국 cached 된 것들은 값을 바꾸면 안되는 건가? → 불변객체로 만들어야 한다.?
내가 저장하는 데이터를 캐싱, 참조될거고, 맘대로 바꾸면 위험할 듯
public final class CachedProduct {
private final int id;
private final String modelName;
private final int price;
public CachedProduct(int id, String modelName, int price) {
this.id = id;
this.modelName = modelName;
this.price = price;
}
}
public record CachedProduct {
int id;
String modelName;
int price;
}
CachedProduct 의 타입이 primitive type 이 아닌 List 가 추가 된다면?? 어떻게 될까? List 를 불변객체 ?
List
그 외 생각해볼 것
- 우리 사이트에서 물품을 원화(KRW)로만 판매하다가 , 달러 (USD)로도 판매할 예정이다.
- 백엔드 프론트 각각 코드를 조금씩 고치면 달러로도 판매하게 끔 만들 수 있다.
- 음 이게 최선일까?
- 그런데 앞으로 일본과 동남아 쪽도 공략 예정이라고 한다.
- 엔화 등 추가적인 통화 (currency) 지원이 필요할 수 있다.
- 이 상황에서 어떤 것이 최선일까?
- 매번 통화가 추가될때 마다 백엔드 프론트 코드를 조금 씩 고치는 게 나을까?
- 아니면 어드민 페이지에서 딸깍 한번이면 통화 추가가 자유롭게 추가 삭제 되는 게 좋을까?
- 백엔드 프론트 각각 코드를 조금씩 고치면 달러로도 판매하게 끔 만들 수 있다.
정리 : 이게 최선일까? 고민하는 습관
-
성능 혹은 안전성의 관점에서 늘 고민
-
리소스는 언제나 한정되어 있다.
-
명확한 근거를 추구하고 있는가 ? (단, 너무 집착, 오버엔지니어링은 경계할 것)
-
바라보는 관점을 다양화 하기(내가 너무 스레드 개수로만 집착하지 않았는 가? .., db? redis ? 방법론 측면에서 ?! )
-
더 편할 순 없는가?
…
출처
https://www.youtube.com/watch?v=ZWWUSN13Wzw