15. 폐기
20 Mar 2023 | Software Engineering
15. 폐기
- 새로운 기술, 라이브러리, 기법, 언어 등이 등장하면서 기존의 시스템은 서서히 구식이 되어감
- 이러한 오래된 시스템을 유지하는데에 비용이 들어가고 난해한 옛 기술에 대한 전문지식이 필요함
- 낡은 시스템을 떼어 내는 것은 고통스럽지만, 궁극적으로 떼어내는 것이 이득
- 이주를 순차적으로 신행하여 궁극적으로 낡은 시스템을 완전히 걷어내는 과정을 폐기(deprecation) 이라고 함
- 폐기는 시스템 관리에 세월을 고민해야하는 소프트웨어 엔지니어링 원칙에 속함
- 제대로 폐기를 한다면 자원을 아끼고 개발 속도를 높여주지만, 그렇지 못하면 방치보다 더 큰 비용을 치를 수 있음
15.1 폐기시키는 이유
- 기본 전제 : 코드는 자산이 아닌 부채다.
- 자산은 기능이다.
- 코드에는 비용이 따라온다
- 일부는 구축시 발생하지만, 대부분은 구축 후 생이 끝날 떄까지 유지보수하는 데서 발생
- 시스템이 오래되었다고 해서 무조건 폐기시켜야 하는 것은 아님 (ex: LaTeX)
- 같은 일에 구식과 신식 시스템을 모두 사용하는 것도 큰 비용을 초래함
- 두 시스템간 정보 교류를 위한 복잡한 변환 코드 발생
- 둘 모두 버전업을 계속하며 서로를 의존하게 됨 -> 망조
코드는 자산이 아닌 부채이다. 코드 자체는 가치를 창출하지 않는다, 기능이 가치를 창출함.
특정 기능을 지원하는 최소한의 단순한 코드가 좋다.
- 한 조직이 동시에 진행할 수 있는 폐기 작업의 양에는 한계가 있음
- 어느날 갑자기 좋은 도로를 만들겠다고 모든 도로를 공사하면? -> 망함
- 폐기 대상을 신중하게 선택한 다음, 집중해서 빠르게 완료하는 것이 중요함
15.2 폐기는 왜 그리 어려운가?
- 하이럼의 법칙
- 시스템은 사용자가 늘수록 설계자가 예상하지 못한 이용방식이 늘어나서 폐기 작업이 어려워짐
- 새로운 시스템은 더 좋지만 기존과 다르다
- 옛 시스템을 향한 애착이 의외의 저항으로 나타날 수 있음
- 정치 (politics)적인 문제로 해결해야 함
구글의 농담 : 일을 처리하는 방법은 두가지다. 폐기 중인 시스템을 이용하거나, 아직 준비가 덜 된 시스템을 이용하거나.
15.2.1 설계 단계에서의 폐기
- 시스템을 처음 구축할 때 폐기 계획을 세울 수 있음
- 원자로 설계 시, 이를 해체하기 쉬운 설계를 고민한다
- 큰 회사일수록 마음대로 제품을 폐기할 수 없기 때문에 큰 고민이 필요하다.
15.3 폐기 유형
- ‘권고’와 ‘강제’로 구분 가능
15.3.1 권고 폐기
- 권고 폐기 (advisory deprecation) : 기한이 없고 조직에서도 우선순위가 높지 않은 경우
- 다른 말로 희망 폐기 (aspirational deprecation)
- 이 유혀으이 폐기에는 대체로 강제성이 없음
- 하지만, 희망은 전략이 아니다
- 권고폐기는 새로운 시스템이 사용자에게 주는 혜택이 매우 클 때 효ㅑ과가 좋음
- ‘정말 좋다’ 정도가 아니라 ‘혁신적이다’ 수준이어야 함
- 구글에서의 경험 상 구식 시스템의 사용률이 살짝 줄어들 수는 있지만 적극적인 이주로 이어지는 일은 거의 없음
15.3.2 강제 폐기
- 강제 폐기 (compulsory deprecation) : 낡은 시스템의 지원 종료일을 못 박는 평태
- 강제 폐기를 효율적으로 수행하려면 기존 시스템을 완전히 제거하는 역할을 전담할 팀을 하나 따로 꾸리는 게 가장 좋음
- 강제 폐기가 잘 이루어지려면 일정대로 집행할 수 있는 권한이 주어져야 함
- 그래프 분석만으로 의존성을 빠짐없이 찾아 내기는 어려움
- 기존 시스템의 가동을 임시로 중단시키는 빈도와 시간을 점차 늘려보는 실험을 해보면 여전히 기존 시스템을 이용중인 서비스들은 작동하지 않을 것
15.3.3 폐기 경고
- 권고 폐기든 강제 폐기든 해당 시스템이 폐기 대상임을 프로그래밍적으로 알려주면 좋음
- 실제로 경고들이 날이 갈수록 불어나는 일이 벌어짐 -> 경보 피로 (alert fatigue)
폐기 경고 메시지의 중요한 2가지 특성 실행 가능성 (actionability)과 적시성 (relevance)
- 실행 가능한 경고 : 폐기 시킬 함수를 호출한 대상에게 대체 API를 알려주는 도구 등 어떤 경우든 경고 메시지에는 폐기될 시스템으로의 의존성을 떼어내기 위해 엔지니어가 수행할 다음 단계를 야려줘야 함
- 적시에 뜨는 경고 : 사용자가 실제로 관련 동작을 수행할 때 경고가 떠야함, 함수 폐기 경고는 함수를 사용할 때, 데이터 마이그레이션 안내 메일은 기존 시스템 제거 직전 주말이 아니라 몇 달 전에 보내는게 좋음
15.4 폐기 프로세스 관리
15.4.1 프로세스 소유자
- 시스템이 아무리 경고를 쏟아내도 소유자가 명확하지 않으면 프로세스는 직척되지 않음
- 소유자 없이는 아무것도 폐기시키지 마라! 폐기 업무를 시스템 이용자들에게 절대 떠넘기지 마라!
- 소유자 없는 폐기는 모든 낡은 시스템들을 무한정 유지하겠다는 선언과 같음
- 소유자가 없어진 버린 프로젝트에는 폐기 전문가를 배정하여 하루빨리 제거애햐 함
- 폐기 전문 팀을 두어 낡은 시스템 제거를 주된 목표로 진행시켜야 함
15.4.2 마일스톤
- 완전히 제거하는 것만이 유일한 마일스톤이 아니다!
- 폐기팀을 관리할 때도 측정할 수 있고 고객에게 가치를 전달해주는 명확하고 점진적인 마일스톤들을 세워야 함
- 폐기시킬 때도 핵심 컴포넌트들을 하나씩 제거하는 걸 점진적 마일스톤으로 삼으면 효과가 좋다.
15.4.3 폐기 도구
발견
- 낡은 시스템을 누가, 어떻게 이용하고 있는지를 알아내야 함
- 폐기 작업 초기에는 낡은 시스템을 이용하는 곳을 찾은 다음 예상하지 못한 방식으로 이용하지는 않는지를 알아내는 일이 대부분을 차지 함
- 구글에서는 Code Search같은 검색 도구와 Kythe 같은 정적 분석 도구를 사용
- 런타임 의존성은 정적 라이브러리나 씬 클라이언트를 사용할 때 생겨나므로 이 기법으로 폐기 프로세스를 시작하고 진행하는 데 필요한 다양한 정보를 얻을 수 있음
- 프로덕션 시스템에서 얻은 로그 데이터와 런타임 데이터 샘플은 동적 의존성 관련 문제를 발견하는데 유용
- 구글은 폐기시킬 심볼의 참조가 모두 제거되었는지를 확인하는 데 전역 테스트 스위트를 신탁처럼 이용함
마이그레이션(이주)
- 새로운 라이브러리나 런타임 서비스를 이용하도록 코드베이스를 업데이트할 때는 대규모 변경 프로세스와 도구가 매우 유용함
퇴행 방지
- 새로 작성하는 코드에서 폐기 중인 대상을 이용하는 걸 퇴행이라 함
- 새로 커밋되는 코드에서 폐기 중인 시스템을 이용하려 든다면 뜨끔해지게끔 경고해주는 것이 좋음
- 퇴행을 실무 수준에서 방지하기 위해 구글은
Tricorder
라는 정적 분석 프레임워크를 이용
- 폐기 중인 시스템을 호출하는 코드를 추가한 사용자에게 적절한 대체 방법을 피드백함
- 폐기 시스템의 소유자가 컴파일러 애너테이션에 자바의
@deprecated
애너테이션 같은 폐기 심볼을 추가해두면 Tricorder가 자동으로 알려 줌
- 거시적으로는 빌드 시스템에 가시성 (visibility) 허용몰곡을 도입하여 폐기된 시스템에 의존하는 시스템이 새로 생겨나는 일을 막음
핵심 정리
- 소프트웨어 시스템이 존재하는 한 유지보수 비용은 계속 발생하므로 제거하는 비용과 저울질해봐야 함
- 시스템을 원래 설계 의도와 다르게 사용하는 사용자가 많기 때문에 제거하는 일이 아예 처음부터 만들기보다 어려울 때도 많음
- 폐기 비용을 생각하면 새로운 시스템으로 교체하기보다 기존 시스템을 개선하는 편이 일반적으로 더 저렴
- 폐기 여부를 결정하려면 비용을 따져와야 함, 하지만 이는 매우 어려움. 생태계 비용은 곳곳에 퍼져있어서 측정하기 어려움. 폐기와 제거 비용도 마찬가지로 흩어져 있는 경우가 많음
15. 폐기
- 새로운 기술, 라이브러리, 기법, 언어 등이 등장하면서 기존의 시스템은 서서히 구식이 되어감
- 이러한 오래된 시스템을 유지하는데에 비용이 들어가고 난해한 옛 기술에 대한 전문지식이 필요함
- 낡은 시스템을 떼어 내는 것은 고통스럽지만, 궁극적으로 떼어내는 것이 이득
- 이주를 순차적으로 신행하여 궁극적으로 낡은 시스템을 완전히 걷어내는 과정을 폐기(deprecation) 이라고 함
- 폐기는 시스템 관리에 세월을 고민해야하는 소프트웨어 엔지니어링 원칙에 속함
- 제대로 폐기를 한다면 자원을 아끼고 개발 속도를 높여주지만, 그렇지 못하면 방치보다 더 큰 비용을 치를 수 있음
15.1 폐기시키는 이유
- 기본 전제 : 코드는 자산이 아닌 부채다.
- 자산은 기능이다.
- 코드에는 비용이 따라온다
- 일부는 구축시 발생하지만, 대부분은 구축 후 생이 끝날 떄까지 유지보수하는 데서 발생
- 시스템이 오래되었다고 해서 무조건 폐기시켜야 하는 것은 아님 (ex: LaTeX)
- 같은 일에 구식과 신식 시스템을 모두 사용하는 것도 큰 비용을 초래함
- 두 시스템간 정보 교류를 위한 복잡한 변환 코드 발생
- 둘 모두 버전업을 계속하며 서로를 의존하게 됨 -> 망조
코드는 자산이 아닌 부채이다. 코드 자체는 가치를 창출하지 않는다, 기능이 가치를 창출함. 특정 기능을 지원하는 최소한의 단순한 코드가 좋다.
- 한 조직이 동시에 진행할 수 있는 폐기 작업의 양에는 한계가 있음
- 어느날 갑자기 좋은 도로를 만들겠다고 모든 도로를 공사하면? -> 망함
- 폐기 대상을 신중하게 선택한 다음, 집중해서 빠르게 완료하는 것이 중요함
15.2 폐기는 왜 그리 어려운가?
- 하이럼의 법칙
- 시스템은 사용자가 늘수록 설계자가 예상하지 못한 이용방식이 늘어나서 폐기 작업이 어려워짐
- 새로운 시스템은 더 좋지만 기존과 다르다
- 옛 시스템을 향한 애착이 의외의 저항으로 나타날 수 있음
- 정치 (politics)적인 문제로 해결해야 함
구글의 농담 : 일을 처리하는 방법은 두가지다. 폐기 중인 시스템을 이용하거나, 아직 준비가 덜 된 시스템을 이용하거나.
15.2.1 설계 단계에서의 폐기
- 시스템을 처음 구축할 때 폐기 계획을 세울 수 있음
- 원자로 설계 시, 이를 해체하기 쉬운 설계를 고민한다
- 큰 회사일수록 마음대로 제품을 폐기할 수 없기 때문에 큰 고민이 필요하다.
15.3 폐기 유형
- ‘권고’와 ‘강제’로 구분 가능
15.3.1 권고 폐기
- 권고 폐기 (advisory deprecation) : 기한이 없고 조직에서도 우선순위가 높지 않은 경우
- 다른 말로 희망 폐기 (aspirational deprecation)
- 이 유혀으이 폐기에는 대체로 강제성이 없음
- 하지만, 희망은 전략이 아니다
- 권고폐기는 새로운 시스템이 사용자에게 주는 혜택이 매우 클 때 효ㅑ과가 좋음
- ‘정말 좋다’ 정도가 아니라 ‘혁신적이다’ 수준이어야 함
- 구글에서의 경험 상 구식 시스템의 사용률이 살짝 줄어들 수는 있지만 적극적인 이주로 이어지는 일은 거의 없음
15.3.2 강제 폐기
- 강제 폐기 (compulsory deprecation) : 낡은 시스템의 지원 종료일을 못 박는 평태
- 강제 폐기를 효율적으로 수행하려면 기존 시스템을 완전히 제거하는 역할을 전담할 팀을 하나 따로 꾸리는 게 가장 좋음
- 강제 폐기가 잘 이루어지려면 일정대로 집행할 수 있는 권한이 주어져야 함
- 그래프 분석만으로 의존성을 빠짐없이 찾아 내기는 어려움
- 기존 시스템의 가동을 임시로 중단시키는 빈도와 시간을 점차 늘려보는 실험을 해보면 여전히 기존 시스템을 이용중인 서비스들은 작동하지 않을 것
15.3.3 폐기 경고
- 권고 폐기든 강제 폐기든 해당 시스템이 폐기 대상임을 프로그래밍적으로 알려주면 좋음
- 실제로 경고들이 날이 갈수록 불어나는 일이 벌어짐 -> 경보 피로 (alert fatigue)
폐기 경고 메시지의 중요한 2가지 특성 실행 가능성 (actionability)과 적시성 (relevance)
- 실행 가능한 경고 : 폐기 시킬 함수를 호출한 대상에게 대체 API를 알려주는 도구 등 어떤 경우든 경고 메시지에는 폐기될 시스템으로의 의존성을 떼어내기 위해 엔지니어가 수행할 다음 단계를 야려줘야 함
- 적시에 뜨는 경고 : 사용자가 실제로 관련 동작을 수행할 때 경고가 떠야함, 함수 폐기 경고는 함수를 사용할 때, 데이터 마이그레이션 안내 메일은 기존 시스템 제거 직전 주말이 아니라 몇 달 전에 보내는게 좋음
15.4 폐기 프로세스 관리
15.4.1 프로세스 소유자
- 시스템이 아무리 경고를 쏟아내도 소유자가 명확하지 않으면 프로세스는 직척되지 않음
- 소유자 없이는 아무것도 폐기시키지 마라! 폐기 업무를 시스템 이용자들에게 절대 떠넘기지 마라!
- 소유자 없는 폐기는 모든 낡은 시스템들을 무한정 유지하겠다는 선언과 같음
- 소유자가 없어진 버린 프로젝트에는 폐기 전문가를 배정하여 하루빨리 제거애햐 함
- 폐기 전문 팀을 두어 낡은 시스템 제거를 주된 목표로 진행시켜야 함
15.4.2 마일스톤
- 완전히 제거하는 것만이 유일한 마일스톤이 아니다!
- 폐기팀을 관리할 때도 측정할 수 있고 고객에게 가치를 전달해주는 명확하고 점진적인 마일스톤들을 세워야 함
- 폐기시킬 때도 핵심 컴포넌트들을 하나씩 제거하는 걸 점진적 마일스톤으로 삼으면 효과가 좋다.
15.4.3 폐기 도구
발견
- 낡은 시스템을 누가, 어떻게 이용하고 있는지를 알아내야 함
- 폐기 작업 초기에는 낡은 시스템을 이용하는 곳을 찾은 다음 예상하지 못한 방식으로 이용하지는 않는지를 알아내는 일이 대부분을 차지 함
- 구글에서는 Code Search같은 검색 도구와 Kythe 같은 정적 분석 도구를 사용
- 런타임 의존성은 정적 라이브러리나 씬 클라이언트를 사용할 때 생겨나므로 이 기법으로 폐기 프로세스를 시작하고 진행하는 데 필요한 다양한 정보를 얻을 수 있음
- 프로덕션 시스템에서 얻은 로그 데이터와 런타임 데이터 샘플은 동적 의존성 관련 문제를 발견하는데 유용
- 구글은 폐기시킬 심볼의 참조가 모두 제거되었는지를 확인하는 데 전역 테스트 스위트를 신탁처럼 이용함
마이그레이션(이주)
- 새로운 라이브러리나 런타임 서비스를 이용하도록 코드베이스를 업데이트할 때는 대규모 변경 프로세스와 도구가 매우 유용함
퇴행 방지
- 새로 작성하는 코드에서 폐기 중인 대상을 이용하는 걸 퇴행이라 함
- 새로 커밋되는 코드에서 폐기 중인 시스템을 이용하려 든다면 뜨끔해지게끔 경고해주는 것이 좋음
- 퇴행을 실무 수준에서 방지하기 위해 구글은
Tricorder
라는 정적 분석 프레임워크를 이용- 폐기 중인 시스템을 호출하는 코드를 추가한 사용자에게 적절한 대체 방법을 피드백함
- 폐기 시스템의 소유자가 컴파일러 애너테이션에 자바의
@deprecated
애너테이션 같은 폐기 심볼을 추가해두면 Tricorder가 자동으로 알려 줌 - 거시적으로는 빌드 시스템에 가시성 (visibility) 허용몰곡을 도입하여 폐기된 시스템에 의존하는 시스템이 새로 생겨나는 일을 막음
핵심 정리
- 소프트웨어 시스템이 존재하는 한 유지보수 비용은 계속 발생하므로 제거하는 비용과 저울질해봐야 함
- 시스템을 원래 설계 의도와 다르게 사용하는 사용자가 많기 때문에 제거하는 일이 아예 처음부터 만들기보다 어려울 때도 많음
- 폐기 비용을 생각하면 새로운 시스템으로 교체하기보다 기존 시스템을 개선하는 편이 일반적으로 더 저렴
- 폐기 여부를 결정하려면 비용을 따져와야 함, 하지만 이는 매우 어려움. 생태계 비용은 곳곳에 퍼져있어서 측정하기 어려움. 폐기와 제거 비용도 마찬가지로 흩어져 있는 경우가 많음