Home 22. 대규모 변경
Post
Cancel

22. 대규모 변경

22.1 대규모 변경이란?

우리 경험상 대규보 변경(LSC)는 논리적으로는 연관되어 있으나 현실적인 한계 때문에 원자적으로 서브밋할 수 없는 변경들의 집합이다.

구글의 경우 LSC는 거의 항상 자동화 도구를 이용해 생성한다. LSC를 만드는 이유는 다양하지만 LSC로 인해 생성되는 변경들은 대체로 다음과 같다.

  • 코드베이스 전반을 훑는 분석도구로 찾은 공통 안티패턴 청소
  • 폐기 대상 API 호출 대체
  • 저수준 인프라 개선사항 활성화
  • 사용자들을 옛 시스템에서 새로운 시스템으로 마이그레이션

LSC를 촉발하는 원인은 다양하다. 더 효율적인 프로그래밍 이디엄을 적용하거나 내부 라이브러리의 인터페이스가 바뀌었을 수 있고 잠재해 있던 문제들을 신버전 컴파일러가 찾아줘서 모두 해결해야 할 수도 있다. 구글에서 수행하는 LSC의 대다수는 기능은 거의 변경하지 않는다. 주로 명확성, 최적화, 미래 호환성 개선이 목표이다.

22.2 누가 대규모 변경을 처리하나?

구글에서는 LSC의 상당 비중을 인프라팀이 수행한다. 하지만 LSC 도구들과 지원 자원들은 누구나 이용할 수 있다. 이 일을 인프라팀이 수행하는 이유는

  1. 하부 시스템을 구축하고 관리하는 인프라팀들은 그 시스템을 활용하는 수만 개의 참조를 수정하는 데 필요한 도메인 지식 역시 갖추고 있다. 인프라팀이 이미 잘 아는 전문 지식을 다른 모든 팀에게 새로 배우도록 시키는 것도 비효율적이다.
  2. 합당한 보상 없이 할 일만 늘어나는 상황을 좋아할 사람은 없다. 반드시 마이그레이션해야 할 만큼 새로운 시스템이 중요하다면 비용을 조직 차원에서 부담하는 게 맞다.
  3. 대규모로 변경해야 할 시스템을 소유한 팀이 주도해야 변경을 완료하는 데 유리하다.

22.3 원자적 변경을 가로막는 원인

22.3.1 기술적 한계

대부분의 버전 관리 시스템에서는 기능을 수행하는 비용이 변경의 크기에 비례해 커진다. 파일 수천 개를 원자적으로 커밋하기에는 메모리나 프로세싱 능력이 부족할 수 있다. 중앙집중형 버전 관리 시스템에서는 커밋 중에는 다른 사용자가 쓰기 작업을 하지 못한다. 다시 말해 거대한 커밋은 다른 사용자들의 일을 멈춰세운다.

22.3.2 병합 충돌

변경의 규모가 커질수록 자연스럽게 병합 시 충돌이 생길 가능성이 커진다. 버전 관리 시스템은 변경하려는 파일보다 중앙 리포지터리에 있는 파일의 버전이 높다면 수동으로 업데이트후 병합하는 기능을 제공한다. 이 일을 완벽하게 처리해주는 시스템은 없다.

22.3.3 유령의 묘지

유령의 묘지란 너무 오래되고 둔하고 복잡해서 아무도 손대려 하지 않는 시스템을 뜻한다.

구글은 충실한 테스트가 유령의 묘지 퇴출에 아주 효과적임을 깨달았다. 소프트웨어가 철저하게 테스트된다면 변경해도 이상이 생기지 않으리라는 믿음이 생긴다.

22.3.4 이질성

LSC가 가능하려면 LSC에 수반되는 작업 대부분을 사람이 아니라 컴퓨터가 처리해줘야 한다. 사람과 달리 컴퓨터는 모호한 일은 잘 처리하지 못한다. 그래서 컴퓨터가 변경 코드를 정확한 위치에 올바르게 반영하려면 환경이 일관되어야 한다.

22.3.5 테스트

모든 변경은 테스트되어야 한다. 하지만 변경의 덩치가 커지면 제대로 테스트하기가 훨씬 어렵다. 구글의 CI 시스템은 변경이 직접적으로 영향을 주는 테스트뿐 아니라 변경된 파일들을 간접적으로 이용하는 코드의 테스트도 모두 수행한다.

작고 독립적인 변경은 검증하기가 쉽다. 수정된 파일이 25개뿐이라면 근본 원인을 어렵지 않게 찾을 수 있다. 하지만 파일 10,000개가 수정됐다면 쉽지 않다.

사례) 595~596p

22.3.6 코드 리뷰

모든 변경은 서브밋하기 전에 리뷰를 거쳐야 한다. LSC도 예외가 아니다. 거대한 커밋을 검토하기란 지루하고 번거롭고 오류가 스며들기 쉽다.

사례) 597p

22.4 대규모 변경 인프라

22.4.1 정책과 문화

구글은 수많은 소스 코드를 하나의 리포지터리에 보관하며 모든 엔지니어가 그 안의 코드 대부분을 볼 수 있다. 이러한 개방성 덕에 구글에서는 누구라도 다른 프로젝트의 파일을 수정한 후 승인 권한자에게 검토를 요청할 수 있다. 하지만 그럴때마다 변경하는 비용과 리뷰 비용이 발생한다.

구글에서는 LSC 도구가 진화하면서 큰 변경을 매우 저렴하게 생성할 수 있게 되었다.

최종적으로 구글은 LSC를 만들려는 팀과 개인을 위한 가벼운 승인 프로세스를 고안했다. 이 프로세스는 다양한 언어의 미묘한 특성에 익숙한 숙련된 엔지니어 그룹이 감독하며, 이때 새로 만들려는 LSC 관련 도메인 전문가를 초대한다. 프로세스의 목표는 LSC를 막은게 아니다. 오히려 변경 작성자가 구글의 기술과 인적 자원을 최대한 활용하여 가장 이상적인 변경을 생성하도록 돕는 것이다.

이러한 정책과 관련하여 LSC를 둘러싼 문화적 규범에 변화가 있었다. 코드 소유자가 담당 소프트웨어에 대한 책임감을 갖는 것도 중요하지만 LSC가 구글의 소프트웨어 엔지니어링 관행을 확장하는 데 중요한 축임도 이해해야 한다.

22.4.2 코드베이스 인사이트

LSC를 진행하려면 코드베이스 전반을 분석할 수 있어야 한다. 텍스트 기반의 전통적인 분석은 물론 의미를 추적하는 분석도 중요하다.

어떤 도구로 변경을 생성하든 인력 투입량이 코드베이스보다 느리게 커져야 한다. 달리 말하면 리포지터리가 커져도 사람이 개입하는 시간은 크게 달라지지 않아야 한다. 또한 변경 생성 도구가 코드베이스 전반을 포괄해 다룰 수 있어야 한다.

22.4.3 변경 관리

대규모 변경 인프라에서 가장 중요한 도구는 마스터 변경을 여러 개의 샤드로 나눈 후 테스트, 메일링, 리뷰, 커밋 단계를 독립적으로 관리해주는 도구일 것이다. 구글은 Rosie라는 도구를 사용하는데, 이는 단순 도구라기 보다 LSC를 구글 규모에서 진행할 수 있게 해주는 플랫폼이라 할 수 있다.

22.4.4 테스트

테스트도 대규모 변경 인프라에서 없어서는 안 될 요소이다. 테스트는 소프트웨어가 기대한 대로 동작함을 검증하는 중요한 수단이다. 사람이 작성하지 않은 변경을 적용하려 할 때 특히 중요하다.

22.4.5 언어 지원

구글은 LSC를 주로 언어별로 진행하며, 언어에 따라 LSC 난이도가 크게 다르다. 또 정적 타입 언어가 동적 타입 언어보다 훨씬 유리하다. 강력한 정적 분석과 컴파일러 기반 도구가 제공하는 상당한 양의 정보를 LSC 도구 제작에 활용하면 문제를 일으키는 변경을 테스트 단계까지 가기 전에 걸러낼 수 있다.

마지막으로 자동 포맷터 역시 LSC 인프라에서 중요한 역할을 담당한다. 구글은 코드베이스를 읽기 좋게 만들고자 노력한다.

22.5 대규모 변경 프로세스

LSC 프로세스는 크게 다음의 네 단계로 이루어진다.

22.5.1 권한 부여

구글은 LSC 작성자에게 다음의 내용을 포함한 간단한 제안 문서를 작성해달라고 요청한다.

  1. 변경을 제안하는 이유
  2. 코드베이스 전반에 주는 예상 영향
  3. 리뷰어들이 던질만한 질문과 그에 대한 답변

이 절차는 해당 변경과 관련한 기반 지식이 부족한 사람들에게 변경을 어떻게 설명할지를 다시 한번 생각해보게 하는 효과가 있다. 작성자는 또한 리팩터링될 API들의 소유자들로부터 도메인 리뷰도 받아야 한다.

그런다음 전체 프로세스 감독자 10여명으로 구성된 위원회에 제안을 송부한다. 이때 위원회는 LSC에 관한 코드 리뷰 전체를 한 명의 글로벌 승인자에게 할당한다.

22.5.2 변경 생성

승인을 얻은 LSC 작성자는 실제로 코드를 수정하기 시작한다. 변경 생성 프로세스는 가능한 한 자동화해야 한다.

우리는 사람이 읽기 편한 코드베이스를 원한다. 그래서 도구가 생성한 변경들로 되도록 사람이 생성한 코드와 비슷해야 한다. 그래서 스타일 가이드와 자동 포맷팅 도구를 적용한다.

22.5.3 샤드로 나누기와 서브밋

글로벌 변경을 생성했다면 작성자는 이어서 Rosie를 실행한다. Rosie는 거대한 변경을 하나 입력받아서 서브밋할 수 있는 작은 변경(샤드)들로 쪼개준다. 이때 프로젝트 경계와 소유권 규칙을 참고한다. 그런 다음 개별 샤드를 독립된 테스트-메일-서브밋 파이프라인에 태운다.

테스트하기

독립된 샤드 각각은 구글의 CI 프레임워크인 TAP에 의해 테스트된다. 이때 수정되는 파일들에 직간접적으로 의존하는 모든 테스트를 수행하기 때문에 때로는 CI 시스템에 큰 부담을 준다.

리뷰어에게 메일 보내기

Roise는 테스트를 수행하여 변경이 안전하다고 검증한 다음 적절한 리뷰어에게 메일을 보낸다.

리뷰하기

Rosie가 생성한 변경들도 표준 코드 리뷰 프로세스를 거쳐야 한다. 하지만 각 코드의 소유자들이 LSC를 여느 변경만큼 엄격하게 살펴보지 않는 경우가 많다. 이상적으로는 LSC 변경들도 똑같이 리뷰해야겠지만 인프라팀을 믿고 피상적인 수준으로만 살펴보고 통과시킨다.

서브밋하기

마지막으로 개별 변경을 커밋힌다. 메일 보내기 단계 때와 마찬가지로 변경을 리포지터리로 실제 커밋하기 전에는 다양한 프로젝트별 프리커밋 검사가 진행된다.

22.5.4 마무리 청소

22.6 마치며

LSC는 구글 소프트웨어 엔지니어링 생태계에서 중요한 요소이다. 과거에는 한 번 결정하면 되돌릴 수 없던 설계를 LSC 덕분에 필요하면 사후에 변경할 수 있게 되었다. 설계 시 새로운 가능성을 열어준 것이다.

22.7 핵심 정리

  • LSC 프로세스는 되돌릴 수 없다고 여기던 기술적 결정들을 다시 생각해볼 수 있게 해준다.
  • 전통적인 리팩터링 모델은 코드 규모가 커지면 한계를 드러낸다.
  • LSC에 성공하려면 LSC를 습관처럼 진행해야 한다.
This post is licensed under CC BY 4.0 by the author.

21. 의존성 관리

23. 지속적 통합