DevTools팀은 TypeScript를 매우 좋아합니다. DevTools의 새 코드가 TypeScript로 작성되고 있으며 전체 코드베이스를 TypeScript로 유형 검사하는 대규모 이전 작업이 진행 중입니다. Chrome Dev Summit 2020의 강연에서 이전에 관해 자세히 알아보세요. 따라서 Puppeteer의 코드베이스도 TypeScript로 이전하는 것이 좋습니다.
이전 계획
마이그레이션 방법을 계획할 때 작은 단계로 진전을 이룰 수 있기를 원했습니다. 이렇게 하면 이전 오버헤드가 줄어들고(한 번에 코드의 일부만 작업) 위험도 줄어듭니다. 단계 중 하나에 문제가 발생하면 쉽게 되돌릴 수 있습니다. Puppeteer 사용자는 많고 손상된 출시는 많은 사용자에게 문제를 일으킬 수 있으므로 중단 위험을 최소화하는 것이 중요했습니다.
또한 Puppeteer에는 모든 기능을 다루는 강력한 단위 테스트 세트가 마련되어 있어 다행이었습니다. 즉, 이전 과정에서 코드가 중단되지 않았을 뿐만 아니라 API에 변경사항이 도입되지 않았음을 확신할 수 있었습니다. 이전의 목표는 Puppeteer 사용자가 이전했음을 인지하지 못하도록 이전을 완료하는 것이었고 테스트는 이 전략의 중요한 부분이었습니다. 테스트 범위가 충분하지 않았다면 이전을 계속하기 전에 테스트 범위를 추가했을 것입니다.
테스트 없이 코드 변경을 실행하는 것은 위험하지만 전체 파일이나 전체 코드베이스를 수정하는 변경사항은 특히 위험합니다. 기계적으로 변경할 때는 한 단계가 누락되기 쉽습니다. 테스트에서 구현자와 검토자 모두 놓친 문제를 여러 번 포착했습니다.
사전에 시간을 투자한 것 중 하나는 지속적 통합 (CI) 설정입니다. 풀 리퀘스트에 대한 CI 실행이 불안정하고 종종 실패하는 것으로 확인되었습니다. 이 문제가 너무 자주 발생하여 Puppeteer의 문제가 아니라 CI의 일회성 문제라고 가정하고 CI를 무시하고 풀 리퀘스트를 병합하는 버릇이 생겼습니다.
일반적인 유지보수와 일부 일반 테스트 플래크를 수정하기 위한 전담 시간을 거친 후 훨씬 더 일관되게 통과하는 상태가 되었습니다. 이를 통해 CI를 리슨하고 실패가 실제 문제를 나타내는지 알 수 있었습니다. 이 작업은 매력적이지 않고 끝없는 CI 실행을 지켜보는 것은 불편하지만 이전으로 인해 발생한 풀 리퀘스트 수를 고려할 때 테스트 모음을 안정적으로 실행하는 것이 매우 중요했습니다.
하나의 파일을 선택하고 배치
이제 마이그레이션을 시작할 준비를 마쳤고, 테스트로 가득 찬 강력한 CI 서버를 확보하여 지원을 진행했습니다. 임의의 파일을 자세히 살펴보는 대신 의도적으로 이전할 작은 파일을 선택했습니다. 이 작업은 수행하려는 계획된 프로세스의 유효성을 검사할 수 있으므로 유용합니다. 이 파일에서 작동하면 접근 방식이 유효합니다. 그렇지 않으면 드로잉 보드로 돌아갈 수 있습니다.
또한 파일별로 파일을 이동하면서 (그리고 일반 Puppeteer 릴리스에서는 모든 변경 사항이 동일한 npm 버전으로 제공되지 않음) 위험을 줄일 수 있었습니다. DeviceDescriptors.js
를 첫 번째 파일로 선택했습니다. 코드베이스에서 가장 간단한 파일 중 하나이기 때문입니다. 이렇게 많은 준비 작업을 거쳐서 아주 작은 변경사항을 적용하는 것이 다소 실망스러울 수 있지만, 목표는 즉시 큰 변화를 주는 것이 아니라 신중하게 파일별로 체계적으로 진행하는 것입니다. 접근 방식을 검증하는 데 시간을 들여 나중에 더 복잡한 파일을 마주쳤을 때 마이그레이션에 드는 시간을 확실히 줄일 수 있습니다.
패턴을 증명하고 반복
다행히 DeviceDescriptors.js
변경사항이 코드베이스에 적용되었으며 계획대로 작동했습니다. 이제 본격적으로 시작할 준비가 되었습니다. Google이 바로 그렇게 했습니다. GitHub 라벨을 사용하면 모든 pull 요청을 그룹화할 수 있으며 진행 상황을 추적하는 데 유용합니다.
마이그레이션 후 나중에 개선
개별 JavaScript 파일의 경우 Google의 프로세스는 다음과 같습니다.
- 파일 이름을
.js
에서.ts
로 바꿉니다. - TypeScript 컴파일러를 실행합니다.
- 문제가 있으면 해결합니다.
- pull 요청을 만듭니다.
이러한 초기 풀 리퀘스트의 대부분의 작업은 기존 데이터 구조의 TypeScript 인터페이스를 추출하는 것이었습니다. 이전에 설명한 DeviceDescriptors.js
를 이전한 첫 번째 풀 리퀘스트의 경우 코드가 다음과 같이 변경되었습니다.
module.exports = [
{
name: 'Pixel 4',
… // Other fields omitted to save space
},
…
]
다음과 같이 변경되었습니다.
interface Device {
name: string,
…
}
const devices: Device[] = [{name: 'Pixel 4', …}, …]
module.exports = devices;
이 과정에서 코드베이스의 모든 라인을 살펴보고 문제를 확인했습니다. 수년 전부터 시간이 지남에 따라 증가한 다른 코드베이스와 마찬가지로 코드를 리팩터링하고 상황을 개선할 수 있는 기회가 있습니다. 특히 TypeScript로 전환하면서 코드를 약간 재구성하면 컴파일러를 더 많이 활용하고 유형 안전성을 개선할 수 있는 부분이 있었습니다.
직관적이지 않게 이러한 변경을 당장 거부하는 것이 매우 중요합니다. 이전의 목표는 코드베이스를 TypeScript로 가져오는 것이며 대규모 이전 중에는 항상 소프트웨어와 사용자에게 중단이 발생할 위험을 고려해야 합니다. 초기 변경사항을 최소화하여 이러한 위험을 낮췄습니다. 파일이 병합되고 TypeScript로 이전되면 후속 변경사항을 적용하여 유형 시스템을 활용하도록 코드를 개선할 수 있습니다. 이전 시 엄격한 경계를 설정하고 그 범위를 벗어나지 않도록 해야 합니다.
유형 정의를 테스트하기 위해 테스트 이전
전체 소스 코드를 TypeScript로 이전한 후 테스트에 집중할 수 있었습니다. 테스트의 적용 범위는 넓었지만 모두 JavaScript로 작성되었습니다. 즉, 유형 정의는 테스트하지 않았습니다. 프로젝트의 장기 목표 중 하나 (아직 진행 중)는 Puppeteer와 함께 고품질 유형 정의가 기본적으로 제공되도록 하는 것이지만 코드베이스에는 유형 정의에 관한 검사가 없었습니다.
테스트를 TypeScript로 이전 (동일한 프로세스를 따라 파일별로 이동)함으로써 TypeScript에서 문제가 해결되지 않았다면 사용자가 찾아낼 수 있는 문제를 발견했습니다. 이제 테스트가 모든 기능을 다루는 것뿐만 아니라 TypeScript의 품질 검사 역할도 합니다.
Puppeteer 코드베이스에서 작업하는 엔지니어로서 이미 TypeScript의 큰 이점을 누리고 있습니다. 훨씬 개선된 CI 환경이 결합되어 Puppeteer에서 작업할 때 생산성을 높이고 TypeScript로 npm 릴리스로 만들었을 버그를 포착할 수 있었습니다. Puppeteer를 사용하는 모든 개발자가 이 작업의 이점을 누릴 수 있도록 고품질 TypeScript 정의를 제공하게 되어 기쁩니다.
미리보기 채널 다운로드
Chrome Canary, Dev 또는 베타를 기본 개발 브라우저로 사용하는 것이 좋습니다. 이러한 미리보기 채널을 사용하면 최신 DevTools 기능에 액세스하고, 최신 웹 플랫폼 API를 테스트하고, 사용자가 발견하기 전에 사이트에서 문제를 찾을 수 있습니다.
Chrome DevTools팀에 문의하기
다음 옵션을 사용하여 새로운 기능, 업데이트 또는 DevTools와 관련된 다른 내용을 논의하세요.
- crbug.com에서 의견 및 기능 요청을 제출하세요.
- DevTools에서 옵션 더보기 > 도움말 > DevTools 문제 신고를 사용하여 DevTools 문제를 신고하세요.
- @ChromeDevTools에 트윗하세요.
- DevTools의 새로운 기능 YouTube 동영상 또는 DevTools 도움말 YouTube 동영상에 댓글을 남겨주세요.