프로그래밍 초식:사소한 개선 -for문 분리 (최범균님 youtube 참고)
평소 처범균님 유툽 채널의 프로그래밍 초식에 영상이 올라오면 챙겨 보는 편이다.
클린 코드나 디자인 패턴같은것 보다는 실무에서 코딩하면서 가져야 할 원칙이나 습관에 대해서 매우 합리적이고 쉽게 설명해주신다.
특히 주니어들이라면 꼭꼭!! 챙겨서 봤으면 하는 마음에서 주변에 추천해주고 있다.
나 또만 눈으로만 볼 것이 아니라 종종 찾아서 볼 수 있도록 따로 기록해두기로 했다!
오늘은 여러 기능을 가지고 있는 for문에 관한 이야기. (https://www.youtube.com/watch?v=ZNDDy77WInY)
위와 같이 for 문에서 2가지 역할을 하는 (dotList에 데이터 add, invoices 에 데이터 add) 코드가 있다.
List<StoreApiDto> dtoList = new ArrayList<>();
List<InvoiceDto> invoices = mapper.selectRegularInvoices(cond);
for (InvoiceDto invoice : invoices) {
try {
ApprovalReq req = ...
ApprovalReq resp = payGwApi.approve(req, ...)
paymentService.saveAfterApproval(resp, ...)
List<Bill> bills = mapper.selectBillsOf(...)
for (Bill b: bills) {
StoreApiDto dto = ...// 성공 dto 생성
dtoList.add(dto);
}
} catch(Exception ex) {
applyErrorResult(invoice, ex);
List<Bill> bills = mapper.selectBillsOf(...)
for (Bill b : bills) {
StoreApiDto dto = ... //실패 dto 생성
dtoList.add(dto);
}
}
}
if (dtoList.size() > 0) { callStoreApi(dtoList); ...}
이 로직에 새로운 기능이 추가 되어야 한다면, 어떤 어려움이 있을까?
- 두가지 기능에 추가로 동일하게 적용 되어야 할 로직이 추가 될 경우 계속해서 2번씩 반복되는 코드가 발생함
- 계속해서 새로운 기능이 추가 될때마다 for문이 길어짐 -> 코드 복잡도 증가, 코드 이해 어려워짐
for 루프가 한 가지 일을 하도록 수정하자~!
예시로 든 코드를 같은 목적을 가진 부분끼리 색으로 표시를 하면 아래와 같다.
List<StoreApiDto> dtoList = new ArrayList<>(); List<InvoiceDto> invoices = mapper.selectRegularInvoices(cond); for (InvoiceDto invoice : invoices) { try { ApprovalReq req = ... ApprovalReq resp = payGwApi.approve(req, ...) paymentService.saveAfterApproval(resp, ...) List<Bill> bills = mapper.selectBillsOf(...) for (Bill b: bills) { StoreApiDto dto = ...// 성공 dto 생성 dtoList.add(dto); } } catch(Exception ex) { applyErrorResult(invoice, ex); List<Bill> bills = mapper.selectBillsOf(...) for (Bill b : bills) { StoreApiDto dto = ... //실패 dto 생성 dtoList.add(dto); } } } if (dtoList.size() > 0) { callStoreApi(dtoList); ...} |
1. 파란색 코드는 녹색 코드 부분인 payGwApi.approve 로부터 데이터를 가져와야 실행이 가능한 부분이다.
2. 따라서 파란색코드는 payGwApi로 부터 결과 리스트를 파라미터로 넘겨주면 실행 가능 하다.
이러한 점을 고려하여 메소드로 추출하면 아래와 같은 모습이 된다.
#1 List<Invoices> invoices = mapper.selectRegularInvoices(cond); #2 List<InvoiceResult> results = approveInvoice(invoices); //1) payGwApi를 호출하여 결과 데이터 리스트를 만듬 #3 sendInvoiceResultToStore(results); //2) API 결과 데이터를 파라미터로 받아서 dtoList 생성 #4 sendInvoiceResultExcel(results); //3) 추가로 기능이 필요하도라도 심플하게 추가 될 수 있음. |
1. #2 루프를 돌며 payGwApi 를 호출하여 얻은 결과 값을 리스트로 추출 한다.
2. #3 pyaGwApi 호출 결과 리스트를 통해 본래 for문의 목적이었던 List<StoreApiDto> dtoList 객체에 데이터를 add 해줌.
3. #4 엑셀로 무언가 하는 새로운 기능이 추가되더라도 기존 코드를 분석해야 하는 어려움 없이 간편해 진것을 볼 수 있다.
성능은?
- 루프를 여러 번 돌면 문제 없나?
- 대세에 지장 없을 때가 많음
- 정말로 문제가 될 때만 개선
- 복잡한 코드 보다는 이해하기 좋은 코드가 좋다!