Skip to main content

Command Palette

Search for a command to run...

실패로부터 배우기

Updated
•3 min read•View as Markdown

"간단해 보이네, 금방 끝나겠지"라고 생각했다가 예상보다 오래 걸리는 경험은 누구나 한 번쯤 겪어봤을 것 같은데요. 저 역시 최근에 이런 경험을 했고, 그 과정에서 제가 어떤 부분을 잘못했었는지 살펴보려고 합니다.

배경

처음 이 업무를 맡았을 때는 단순해 보였습니다. 상품 테이블에 컬럼 하나를 추가하고, 그 컬럼을 통해 상품의 배송비 할인 여부를 체크한 후, 비즈니스 로직에 따라 할인을 적용하는 기능이었습니다.

// 이해를 돕기 위한 예시 코드 입니다.
public ShippingFee calculateShippingFee(List<Product> products) {
   ShippingFee shippingFee = new ShippingFee(3000);

      for (Product product : products) {
       if (product.isDiscountable()) {
           shippingFee = shippingFee.applyDiscount();
       }
   }

   return shippingFee;
}

하지만 코드를 검토하면서 문제점을 발견했습니다. 배송비 계산 로직이 JSP 파일과 Java 코드에 분산되어 있었고, 특히 JSP 파일에 상당 부분의 로직이 구현되어 있었습니다. 이렇게 프레젠테이션 로직과 비즈니스 로직이 혼재된 구조는 코드의 가독성과 유지보수성을 크게 저하시키고 있었습니다. 더욱이 JSP는 컴파일러의 도움을 받기 어렵고 테스트 코드로 검증하는 것이 제한적인 환경입니다. 따라서 이러한 구조에 새로운 할인 로직을 추가하는 것은 리스크가 크다고 판단했습니다.

문제의 시작

JSP에 구현된 배송비 계산 로직을 그대로 Java로 옮기려고 했지만, 상품의 복잡성 때문에 배송비 계산을 위한 별도의 상품 모델을 만들며 진행했어야 했습니다. 그래서 우아한 모델을 만들거나 TDD를 적용하려 하기보다 전체적인 흐름을 파악하기 위해 대략적인 구현을 시도했습니다. 그러나 여러 가지 사정으로 인해 이 작업 자체가 지연되기 시작했습니다. 이 시점에서 작업이 왜 지연되고 있는지 분석하고, 혼자 해결할 수 없다면 주변 동료들에게 도움을 요청했어야 했습니다. 하지만 빠르게 작업을 마무리하겠다는 생각에 사로잡혀, 프로토타입처럼 작성된 코드를 기반으로 계속해서 진행하게 되었습니다. 빈약한 코드 베이스 위에서 계속 개발을 진행하다 보니 버그도 많이 발생하고 가독성도 좋지 않은 상태가 유지되었습니다.

문제의 연속

작업을 마무리할 즈음, 저는 중요한 부분을 간과했다는 것을 깨달았습니다. 배송비 계산 로직이 두 곳에서 필요했던 것입니다. 하나는 고객이 주문 전에 금액을 확인하는 단계였고, 다른 하나는 최종 주문이 생성되는 시점이었습니다. 사실 배송비 할인의 진정한 완료 조건은 할인이 적용된 주문이 생성되는 것이었습니다. 그러나 저는 단순히 배송비 계산 기능 구현이라는 중간 목표에만 집중하여 전체 업무의 목적을 놓쳤습니다. 그 결과, 뒤늦게 주문 완료 단계에서도 배송비 할인 기능을 추가해야 했습니다.

이로 인해 또 다른 문제가 발생했습니다. 배송비 계산이 두 곳에서 이루어지다 보니, 요구사항이 변경되거나 버그가 발견될 때마다 항상 두 곳을 함께 수정해야 했습니다. 레거시 시스템의 특성상 두 부분이 약간씩 다르게 구현되어 있어서, 처음에는 리팩터링을 진행하지 않았습니다. 하지만 작업이 진행될수록 이런 중복 수정이 계속 필요해져 비효율적이었습니다. 결국 배송비 계산 로직을 한 곳으로 통합하여 두 단계에서 모두 같은 로직을 사용하도록 변경한 후에야 남은 업무를 잘 마무리할 수 있었습니다.

인수 조건의 부재

저의 실패 사례를 보면 어떤 부분을 가장 먼저 조언해주고 싶으신가요? 저는 과거의 저에게 조언을 해줄 수 있다면 인수 조건의 부재에 대한 이야기를 해주고 싶습니다. 예를 들어 아래와 같은 간단한 인수 조건만 설정했더라도 좋았을 것입니다:

  • 배송비 할인 로직이 적용된 경우, 주문 생성 시 할인된 배송비로 계산되어야 한다.

이렇게라도 설정하고 상황에 따라 세부 조건들을 추가하고 수정해가며 업무를 진행했더라면, 좀 더 효율적으로 작업이 진행되었을 것으로 생각됩니다. 만약 다시 해당 업무를 진행하게 된다면, 아래와 같은 순서대로 진행할 것 같습니다:

  1. 인수 조건을 설정한다. (진행하면서 세부 조건을 추가하고 수정함)

  2. JSP의 로직을 Java로 다시 구현한다.

  3. 배송비 로직을 한 곳에서 처리하도록 리팩터링한다.

  4. 배송비 할인 로직을 구현한다.

마치며

이 글을 쓰게 된 가장 큰 이유는 제가 자신 있게 여겼던 부분에서 실패를 경험했기 때문입니다. 그동안 잘한다고 생각했던 영역에서 문제가 생기니 스스로에게 많은 실망을 했었습니다. 하지만 변명을 찾거나 과거에 연연하기보다는, 앞으로 같은 실수를 반복하지 않기 위해 이 경험을 공유하게 되었습니다. 이 글을 읽는 분들에게도 도움이 되어 비슷한 상황을 미리 피할 수 있기를 바랍니다.

More from this blog

배치 처리를 선택한 이유

들어가며 배치성 작업으로 보이는 업무가 있을 때, 이것이 정말 배치 처리로만 해결 가능한 문제인지 고민하게 됩니다. 애플리케이션에서 직접 처리하거나 이벤트 스트리밍 같은 방법으로 문제를 해결한다면 실시간성이 확보되고 자원도 더 효율적으로 사용할 수 있기 때문입니다. 하지만 이번에 소개할 사례는 다양한 대안을 검토했음에도 결국 배치 처리를 선택할 수밖에 없었던 케이스입니다. 1. 문제 상황 1.1 기존 구조 및 접근 방식 저는 이커머스 플랫폼을 ...

Mar 28, 20255 min read

상품 조회 성능 개선 이야기

최근에, 상품 상세 API의 문제를 빠르게 개선할 수 있었는데요. 어떻게 빠르게 개선할 수 있었는지에 대해 작성해보려고합니다. 이슈 발견과 해결 과정 슬랙에서 상품 상세 API의 성능 저하 이슈가 제기되었습니다. 제가 이전에 이 API를 레거시 서비스에서 신규 서비스로 전환하는 작업을 담당했었기 때문에, 문제의 원인을 빠르게 파악할 수 있었습니다. 원인은 판매량을 구하기 위해 사용하던 쿼리에 있는 SUM 함수였습니다. 데이터가 많은 경우 이런 ...

Feb 21, 20253 min read

조회수 개발기

배경 관리자가 등록한 게시글을 사용자들이 얼마나 조회했는지 확인할 수 있는 기능이 필요했습니다. 주요 목표는 빠르고 단순하게 기능을 구현하는 것이었으며, 복잡한 데이터 분석보다는 얼마나 많은 사용자가 게시글을 조회했는지 간단히 확인할 수 있는 시스템을 만드는 것이 핵심이었습니다.중요한 요구사항 중 하나는 조회수를 실시간으로 표시하는 것이었습니다. 사용자가 게시글을 클릭할 때마다 즉시 조회수가 증가하고, 이를 화면에 바로 반영해야 했습니다. 이는...

Feb 21, 20254 min read

2023 회고 : 본 만큼 알게 된다.

우리는 아는 만큼 볼 수 있지만, 본 만큼 알게 되기도 한다. 1분 1초도 그냥 스치지 말라. 더 다가가서 더 깊이 보라. -김종원- 김종원 작가님의 '글은 어떻게 삶이 되는가' 라는 책에 나오는 문장이다. 나의 1년을 한 문장으로 정리한다면 이 문장이지 않을까라는 생각이 든다. 케이타운포유 라는 회사를 선택할 때, CTO님과 팀장님이 개발 조직을 바꿔 나가는 것을 바로 옆에서 지켜볼 수 있다는 부분이 크게 다가왔었다. 전 직장에서 혼자서 개...

Feb 21, 20253 min read

weno's blog

5 posts