탭조이(Tapjoy) 오퍼월+ 프론트엔드 사용 기술

…과 그에 대한 단상…과 개인적인 관심사

이번 포스팅에서는 별도의 포스팅에서 다루었던 탭조이(Tapjoy)의 주력 광고 상품 중 하나인 오퍼월 플러스(이하 오퍼월)의 프론트엔드 기술 스택에 대해 정리하고 일부 기술에 대한 개인적인 견해도 공유해보도록 하겠다.

현재 오퍼월은 자바스크립트 기반의 싱글 페이지 앱으로 구현되어 있다. 다양한 기술들이 사용되고 있지만, 굵직한 라이브러리들을 중심으로 정리하면 다음과 같다.

이외에도 자잘한 목적에 맞게 사용하고 있는 라이브러리들이 더 있으나 큰 의미는 없는 듯 하여 포함시키지 않았다.

렌더링: React.js

React에 대해서는 더이상 무슨 말이 필요할까 싶다. 해외에선 수년 전부터 사용되어 왔고, 한국에서도 최근에는 보급율과 인지도가 급격하게 올라가고 있는 것이 체감 될 정도다.

나름 2년째 React를 사용하면서 개인적으로 느낀 점과 팀원들의 의견을 수렴해보면 다음과 같은 특징적인 요소가 있다.

특정한 구조나 컨벤션을 강하게 강요하지 않음 (Unopinionated)

이 특징은 개발자 개인적 성향에 따라서 호불호가 크게 갈릴 수 있는 부분이다. React는 잘 정리된 API는 제공하고 훌륭한 예시들을 어디서나 찾을 수 있지만, 엄격한 규칙으로 개발자를 제한하지는 않는다. 따라서 누구나 자유롭게 뷰(View)의 구조를 잡고 로직을 구현할 수 있는 장점이 있지만, 이러한 특성은 팀에서 사용할 때 양날의 검으로 작용하기도 한다.

여러 개발자가 제각각의 방식으로 코드를 작성할 경우, 일관되지 못한 형태의 누더기같은 앱이 탄생할 가능성이 높다. 당연히 유지/보수와 가독성과 같인 생산성 측면에서 치명적으로 작용한다.

따라서 React를 사용하는 팀이라면 이러한 점을 염두에 두고, 좋은 예시를 많이 살펴보고 팀원과의 빈번한/깊이있는 토론을 통해서 팀에 맞는 규칙을 확립해 나갈 것을 제안한다.

템플릿과 로직을 하나의 컴포넌트에서 관리 가능

이 특징은 React가 처음 등장했을 때, 전통적인 개발자들에게 무수히 많은 공격을 받는 부분으로, “감히 HTML과 JavaScript”를 한 공간에서 혼용한다는 점은 React를 처음 접하는 개발자에겐 선뜻 받아들이기 어려울 수도 있다.

역시나 팀내에서도 다소 생소하다는 의견도 있었지만, 개인적으로는 코드의 가독성 측면에서 템플릿과 로직이 통합되어 있는 구조가 상당히 마음에 든다. 게다가 개발자가 조금 방심하면 개별 컴포넌트의 크기(줄 수)가 급격하게 커지는 경우도 있어서, 반강제적으로 깔끔한 코드를 쓰게끔하는 효과도 있다.

React 이후의 자바스크립트 프레임워크/렌더링 라이브러리는 여전히 분리주의통합주의가 공존하고 있으며, 앞으로도 계속 개발자의 선택의 문제로 남아있을 듯 하다. (유행은 언제나 돌고 돈다)

디자인에 신경쓰면 구성 요소의 재사용 용이

React가 워낙 디자인부터 재사용을 용이하게 하는 라이브러리라는 목표의식을 갖고 있었던 탓에, 재사용 가능한 컴포넌트(Reusable component)는 일종의 React를 표현하는 상징 중의 하나가 되었다.

우리 팀도 항상 새로운 기능을 추가할 때는 새롭게 추가되는 컴포넌트 중 기존의 컴포넌트에서 재사용이 가능한 부분이 있는지 확인하고, 가능하다면 공통되는 부분을 추출하여 재사용 컴포넌트로 따로 관리하려고 노력한다. 이런 방법과 습관은 깨끗한 코드(Clean code)를 작성하려고 항상 노력하는 개발자라면 익숙할 것이라 크게 어려울 것은 없다. (Don’t Repeat Yourself)

다만 재사용을 고려할 때, 컴포넌트간에 주고받는 데이터의 형태나 흐름 등을 면밀히 따져보고 확장성이 있는 공용 컴포넌트를 작성하는게 중요하다. 그렇지 않으면 막상 재사용 컴포넌트를 만들어도 특정 부분에서밖에 재사용이 불가능한 사태가 발생하곤 하니 주의가 필요하다.

Facebook에서 관리

더이상 설명이 필요한가. 메이저 벤더에서 관리하는 프로젝트는 자체적으로도 관리가 잘될뿐만 아니라, 전세계 많은 개발자가 오픈소스로 참여하고 있어서 활발하게 커뮤니티가 운영된다. 개인 혹은 팀에서 선택한 라이브러리가 융성하지 못하고 수명을 다해버린 경험을 해본 사람이라면 이 특징의 소중함을 잘 알 수 있을 것이다.

상태 관리: Redux, Redux-Saga, Reselect

팀에서 프론트엔드의 상태 관리를 위해서 Redux, Redux-Saga, Reselect를 사용하고 있다.

Redux는 앱의 여러 장소에서 상태가 관리되는 React의 문제를 해결하는 상태 저장소와 API를 제공하는 라이브러리이다. 이미 국내에서도 상당수의 스타트업을 중심으로 널리 사용되고 있는 것으로 보이며, MobX가 등장하기 전까지 React 커뮤니티의 사실상 표준과도 같이 사용되었다. MobX는 RxJS 등에서 사용되는 Observable을 활용한 상태 관리 라이브러리인데, 아직은 규모가 큰 앱에서의 활용도에 의구심이 있는 것으로 보이는 관계로 Redux는 앞으로도 한동안 그 지위를 유지할 것으로 판단된다.

Redux-Saga는 일반적으로 Redux에서 비동기 작업을 처리할 때 사용되던 Redux-thunk를 대체하는 라이브러리인데, 기존의 콜백 방식의 처리를 Es2015의 생성자(Generator) 함수를 활용한 좀 더 깔끔한 방식으로 처리하게끔 지원한다.

단순하게 콜백 지옥을 피할 수 있다는 장점뿐만 아니라, 비동기 작업을 동기 작업처럼 처리할 수 있게 도와주는 생성자 함수의 특성을 활용하여 비동기 작업의 테스트에도 많은 장점을 제공한다. 특히 Redux-Saga는 팀에서도 새롭게 도입한 기술로 여전히 많은 연구가 필요한 관계로 개인적으로도 공식 문서나 소스 코드를 살펴보며 공부를 계속하고 있다.

Reselect는 Redux를 사용해 상태를 하나의 저장소(Store)에서 관리할 때 발생할 수 있는 문제 중에 하나인 복잡하고 깊은 데이터 구조를 편리하게 사용할 수 있도록 도와주는 라이브러리이다.

이름처럼 Selector 함수를 조합하여 깊은(Nested) 데이터 구조에서 필요한 정보만 선택(Select)해서 사용할 수 있다. 뿐만 아니라 Selector 함수를 이용해서 필요한 정보를 뽑아낼 때, 기존의 상태값을 기억(Memoize)해두어 값이 변하지 않았을 경우에는 재계산을 피해 성능 최적화를 꾀하는 똑똑한 라이브러리이다.

팀에서 사용하는 상태 관리와 관련된 기술들은 앱의 안정성에 직접적으로 영향을 미치는만큼 최대한 검증된 기술을 꾸준히 사용해야 한다고 생각한다. (개인적으로는 MobX를 토이 프로젝트로 실험해 볼 계획이다)

유틸리티: Lodash

Babel을 통해서 Es2015의 새로운 기능들이 손쉽게 사용가능해짐에 따라서 Lodash와 같은 자바스크립트 유틸리티 라이브러리의 활용도가 많이 떨어진 것이 사실이다.

하지만 여전히 Lodash는 여러 상황에서 유용하며, 자바스크립트의 새로운 기능들로 완전히 대체할 수 없는 유틸리티 함수를 제공한다. 함수형 프로그래밍에서 일반적으로 사용되는 함수 역시 다수 제공하고 있어 골라서 사용하는 재미가 있다.

또한 babel-plugin-lodash, lodash-webpack-plugin 등과 같은 플러그인을 통해서 더 가볍고 효율적으로 사용할 수 있기에 팀에서 꾸준히 사용되는 라이브러리이다.

테스트: Karma, Mocha, Chai, SinonEnzyme

이 조합은 전통적으로 두루 사용되던 조합이긴 하나, React에 맞추어 개발되었다고 볼 수 있는 Jest나 요즈음 인지도를 넓혀가는 AVA 등에 비하면 새로운 기술이라고는 할 수 없다.

하지만 전통적인 조합인만큼 훌륭한 커뮤니티가 형성되어 있고, 좋은 참고자료들을 손쉽게 구할 수 있다는 장점이 있다. 또한, 이미 성숙한 API를 최대한 활용하면 테스트 본연의 목적을 달성하는데 부족함이 없다. 그리고 오랜 시간 현업에서 증명된(Battle-proven) 조합이라는 점은 테스트라는 업무의 특성상 명백한 강점이라고 볼 수 있다.

추후에 새롭게 시작하는 프로젝트에서는 테스트 프로세스를 병렬로 처리하는 AVA를 실험해보고 싶다. 만약 해당 프로젝트가 React를 사용하게 된다면 Jest도 고려해볼 수 있을 것 같다.

번들/컴파일/린트: Webpack, BabelESLint

이 기술 또한 자바스크립트 개발자들에게는 전혀 새로운 기술이 아닐 것이다. 초반 프로젝트 세팅 단계에서 가장 손이 많이가고 신경써줘야 할 점이 많은 영역이지만, Webpack과 Babel은 자바스크립트 개발을 완전히 업그레이드 시켜준 위대한 발명이라고 생각한다.

Webpack을 사용함으로써 개발자는 좀 더 쉽게 파일을 분리하고 손쉽게 관리할 수 있게 되었고, Babel 덕분에 항상 새롭게 등장하는 ECMAScript의 기능들을 빨리 사용할 수 있게 되었다.

Webpack이 다른 많은 언어들이 기본적으로 제공하는 모듈링을 비로소 가능하게 해주었다는 점에서 자바스크립트의 단점을 보완했다면, Babel은 새로운 기능을 아주 빠르게 사용해볼 수 있게 확장성을 제공했다는 점에서 자바스크립트 자체의 장점을 더욱 강화시켰다고 볼 수 있다.

팀에서도 새로운 ECMAScript의 새로운 기능이 도입되면 팀원들과 공유하며 프로젝트 도입 여부를 결정하곤 한다. (최근에는 Optional Chaining 도입을 결정하고 Babel 업그레이드 작업을 진행하고 있다)

ESLint 자체는 일반적으로 사용되는 Lint 기능을 제공하는 라이브러리지만, 다양한 프리셋을 활용해서 다른 회사들의 규칙과 우리 팀이 정한 커스텀 규칙을 조합할 수 있어서 팀의 여러 프로젝트에서 계속해서 사용하고 있다.

앞으로…

이렇게 팀에서 사용하는 프론트엔드 기술들을 정리해보니, 자바스크립트 생태계는 참으로 빨리 변한다는 것이 실감이 난다. 작년까지만 해도 핫하던 기술들 중에 이미 폐기된 것들도 있고, 우리가 사용하는 기술 중에 일부는 굉장히 오래된 기술이 되기도 했다.

새로운 것을 다 체크하고 받아들여야 하는 것은 아니지만, 앞으로도 계속해서 눈과 귀를 열어놓고 자바스크립트 세상의 흐름을 파악하기 위해 부던히 노력해야 할 것 같다. 그래도 이렇게 새로운 기술들을 열린 마음으로 받아들이고 함께 고민하는 팀원들이 있고, 믿고 지원해주는 환경에서 일을 할 수 있어서 길을 잃을 걱정은 없다.