# 소프트웨어 유지보수

**소프트웨어 유지보수**(software maintenance)는 소프트웨어 배포 후 소프트웨어를 수정하는 것이다.

소프트웨어 유지보수는 종종 신규 개발보다 낮은 기술력과 보상이 적은 것으로 간주된다. 따라서 아웃소싱이나 업무위탁의 일반적인 대상이 된다. 보통 소프트웨어를 개발하는 팀과 유지보수하는 팀은 다르다. 개발자들은 쉽게 유지보수될 수 있는 코드를 작성할 유인이 부족하다. 소프트웨어는 종종 불완전하게 배포되며, 거의 항상 유지보수 팀이 수정해야 할 버그가 포함되어 있다. 소프트웨어 유지보수는 초기에는 새로운 기능 개발을 포함하지만, 제품의 수명이 끝에 다다르면 유지보수는 최소한으로 줄어들고 제품이 단종되기 전에 완전히 중단된다.

각 유지보수 주기는 일반적으로 최종 사용자로부터 시작되는 변경 요청으로 시작된다. 이 요청은 평가되고, 구현하기로 결정되면 프로그래머는 변경 사항을 구현하기 전에 기존 코드를 연구하여 작동 방식을 이해한다. 기존 기능이 유지되고 원하는 새 기능이 추가되었는지 확인하기 위한 테스트는 종종 유지보수 비용의 대부분을 차지한다.

소프트웨어 유지보수는 비용의 대부분을 차지함에도 불구하고 소프트웨어 생명 주기의 다른 단계만큼 잘 연구되지 않았다. 이해도는 1980년대 이후 크게 변하지 않았다. 소프트웨어 유지보수는 예방적인지 반응적인지, 기능을 추가하려는 것인지 기존 기능을 보존하려는 것인지(후자는 일반적으로 변경된 환경에 직면했을 때)에 따라 여러 유형으로 분류될 수 있다.

## 역사

1970년대 초, 기업들은 소프트웨어 개발 팀을 지원 업무에서 해방시키기 위해 소프트웨어 유지보수를 별도의 엔지니어 팀으로 분리하기 시작했다. 1972년, R. G. 캐닝은 "유지보수 빙산(The Maintenance 'Iceberg)"을 출판했는데, 그는 여기서 소프트웨어 유지보수가 추가 입력인 기존 시스템을 포함하는 소프트웨어 개발의 확장이라고 주장했다. 소프트웨어 유지보수 분야는 그 이후로 크게 변하지 않았다. 21세기 혁신 중 하나는 기업들이 불완전한 소프트웨어를 의도적으로 출시하고 출시 후 완료할 계획을 세우는 것이었다. 이러한 유형의 변경 및 기능을 확장하는 다른 변경은 종종 유지보수 대신 소프트웨어 진화라고 불린다.

## 소프트웨어 생명 주기

1988년 전통적인 소프트웨어 개발 수명 주기 다이어그램
소프트웨어 테스트 및 소프트웨어 품질보증에도 불구하고 거의 모든 소프트웨어는 시스템이 의도한 대로 작동하지 않는 소프트웨어 버그를 포함한다. 발견된 버그를 해결하기 위해서는 출시 후 유지보수가 필요하다. 대부분의 소프트웨어는 미리 존재하는 상용 기성품(COTS) 및 오픈 소스 소프트웨어 구성 요소와 맞춤형 코드를 조합한 것이다. COTS 및 오픈 소스 소프트웨어는 일반적으로 시간이 지남에 따라 업데이트되어 유지보수 부담을 줄일 수 있지만, 이러한 소프트웨어 구성 요소의 수정 사항은 최종 제품에 맞게 조정되어야 한다. 지정된 요구사항을 충족하는 데 중점을 두는 소프트웨어 개발과 달리 소프트웨어 유지보수는 사용자 요청 또는 버그 감지와 같은 이벤트에 의해 주도된다. 주요 목적은 일반적으로 변화하는 요구사항에 직면하여 소프트웨어의 유용성을 보존하는 것이다.

소프트웨어 개발 수명 주기의 일부로 간주될 경우, 유지보수는 주기의 마지막 단계이자 일반적으로 가장 긴 단계이며, 생명 주기 비용의 80~90%를 차지한다. 다른 모델은 유지보수를 소프트웨어 개발과 분리하여 대신 소프트웨어 유지보수 생명 주기(SMLC)의 일부로 간주한다. SMLC 모델은 일반적으로 코드 이해, 수정 및 재검증을 포함한다.

### 출시에서 유지보수, 수명 종료로의 전환

소프트웨어 단종 단계를 보여주는 다이어그램
자주 소프트웨어는 불완전한 상태로 배포된다. 개발자들은 시간이나 자금이 부족할 때까지 제품을 테스트하는데, 이는 불완전한 제품에 대한 결과보다 시간이나 예산을 초과하는 것에 대한 결과가 더 적기 때문이다. 개발 팀에서 유지보수 팀으로의 전환은 종종 비효율적이며, 알려진 문제 목록이나 검증 테스트가 없어 유지보수 팀이 이를 다시 만들 가능성이 높다. 출시 후, 개발 팀 구성원들은 재배치되거나 다른 이유로 사용할 수 없게 될 가능성이 높다. 유지보수 팀은 출시 후 첫 해에 기술 지원과 개발에서 남은 결함 수정을 위해 추가 자원이 필요할 것이다.

초기에 소프트웨어는 출시 후 개선 기간을 거칠 수 있다. 사용자 피드백에 따라 새로운 기능이 추가된다. 특정 시점에 회사는 기능 개선이 더 이상 수익성이 없다고 판단하고 버그 수정 및 긴급 업데이트로 지원을 제한할 수 있다. 전문 지식 부족이나 소프트웨어 노화로 인한 아키텍처 손상으로 인해 변경 사항이 점점 더 어려워지고 비싸진다. 제품이 더 이상 유지보수되지 않고 이러한 제한된 수준의 업데이트조차 받지 못하게 되면, 일부 공급업체는 제품이 점점 더 기피될 가능성이 높더라도 가능한 한 오랫동안 소프트웨어에서 수익을 창출하려고 노력한다. 결국 소프트웨어는 시장에서 철수되지만, 계속 사용될 수도 있다. 이 과정에서 소프트웨어는 레거시 시스템이 된다.

### 변경 주기

변경 주기의 첫 번째 단계는 고객으로부터 변경 요청을 받고 이를 분석하여 문제를 확인하고 변경을 구현할지 여부를 결정하는 것이다. 이는 여러 부서의 의견을 필요로 할 수 있다. 예를 들어, 마케팅 팀은 변경이 더 많은 비즈니스를 가져올 것으로 예상되는지 평가하는 데 도움을 줄 수 있다. 소프트웨어 개발 노력 추정은 유지보수 변경 요청을 포함하여 어려운 문제이지만, 요청이 너무 비싸거나 실행 불가능할 경우 거부될 가능성이 높다. 요청을 구현하기로 결정되면 예정된 릴리스에 할당되어 구현될 수 있다. 애자일 방법론에는 유지보수 단계가 없지만, 변경 주기는 스크럼 스프린트로 실행될 수 있다.

기존 코드를 수정하기 전에 이해하는 것은 필수적인 단계이다. 이해 속도는 코드 베이스와 프로그래머의 기술에 따라 달라진다. 목적에 해당하는 명확한 함수 및 변수 이름을 사용하는 등 코딩 규칙을 따르면 이해가 더 쉬워진다. 코드가 한 번 이상 실행될 수 있는 경우에만 조건부 루프 문을 사용하고, 절대 실행되지 않을 코드를 제거하는 것도 이해도를 높일 수 있다. 숙련된 프로그래머는 코드가 높은 수준에서 무엇을 하는지 이해하는 데 더 쉽다. 소프트웨어 시각화는 때때로 이 과정을 가속화하는 데 사용된다.

코드 수정은 어떤 방식으로든 이루어질 수 있다. 한편으로는 코드 문서화를 업데이트할 충분한 시간을 부여받지 못하고 무질서하게 빠른 수정을 적용하는 것이 일반적이다. 다른 한편으로는 구조화된 반복적 개선은 최상위 요구사항 문서를 변경하고 시스템의 하위 수준으로 변경 사항을 전파하는 것으로 시작할 수 있다. 수정에는 종종 리팩터링(기능 변경 없이 구조 개선) 및 재구조화(구조 및 기능 동시 개선)가 포함된다. 상용 소프트웨어와 달리 자유 및 오픈 소스 소프트웨어 변경 주기는 최소한의 문서화와 함께 코딩 및 테스트로 크게 제한된다. 오픈 소스 소프트웨어 프로젝트는 대신 메일링 리스트와 많은 수의 기여자에게 의존하여 코드 베이스를 이해하고 버그를 효율적으로 수정한다.

유지보수의 추가적인 문제는 코드에 대한 거의 모든 변경이 새로운 버그 또는 예상치 못한 파급 효과를 도입하여 또 다른 수정 라운드를 필요로 한다는 것이다. 안전에 중요한 코드의 경우, 변경 사항이 발생하면 전체 소프트웨어를 재검증해야 하기 때문에 테스트가 유지보수 자원의 대부분을 차지할 수 있다. 재검증에는 코드 검토, 회귀 테스트와 단위 테스트, 통합 테스트 및 시스템 테스트의 하위 집합이 포함될 수 있다. 테스트의 목표는 이전 기능이 유지되고 새로운 기능이 추가되었는지 확인하는 것이다.

## 소프트웨어 유지보수의 범주

소프트웨어 유지보수의 핵심 목적은 제품이 사용성 요구사항을 계속 충족하도록 보장하는 것이다. 때때로 이는 제품의 기능을 처음 예상했던 것 이상으로 확장하는 것을 의미할 수 있다.

ISO/IEC 14764 사양에 따르면 소프트웨어 유지보수는 네 가지 유형으로 분류할 수 있다.

* 수정 유지보수: 일반적으로 최종 사용자가 보고한 소프트웨어 버그 또는 기타 요구사항 미충족을 수정하기 위한 소프트웨어 수정.
* 예방 유지보수: 배포 후 소프트웨어의 선제적 수정으로, 요구사항을 계속 충족하거나 아직 나타나지 않은 문제를 수정하도록 보장. 이 유형의 유지보수는 특히 높은 안전성 또는 가용성이 요구되는 시스템에 대해 수행된다. 소프트웨어 회복은 상태를 정리하고 미래의 문제를 예방하기 위한 예방 유지보수의 한 형태이다.
* 적응 유지보수: 배포 후 소프트웨어 수정으로, 변경되거나 변화하는 환경에서 소프트웨어의 지속적인 사용성을 보장.
* 완전화 유지보수: 배포 후 소프트웨어 개선으로, 사용자 경험, 처리 효율성, 유지보수성과 같은 품질 향상. 완전화 유지보수는 다른 유형의 유지보수가 수행될 경우 필수적인데, 그렇지 않으면 기존 코드 베이스의 수정이 복잡성을 증가시키고 기존 구조를 악화시키기 때문이다. 완전화 유지보수에는 문서화 재작성, 리팩터링, 성능 튜닝이 포함될 수 있다.

일부 추정에 따르면, 개선(후자 두 범주)은 소프트웨어 유지보수의 약 80%를 차지한다.

## 유지보수성

유지보수성은 기존 기능을 손상시키지 않고 소프트웨어가 쉽게 수정될 수 있도록 하는 소프트웨어의 품질이다. ISO/IEC 14764 사양에 따르면, 출시 전 소프트웨어 유지보수성을 보장하기 위한 활동은 소프트웨어 유지보수의 일부로 간주된다. 많은 소프트웨어 개발 조직은 장기적인 비용을 증가시킬 것임에도 불구하고 유지보수성을 소홀히 한다. 기술 부채는 프로그래머가 종종 게으름이나 마감 기한을 맞추기 위한 긴급성으로 인해 코드에 유지보수성을 내장하는 대신 빠르고 더러운 솔루션을 선택할 때 발생한다. 일반적인 원인은 소프트웨어 개발 노력 추정의 과소평가로, 개발에 할당된 자원이 불충분해진다. 중요한 측면 중 하나는 변경으로 인해 기존 기능이 손상되는지 감지할 수 있는 많은 양의 자동화된 소프트웨어 테스트를 보유하는 것이다.

유지보수성 지수는 코드 라인 측정, 매케이브 측정 및 할스테드 복잡도 측정의 특정 공식으로 계산할 수 있다.

유지보수성의 측정 및 추적은 시스템의 "코드 엔트로피" 또는 손상된 무결성 경향을 줄이거나 되돌리는 데 도움이 되고, 코드를 변경하는 것보다 다시 작성하는 것이 더 저렴하고/또는 덜 위험한 시기를 나타내는 것을 목표로 한다.

유지보수성의 한 가지 문제는 많은 소프트웨어 공학 과정이 이를 강조하지 않고, 명확하고 변하지 않는 사양을 가진 일회성 과제를 제공한다는 것이다. 소프트웨어 공학 과정은 실제 세계에서 발생하는 복잡한 시스템을 다루지 않는다. 소프트웨어를 유지보수할 책임이 없다는 것을 아는 개발 엔지니어는 유지보수성을 구축할 유인이 없다.

## 인력

유지보수는 종종 소프트웨어 공학자들에게 보상이 적은 직무로 간주되며, 유지보수에 배정되면 퇴사할 가능성이 더 높았다. 이는 종종 소프트웨어 개발의 비슷한 직무보다 급여가 적다. 이 작업은 종종 임시직 또는 기술력이 낮은 직원에게 할당되지만, 유지보수 엔지니어는 개발자보다 나이가 많은 경향이 있는데, 부분적으로는 오래된 기술에 익숙해야 하기 때문이다. 2008년 미국에서 일하는 130만 명의 소프트웨어 엔지니어 및 프로그래머 중 약 90만 명이 유지보수 업무를 수행하고 있었다.

기업들은 유지보수를 위한 별도의 팀을 만들기 시작했고, 이는 이 작업을 다른 회사에 아웃소싱하게 만들었으며, 21세기 초에는 때때로 원래 회사 또는 별도의 법인의 일부로 이 작업을 다른 나라로 업무위탁하게 되었다. 아웃소싱의 일반적인 공급원은 미국, 영국, 일본, 호주와 같은 선진국이며, 목적지는 보통 중국, 인도, 러시아, 아일랜드와 같은 저비용 국가이다. 업무위탁의 이유는 낮은 인건비 활용, 24시간 지원 가능, 개발자의 시간 압력 감소, 제품 시장에 지원을 더 가깝게 이동시키는 것을 포함한다. 업무위탁의 단점은 시간대 및 조직적 분열, 문화적 차이와 같은 형태의 의사소통 장벽을 포함한다. 많은 고용주가 유지보수를 기술력이 낮은 작업이자 소프트웨어 개발 단계 중 업무위탁에 가장 적합하다고 간주함에도 불구하고, 이는 고객과의 긴밀한 의사소통과 신속한 대응을 필요로 하는데, 이 두 가지 모두 이러한 의사소통 어려움으로 인해 방해받는다.

## 유지보수의 대안

소프트웨어 공학에서 레거시 시스템이라는 용어는 고정된 의미를 가지지 않지만, 종종 크고 수정하기 어렵고 현재 비즈니스 요구에 필수적인 오래된 시스템을 지칭한다. 종종 레거시 시스템은 쓸모없는 프로그래밍 언어로 작성되고, 문서화가 부족하며, 수년간의 변경 후 구조가 악화되고, 전문가에게 의존하여 작동된다. 이러한 시스템을 다룰 때, 어느 시점에는 너무 많은 기술 부채가 축적되어 유지보수가 실용적이지 않거나 경제적이지 않게 된다. 다른 선택지로는 다음과 같은 것들이 있다.

* 동결—레거시 시스템에 더 이상 작업하지 않는다. 이 옵션은 공급업체가 유지보수 비용을 피하면서 가능한 한 오랫동안 수익을 추출하려고 할 때 선택될 수 있다.
* 레거시 시스템의 기능을 다른 회사에 아웃소싱하는 것, 특히 핵심 비즈니스 기능으로 간주되지 않는 경우.
* 기존 레거시 시스템을 폐기하고 동일한 목적을 달성하기 위해 새로운 애플리케이션을 처음부터 재개발하는 것. 그러나 이 접근 방식은 작동하는 시스템을 폐기하기 때문에 비효율적이며, 이 접근 방식으로는 새 시스템이 변화하는 비즈니스 요구사항을 충족하지 못할 위험이 있다.
* 레거시 애플리케이션을 추상화 계층으로 래핑하여 오래된 인터페이스를 단순화하는 것. 소스 코드는 수정되지 않지만 새 인터페이스를 통해 시도되고 테스트된 구성 요소에 새 애플리케이션이 접근할 수 있다. 이 접근 방식은 레거시 시스템 유지보수와 관련된 어떤 문제도 해결하지 못한다. 데이터베이스, 기능 및 전체 애플리케이션은 이러한 방식으로 래핑될 수 있다.
* 레거시 시스템을 새 플랫폼으로 마이그레이션하는 것. 이는 레거시 시스템의 구현, 설계, 사양 및 요구사항을 재사용하여 새 소프트웨어 개발 비용을 줄일 수 있다. 마이그레이션은 5~10년이 걸릴 수 있지만, 더 큰 유연성과 소프트웨어 유지보수에서 장기적인 절감을 가져온다. 비용의 80%는 테스트에 있다. 즉, 새 시스템이 이전 시스템과 동일한 출력을 갖도록 보장하는 것이다. 새 시스템이 완성된 후에는 비즈니스 기능에 최소한의 중단으로 이전 시스템에서 새 시스템으로 전환해야 한다.

## 연구

소프트웨어 개발 자원의 대부분을 차지함에도 불구하고 유지보수는 소프트웨어 개발에서 가장 연구가 덜 된 단계이다. 문헌의 대부분은 처음부터 유지보수 가능한 코드를 개발하는 방법에 중점을 두었으며, 엔지니어들에게 유지보수성을 우선순위로 삼도록 동기를 부여하는 데는 덜 집중했다. 2020년 기준, 유지보수 노력을 줄이기 위한 코드 리팩터링의 자동화된 솔루션은 활발한 연구 분야이며, 기계 학습으로 강화된 유지보수성 평가도 마찬가지이다.

* 총소유비용

* Ali, Muhammad; Cheema, Sehrish Munawar; Naz, Ammerha; Pires, Ivan Miguel (2024). 〈SAMSEF: An Agile Software Maintenance Leveraging Scrum Framework for Improved Efficiency and Effectiveness〉 (영어). 《Good Practices and New Perspectives in Information Systems and Technologies》. Lecture Notes in Networks and Systems **989**. Springer Nature Switzerland. 126–136쪽. doi:10.1007/978-3-031-60227-6\_11. ISBN 978-3-031-60226-9.
* Alsolai, Hadeel; Roper, Marc (2020). 《A systematic literature review of machine learning techniques for software maintainability prediction》 (PDF). 《Information and Software Technology》 **119**. 106214쪽. doi:10.1016/j.infsof.2019.106214.
* Baqais, Abdulrahman Ahmed Bobakr; Alshayeb, Mohammad (2020). 《Automatic software refactoring: a systematic literature review》. 《Software Quality Journal》 **28**. 459–502쪽. doi:10.1007/s11219-019-09477-y.
* Madhusudhan, V.; Suma, V.; Rao, Jawahar J. (2017). 《Software Maintenance: From the Perspective of Effort and Cost Requirement》 (영어). Proceedings of the International Conference on Data Engineering and Communication Technology. Springer. 759–768쪽. ISBN 978-981-10-1678-3.
* Rahman, Hanif Ur; da Silva, Alberto Rodrigues; Alzayed, Asaad; Raza, Mushtaq (2024). 《A Systematic Literature Review on Software Maintenance Offshoring Decisions》. 《Information and Software Technology》 **172**. 107475쪽. doi:10.1016/j.infsof.2024.107475.
* Rahman, Hanif Ur; Raza, Mushtaq; Afsar, Palwasha; Khan, Habib Ullah (2021). 《Empirical Investigation of Influencing Factors Regarding Offshore Outsourcing Decision of Application Maintenance》. 《IEEE Access》 **9**. 58589–58608쪽. Bibcode:2021IEEEA...958589R. doi:10.1109/ACCESS.2021.3073315. hdl:10576/37687. ISSN 2169-3536.
* Reifer, Donald J. (2012). 《Software Maintenance Success Recipes》 (영어). CRC Press. ISBN 978-1-4398-5167-8.
* Tripathy, Priyadarshi; Naik, Kshirasagar (2014). 《Software Evolution and Maintenance: A Practitioner's Approach》 (영어). John Wiley & Sons. ISBN 978-0-470-60341-3.
* Ulziit, Bayarbuyan; Warraich, Zeeshan Akhtar; Gencel, Cigdem; Petersen, Kai (2015). 《A conceptual framework of challenges and solutions for managing global software maintenance》. 《Journal of Software: Evolution and Process》 **27**. 763–792쪽. doi:10.1002/smr.1720.
* Varga, Ervin (2018). 《Unraveling Software Maintenance and Evolution: Thinking Outside the Box》 (영어). Springer. ISBN 978-3-319-71303-8.