NerdVana
홈 About
search
arrow_back 블로그로 돌아가기
읽는 시간 —

테스트는 코드가 아니라 신뢰의 설계다 — IT 서비스 품질 관리의 본질

작성자 최진호  · 5 Views
테스트는 코드가 아니라 신뢰의 설계다 — IT 서비스 품질 관리의 본질
# 테스트는 코드가 아니라 신뢰의 설계다 — IT 서비스 품질 관리의 본질 ![대표 이미지: 새벽 장애 상황 속에서 결제 서버 다운과 사용자 불만, 그리고 '테스트는 코드가 아니라 신뢰의 설계'라는 메시지를 상징적으로 보여주는 장면](https://nerdvana.kr/download?f=20260516_100414_55d9a33e.jpg) 새벽 세 시, 결제 서버가 멈췄다. 알람이 울리기 전에 사용자는 이미 알고 있었다. 트위터에 항의가 올라오고, 고객센터 대기열이 부풀고, 책임자가 잠에서 깬다. 그 순간 누구도 단위 테스트 커버리지가 몇 퍼센트였느냐고 묻지 않는다. 테스트의 목적은 버그를 찾는 데 있지 않다. 신뢰를 쌓는 데 있다. 검증되지 않은 코드는 가설에 불과하고, 가설로 지어진 시스템은 운에 의지한다. 그리고 운은 통계적으로 반드시 배반한다. ![테스트 피라미드 구조를 시각화한 다이어그램: 바닥의 단위 테스트, 중간의 통합 테스트, 꼭대기의 E2E 테스트를 층별로 표현](https://nerdvana.kr/download?f=20260516_100422_e13a931d.jpg) ![단위 테스트의 역할과 예시 코드를 강조하는 이미지: 함수/클래스와 그에 대응하는 테스트 코드, 그리고 도메인 규칙을 연결한 구조](https://nerdvana.kr/download?f=20260516_100433_1f0c7f30.jpg) ## 현상: 의례가 되어버린 테스트 ![커버리지 지표와 실제 장애 지표(MTTR, 재발률)를 비교하는 그래프: 높은 라인 커버리지와 별개로 발생하는 장애, MTTR 및 재발률 추세를 대비](https://nerdvana.kr/download?f=20260516_100442_9dd31de4.jpg) ![카오스 엔지니어링 개념을 표현하는 인프라 다이어그램: 넷플릭스 카오스 멍키가 일부 서버 인스턴스를 임의로 종료하는 장면과 그에 대응하는 회복력 있는 시스템](https://nerdvana.kr/download?f=20260516_100451_b7c39dcf.jpg) 많은 조직에서 테스트는 의례가 되어 있다. 커버리지 80퍼센트라는 숫자가 게시판에 걸리고, CI는 초록 불을 켠 채 통과한다. 그러나 운영 환경의 장애는 줄지 않는다. 왜인가. 대부분의 테스트는 작성자가 이미 옳다고 믿는 경로를 한 번 더 확인하는 데 그친다. 입력이 1일 때 출력이 2임을 확인하는 검증은 무수히 쌓이지만, 입력이 null이거나 음수이거나 동시에 만 건이 들어오는 경우는 누구도 묻지 않는다. 검증된 것은 의도된 동작이고, 검증되지 않은 것은 의도하지 않은 동작이다. 장애는 늘 후자에서 발생한다. 품질 관리의 첫 자기 점검은 여기서 출발한다. 우리가 작성한 테스트는 우리가 모르는 것을 드러내는가, 아니면 우리가 이미 아는 것을 반복하는가. ![시프트 레프트와 시프트 라이트를 시간축 상에서 함께 보여주는 소프트웨어 라이프사이클 다이어그램: 요구사항, 개발, 테스트, 배포, 운영 단계 위에 각 활동을 배치](https://nerdvana.kr/download?f=20260516_100501_09d5097e.jpg) ## 구조: 테스트 피라미드라는 위계 마이크 콘이 정리한 테스트 피라미드는 단순한 도식이 아니라 비용과 신뢰의 위계다. 바닥에 단위 테스트, 중간에 통합 테스트, 꼭대기에 E2E(End-to-End) 테스트가 놓인다. 아래로 갈수록 빠르고 저렴하고 안정적이며, 위로 갈수록 느리고 비싸고 깨지기 쉽다. ### 단위 테스트: 가장 가까운 거울 단위 테스트는 함수와 클래스의 동작을 격리된 환경에서 검증한다. 실행은 밀리초 단위로 끝나고, 실패 원인은 거의 즉시 특정된다. 좋은 단위 테스트는 코드의 명세서 역할도 겸한다. 후임 개발자는 함수의 주석이 아니라 그 함수의 테스트를 읽고 의도를 파악한다. ```python def test_discount_applies_only_to_eligible_items(): cart = Cart() cart.add(Item("book", 10_000, eligible=True)) cart.add(Item("gift_card", 50_000, eligible=False)) cart.apply_coupon(rate=0.1) assert cart.total == 10_000 * 0.9 + 50_000 ``` 이 테스트가 전달하는 정보는 단순한 통과/실패가 아니다. "쿠폰은 적격 상품에만 적용된다"는 도메인 규칙 자체다. ### 통합 테스트: 경계의 검증 단위가 모이면 새로운 위험이 생긴다. 함수 A와 B는 각각 옳지만, A가 B를 호출하는 방식은 틀릴 수 있다. ORM이 던지는 쿼리, 외부 API의 응답 포맷, 메시지 큐의 직렬화 — 경계는 늘 미끄럽다. 통합 테스트는 이 경계에서 가정과 현실이 어긋나는 지점을 드러낸다. ### E2E 테스트: 사용자의 시선 E2E는 가장 비싸다. 브라우저를 띄우고, 실제 데이터베이스에 쓰고, 결제 모의 서버를 호출한다. 모든 경로를 E2E로 덮으려는 시도는 파산을 부른다. E2E의 자리는 좁아야 한다. 사용자가 가장 자주 밟는 경로, 그리고 깨지면 회사가 멈추는 경로. 그 두 가지에 집중해야 한다. 피라미드가 무너지는 가장 흔한 형태는 역삼각형이다. 단위 테스트는 빈약하고 E2E만 비대한 조직은 빌드 시간이 한 시간을 넘기며, 그중 절반은 깜빡이는 실패에 허비된다. 흔히 '아이스크림 콘'으로 불리는 안티패턴이다. ## 본질: 커버리지의 함정과 회복력의 우위 커버리지는 측정 가능하다는 이유만으로 과대평가된다. 그러나 라인 커버리지 100퍼센트의 코드도 장애에서 자유롭지 않다. 라인이 실행되었다는 사실이 곧 그 라인이 모든 입력에 옳게 동작한다는 뜻은 아니기 때문이다. > "측정되는 것은 관리된다. 그러나 측정될 수 없는 것이 더 중요할 때가 있다." 피터 드러커의 격언을 비틀어 회자되는 이 말은 품질 영역에서 특히 정확하다. 진정한 품질 지표는 둘이다. 장애 발생 시 평균 복구 시간(MTTR), 그리고 같은 장애의 재발률. 전자는 시스템이 얼마나 빨리 일어서는가를, 후자는 조직이 얼마나 배우는가를 측정한다. ### 카오스 엔지니어링: 깨뜨려야 단단해진다 넷플릭스가 2010년대 초 공개한 카오스 멍키는 운영 중인 서버를 임의로 종료시키는 도구다. 처음 들으면 광기처럼 들리지만 그 안에는 분명한 논리가 있다. 어차피 서버는 죽는다. 죽는 시점을 예측 불가능하게 둘 것인가, 통제된 시점에 죽게 하여 시스템이 그 죽음에 익숙해지게 할 것인가. 장자(莊子)는 "지인무기(至人無己)"라 했다. 지극한 사람은 자기를 고집하지 않는다. 시스템도 같다. 어느 한 노드를 자기로 고집하는 시스템은 그 노드와 함께 죽는다. 회복력 있는 시스템은 어떤 부분도 자기라고 고집하지 않는다. ### 테스트 더블의 절제 목(mock), 스텁(stub), 페이크(fake)와 같이 외부 의존성을 흉내 내는 도구들은 테스트 작성을 가능하게 하는 동시에, 테스트를 거짓 안심으로 만들기도 한다. 흉내 낸 외부는 진짜 외부와 다르다. 결제 API가 30초 만에 타임아웃을 던지는 현실은 즉시 200을 돌려주는 목으로 재현되지 않는다. 따라서 의존성을 흉내 낼 때는 그 흉내가 무엇을 가정하는지 명시해야 한다. 가능하면 계약 테스트(contract test)로 실제 API의 응답 스키마와의 일치 여부를 주기적으로 검증한다. Pact, Spring Cloud Contract 같은 도구가 그 역할을 한다. ## 함의: 품질은 사람과 흐름의 문제다 도구는 이미 충분히 성숙했다. JUnit, pytest, Jest, Playwright, k6, Sentry — 어느 것 하나 부족하지 않다. 그럼에도 품질이 흔들리는 것은 도구의 부재가 아니라 흐름의 부재 때문이다. ### 시프트 레프트, 그리고 시프트 라이트 시프트 레프트(shift left)는 검증을 개발 초기 단계로 당기는 전략이다. 코드 리뷰, 정적 분석, 타입 시스템, IDE 차원의 린트가 모두 그 일환이다. 결함은 발견이 늦을수록 비용이 기하급수적으로 증가한다. 요구사항 단계에서 발견된 결함의 비용을 1이라 하면, 운영 단계에서 발견된 동일 결함의 비용은 수십에서 수백 배에 달한다는 보고가 오래전부터 반복되어 왔다(IBM Systems Sciences Institute 등). 그러나 시프트 레프트만으로는 부족하다. 운영 환경의 행동을 관측하는 시프트 라이트(shift right)가 짝을 이뤄야 한다. 카나리 배포, 기능 플래그, A/B 라우팅, 분산 추적은 모두 "운영 환경이 곧 최후의 테스트 환경"이라는 인정에서 출발한다. 어떤 스테이징도 실제 사용자 수십만 명의 다양한 단말과 네트워크 조건을 재현하지 못한다. ### 포스트모템: 비난 없는 부검 장애가 났을 때 누구를 탓할지부터 묻는 조직은 다음 장애에서도 같은 질문을 반복한다. 비난받지 않기 위해 정보가 은폐되기 때문이다. 구글 SRE 팀이 정착시킨 '비난 없는 포스트모템(blameless postmortem)'은 사건의 인과를 시스템의 결함으로 환원한다. 사람은 시스템이 허용한 실수만 저지른다. 그 실수를 허용한 시스템을 고치는 것이 부검의 목적이다. 논어는 "과즉물탄개(過則勿憚改)"라 말한다. 허물이 있으면 고치기를 꺼리지 말라. 조직의 품질은 결국 허물을 드러낼 수 있는가, 그리고 그 드러냄을 고침으로 이어갈 수 있는가에 달려 있다. ## 닫는 단락 테스트는 코드가 아니라 약속이다. 사용자에게는 동작에 대한 약속이며, 동료에게는 의도에 대한 약속이고, 미래의 자신에게는 회귀하지 않겠다는 약속이다. 약속은 글로 적힐 때 비로소 강제력을 갖는다. 지난 십여 년간 내가 본 안정적인 시스템에는 공통점이 있었다. 화려한 아키텍처도, 비싼 도구도 아니었다. 장애가 나면 그날 안에 부검을 끝내고, 다음 주에는 그 부검에서 도출된 테스트가 CI에 들어가 있었다. 흐름은 단순했고, 흐름이 끊기지 않았다. > 子曰, 知之者不如好之者, 好之者不如樂之者. (지지자불여호지자, 호지자불여낙지자.) > 아는 자는 좋아하는 자만 못하고, 좋아하는 자는 즐기는 자만 못하다. 품질을 의무로 아는 조직은 품질을 좋아하는 조직만 못하고, 좋아하는 조직은 깨뜨리고 다시 세우는 일을 즐기는 조직만 못하다. 안정은 정적인 상태가 아니다. 부단히 흔들어 보고도 무너지지 않는 운동의 결과다.
5
조회수
0
좋아요
관련 포스트
콜로세움은 건축이 아니라 회계였다: 전리품을 신뢰로 바꾼 베스파시아누스의 재정 설계
콜로세움은 건축이 아니라 회계였다: 전리품을 신뢰로 바꾼 베스파시아누스의 재정 설계
2026 AI 네이티브 개발: 최소 자원으로 에이전트와 로우코드를 운영 가능하게 만드는 설계
2026 AI 네이티브 개발: 최소 자원으로 에이전트와 로우코드를 운영 가능하게 만드는 설계
2026년 백엔드 개발자: 코딩 속도가 아니라 변화의 비용을 통제하는 역할
2026년 백엔드 개발자: 코딩 속도가 아니라 변화의 비용을 통제하는 역할
NerdVana

AI 기반 지식 탐구 플랫폼. 기술과 사유의 교차점에서 질서를 설계합니다.

Home Blog

탐색

  • 최신 포스트
  • 아카이브
  • 주제

정보

  • About
  • 아키텍처
  • 파이프라인

© 2025 NerdVana. All rights reserved.

Designed for the future