[개발] TypeScript 현업 적용 후기
** 이 글은 필자의 Medium 포스팅을 포팅한 것 입니다
React와 Redux 그리고 TypeScript는 국내에서도 더이상 생소한 단어가 아니다. 이미 많은 회사와 서비스에서 해당 기술들을 사용하고 있고 활발하게 정보가 공유되고 있다. 이미 진부한 내용일 수도 있으나 실제 서비스 되고 있는 제품에 React + Redux + TypeScript 조합을 적용한 경험을 널리 공유하고자 이 포스팅을 작성하게 되었다.
* 이 글은 기본적인 TypeScript에 대한 배경 지식을 전제로 하고 있습니다.
TypeScript 도입에 앞서
아마 현업에서 TypeScript(이하 TS)가 사용된 상당수의 케이스는 프론트엔드 기술로 Angular를 사용하는 경우가 아닐까 한다. Angular2 이후부터 TS를 권유하기 시작했으니 해당 언어를 실제 제품에 적용할 때는 Angular를 가장 먼저 떠올리게 된다. 하지만 현재 우리 팀의 주된 프론트엔드 기술은 React이었고, TS를 자연스럽게 적용할 수 있는지에 대한 의구심도 가졌다.
또한 자유분방한 JavaScript(이하 JS)를 만끽하던 팀원들이 가지는 타입 시스템에 대한 불신과 거부감 또한 TS를 적용하기에 큰 장벽으로 작용했다.
당시 우리 팀에서 가졌던 의문과 불안요소들을 정리해보았다.
- 정적 타입 시스템이 정말 필요한가? 상당수의 버그를 잡아준다고 하는데, 타입 시스템의 도입으로 잡을 수 있는 버그가 유의미한 수준인가?
- React 생태계와 TS의 호환성 문제는 없는가?
- 코드가 장황(Verbose)해짐으로써 생산성의 저하가 발생하지 않는가?
- 기타 마이너한 기술적 우려와 심리적인 저항감(M$)
이런 고민들이 있었지만 결과적으로 TS를 도입하게 되었고, 실제 제품에 적용하고 약 4개월이 지난 지금, 팀원들과의 대화를 통해 정리한 내용과 개인적인 소감을 버무려 사용 경험을 공유해보겠다.
Happy and Safe Refactoring
JS로 대규모 웹 어플리케이션을 개발할 때 종종 경험하는 어려움 중 하나는 바로 여러 모듈에 걸쳐있는 객체의 리팩토링 작업이다. 일반적인 타입-컴파일 언어와 달리 JS는 객체 속성의 이름은 변경하는 작업을 할 때 단순한 오타가 발생하더라도 런타임 환경에서만 발견할 수 있다. 개발 중에 테스트를 통해서 발견할 수 있다면 다행이지만, 프로덕션 레벨에서 발견되면 장애로 이어진다.
필자와 팀이 TS를 도입하고 크게만족하는 부분 중 하나가 리팩토링의 용이함이다. 사전에 정의된 객체의 인터페이스를 여러 모듈에 걸쳐서 빈틈없이 적용해두었다면, 인터페이스 정의 한군데만 수정해도 해당 객체의 수정된 부분이 사용되는 모든 파일에서 경고를 띄워주고 컴파일도 되지 않는다.
특히 Redux를 이용하여 어플리케이션의 상태관리를 할 경우 하부 State 객체들이 여러 React 컴포넌트에서 참조하게 되는데, 단순한 State 필드 이름 변경부터 실제 값의 타입을 변경하는 변경까지 TS의 도움으로 안전한 리팩토링을 진행할 수 있었다.
버그를 사전에 잡아준다는 캐치프레이즈에 부정적이었던 필자도 몇차례에 걸친 위와 같은 경험을 통해서, 다양한 상황에서 정적 타입 시스템이 빛을 발할 수 있음을 인정하게 되었다.
훌륭한 도구
JS는 언어의 특성상 개발 도구의 도움 받을 수 있는 영역이 제한적이다. C#의 Visual Studio 수준의 지원은 기대하기 어렵다. TS를 사용함으로써 얻을 수 있는 또 다른 큰 이점은 훌륭한 도구의 지원을 받을 수 있다는 점이다.
MS에서 개발한 언어인만큼 동 회사에서 개발하여 공개한 Visual Studio Code(이하 VS Code)와의 궁합이 매우 훌륭하다. 물론 C#과 Visual Studio 수준의 기능을 제공하지는 않지만, 타입 시스템을 비롯한 언어적 특성을 십분 활용한 VS Code의 기능은 생산성에 큰 도움을 준다.
향상된 Intellisense
위 예시는 VS Code의 Intellisense가 특정 객체의 속성을 자동완성 시켜주고 해당 속성의 타입까지 알려주는 모습이다. 일반적인 JS의 자동완성과는 달리 파일 내에서만 지원하는 것이 아니라, 특정 객체의 타입(인터페이스)가 올바르게 정의되어있다면 정확한 자동완성의 지원을 받을 수 있다.
Auto Import
VS Code가 TS에 대응하여 제공하는 기능 중 하나인 Auto Import는 대규모 웹어플리케이션을 개발하면서 종종 경험하는 불편함 중 하나인 모듈 Import의 번거로움을 일거에 해결해준다. 특히 Redux를 이용한 어플리케이션에서는 Action을 중심으로 모듈 Import가 빈번하게 발생하는데, 이런 단순 작업의 로드를 상당 부분 줄여준다.
VS Code가 제공하는 많은 기능 중 일부를 예시로 들었으나, 이외에도 다양한 기능들을 제공하고 있으며 대부분의 기능을 추가적인 Extension 설치 없이도 사용할 수 있다는 간편함 또한 장점이다.
웹 프론트엔드 개발을 할 때, 언제나 목마름을 느꼈던 훌륭한 도구에 대한 니즈는 TS와 VS Code를 사용함으로써 상당 부분 해소되었다.
기존 JS 생태계와의 호환성도 안정화 단계
React를 비롯한 JS 기반 라이브러리들이 TS에 원활하게 돌아가느냐에 대한 우려도 있었으나, 수개월 동안 사용한 유수의 라이브러리들은 이미 호환성에 대한 이슈가 거의 존재하지 않았다.
JS 라이브러리를 TS에서 Import하여 사용하기 위해서는 해당 라이브러리의 타입이 정의된 모듈을 추가로 설치해줘야 한다.
특정 모듈에 타입 정의 패키지가 존재하는지는 이곳에서 확인이 가능하다.
필자가 처음 TS를 접했던 2016년에는 많은 라이브러리에 타입 정의 패키지가 존재하지 않아 타입 시스템의 도움을 받지 못했으나, 이제는 안정화 단계에 올라서있다고 단언할 수 있겠다.
그리고 React로 개발을 할때, 대부분 사람들이 활용하는 JSX 문법도 TS에서 훌륭하게 지원하고 있으므로, 이 부분에 대해서도 문제없다. 물론 타입 시스템을 적용한 React 컴포넌트나 Props 타입과 관련한 지식이 필요하나, 기술적 장벽으로 작용할 수준은 전혀 아니다.
https://www.typescriptlang.org/docs/handbook/jsx.html
생산성과의 Trade-Off
정적 타입 시스템을 적극적으로 활용할 경우, JS로 코드를 작성했을 때보다 다소 코드의 양이 늘어난다는 것은 부정할 수 없는 사실이다. 이로 인해서 생산성이 저하될 수도 있다는 팀내 우려도 있었다.
실제로 작성하는 코드의 양은 체감이 될 정도로 증가하였다. 하지만 그것으로 인해 생산성이 저하되었다고 단언하기는 힘들다. 위에서 언급한 다양한 기능들의 지원으로 단순 작업의 속도는 상당부분 개선되었으며, 오히려 불필요한 디버깅 시간을 절감함으로써, 코드 양 증가로 인한 생산성 저하가 상쇄되는 느낌이었다.
다음 프로젝트도 TypeScript로…
이상으로 현업에서 TS를 적용하면서 마주했던 우려와 실제로 사용하면서 느낀 점들을 정리해보았다. 상당 부분 간소화되어있으나, 이 포스팅을 통해서 TS 적용을 고민하는 팀/개인들이 의사결정을 함에 있어서 도움이 되기를 바라면서 글을 마무리하도록 하겠다.
개인적으로도 팀 전체로도 TS 적용은 성공적이었다고 느꼈으며, 특히 필자는 큰 이변이 없는 한 앞으로도 하게 될 프로젝트는 TS를 사용할 생각이다.