Skip to content

Latest commit

 

History

History
132 lines (101 loc) · 18 KB

15. Deprecation.md

File metadata and controls

132 lines (101 loc) · 18 KB

15. 폐기

  • 새로운 기술, 라이브러리, 기법, 언어 등이 등장하면서 주변 환경이 끊임없이 변하기 때문에 기존의 시스템은 서서히 구식이 되어 간다.
  • 오래된 시스템을 유지하려면 관리하는 데 지속해서 비용이 들어가고 난해한 옛 기술에 대한 전문지식이 필요해진다.
  • 기존에 의존하던 낡은 생태계에서 떼어내 새로운 환경으로 이주시키려면 일반적으로 처리해야 할 작업도 늘어난다.
  • 낡은 시스템을 언제까지고 끌고 다니기보다는 차라리 완전히 떼어내는 편이 나을 때가 많다.
  • 이주를 순차적으로 진행하여 궁극적으로는 낡은 시스템을 완전히 걷어내는 과정을 폐기(deprecation)라 한다.
  • 장기간 운영되는 소프트웨어 생태계에서는 폐기 계획을 세워고 올바로 실행해야 한다. 그러면 시스템을 운영하고 업그레이드하는 과정에서 수많은 중복 투자와 복잡성을 줄여준다. 결국은 자원을 아끼고 개발속도를 높여준다.
  • 제대로 폐기시키지 못하면 시스템을 방치할 때보다 더 큰 비용을 치를 수 있다.
  • 폐기시키는 데는 추가 노력이 들지만 시스템 설계 댄계에서 계획을 세워두면 훨씬 수월하게 진행할 수 있다.
  • 최종 사용자용 제품이 아닌 기술적인 시스템을 폐기시키는 데 집중한다. '시스템 소유자가 공개 여부를 통제할 수 있는' 낡은 시스템을 폐기시키는 기술적이고 정책적인 측면을 논한다.

15.1 폐기시키는 이유

  • '코드는 자산이 아니라 부채다'라는 기본 전제에서 시작한다.
  • 시스템을 운용하는 데 드는 운영 자원, 그리고 주변 생태계의 진화에 발맞춰 코드베이스를 업데이트하는 노력 등 비용이 계속 투입된다는 사실은 낡아가는 시스템을 계속 운영할지 아니면 슬슬 폐기시킬지를 놓고 손익을 저울질해봐야 함을 뜻한다.
  • 시스템이 오래됐다고 해서 무조건 폐기시켜야 하는 건 아니다. 몇 해에 걸쳐 정교하게 다듬어져서 자신의 영역에서 독보적인 소프트웨어가 될 수 있다 (LaTex).
  • 신식 시스템은 자원을 더 효율적으로 쓰고, 보안도 뛰어나고, 지속 가능성이 높은 구조를 갖췄을 수 있다. 같은 일에 신식과 구식 시스템을 모두 활용하는 것도 당장은 크게 문제 없어 보일지 모른다. 하지만 날이 갈수록 두 가지 시스템을 같이 유지보수하는 비용은 눈덩이처럼 불어날 것이다. 새 시스템을 사용해야 하는 사용자들도 여전히 옛 시스템에서 완전히 자유롭지 못할 것이다.
  • 두 시스템은 정보를 교류해야 해서 복잡한 변환 코드가 필요할 것이다. 둘 모두 버전업을 계속하며 서로를 의존하게 되어 다른 하나를 떼어내기가 점점 어려워질 것이다. 이 상황이 오래 지속되면 신식 시스템의 개선 작업마저도 지연시키는 결과를 초래한다. 구형 시스템과의 호환성을 계속 유지해야 하기 때문이다. 이쯤 되면 낡은 시스템을 걷어내고 신식 시스템을 더 빠르게 진화시키는 편이 이득이다.
  • 코드 자체는 비용을 낳기 때문에 기능이 같다면 코드 자체는 단순할수록 좋다.
  • 우리는 얼마나 많은 코드를 작성하느냐나 코드베이스가 얼마나 큰가가 아니라, 단위 코드당 얼마나 많은 기능을 제공하느냐에 집중하여 이 지표를 극대화해야 한다.
  • 지나친 코드나 더 이상 필요 없는 시스템들을 제거해야 한다. 이 때 필요한 것이 바로 폐기 정책과 절차다.
  • 폐기 대상을 신중하게 선택한 다음, 집중해서 빠르게 완료하는 게 중요하다.

15.2 폐기는 왜 그리 어려운가?

  • 하이럼의 법칙에 의해 시스템은 사용자 수가 늘수록 설계자가 예상하지 못한, 전에 본 적 없는 방식으로 이용될 가능성이 커져서 폐기 작업을 그만큼 어렵게 만든다.
    • 사용자가 발견한 새로운 사용법은 '되니깐 쓰는 것'이지 시스템이 '보장하는 동작'이 아니다.
    • 시스템 하나를 제거한다는 것은 돌이킬 수 없는 변경이 될 수 있다.
  • 일반적으로 같은 (혹은 더 나은) 기능을 제공하는 새로운 시스템이 준비된 다음에야 폐기를 고려하게 된다. 새로운 시스템은 아마도 더 좋을 것이며, 동시에 분명히 다를 것이다. 두 시스템의 기능이 일대일로 일치하는 일은 드물며, 옛 시스템의 쓰임 하나하나를 새로운 시스템을 기준으로 새로 확인해봐야 한다.
  • 옛 시스템을 향한 애착이 의외의 저항으로 나타날 수 있다.
    • 궁극적으로는 스스로에게 피해가 돌아온다. 시스템이 낡으면 조직에 비용을 발생시키므로 제거해야 한다.
    • 기존 코드를 제거하려는 데서 오는 거부감을 완화해주는 방책으로, 구글은 코드 리포지터리의 과거 이력까지 검색할 수 있도록 했다. 과거 이력은 제거된 코드라도 언제든 다시 찾을 수 있게 하여 상실감을. 줄여준다.
  • 비용을 확보해 폐기를 진행하려면 정치(politics)라는 관문도 통과해야 한다.
    • 팀을 꾸리고 시간을 들여 오래된 시스템을 제거하는 데는 실제로 눈에 보이는 비용이 드는 반면, 아무것도 하지 않고 시스템을 방치해서 새어나가는 비용은 눈에 잘 띄지 않는다.
    • 특히 신기능 개발이 지연된다면 폐기시키는 편이 오히려 더 이득임을 이해관계자들 에게 납득시키기가 더욱 어렵다.
  • 현장에서 조금씩 리팩터링하여 폐기를 점진적으로 진행하면 기존 시스템을 계속 운영하면서도 이용자에게 더 쉽게 혜택을 제공할 수 있다.

15.2.1 설계 단계에서의 폐기

  • 소프트웨어 시스템의 폐기 계획 역시 시스템을 처음 구축할 때 함께 세워둘 수 있다.
  • 엔지니어들이 '이 시설은 언젠가는 해체시켜야 한다'라는 사실을 인지하고 있느냐가 실제로 원자력 발전소 설계에 큰 영향을 준다.
  • 많은 소프트웨어 엔지니어가 기존 시스템을 유지보수하는 일보다는 새로운 시스템을 구축하고 런칭하는 일을 원한다. 그래서 처음부터 폐기를 고려해 설계해야 할 동기를 떨어뜨린다.
  • 언젠가 이루어질 폐기가 매끄럽게 진행되게 하려면 시스템을 설계할 때 무엇을 고려해야 하는가?
    • 내 제품의 고객이 잠재적인 대체품으로 이주하기가 얼마나 쉬울까?
    • 내 시스템을 한 부분씩 점진적으로 교체하려면 어떻게 해야 할까?
  • 이 질문들은 사실 시스템이 의존성을 이용하고 외부로 제공하는 방식과 관련이 깊다.
  • 프로젝트의 장기 지원 여부는 조직에서 프로젝트를 처음 승인할 때 결정된다.
  • 회사에서 기대 수명 동안 제대로 지원하지 못할 것 같은 프로젝트는 시작하지 마라. 회사에서 폐기시키기로 결정한다 해도 여전히 비용이 든다. 하지만 잘 계획하고 적절한 도구와 정책 개발에 투자한다면 이 비용을 상당히 줄일 수 있다.

15.3 폐기 유형

15.3.1 권고 폐기(advisory deprecation)

  • 기한이 없고 조직에서도 우선순위가 높지 않은(혹은 폐기 작업에 자원을 투입할 의지가 없는) 경우.
  • 담당 팀은 고객들이 새로운 시스템으로 이주하기를 바라지만 서둘러 이주를 돕거나 옛 시스템을 바로 걷어낼 계획은 없다. 이런 관점에서 희망 폐기(aspirational deprecation)이라고 부르기도 한다.
  • 강제성이 없다.
  • 반드시 기능과 안정성 모두 정식 서비스가 가능한 수준에 올라섰을 때, 그리고 새로운 사용자를 확실하게 지원할 준비가 되었을 때 시행해야 한다.
  • 권고 폐기는 새로운 시스템이 사용자에게 주는 혜택이 매우 클 때 효과가 좋다. 단순히 사용자들에게 새로운 시스템의 출시를 알리고 자가 이주 도구를 제공하는 정도만으로도 이주가 빠르게 이루어진다. 이 때 혜택은 '정말 좋다' 정도가 아니라 '혁신적이다' 수준이 되어야 한다.

15.3.2 강제 폐기(compulsory deprecation)

  • 낡은 시스템의 지원 종료일을 못 박는 형태로 이루어진다. 종료일 이후까지 이주를 끝내지 못한 시스템은 제대로 작동되지 않는다.
  • 큰 조직에서 강제 폐기를 효율적으로 수행하려면 기존 시스템을 완전히 제거하는 역할을 전담할 팀을 하나 따로 꾸리는 게 가장 좋다. 이주 관련 전문지식을 집중시키는 것.
  • 강제 폐기가 잘 이루어지려면 일정대로 집행할 수 있는 권한이 주어져야 한다. 일정이 고정불변이어야 한다는 뜻은 아니지만, 이주 과정에서 충분히 경고하였다면 기한을 넘겨서까지 기존 시스템을 이용하는 시스템에 문제가 생겨도 책임을 묻지 않도록 해야 한다. 이런 권한이 없다면 고객 팀들은 폐기 작업을 무시하고, 대신 새로운 기능 구현처럼 자신들에게 더 시급하다고 생각하는 다른 일에 매진할 것이다.
  • 인력 지원 없이 강제 폐기를 밀어붙이면 고객 팀들의 반발을 사서 폐기 작업이 지연될 것이다. 강제 폐기를 시도하려면 반드시 전문 팀을 꾸려 적극적으로 지원하게 할 것을 강력히 권고한다.
  • 정책적으로 뒷받침되더라도 강제 폐기는 여전히 정치적인 반대로 직면할 수 있다. 핵심 팀이 거부한다면 폐기를 강제로 진행하기에는 현실적으로 매우 어렵다.
  • 구글에서는 어떤 시스템을 폐기시켜야 할 때면 담당 팀이 D-데이 몇 달 또는 몇 주 전에 서비스의 점진적인 일시 중지 일정을 계획해 공표한다. 구글의 DiRT(재해 복구 테스트) 연습과 비슷하게 이 실험을 통해 인지하지 못하던 시스템들 사이의 의존성을 새로 발견하는 경우가 많다. 의존성을 발견한 팀은 폐기에 대비한 해법을 계획하거나, 여의치 않으면 폐기 담당 팀과 협의해 일정을 조정할 수 있다.

15.3.3 폐기 경고

  • 권고 폐기든 강제 폐기든 해당 시스템이 폐기 대상임을 프로그래밍적으로 알려주면 좋다.
  • 폐기 경고는 새로운 사용자 유입은 대체로 잘 막아주지만 기존 사용자들을 이주시키는 데는 효과가 거의 없다.
  • 경보 피로(alert fatigue)로 인해 이용자들이 경고를 무시해버릴 수 있다.
  • 사용자에게 전달되는 폐기 경고 메시지에 반드시 담겨야할 특성
    • 실행 가능성(actionability), 적시성(relevance)
    • 해당 문제와 관련한 전문 지식을 갖춘 평균적인 엔지니어가 이론적으로 뿐 아니라 실질적인 조치를 취할 수 있다면 실행 가능한 경고이다.
    • 어떤 경우든 경고 메시지에는 폐기될 시스템으로의 의존성을 떼어내기 위해 엔지니어가 수행할 다음 단계를 알려줘야 한다.
    • 폐기 경고가 유용하려면 적시에 떠야 한다. 사용자가 실제로 관련 동작을 수행할 때 경고가 뜬다면 적절한 때라고 할 수 있다. 함수 폐기 경고는 엔지니어가 해당 함수를 사용하는 코드를 작성할 때 알려주는 게 가장 좋다.
    • 데이터 마이그레이션 안내 메일은 기존 시스템 제거 직전 주말이 아니라 몇 달 전에 보내는 게 좋다.

15.4 폐기 프로세스 관리

  • 폐기 프로젝트는 시스템 구축이 아니라 해체가 목적이므로 결이 전혀 다를 것 같지만 관리하고 실행해야 한다는 점에서 다른 소프트웨어 엔지니어링 프로젝트와 비슷하다.

15.4.1 프로세스 소유자

  • 시스템이 아무리 경고를 쏟아내도 소유자가 명확하지 않으면 폐기 프로세스가 진척되지 않는다는 것을 알았다.
  • 소유자 없이는 아무것도 폐기시키지 말고, 폐기 업무를 시스템 이용자들에게 절대 떠넘기지 마라.
  • 소유자 없는 폐기는 모든 낡은 시스템들을 무한정 유지하겠다는 선언과 같으며, 이용자에게 떠넘기면 권고 폐기와 같아진다. 책임자를 두어 폐기에 필요한 전문지식을 집중시키면 집행 비용을 더 투명하게 알 수 있어 실제로도 비용이 절감된다.
  • 소유권을 조정하다 보면 종종 버려진 프로젝트들이 문제를 일으킨다. 이런 프로젝트가 저절로 사라지기는 어렵다. 이런 프로젝트에는 폐기 전문가를 배정하여 하루빨리 제거해야 한다. 폐기 전문가에게 맡겨 시스템을 완벽하게 걷어내야 뜻하지 않은 상황에 갑자기 문제를 일으키는 사태를 예방할 수 있다.
  • 폐기 전문 팀을 두어 낡은 시스템 제거를 주된 목표로 진행시켜야 한다.

15.4.2 마일스톤

  • 폐기 프로젝트에서는 낡은 시스템을 완전히 제거하는 것만이 유일한 마일스톤이라고 생각하는 경향이 있다.
  • 폐기팀을 관리할 때도 측정할 수 있고 고객에게 가치를 전달해주는 명확하고 점진적인 마일스톤들을 세워야 한다. 진척 정도를 평가하는 지표는 다르겠지만 점진적인 성취를 제때 축하해줘야 팀 사기가 높아진다는 사실은 똑같다.
  • 새로운 제품을 구축할 때 주요 컴포넌트를 하나씩 완성하는 걸 마일스톤으로 삼듯, 폐기시킬 때도 핵심 컴포넌트들을 하나씩 제거하는 걸 점진적 마일스톤으로 삼으면 효과가 좋았다.

15.4.3 폐기 도구

발견

  • 폐기를 진행하는 내내, 특히 프로세스의 초기 단계에서는 낡은 시스템을 '누가' 그리고 '어떻게' 이용하고 있는지를 알아야 한다.
  • 폐기 작업 초기에는 낡은 시스템을 이용하는 곳을 찾은 다음 예상하지 못한 방식으로 이용하지 않는지를 알아내는 일이 대부분을 차지한다. 어떻게 이용 중인지에 따라 폐기를 계속 진행할지 혹은 결정을 번복해야 할지를 다시 검토해야 할 수도 있다. 이 때 쓰이는 발견 도구들은 폐기 프로세스 내내 진척 상황을 파악하는데 계속 이용된다.
  • 구글에서느 Code Search 같은 검색 도구와 Kythe 같은 정적 분석 도구를 써서 폐기시킬 라이브러리를 누가 이용 중인지를 코드를 돌려보지 않고도 알아낸다.
  • 구글은 폐기시킬 심볼의 참조가 모두 제거되었는지를 확인하는 데 전역 테스트 스위트를 이용한다. 고객들은 낡은 시스템을 제거해도 피해를 입지 않도록 충분히 테스트해야 할 책임이 있다.

마이그레이션(이주)

  • 구글에서는 폐기에 필요한 일의 상당 부분을 앞에서 이야기한 코드 생성 및 리뷰 도구들을 활용해 처리한다. 특히 새로운 라이브러리나 런타임 서비스를 이용하도록 코드베이스를 업데이트할 때는 대규모 변경 프로세스와 도구가 매우 유용하다.

퇴행 방지

  • 새로 작성하는 코드에서 폐기 중인 대상을 이용하는 걸 퇴행이라 한다. 이러한 퇴행 방지는 폐기 지원 인프라가 챙겨야 할 중요한 역할임에도 자주 간과되곤 한다.
  • 새로 커밋되는 코드에서 폐기 중인 시스템을 이용하려 든다면 경고해주는 게 좋다.
  • 폐기 중인 시스템을 호출하는 코드를 추가한 사용자에게 적절한 대체 방법을 피드백한다.
  • 거시적으로는 빌드 시스템에 가시성(visibility) 허용 목록을 도입하여 폐기된 시스템에 의존하는 시스템이 새로 생겨나는 일을 막는다. 자동화된 도구가 허용 목록을 검사하고, 낡은 시스템과의 의존성을 끊은 시스템들은 리스트에서 제거해준다.

15.5 마치며

  • 폐기 덕분에 유지보수 부담이 줄고 엔지니어가 알고 신경 써야 할 정보량이 줄어서 전체적인 소프트웨어 생태계가 개선된다.
  • 점점 커지고 복잡해져가는 소프트웨어 시스템을 오래도록 관리하려면 단순히 새로운 소프트웨어를 구축해 운영하는 것만으로는 부족하다. 낡았거나 더는 쓰이지 않는 시스템은 없애줘야 한다.
  • 정책과 도구를 적절히 활용하여 사회적인 장애물과 기술적인 문제를 잘 관리해야 폐기 프로세스가 완벽하게 이루어질 수 있다.
  • 체계적으로 잘 관리되는 폐기 프로세스가 조직에 큰 보탬이 된다는 사실을 깨닫기가 쉽진 않겠지만, 오래 살아남기 위해서는 반드시 필요하다.

15.6 핵심 정리

  • 소프트웨어 시스템이 존재하는 한 유지보수 비용은 계속 발생하므로 제거하는 비용과 저울질해봐야 한다.
  • 시스템을 원래 설계 의도와 다르게 사용하는 사용자가 많기 때문에 제거하는 일이 아예 처음부터 만들기보다 어려울 때도 많다.
  • 폐기 비용을 생각하면 새로운 시스템으로 교체하기보다 기존 시스템을 개선하는 일이 일반적으로 더 저렴하다.
  • 폐기 여부를 결정하려면 비용을 따져봐야 한다. 하지만 몇 가지 이유로 정확히 평가하기 어렵다. 먼저, 기존 시스템을 유지하는 데 드는 직접적인 유지보수 비용 외에도, 비슷한 시스템을 여러 개 운용하는 데 드는 생태계 비용도 고려해야 한다. 예를 들어 구식과 신식 시스템 중 어느 것을 이용할지 고민해야 하며, 공존하는 기간 동안 두 시스템을 연동시켜야 할 것이다. 그러면 새로운 시스템에 신기능을 추가하려 할 때 연동 문제 때문에 낡은 시스템이 간접적으로 방해가 된다. 이처럼 생태계 비용은 곳곳에 퍼져 있어서 측정하기 어렵다. 폐기와 제거 비용도 마찬가지로 흩어져 있는 경우가 많다.