오픈은 끝이 아니라 시작이다
1장에서 소프트웨어 개발의 여섯 단계 중 마지막을 유지보수라 불렀고, "잘 만든 시스템도 유지보수 비용이 초기 개발 비용을 넘어서는 경우가 대부분"이라고 미리 경고해두었다. 17장에서 책마루 시스템의 재고 동시성 버그를 테스트로 발견했다고 가정했는데, 이번 장은 그 이후의 이야기다 — 버그를 실제로 고치고, 시스템이 배포된 뒤에도 계속 손을 봐야 하는 활동 전체를 다룬다.
소프트웨어의 유지보수 비용은 개발 당시에는 잘 보이지 않는다. 계약서에는 "8주 개발, 500만원"이라는 숫자만 적히고, 그 뒤로 몇 년간 이어질 수정·개선 비용은 별도로 계산되지 않는 경우가 많다. 이 비용을 빙산에 비유하면, 개발 당시 보이는 부분은 물 위로 드러난 작은 꼭대기이고 실제 유지보수 비용은 수면 아래 훨씬 큰 덩어리로 숨어 있다. 책마루 시스템이 오픈한 뒤에도 택배사 API가 바뀌고, 손님들이 새 기능을 요청하고, 코드 자체가 점점 손대기 어려워지는 상황이 계속 이어진다 — 이 모든 활동이 유지보수라는 이름 아래 묶인다.
소프트웨어라는 이름 자체가 "유연함(soft)"을 내포하고 있어서 하드웨어보다 고치기 쉬워 보이지만, 이 유연함이 계획 없이 남용되면 오히려 손댈수록 더 손대기 어려워지는 역설적인 상황에 빠진다. 그래서 소프트웨어는 개발되는 시점부터 이미 "이후에 계속 바뀔 것"이라는 전제를 깔고, 변경에 잘 견디는 구조로 설계되어야 한다.
유지보수의 네 가지 얼굴
"유지보수"라는 말은 흔히 버그 수정만을 떠올리게 하지만, 실제로는 성격이 전혀 다른 네 가지 활동을 모두 포함한다.
| 유형 | 정의 | 책마루 예시 |
|---|---|---|
| 수정 유지보수 | 이미 발생한 잘못을 고침 | 재고 동시성 버그로 재고가 마이너스로 내려가는 문제를 고침 |
| 적응 유지보수 | 시스템을 바뀐 외부 환경에 맞춤 | 택배사가 API 규격을 바꿔서 배달 상태 조회 코드를 그에 맞게 수정 |
| 완전 유지보수 | 새로운 기능을 추가하거나 기존 기능을 개선 | 단골 손님을 위한 정기구독 배송 기능 추가 |
| 예방 유지보수 | 미래의 유지보수를 쉽게 하기 위한 사전 정비 | 재고 로직이 여기저기 흩어져 있는 코드를 하나의 모듈로 정리 |
네 유형을 구분하는 실익은 각각 우선순위를 매기는 기준이 다르다는 데 있다. 수정 유지보수는 심각도(severity)가 높을수록 즉시 처리해야 하는 반면 — 책마루의 재고 마이너스 버그처럼 손님에게 실제 피해를 주는 문제는 다른 작업을 제쳐두고 먼저 처리해야 한다 — 완전 유지보수는 "이 기능이 정말 필요한가", "비용 대비 가치가 있는가"를 따져 우선순위를 정한다. 적응 유지보수는 대개 외부 일정(택배사가 API를 언제 바꾸는가)에 끌려가는 성격이 강하고, 예방 유지보수는 급하지 않다는 이유로 가장 먼저 뒤로 밀리기 쉽지만 방치할수록 다른 세 유형의 비용을 함께 끌어올린다는 특징이 있다 — 코드가 정리되어 있지 않으면 버그 하나 고치는 데도, 기능 하나 추가하는 데도 시간이 더 든다.
유지보수가 유독 어려운 이유
유지보수는 새로 개발하는 것보다 흔히 더 까다롭다고 여겨지는데, 몇 가지 구조적인 이유가 있다. 새로 개발할 때는 설계자가 시스템 전체를 머릿속에 그리고 있지만, 유지보수를 맡은 사람은 대개 그 설계 의도를 문서만으로, 혹은 문서조차 없이 코드만으로 재구성해야 한다. 책마루 시스템을 처음 만든 개발사와 6개월 뒤 기능을 추가하는 개발사가 다르다면, 새 개발사는 "왜 재고 차감 로직이 이렇게 짜여 있는지" — 어쩌면 동시성 버그를 막기 위한 잠금 처리였을 수도 있는 코드를 — 정확한 배경 없이 마주하게 된다. 여기에 서비스가 운영 중인 상태에서 변경을 가해야 한다는 제약도 더해진다. 책마루 시스템은 새로 개발하는 시스템과 달리 이미 손님들이 매일 쓰고 있는 상태이므로, 수정 하나가 다른 기능을 망가뜨리지 않는지 항상 확인하며 조심스럽게 진행해야 한다.
유지보수 요청은 즉흥적으로 처리하지 않는다
유지보수가 어려운 활동인 만큼, 요청이 들어올 때마다 담당자가 즉흥적으로 판단해 코드를 고치는 방식은 오래 못 간다. 소규모 조직도 최소한의 절차를 갖추는 것이 좋다.
요청은 표준화된 양식인 유지보수 요청서(MRF: Modification Request Form) 또는 변경 요청서(Change Request)로 접수된다. 이 문서에는 보통 요구자와 요청일, 대상 시스템, 변경 유형(정정/개선/적응), 변경 내용, 그리고 변경의 심각도와 처리 기한이 담긴다. 책마루라면 매장 직원이 "재고가 마이너스로 표시되는 오류가 있다"는 변경 요청서를 작성해 제출하는 식이다.
요청이 접수되면 먼저 무엇이 수정 또는 개선되어야 하는지 분석한다. 오류에 대한 요청이라면 오류가 발생한 입력값과 환경이 요청서에 함께 담겨야 하고, 적응이나 완전을 위한 요청이라면 간략한 변경 명세서가 추가로 제출된다. 이 분석을 바탕으로 유지보수를 수행하는 조직 내부에서는 소프트웨어 변경 보고서(SCR: Software Change Report)를 작성하는데, 여기에는 변경에 필요한 시간과 노력의 크기, 수정의 성질, 우선순위 또는 문제의 심각도, 수정 이후의 후속 자료가 담긴다.
전체 흐름을 정리하면 이렇다.
- 요청이 들어오면 유형을 판단한다 — 수정(오류)인가, 적응·완전을 위한 것인가.
- 수정 요청이라면 오류의 심각도를 평가한다. 심각한 오류는 즉시 담당자를 지정해 분석에 들어간다.
- 급하지 않은 요청은 분류해 우선순위를 매기고 다른 작업과 함께 일정에 편성한다.
- 우선순위에 따라 실제 수정 작업을 진행한다 — 필요하면 기존 분석·설계·구현·시험 산출물까지 재검증하고 고친다.
- 수정이 끝나면 재검증을 거쳐 반영하고, 다음 요청을 위해 이 사이클이 반복된다.
책마루의 재고 동시성 버그라면, 매장 직원이 "특정 시간대에 재고가 마이너스로 찍힌다"는 변경 요청서를 제출하고, 이는 심각도가 높은 수정 유지보수로 분류되어 즉시 담당자가 배정된다. 담당자는 17장에서 설계했던 것과 같은 동시 접근 테스트 케이스로 문제를 재현하고, 재고 차감 로직에 잠금(lock) 처리를 추가한 뒤, 이 수정이 다른 주문 흐름을 깨뜨리지 않는지 회귀 테스트로 재확인하고 나서야 반영을 완료한다.
유지보수하는 사람의 동기 부여: 유지보수는 새 기능을 만드는 일보다 눈에 띄는 성과로 인정받기 어려운 경우가 많다. 그래서 조직 차원에서 유지보수가 개발과 동등하게 중요하고, 오히려 기술적으로는 더 까다로운 작업이라는 인식을 갖추는 것이 필요하다. 그렇지 않으면 경험 많은 개발자일수록 유지보수를 피하게 되고, 정작 가장 복잡한 레거시 코드는 가장 경험이 적은 사람에게 맡겨지는 악순환이 생긴다.
역공학과 재공학
시간이 지날수록 유지보수의 난이도를 끌어올리는 또 다른 요인은 "이 코드가 원래 무엇을 하려던 것인지" 자체를 파악하기 어려워진다는 것이다. 이럴 때 필요한 것이 역공학(reverse engineering)이다.
역공학이라는 용어는 원래 하드웨어에서 나왔다 — 경쟁사 제품을 분해해 설계와 제조 방식을 알아내는 활동이다. 그런데 소프트웨어에서 역공학은 대개 경쟁사의 코드가 아니라 자사가 예전에 만든, 지금은 아무도 그 구조를 온전히 이해하지 못하는 코드를 대상으로 이루어진다. 소프트웨어 역공학은 소스 코드를 분석해서 그보다 더 추상화된 표현 — 이를테면 모듈 간의 관계도나 자료 구조 다이어그램 — 을 다시 끌어내는 과정이다. 책마루 프로젝트를 예로 들면, 문서 없이 코드만 넘겨받은 두 번째 개발사가 재고 차감 로직을 분석해 "재고 확인 → 잠금 → 차감 → 잠금 해제"라는 흐름도를 코드로부터 역으로 재구성하는 작업이 역공학이다.
재공학(reengineering)은 여기서 한 걸음 더 나아간다. 역공학이 설계 정보를 "끌어내는" 데서 멈춘다면, 재공학은 그 정보를 활용해 실제로 더 나은 시스템을 만드는 것까지 포함한다. 성능을 개선하거나, 변경하기 힘들었던 구조를 변경이 쉬운 구조로 재구성하거나, 그 과정에서 새로운 기능을 얹는 것도 재공학에 속한다. 책마루의 재고 로직이 여러 화면 코드에 중복되어 흩어져 있다는 사실을 역공학으로 확인했다면, 재공학은 그 흩어진 로직을 하나의 재고 서비스 모듈로 통합해 다시 짜는 것이다. 최근 자주 쓰이는 리엔지니어링, BPR(business process reengineering), 경영 혁신 같은 용어들도 결국 이 재공학과 같은 맥락에서 쓰인다.
유지보수의 끝은 없다
유지보수 활동은 소프트웨어가 사용자에게 전달된 뒤 폐기될 때까지 계속되는, 사실상 개발 과정의 순환이다. 한 가지 조직이 흔히 겪는 현상은 유지보수 한계점(maintenance bound)이다 — 유지보수에 들어가는 비용과 인력이 너무 많아진 나머지, 조직이 더 이상 새로운 시스템을 만들 여력을 잃어버리는 상태를 가리킨다. 책마루처럼 작은 조직이라도 이 함정에서 자유롭지 않다. 정기구독 배송, 회원 등급 할인처럼 계속 쌓이는 완전 유지보수 요청과, 택배사·PG사 규격이 바뀔 때마다 따라가야 하는 적응 유지보수를 방치하면, 어느 순간부터는 새 기능을 논의할 여유조차 없이 기존 시스템을 지탱하는 데만 인력이 소진된다.
이 한계점을 늦추는 방법은 결국 이 장에서 다룬 것들로 되돌아간다 — 예방 유지보수를 꾸준히 챙기고, 변경 요청을 절차 없이 즉흥적으로 처리하지 않고, 코드가 이해하기 어려워지기 전에 역공학·재공학으로 정리하는 것이다. 그리고 이 모든 변경이 서로 충돌하지 않고 추적 가능하게 관리되려면, 변경 자체를 체계적으로 통제하는 별도의 활동이 필요하다.
핵심 정리
- 유지보수는 개발이 끝난 뒤 덧붙는 부수적인 활동이 아니라, 시스템이 사용되는 내내 이어지는 별도의 순환 과정이며 흔히 초기 개발 비용을 넘어서는 비용이 든다.
- 유지보수는 수정(잘못을 고침), 적응(환경 변화에 맞춤), 완전(기능을 추가·개선), 예방(미래를 대비해 정비) 네 유형으로 나뉘며, 유형마다 우선순위를 매기는 기준이 다르다.
- 유지보수는 원래 설계자가 아닌 사람이, 운영 중인 시스템을 대상으로 수행해야 하기 때문에 신규 개발보다 까다롭다. 그래서 변경 요청서(MRF)와 소프트웨어 변경 보고서(SCR) 같은 절차로 즉흥적인 처리를 막아야 한다.
- 역공학은 코드로부터 설계 정보를 끌어내는 것이고, 재공학은 그 정보로 실제로 더 나은 시스템을 만드는 것까지 포함한다.
- 유지보수를 방치하면 조직이 새 시스템을 만들 여력조차 잃는 유지보수 한계점에 이를 수 있다.
이 장에서 다룬 변경 요청과 SCR 같은 절차는 결국 "누가, 언제, 무엇을, 왜 바꿨는가"를 놓치지 않기 위한 것이었다. 다음 장(19장)에서는 이 문제의식을 조직 전체로 확장해, 품질을 어떻게 측정하고 개발 프로세스 자체를 어떻게 개선해나가는지를 다룬다.