• 함께 일할 UI Developer를 찾습니다

    비바리퍼블리카에서 저와 함께 토스를 만들어 갈 웹 프론트엔드 개발자를 찾습니다.

    2019-08-22 수정: 저는 복학을 비롯한 개인 사정으로 2019년 8월 16일을 마지막으로 토스팀에서 퇴사했습니다. 하지만 이 글을 작성한 시점으로부터 토스팀에는, 그리고 웹 프론트엔드 챕터에는 훌륭한 동료들께서 다수 합류하셨고, 개발 환경을 비롯한 많은 부분이 개선되었습니다. 그러한 개선은 앞으로도 지속될 것이라 생합니다. 글 내용의 대부분이 지금보다 유효하거나 2019년 8월 중순 기준으로 더 나아진 만큼, 혹 글을 읽고 관심이 생긴 분이 계시다면 토스팀 지원을 추천드립니다 :)

    ---

    종합금융 서비스 토스를 만드는 비바리퍼블리카로 이직한지 한 달하고도 보름 정도가 되었습니다. 입사 전 기대했던 바를 훨씬 웃도는 환경에서, 정신 없으면서도 즐겁게 회사 다니고 있습니다.

    이 글은 저희 팀에서 함께 일할 UI Developer를 찾는 구인 글입니다. 하지만 뻔한 내용으로 가득찬 광고 대신, 포지션에 관심 있는 분들께서 실제로 궁금해하실 법한 정보를 최대한 제공해 드리고자 합니다.

    토스팀은 어떤 문제를 풀고 있나요?

    금융은 모든 사람의 삶에 크게 영향을 미칩니다. 하지만 많은 이들에게 금융은 복잡하고, 머리 아픈 일입니다. 수많은 광고, 읽고 있으면 눈앞이 아득해지는 복잡한 약관과 혜택 설명, 산 넘어 산처럼 느껴지는 공인인증서와 수십가지 보안 프로그램.

    금융 활동이 내 삶에 미칠 영향이 크고 중요한 것은 너무나 명백하기 때문에 많은 시간과 노력을 투자하며 그 난관을 헤쳐나가지요. 하지만 그러면서도 ‘금융은 원래 이렇게 복잡해야하는 건가’ 하는 의문이 들곤 합니다.

    저희는 꼭 그럴 필요가 없다고 생각합니다. 금융은 쉽고 즐거워질 수 있습니다. 송금, 더치페이, 결제, 계좌 및 카드 조회 등 하루에도 몇 번씩 사용할 기능부터 투자, 대출, 보험, 카드 개설 등 최대한 많은 정보를 갖고 신중하게 판단하고 싶은 결정까지. 살면서 마주치는 금융의 모든 접점을 토스 앱 내에서 캐쥬얼하게 풀어내는 것이 토스팀의 비전입니다.

    팀에서 UI Developer의 역할은 무엇인가요?

    토스팀에는 현재 4명의 UI Developer가 있습니다. 현 상태에서 같은 포지션으로 3–4분 정도 더 모실 계획입니다. 토스를 ‘앱 만드는 회사’로 생각하고 계셨다면 다음과 같은 궁금증이 드는게 당연합니다.

    앱 만드는 회사에 왜 그렇게 많은 웹 프론트엔드 개발자가 필요한가요?

    먼저, 토스 앱 내 많은 페이지가 웹뷰로 구현되어 있습니다. 네이티브 앱은 높은 성능과 유려한 UX를 제공하지만, 상대적으로 배포가 자유롭지 않고 업데이트 비용이 높습니다. 저희는 가설을 세우고 그 가설을 검증하는 실험을 통해 얻은 배움을 제품에 반영하는 식으로 일합니다. 초기 제품일수록 이 주기를 빠르게 가져갈 필요성이 생기는데, 그 경우 웹이 좋은 선택지인 경우가 많습니다.

    또한, 토스 앱 바깥에서 제공되는 웹 페이지들이 많습니다. 대표적으로 토스 회원이 비회원에게 송금 했을 때 돈을 받는 페이지나 비회원 대상 카드 추천 서비스처럼 비회원을 대상으로 하는 페이지들이 있습니다. 그 외에도 랜딩 페이지, 프로모션 페이지 등 다양한 웹 기반 제품이 존재합니다.

    UI Developer로 팀에 합류하신다면 위의 두 영역에서 풀어야 할 다양한 문제가 기다리고 있습니다 😊 저희가 지금 풀고 있는 문제를 보다 거시적인 관점에서 적어보면 다음과 같습니다.

    • 네이티브 앱처럼 느껴질 정도로 유려한 UX를 제공하기 위해 웹뷰 위에서의 어플리케이션을 최적화한다.
    • 웹페이지가 모든 기기 및 해상도에서 디자이너가 의도한 디자인을 그대로 전달하도록 세심히 구현한다.
    • 빠른 가설–실험–교훈 반영의 주기를 유지하기 위해 비효율을 없애고 컴포넌트화, 자동화 할 수 있는 부분을 찾아 반영한다.

    UI Developer는 어떻게 일하나요?

    토스팀 구성원은 대부분 두 종류의 조직에 속하게 됩니다. (참고: 다양한 직군이 함께 하는 토스 팀 구조)

    • 목적 조직: “간편한 계좌 및 카드 내역 조회”, “송금 기능의 안정적으로 유지 및 발전” 등의 목적으로 모인 조직입니다. 제품 오너(PO) 또는 비즈니스 오너(BO), 제품 분석가, 디자이너, 개발자 등의 여러 직군이 모여 구성됩니다. 셀(Cell), 사일로(Silo), 팀(Team)이 속합니다.
    • 기능 조직: 웹 프론트엔드 개발자, 디자이너, iOS 개발자 등 토스팀 내에서 같은 역할을 맡고 있는 직군별로 모인 조직입니다. 챕터(Chapter)라 불립니다.

    예를 들어, 저는 개인의 자금 흐름을 담당하는 Money Flow Tribe 내에서도 계좌 및 카드 조회를 담당하는 Account & Card Silo웹 프론트엔드 챕터에 속해있습니다. 현재 네 명의 UI Developer는 각자 다른 셀∙사일로∙팀에 소속된 채로, 각 조직의 웹 제품 구현에 대한 최종 책임자(DRI, Directly Responsible Individual) 역할을 맡고 있습니다.

    이런 식으로 각자의 목적 조직에 나뉘어 일하다 보면 같은 직군 동료와 소원해질 수 있습니다. 때문에 웹 프론트엔드 챕터는 주기적으로 데일리 미팅을 진행합니다. 데일리 미팅에서는 각자 요즘 어떤 일을 하는지 공유하고, 겪고 있는 어려움이나 새로 배운 교훈을 나눕니다. 또한 SSR 도입 등의 굵직한 작업 착수 전 미리 충분한 논의를 통해 방향을 결정합니다.

    어떤 기술을 사용하나요?

    현재 웹 프론트엔드 챕터는 다음 기술을 사용 중입니다.

    • TypeScriptSCSS를 사용해 안정적이고 빠르게 개발합니다.
    • React를 적극적으로 사용합니다. * 상태 관리를 위해 flux를, 컴포넌트 스타일링을 위해 styled-components를 사용합니다.
    • Webpack을 사용해 프로젝트를 빌드합니다.
    • “Toss Frame” 이라는 사내 디자인 시스템 라이브러리를 사용해 다양한 제품 간의 일관성을 유지합니다. * React 컴포넌트를 제공하는 버전과 정적 페이지를 위해 Bootstrap 확장 CSS 파일을 제공하는 버전이 모두 존재합니다.
    • 초기 렌더링 성능 향상을 위해 Next.js를 사용한 SSR 도입을 진행중입니다. * 동시에 flux를 mobx 또는 redux 로 대체하는 방안을 검토중입니다.
    • Zeplin을 사용해 디자이너와의 협업합니다.

    토스팀의 다른 모든 조직과 마찬가지로, 저희는 수평적인 구조를 지향합니다. 현 상태의 비효율이 거슬리거나 더 나은 대안이 있다 느낄 때 자유롭게 제안하고 토론을 통해 최선을 선택하는 문화가 뿌리 깊이 정착되어 있습니다.

    토스팀에서 일하면 무엇이 좋나요?

    토스팀에 오시면 저랑 일하실 수 있습니다!

    what-did-you-say

    죄송합니다.

    토스팀이 제공하는 가장 큰 장점은 중요한 문제를 풀면서 빠르게 성장하는 팀에서 일하는 경험입니다. 간편송금 서비스로 시작한 토스는 신용조회, 카드 및 계좌조회, 투자 및 대출 등 금융의 모든 접점을 커버하는 종합금융 서비스로 진화하고 있습니다. 누적 다운로드 수는 1,600만 명을, 누적 거래액은 16조 원을 넘겨 지금도 가파르게 성장하고 있지만, 만족하지 않고 늘 다음 스텝을 고민합니다. 이렇듯 빠르게 성장하는 팀에서 중요한 문제를 발견하고 또 풀어나가는 일은 즐거울 뿐 아니라, 개인의 능력 및 커리어적 면에서도 큰 성장을 제공할 것입니다.

    토스팀은 외부 투명성 0%, 내부 투명성 100% 을 지향합니다. 기성 거대 조직보다 훨씬 적은 구성원 수로 혁신을 만들기 위해선 그래야만 한다 믿기 때문입니다. 연봉 등 극히 일부의 민감한 정보를 제외하면, 구성원 전체가 사내 모든 정보에 손쉽게 접근할 수 있습니다. 회사의 비전과 현재 상황, 어떤 일이 필요한 맥락을 제공하고 자율성을 보장하면 각 구성원이 최선의 의사결정을 내릴 것이라 믿습니다. 모든 구성원은 본인이 풀어야 할 가장 중요한 문제를 스스로 규정하고 해결합니다. 이유도 모른 채 실무에서 동떨어진 높으신 분이 내리신 업무지시를 따라야 하는 상황은 없습니다. (참고: 토스의 기업 문화)

    그리고 이 모든 멋진 말들이 계속 사실로 유지될 수 있도록, 토스팀은 각 분야에서 최고 수준의 퍼포먼스를 내는 분들만을 모시고 있습니다. 최고의 동료들과 함께할 수 있는 환경 자체가 일종의 보상이 될 수 있겠지만, 그것만으로는 부족하겠지요. 그렇게 모신 분들께는 당연히 실력에 걸맞는 최고 수준의 대우를 해드리고 있습니다. 금전적 보상 뿐만 아니라, 일 잘 하는 걸 막는 장애물 중 회사가 치워 줄 수 있는 건 최대한 치워 드립니다. (참고: 토스 팀 최고의 복지는?)

    • 업계 최고 수준 연봉
    • 매 6개월 전직원 대상 연봉 인상 및 성과급 지급
    • 주택자금 무이자 1억 사내 대출
    • 점심, 저녁 식사비 및 다양한 간식 지원
    • 세 명의 훌륭한 바리스타가 있는 사내 카페
    • 운동비 및 통신비 (+ 자차 소유시 주차비) 지원
    • 탄력적 출퇴근 , 재택 및 원격 근무 가능

    어떤 사람을 찾고 있나요?

    기술적으로는, 앞서 언급한 저희의 기술 스택에 익숙하신 분을 선호합니다. 기본적으로 탄탄한 HTML, CSS, JS 지식을 갖고 계셔야 합니다. 만약 React 또는 TypeScript 등의 핵심 기술 경험이 많지 않다면 (혹은 없다면), 빠르게 배워서 실무가 가능한 수준까지 도달하실 각오가 필요합니다. 당연히 도움을 드리겠지만, 전통적인 사수–부사수 시스템으로 붙잡고 가르쳐드리지는 않습니다. 서로 믿고 등을 맡길 수 있는 동료를 원합니다.

    문화적으로는, 누군가 할 일을 내려주지 않아도 자율적으로 해야할 일을 찾아 책임지고 끝마치는 분을 원합니다. 가장 큰 영향력을 만들 수 있는 일에 에너지를 쏟을 수 있도록 스스로 우선순위를 조정하는 일에 익숙해야 합니다. 다른 팀원에게 영감을 불어넣고, 학습을 공유하며 서로 더 잘, 즐겁게 일할 수 있는 직장을 만들 수 있는 구성원이라면 더할 나위 없습니다.

    저희가 어떤 문화를 만들려 하고, 어떤 생각으로 일하는지 좀 더 자세한 내용이 궁금하신 분들께서는 아래 자료들을 참고하세요.

    어떻게 지원할 수 있나요?

    UI Developer 포지션으로 지원시 다음 절차를 거치게 됩니다.

    1. 서류 검토
    2. 코딩 테스트 (2일 소요)
    3. UI Developer 개발자들과의 1차 기술 면접
    4. People & Culture 팀 리더와의 2차 문화 면접
    5. 처우 협상

    저희는 채용을 진지하게 생각하고, 지원자의 시간과 노력을 소중히 여깁니다. 모든 단계에서 최대한 빠르고 솔직한 피드백을 드리겠습니다.

    👉 지금 바로 지원하기 👈

    FAQ

    • Q1. 토스 빡센 회사라는 소문이 너무 많아서 걱정됩니다. 가면 맨날 야근하는 것 아닌가요? * A1. 빡세게 일하는 회사 맞습니다. 150명이 채 안되는 구성원으로 이 정도 성과를 이루어내는게 쉬운 일은 아니지요. 다만 그 빡셈이 긴 근무시간과 동치는 아닙니다. 누가 언제 출퇴근하고 어디서 일하는지 전혀 신경쓰지 않고, 맡은바 역할을 다하고 있는지, 어떤 성과를 만들어내는지에만 집중합니다. 저도 들어오기 전에 가장 걱정했던 부분인데, 개인적으로는 들어와서 보니 소문이 다소 과장되어 있다고 느낍니다.
    • Q2. 회사 생활에 만족하시나요? * A2. 만족하고, 훌륭한 분들 모셔서 더더욱 좋은 회사로 만들고 싶습니다. 저 이거 누가 시켜서 쓰는 거 아니에요 :)
    • Q3. 학사 병특도 뽑나요? * A3. 산업기능요원 전직 및 보충역 신규 편입 가능합니다.

    혹시 더 궁금한 점이 있는 분께서는 부담 없이 리크루팅 팀 메일(mailto:recruit@toss.im)로 연락 주세요.

    읽어주셔서 감사합니다. 도움이 되었길 바라며, 많은 지원 기다리겠습니다.

  • 『자바스크립트 개발자를 위한 타입스크립트』 공개

    책의 일부를 선공개하며 앞으로의 연재 일정을 공유합니다.

    오늘 『자바스크립트 개발자를 위한 타입스크립트』의 앞부분을 선공개했습니다.

    저는 웹이라는 플랫폼에 큰 애정을 갖고 있으며, 웹에서 수많은 멋진 일들을 가능하게 해주는 언어인 자바스크립트를 참 좋아합니다. 자바스크립트는 그 난해함으로 악명이 높습니다. 그리고 자바스크립트가 받는 비난 중 일부는 (사실 다수는) 분명 사실입니다. 적어도 복잡하고 거대하면서도 정교하게 동작하는 어플리케이션 개발을 염두에 두고 개발된 언어는 분명 아니지요.

    타입스크립트는 그런 자바스크립트의 단점을 보완하기 위한 많은 시도 중 하나입니다. 사실 그 중 가장 돋보이는 시도지요. 타입스크립트는 저와 다른 많은 자바스크립트 프로그래머가 사랑하는 자바스크립트의 장점을 대부분 살리면서도 훨씬 더 안정적이고 즐거운 대규모 어플리케이션 개발이 가능할 수 있다는 것을 보여줍니다. 그래서 저는 타입스크립트를 참 좋아합니다.

    『자바스크립트 개발자를 위한 타입스크립트』는 타입스크립트 입문서입니다. 하지만 프로그래밍을 처음 시작하는 독자가 읽을 것을 염두에 두고 쓰진 않았습니다. 저와 같이 자바스크립트를 좋아하는 분들, 또 꼭 애정까진 갖고 있지 않더라도 자바스크립트를 매일 개발하는데 사용하는 분들께 타입스크립트가 왜 좋은 도구이고, 이 좋은 타입스크립트를 어떻게 알아가면 좋을지 소개하는 것을 목표로 적었습니다.

    이 책은 현재 베타 버전으로 공개된 상태입니다. 타입스크립트의 기본을 소개하는 4장까지의 선공개를 시작으로, 매 2주마다 한 장(chapter)씩 공개해 나갈 생각입니다. 아래 메일링 리스트에 가입해주시면 격주 간격으로 발행될 새 장 공개를 받아보실 수 있습니다. 책의 내용과 무관한 스팸은 보내지 않을테니 걱정하지 않으셔도 됩니다.

    『자바스크립트 개발자를 위한 타입스크립트』 메일링 리스트 가입하기

    책을 웹으로 무료 공개하는 일의 가장 큰 장점은 빠르게 의견을 수렴하고 반영할 수 있단 점이라 생각합니다. 바라는 점이 있다면 이 책이 많은 분들께 도움이 되었으면 좋겠고, 그리고 여러분과 함께 이 책을 더 나은, 더욱 도움이 되는 자료로 만들고 싶습니다. 의견이나 오류 정정, 원하는 사항 등을 깃헙 저장소에 이슈로 달아주시면 여력이 닿는 한 최대한 수렴할 수 있도록 노력하겠습니다.

  • 프로그래머로서의 성장을 도왔던 태도들

    저를 더 나은 프로그래머로 만들어 주었던 태도들에 대해 이야기합니다.

    프론트엔드 개발 공부에 대한 질문을 종종 받는다. 그럴 때마다 당황해서 제대로 된 답변을 못 드린다. 사실 길지 않은 경력임에도 처음에 어떻게 공부를 시작했는지 기억이 잘 안 난다. 어떤 리소스를 주로 참고하냐고 물어도 1. 각 기술의 공식문서를 본다 2. MDN 자주 본다 3. 기술 뉴스레터 몇 개를 받아본다 정도. 계속 성장하고 있다 느끼지만 그 성장이 구체적으로 어떻게 이루어지는지 평소에 의식을 잘 못 하고 있는 것도 같다.

    “프로그래밍 공부 시작 5단계! 이렇게만 하면 당신도 실무 프론트엔드 프로그래머!” 류의 글을 잘 쓸 자신은 없고, 내가 할 수 있는 이야기를 해보려 한다. 라이브러리, 학습 경로 선택 등의 구체적인 의사 결정에서 한 발짝 물러선, 태도 내지는 자세에 대한 이야기다. ‘이렇게 하면 100% 도움이 된다!’라기보다는 ‘나한텐 이런 태도들이 도움이 되었다’에 가깝다. 프론트엔드 개발이 보다 일반적인 프로그래밍과 크게 다르지 않다고 생각하므로, 프론트엔드에 한정된 이야기는 아님을 미리 밝힌다.

    글을 시작하기 앞서, 이 글에서 다룰 태도를 가지게 되는 데에 큰 영향을 준 세 글을 감사한 마음과 함께 소개한다. 모두 처음 마주한 지 년 단위의 시간이 지났음에도 아직 단어 선택까지 머릿속에 선명히 남아 있는 글들이다. (순서는 글 길이의 역순)

    이론과 실습 사이의 핑퐁

    프로그래밍 언어를 배운다고 하자. A는 코드는 한 줄도 짜지 않고 스펙을 처음부터 끝까지 전부 읽는다. 한참 후 스펙 읽기를 마쳤지만 간단한 프로그램 하나를 짜는데도 고생한다. 반면 B는 기본 문법만 배운 후 곧바로 문서를 치우고 프로그래밍에 들어간다. 높은 확률로, 문서를 한 번만 읽었어도 안 했을 고생을 헤쳐나가느라 엄청난 시간을 쓰게 된다.

    효율적인 학습을 위해선 A나 B처럼 이론과 실제 코딩 중 한쪽으로 치우치는 것보다는 이론적인 배경을 쌓는 공부와 그렇게 쌓은 지식을 활용하는 실습, 두 상태를 빠르게 오가는 것이 도움이 된다. 이렇게 학습의 단계를 잘게 나누는 것이 도움이 되는 이유는 크게 두 가지 정도다.

    먼저 짧은 주기의 반복을 통해 빠른 피드백을 얻을 수 있다. 피드백을 통해 잘못된 결정 – 실제로 뭔가 만들려고 봤더니 잘못된 부분을 보고 있었다든지, 이 도구가 사실 내가 풀려는 문제에 대한 해결책을 제시하는 솔루션이 아니라든지 등 – 으로부터 빠르게 복구하고 다른 방향을 향할 수 있다. 이런 피드백은 빠르게 일어날수록 더 많은 낭비를 방지할 수 있다.

    둘째로, 이론 – 실습 주기를 한 번 반복 할 때마다 돌아올 수 있는 체크포인트가 생긴다. git의 커밋을 생각하면 쉽다. 학습에 있어 주도적으로 이런저런 시도를 해보는 과정은 필수적이다. 게임에서도 체크포인트가 촘촘히 있으면 도전적인 플레이가 가능하듯, 아무리 큰 실수를 해도 돌아올 수 있는 지점이 가까이 있다는 심리적 안정감이 제공되면 더 대범하게 다양한 시도를 해보며 학습할 수 있다.

    앞서 언급한 두 가지 장점을 극대화하기 위해서는 각 이론 – 실습 주기를 끝낸 시점에서 늘 통합 테스트가 가능하도록 학습의 단계를 설계해야 한다. 다르게 표현하자면, 이론을 배우고 해당 이론을 이용해 무언가를 구현했을 때, 구현해낸 결과물이 ‘동작하는’ 상태여야 한다.

    Minimum Viable Product 이미지 출처

    전통적인 MVC 구조의 프로젝트를 짜면서 작업을 다음과 같이 나누었다고 생각해보자.

    1. 모델을 짜는 단계
    2. 컨트롤러를 짜는 단계
    3. 뷰를 짜는 단계

    이런 식으로 작업을 나눈다면 위에서 언급한 장점들이 무색해진다. 1, 2 단계가 끝난 시점에서는 여전히 내가 제대로 짰는지에 대한 피드백을 얻을 수 없기 때문이다. 뷰까지 만들어지기 전에는 현 상태의 코드가 ‘동작하는’ 코드인지 확인할 수 없으므로, 실제로는 단계를 나누지 않은 것과 크게 다를 바가 없다. 그 대신 아래처럼 단계를 나눈다면 단계별로 프로그램이 잘 동작하는지 확인 해 나가며 조금씩 개선할 수 있을 것이다.

    1. 가장 간단한 MVC 구조를 만족하는 단계
    2. 모델의 삭제, 수정을 추가하는 단계
    3. 인증 로직을 추가하는 단계

    MVP 잘 설정하기

    위에서 한 이야기를 다르게 표현하자면, 이론과 실제 코딩 양쪽에서의 MVP(Minimum Viable Product)를 영리하게 설정해야 한다는 것이다. 즉 ‘어디서 끊어야 하는지’를 알아야 한다. 항상 다음 두 질문을 떠올리자.

    • 이 이론(언어, 라이브러리, 패턴)을 사용해 만들어 낼 수 있는 가장 단순하되 실질적인 쓸모가 있는 기능은 어떤 게 있을까?
    • 그 기능을 만들기 위해 알아야 하는 최소한의 지식(언어 문법, 라이브러리 API, 패턴의 구성 요소)은 어느 정도일까?

    널리 알려진 MVP로는 위 글에서 소개된 단어 세기(word count) 프로그램, 웹 프론트엔드 쪽의 TodoApp 등이 있다. 개인적으로 프로그래밍을 시작할 때 구현했던, 터미널에서 돌아가는 2048 게임도 좋은 예시인 것 같다. 학습하려는 도구에 맞는 MVP를 찾는 데에는 관련 분야의 경험이 쌓임에 따라 생기는 ‘감’이 많은 도움이 된다.

    배움에 열린 태도로는 부족하다

    배움에 열린 태도는 당연히 깔고 들어가야 할 조건일 뿐, 충분치 않다. 평범한 개발자인 내가 배우기 위한 만반의 준비를 갖추었다고 남들이 찾아와서 본인의 시간과 노력을 들여가며 가르침을 줄 가능성은 극히 낮다. 배움에 열린 것으론 부족하다. 배움을 적극적으로 찾아야 한다.

    코드 리뷰

    코드 리뷰가 꼭 회사에서만 이루어져야 한다는 법은 없다. 오픈 소스 프로젝트에 쓸만한 기여할 거리를 찾아 풀 리퀘스트를 날린다면 해당 프로젝트의 메인테이너들에게 코드 리뷰를 받을 수 있다. 또한 개인적으로 작성한 코드도 코드 리뷰를 받을 수 있다.

    예를 들어, 나는 알고리즘 공부를 시작하며 러스트를 배워서 작성했는데 한국 러스트 사용자 그룹의 IRC 채널에서 다른 프로그래머분들께 리뷰를 요청해 여러 유용한 조언을 얻고 심지어는 풀 리퀘스트까지 받을 수 있었다.

    원해서든 원치 않아서든 코드 리뷰를 받을 상황에 놓였다면, 코드에 대한 비판은 사람에 대한 비판이 아니라는 점을 유념해야 한다. 코드에 대한 정당한 지적을 개인을 향한 공격이 아닌 더 나은 코드를 위한 발판으로 삼을 수 있는 사람은 그렇지 않은 이보다 훨씬 빠르게 성장할 수 있다. 또한, 시간과 노력을 내어 내 코드를 개선할 방법을 같이 고민해준 리뷰어에게 존중과 감사를 표하는 것을 잊지 말자.

    표준 라이브러리 / API 읽어 보기

    때로는 코드를 작성하는 것보다 코드를 읽는 과정에서 훨씬 많은 것을 배울 수 있다. 이 때 유명한 라이브러리나 언어의 소스 코드, 그리고 표준 라이브러리를 비롯한 API는 쉽게 접근 가능한 좋은 소스다.

    사용자의 입장에서 언어의 표준 라이브러리, API를 바라보면 ‘와 편하다’ ‘으 불편하네’ 정도의 감상에서 그치기 쉽다. 하지만 충분히 사용자가 많은 언어, 라이브러리는 그 자체로 오랫동안 수많은 사용자의 요구와 시대적 환경을 반영하며 발전해온 결과물이다.

    실용적인 용도로 언어나 라이브러리 문서를 볼 때는 보통 ‘어떻게’를 많이 생각하게 되는데, 학습을 위해 소스나 API를 볼 때는 ‘왜’를 생각하는 것이 도움이 된다.

    • 왜 표준 라이브러리를 이렇게 디자인 했을까?
    • 왜 이 API는 인자를 이런 순서로 받을까?
    • 왜 추상화 레벨을 이 정도로 정했을까?

    하다못해 어떤 API가 못난 모습을 하고 있는 게 과거의 잘못된 선택으로 인해 생긴 레거시라는 사실을 알게 되더라도, 그로부터 별 것 아닌 듯 보이는 선택이 끼칠 수 있는 영향력에 대해 배울 수 있을 것이다.

    세상은 변하고 사람들은 틀린 말을 한다

    더 나은 프로그래머가 되는 데에 다음 두 가지 변치 않을 사실을 기억하는 것이 도움이 된다. 세상은 변하고, 사람들은 틀린 말을 한다.

    세상은 변한다

    코드는 적게 짤수록 좋고, 코드를 짜지 않고도 할 수 있으면 더욱 좋다.

    왜냐고?

    소프트웨어는 가만 냅두면 녹이 슨다.

    왜냐고?

    세상이 변하기 때문이다. 모든 소프트웨어는 특정한 가정의 집합 위에 세워진다.

    • 프로그램을 짜는 데에는 알파벳을 포함해 127개의 문자면 충분할 것이다.
    • 프로그램은 32비트 운영체제 위에서 돌아갈 것이다.
    • 자바스크립트는 브라우저에서 간단한 작업을 하는 데나 필요한 언어고, 따라서 이 정도 정합성이면 충분하다.

    이런 가정 중 굉장히 많은 수는 현시점의 세상의 모습을 반영한다. 하지만 시간이 지나면서 세상은 변하고, 언젠가 당연하게 여겨졌던 가정이 자연스레 깨진다. 회사에서 지금 요청된 그 요구사항이 한 달 후에 바뀌지 않을 가능성은 얼마나 될까? 만약 바뀐다면 어느 정도 수준에서 바뀌게 될까? 같은 노력을 들이되, 나중에 갑작스런 변경사항이 닥쳤을 때 일을 쉽게 만들어 줄 방식으로 코드를 짤 수 없을까?

    개인적으로 언어의 기능만을 이용해서 쉽게 구현할 수 있는 일에 써드파티 라이브러리를 사용하는 걸 싫어하는 것도 이런 이유에서다. 시시각각 바뀌는 세상 속에서 프로그램이 오래 동작하기 위해선 그 모든 구성 부품이 변화에 기민하게 대응해야 한다. 한데 프로그램이 의존하는 써드파티 라이브러리의 수가 늘수록 그러기가 기하급수적으로 어려워진다. 라이브러리가 제공하는 편리함에는 채무증서가 따라온다.

    물론 변화에 대비하는 작업은 공짜가 아니다. 나중에 고생할 걸 알면서도 당장 급한 불을 끄기 위해 경직된 코드를 눈감아야 할 때도 있는 법이다. 당장 내일 배포를 해야 하는데 일주일 동안 리팩토링만 하고 있을 순 없다. 하지만 가깝든 멀든 변화가 있으리라는 것을 늘 인식하는 사람과 그렇지 않은 사람이 짜는 코드, 내리는 결정은 분명 다르다.

    사람들은 틀린 말을 한다

    사람들은 틀린 말을 한다. 의도적으로 그러는 경우도 있고, 의도치 않게 그러는 경우도 많다. 사람들이 틀린 말을 한다는 그 사실에 비하면 의도가 어쨌는지는 별로 중요하지 않다. 그럼, 사람들의 틀린 말에 덜 휘둘리기 위해선 어떻게 해야 할까?

    무언가 배울 때 가장 근원이 되는 소스 – 소스 코드, 언어 스펙, 라이브러리 공식 문서, 어떤 개념을 처음으로 주창한 이의 글 – 를 찾아보는 습관을 들이는 것이 한 방법이 된다. 무언가를 ‘쉽게’ ‘풀어서’ 설명해주는 블로그 글에는 필연적으로 저자의 재해석이 들어간다. 무엇을 말하고 무엇을 말하지 않을지에 대한 결정은 차치하더라도, 재해석의 단계가 깊어질수록 가장 사실에 가까운 정보로부터 무언가 어긋날 확률이 높아진다.

    자동화할 수 있는 검증의 책무를 사람이 아닌 기계에게 맡기는 것 또한 도움이 된다. 사람이 ‘이 풀 리퀘스트는 기존의 기능을 깨먹지 않았습니다’고 말하는 것을 믿는 대신, 자동화된 회귀 테스트가 검증하게 한다. 문서에 적힌 ‘이 함수를 이런 파라미터를 받습니다’라는 정보를 믿기보다는 정말 그러한지, 혹 잘못 사용하고 있는 곳은 없는지 타입 체커가 자동으로 검사하게 만들면 더 안심할 수 있다.

    신뢰는 아름다운 가치다. 하지만 더 견고한 프로그램을 위해서 프로그래머는 스스로 검증하지 않은 정보를 함부로 믿지 않고, 다른 프로그래머와 사용자를 올바르게 의심할 줄 알아야 한다. 최선을 바라되, 최악을 대비하는 태도를 견지하자.

    세상은 넓고 나는 작지만 내가 할 수 있는 일이 있다

    마지막으로 가장 중요하다고 생각하는 내용이다. 어차피 학습에 있어 병목은 나의 시간, 에너지, 이해력이지 외부 정보량이 아니다. 따라서 더 많은 소스 확보가 아니라 큐레이션에 집중해야 한다. 들어오는 정보량이 얼마나 많은지는 중요하지 않은 경우가 많으므로, 인터넷에 올라오는 모든 링크를 읽고 모든 라이브러리에 별을 찍기 위해 집착할 필요가 없다.

    수천, 수만 명이 있는 페이스북 그룹에 아무리 많이 가입해봐야 신호대잡음비만 낮아질 뿐, 어차피 모든 구성원과 소통할 수 없다. 뉴스레터 100개를 구독하는 것은 결국 아무 뉴스레터도 읽지 않고 메일함에 쌓이게 내버려 두는 지름길이다. 관심사를 공유하고 열정적인 동료 한 명으로부터 수천 명짜리 그룹에게 받을 수 있는 것 이상의 도움을 받을 수 있다.

    그런 좋은 동료를 만나는 데에는 분명 운도 많이 작용한다. 하지만 노력으로 만들 수 있는 변화도 분명 있다. 많은 방법 중 특히 스스로 먼저 좋은 친구가 되려 노력하는 것이 도움이 된다고 생각한다. 내가 원하는 동료를 생각하고, 남들에게 그런 동료가 되기 위해선 어떻게 할 수 있을지 생각해보면 자연스레 **‘다른 이를 돕고, 고통을 덜어줄 방법이 뭐가 있을까?’**를 고민하게 된다.

    어떤 기술을 공부하는데 한국어로 된 자료가 없어 고생했다면, 그 공부한 내용을 한국어로 써보는 건 어떨까? 어떤 라이브러리 때문에 고생했다면, 다음 사람을 위해 그 버그를 픽스하는 작업을 해서 풀 리퀘스트를 날려보는 것도 좋을 것이다. 너무 좋은 아티클이 있는데 언어의 장벽으로 못 읽을 사람들이 생각난다면 저자의 허락을 얻어 번역할 수도 있겠다.

    오늘날 대부분의 프로그래머는 고생하며 얻은 귀중한 경험과 지식을 공유하고, 남의 고생을 덜어주고, 얻기 이전에 가치 있는 것을 남들에게 나누어 주려 노력하는 이들에게 빚지고 있다. 그런데 받기만 하는 입장에서 주기도 하는 입장으로 가기 위해 넘어야 할 문턱은 생각보다 높지 않다. 그 과정에서 나의 성장을 얻을 수 있음은 물론이고, 어느 순간 커뮤니티에게 주는 것보다 더 많은 것을 받고 있는 자신을 발견할 수 있을 것이다.

    맺으며

    글을 맺으려니 너무 추상적인 이야기를 많이 한 것 같다. 구체적인 이야기를 하는 사람은 많으니 이런 글도 하나쯤 있어도 괜찮지 않을까 하는 마음으로 공개하기로 했다. 그렇게 생각하는 사람도 없겠지만 어떤 정답을 제시하려 한 것은 아니다. 어차피 왕도는 없다. 좋은 프로그래머가 되기 위해서는 당연히 많이 짜고 많이 읽고 많이 고민해야 한다.

    이 글에선 내가 그 노력을 들일 방향을 잡는데에 도움을 주었던 태도를 정리해 보려 노력했다. 프로그래밍을 시작했을 때, 허허벌판에 던져진 듯 모든 것이 막막하게 느껴졌다. 그 시절 이정표가 되어 주던 수많은 선배들의 글들을 졸음을 깨워줄 커피를 찾듯 즐겨찾기 등록, 뉴스레터 구독 해가며 찾아 읽던 기억이 난다. 그만큼은 아니더라도, 누군가에게 도움이 된다면 더 바랄 것이 없겠다.

  • React를 Vue.js보다 선호하는 이유

    가장 뜨거운 두 프론트엔드 라이브러리 중 React를 더 선호하는 이유를 정리 해 보았습니다.

    2021-11-02 수정 : 이 글이 작성된지 3년 반이 넘는 시간이 지났습니다. 저는 글 작성 후 얼마 지나지 않아 진행된 이직 이후로 Vue.js 를 실무에서 사용한 경험이 없고, 때문에 지금은 원 주제와 관련하여 유의미한 주장을 하기 위해 필요한 지식을 갖고 있지 않습니다.

    웹 생태계가 변화하는 속도를 감안하면, 이 글이 이제는 사실과 동떨어진 내용을 담고 있을 가능성이 클 것으로 예상됩니다. 따라서 현 시점에서 라이브러리 선택을 고민하는 분께서는 판단의 근거로 이 글의 내용을 사용하지 않으시길 강력하게 권장드립니다.

    그와 별개로 React 는 여전히 만족하며 잘 사용하고 있고, 최근 2021년 FEConf 에서도 관련된 발표(「왜 나는 React를 사랑하는가」)를 진행했습니다. 관심 있는 분께서는 참고하세요.


    들어가며

    회사에서 나는 주로 SPA 기반의 웹 프론트엔드를 개발한다. 전 회사에서는 React를, 현 회사에서는 Vue.js를 메인 기술로 사용했으니 이 분야에서 요새 가장 많은 관심을 받는 두 기술을 각각 몇 달 씩 경험한 셈이다. 그 결과 나름대로 내린 결론이 있는데, 선택권이 있는 상황에선 무조건 React를 사용하겠다는 것이다.

    최근 웹 프로젝트를 시작할 때의 기술 선택에 대해 직·간접적으로 조언을 요청받았는데, 매번 위의 입장을 기초로 대답했다. 그런데 비슷한 대답을 세네번 쯤 하고 있자니 이런 입장을 갖게 된 이유를 한 번 글로 정리해두면 편하기도 하고, 좀 더 도움이 될 수 있겠다는 생각이 들어서 이 글을 적게 되었다.

    글에 들어가기 앞서 이 글의 제목이 ”React가 Vue.js보다 우월하고 모두가 React를 사용해야 하는 이유”가 아니란 점을 강조하고 싶다. 모든 Vue.js 사용자가 React를 사용하도록 만드는 건 이 글의 목표가 아니다. 오류에 대한 지적, 또 미처 생각하지 못한 점에 대한 의견은 환영한다.

    내가 React를 Vue.js보다 선호하는 이유는 크게 세 가지 정도로 정리할 수 있다.

    • 타입스크립트 지원
    • 단순한 컴포넌트 정의의 용의함
    • 더 빠르고 담대한 개선

    하나씩 살펴보자.

    타입스크립트 지원

    이 항목은 상대적으로 다른 항목에 비해 React의 비교우위가 명백하다. React와 타입스크립트(이하 TS)의 결합은 아주 매끄럽다. 큰 보일러플레이트 없이도 SFC와 클래스 기반 컴포넌트 둘 모두의 타입을 정확하게 기술할 수 있고, redux를 비롯한 컴패니언 툴도 대부분 훌륭한 타입 지원을 제공한다.

    반면 Vue.js는 2.5 버전 업데이트 당시 TS 지원의 큰 개선을 홍보했지만 아직까지도 많이 미흡하다. 예를 들어 computedmethods 내의 this 타입은 여전히 제대로 추론되지 않는다. vue-class-component를 사용하면 상황이 좀 나아지지만 이는 아직 실험 기능인 데코레이터에 의존하며, 주류 문법과 이질적이다. vuex의 타입 지원 또한 redux의 그것과 비슷한 수준이 되기는 요원해보인다.

    TS의 필요성에 공감하지 못하거나 도입이 너무 어렵고 귀찮게 느껴져 사용하지 않는 사람들을 꽤 보았는데, 그런 이들에겐 이 항목은 별로 해당 사항이 없다. 개인적으론 TS 도입을 권하는 발표까지 할 정도로 기술의 팬이고, 그 지원 수준에 따라 생산성이 극명하게 달라질 정도로 의존성이 크다. 따라서 Vue.js의 TS 지원이 눈에 띄게 개선되기 전까지는 이 점 하나만 해도 나에겐 React를 선택할 충분한 이유가 될 듯 하다.

    단순한 컴포넌트 정의의 용이함

    Vue.js는 컴포넌트에 관한 템플릿, 스타일과 스크립트를 .vue 확장자를 갖는 한 파일 내에 모두 작성할 수 있는 단일 파일 컴포넌트(Single File Component)를 제공한다. 이를 사용해 허구의 UserList 컴포넌트를 작성하는 경우를 생각해보자.

    <template>
      <ul :id="$style.userList">
        <li
          v-for="user in users"
          :key="user.id"
          :class="{
            [$style.userItem]: true,
            [$style.selected]: user.id === selectedUserId
          }"
        >
          {{ user.name }}
        </li>
      </ul>
    </template>
    
    <script>
      export default {
        data() {
          return { selectedUserId: undefined };
        },
        props: ["users"],
      };
    </script>
    
    <style module>
      /* style definition */
    </style>
    

    React를 사용한다면 이 컴포넌트를 대략 아래와 같이 작성할 것이다.

    import React, { Component } from 'react'
    import classNames from 'classnames'
    import * as styles from './UserList.css'
    
    const UserItem = ({ user, selected }) => (
      <li className={classNames(style.userItem, { [style.selected]: selected })}>
        { user.name }
      </li>
    )
    
    export default class UserList extends Component {
      constructor(props) {
        super(props)
        this.state = { selectedUserId: undefined }
      }
    
      render() {
        const { users } = this.props
        const { selectedUserId } = this.state
    
        return (
          <ul className={styles.userList}>
            {users.map(user => (
              <li className={classNames(styles.userItem, { [styles.selected]: user.id === selectedUserId })}>
                { user.name }
              </li>
            )}
          </ul>
        )
      }
    }
    

    이 시점에서는 비교해보면, Vue.js에 비해 React의 문법이 갖는 몇 가지 단점이 눈에 띈다.

    • styled-components등을 사용하지 않는 이상 컴포넌트의 스타일시트를 별도의 파일에 작성해야 한다.
    • 특정 조건에 따라 엘리먼트의 클래스 명을 다르게 주고 싶을 때 classnames등의 써드파티에 의존해야 한다.
    • 상태를 갖는 컴포넌트를 정의할 때 필요한 보일러플레이트가 Vue.js에 비해 크다.

    하지만 이 파일 내에서만 사용 될 UserItem 컴포넌트를 별도의 컴포넌트로 빼는 경우를 생각해보자.

    Vue.js에서는 두 가지 선택지가 있다. 하나는 별도의 UserItem.vue를 만드는 것이다.

    <template>
      <ul :id="$style.userList">
        <user-item
          v-for="user in users"
          :key="user.id"
          :user="user"
          :selected="user.id === selectedUserId"
        />
      </ul>
    </template>
    
    <script>
      import UserItem from "./UserItem.vue";
    
      export default {
        components() {
          UserItem;
        },
        data() {
          return { selectedUserId: undefined };
        },
        props: ["users"],
      };
    </script>
    
    <style module>
      /* style definition */
    </style>
    

    또는 파일 내에서 ComponentOption 객체를 정의 할 수 있다.

    <template>
      <ul :id="$style.userList">
        <user-item
          v-for="user in users"
          :key="user.id"
          :user="user"
          :selected="user.id === selectedUserId"
        />
      </ul>
    </template>
    
    <script>
      const UserItem = {
        template:
          '<li :class="{ [styles.userItem]: true, [styles.selected]: selected }">{{ user.name }}</li>',
        props: ["user", "selected"],
      };
    
      export default {
        components() {
          UserItem;
        },
        data() {
          return { selectedUserId: undefined };
        },
        props: {
          users: {
            type: Array,
            default: [],
          },
        },
      };
    </script>
    
    <style module>
      /* style definition */
    </style>
    

    이러한 두 가지 방법은 각각의 단점을 갖고 있다.

    먼저 단일 파일 컴포넌트를 사용한 접근의 경우, 한 군데에서만 사용될 작은 컴포넌트를 정의할 때에도 무조건 새 파일을 만들어야 한다. 이는 보일러플레이트의 증가로 이어진다.

    한 편, ComponentOptions를 사용한 접근의 경우, 템플릿을 플레인 문자열로 표현하는 탓에 많은 정보를 잃게 된다. template 대신 render 함수를 사용하고 그 안에서 JSX를 사용할 수 있지만, Vue.js가 권장하는 방식은 아니라는 인상을 받았다.

    React의 무상태 함수 컴포넌트(Stateless Functional Component)를 사용하면 같은 작업을 아래와 같이 우아하게 해낼 수 있다.

    import React, { Component } from 'react'
    import classNames from 'classnames'
    import * as styles from './UserList.css'
    
    const UserItem = ({ user, selected }) => (
      <li className={classNames(style.userItem, { [style.selected]: selected })}>
        { user.name }
      </li>
    )
    
    export default class UserList extends Component {
      render() {
        const { users } = this.props
        const { selectedUserId } = this.state
    
        return (
          <ul className={styles.userList}>
            {users.map(user => (
              <UserItem user={user} selected={this.selectedUserId === user.id} />
            )}
          </ul>
        )
      }
    }
    

    보일러플레이트가 훨씬 적을 뿐더러, UserItem 컴포넌트가 부모가 던져준 데이터에 의존하는 함수라는 점이 코드 자체에서 아주 명백하게 드러난다.

    컴포넌트를 잘게 쪼갤 때 React는 Vue.js에 비해 다음 강점을 갖는다.

    • 작은 컴포넌트를 정의하는 문법이 직관적이고 간결하다.
    • 컴포넌트 정의하는 두 문법(SFC, 클래스 기반 컴포넌트)이 상대적으로 더 일관적이다.
    • 템플릿을 문자열로 표현하지 않으므로 여러 정보를 잃어버리지 않는다.

    커다란 로직을 함수로 쪼개 의도를 명시적으로 인코딩하고 프로그램을 보다 쉽게 소화할 수 있는 의미 덩어리로 나누듯, 컴포넌트를 쪼개는 작업도 비슷한 효과를 갖는다. React는 Vue.js에 비해 UI를 조그마한 컴포넌트들의 조합으로 표현 하는데에 더 적합한 문법을 갖고 있다. 나는 이런 장점이 React의 단점을 상쇄하고 남을 정도라 생각한다.

    더 빠르고 담대한 개선

    마지막 항목은 두 라이브러리의 현재를 비교한 앞선 두 항목과 달리 이 항목은 미래에 대한 이야기인데, 어느 정도 믿음의 영역이라 사람에 따라 의견 차이가 클 수 있겠다. 나는 React가 Vue.js에 비해 앞으로 더 빠르고 담대한 개선을 이루어낼 것이라 기대한다.

    최근 그다지 길지 않은 시간 동안 React에는 Fiber를 비롯해 Fragment, Portal 등 굵직한 변화 내지는 기능 추가가 있었다. 또한 새로운 Context API, 라이플사이클 메소드, time slicing과 suspense 등 다양한 변경사항이 예고되어 있다. 모든 변경사항이 좋은 변경사항이라고 할 순 없겠으나, 그와 별개로 React 팀이 빠르게 움직이고 있다는 사실 자체는 이견의 여지가 없다.

    반면 Vue.js의 릴리즈는 상대적으로 느리게 이루어지고, 주로 마이너한 변경사항 위주인 경우가 많다. 이런 속도의 차이는 결국 현존하는 두 라이브러리 사이의 간극이 더 벌어지는 결과를 낳을 것이다. 빠르게 변화하고, 배우고, 그리고 발전해 결국은 앞서 나갈 React에 베팅하는게 맞다고 생각하는 이유다.

    맺으며

    이상 내가 React를 Vue.js보다 더 선호하는 이유를 정리해 보았다. 끝으로 덧붙이자면, 사실 위 내용 중 많은 부분이 두 라이브러리의 보다 근본적인 철학 차이에서 파생되었다 생각한다. 두 라이브러리가 추구하는 바에 대해 내가 받은 인상은 아래와 같다.

    • React에는 Vue.js에 비해 매직이 덜하다. Vue.js는 사용자에게 쉽게 느껴지는 API를 제공하기 위해 라이브러리가 직접 헤비 리프팅을 하는 경우가 많다.
    • React는 Vue.js에 비해 플레인 자바스크립트에 더 가깝다. 새로운 문법 내지는 컨벤션을 정의하는 대신 자바스크립트의 그것을 활용하는데 무리가 없다면 그리 한다.
    • React는 Vue.js에 비해 사용자 및 사용처에 대해 더 적은 가정을 하고, 컴포넌트 기반의 선언적 UI 렌더링이라는 가장 핵심적인 기능과 관련된 부분만 코어에 포함한다.

    두 가지 다른 방향 중 나는 React의 방향에 더 공감한다. 미래에 두 라이브러리가 어떻게 변할지, 그리고 어떤 새로운 라이브러리가 등장할 지 모른다. 하지만 React가 지금 보여주는 철학을 앞으로도 고수하며 꾸준히 발전해 나간다면 앞으로도 나는 React를 즐겁게 사용할 것이다.

    끝으로 노파심에 다시 덧붙이자면, 글의 목적 상 Vue.js의 단점을 더 많이 언급했지만 Vue.js 역시 분명 좋은 도구다. 만약 1. 상대적으로 자바스크립트에 익숙하지 않은 팀원이 많이 참여하는 2. 소규모의, 오래 유지보수하지 않을 프로젝트라면 Vue.js도 좋은 선택이 될 수 있다고 생각한다. 두 라이브러리가 긍정적인 경쟁을 통해 함께 발전하길 바란다.

  • ECMAScript와 TC39

    자바스크립트 언어의 표준인 ECMAScript와 TC39에 대해 소개합니다.

    들어가며

    수 년 전까지만 해도 자바스크립트는 기껏해야 브라우저 위에 경고 대화창을 띄우거나 웹 페이지의 사이드바를 열고 닫는 용도로만 사용되던, 장난감 같은 언어에 불과했다. 오늘날, 자바스크립트는 프론트엔드는 물론이거니와 서버, 모바일 어플리케이션, 심지어는 데스크톱 앱까지 모든 분야에서 사용된다. 대체 그 사이에 무엇이 달라졌길래 이런 극적인 변화가 생긴걸까?

    물론 이 질문에 대한 하나의 간결한 대답은 존재하지 않는다. 그 동안 웹 브라우저를 실행하는 기기들의 스펙은 매우 빠른 속도로 좋아졌고, 전세계적으로 인터넷 보급율이 증가했으며, 또한 V8이라는 걸출한 자바스크립트 런타임 엔진이 등장하기도 했다. 그리고 빼놓을 수 없는 또다른 이유 중 하나로 프로그래밍 언어로서의 자바스크립트의 발전이 있다.

    지난 십수년간, 자바스크립트는 예전과는 거의 다른 언어라 해도 좋을 정도로 큰 변화를 겪어왔다. 그리고 언어의 표준에 새로운 기능이 추가되거나 변경사항이 있을 때마다, 많은 사람들이 그에 대한 수많은 글을 쓰고, 발표를 진행했다. 하지만 그에 비해 그런 변화가 실제로 어떻게 태동하고 발전해 결국 표준에 편입되는지까지의 과정은 거의 다루어지지 않는다.

    언어는 문법과 동작 방식만으로 이루어지지 않는다. 어플리케이션을 만드는 데에는 현재 존재하는 기능을 아는 것만으로 충분한 경우가 많다. 하지만 생태계를 보다 깊이 이해하고 앞으로 언어가 나아갈 길을 예상하기 위해선 역사와 더불어 언어가 발전하는 과정에 대한 이해가 필요하다. 세상을 집어삼키고 있는 이 언어의 표준이 어떻게 발전하는지 살펴보자.

    ECMAScript 언어 표준과 TC39

    자바스크립트의 역사를 극단적으로 간략히 서술해보자면 다음과 같다. 자바스크립트는 1990년대 중반, (지금은 사라진) Netscape Navigator 브라우저에 동적인 부분을 더하기 위한 목적으로 Brianden Eich에 의해 개발되었다. 인기를 끔에 따라 Microsoft는 (상표권 이슈를 피하기 위해) JScript라 이름 붙인 자바스크립트의 방언을 개발했다. JScript는 1996년 8월, IE 3.0에 포함되어 배포되었다.

    이후 Netscape는 언어의 표준화 및 명세화를 위해 자바스크립트를 Ecma 인터내셔널(Ecma International)에 제출했다. Netscape와 Microsoft 등 이해당사자 간의 이름을 둘러싼 합의 끝에 ECMAScript라는 이름과 ECMA-262, "ECMAScript 언어 표준(ECMAScript Language Specification)"이 탄생했다. 오늘날 우리가 말하는 자바스크립트는 ECMA-262을 만족하는 구현체를 가리킨다. Ecma 인터내셔널의 여러 기술 위원회(Technial Committee, 이하 TC) 중 TC39 라는 위원회가 이 명세를 관리한다.

    ECMAScript 언어 표준

    1997년 6월에 발표된 첫 번째 판(edition)을 시작으로 2017년 12월 현재까지 ECMA-262의 총 8개 판이 존재한다. 각 판은 판 번호 또는 발표된 연도를 따라 이름붙여진다. 예를 들어, 2015년에 발표된 6판의 경우 ECMAScript2015 또는 ECMAScript6 이라 (또는 ECMAScript를 ES로 줄여 ES2015 또는 ES6이라) 불리운다.

    그 중 약 9년만의 메이저 버전 업이 될 예정이었던 ES4는 굉장히 많고 복잡한 변경사항을 포함하고 있었다. 그 복잡도와 하위 호환성을 파괴하는 변경사항은 많은 논쟁을 야기했고, 결국 컨센서스를 불러일으키는데 실패한 ES4는 기각되었다. 비록 4판은 받아들여지지 않았지만, 당시 제안되었던 기능 중 다수는 이후 점진적으로 표준에 추가되었다.

    Technical Committee 39

    Ecma 인터내셔널의 여러 기술 위원회(Technial Committee, 이하 TC) 중 ECMA-262 명세의 관리는 TC39 위원회가 맡고 있다.. TC39의 구성원 목록은 Mozilla, Google, Apple, Microsoft 등의 메이저 브라우저 벤더를 비롯해 Facebook, Twitter 등의 다양한 단체로 이루어져 있다. 대부분의 구성원이 표준을 올바르게 구현해야 할 책임을 갖는, 언어 표준의 변화에 직접적으로 영향을 받는 단체다. 엄밀히는 기업/단체가 구성원이지만, 'TC39 구성원' 이라는 용어가 해당 기업/단체가 보낸 대리인을 지칭하는 경우도 많다.

    TC39는 정기적으로 만나 회의를 진행하는데, 회의록은 모두 웹상에 공개된다. TC39에서 내리는 결정이 단순 다수결이 아닌 컨센서스 체제로 이루어진다는 점은 주목할 만 하다. 대부분이 동의하는 안이라도 한 명이 강하게 거부권을 행사한다면 섣불리 결정을 내리기보단 합의를 이루어내기 위해 더 시간을 갖고 논의를 해 보는 식이다. TC39의 모든 의사 결정이 구성원 대다수의 이해관계와 직결되어 있다는 점을 감안했을 때, 이러한 정책은 이례적이다.


    TC39 프로세스

    이하 1단계: 제안 단계와 구분하기 위해 앞으로 0단계에서 4단계에 이르기까지, 아직 표준에 편입되지도, 명시적으로 거절되지도 않은 제안을 통틀어 프로포절이라 칭한다.

    ECMA-262 표준에 새로운 명세를 추가하기 위한 과정은 공식적으로 명문화되어 있다. TC39 프로세스라고도 불리는 이 과정은 0단계부터 4단계까지 총 5개의 단계로 나누어져 있으며, 각 단계로의 승급을 위한 명시적인 조건들이 존재한다. 해당 조건을 만족한 이후 위원회의 동의를 얻은 프로포절만이 다음 단계로 넘어간다. 물론 그 과정에서 최종적으로 표준에 편입되지 않기로 결정되어 버려지는 제안들도 존재한다.

    모든 프로포절은 TC39의 깃헙 단체 계정proposals 저장소에 등재된다. 2017.12.19 기준, 0단계의 경우 stage-0-proposals.md 파일에서, 4단계에 이르러 표준에 편입된 프로포절은 finished-proposals.md 파일에서 확인할 수 있다. 활성화된 프로포절(active proposal)이라 불리는 1-3단계 프로포절의 경우 README.md에 등재되어 있다. 대부분의 프로포절은 별도의 저장소를 갖고 있고, 그 곳에선 해당 프로포절을 어떻게 발전시킬지, 어떤 어려움이 예상되는지 등의 다양한 논의가 이루어진다.

    0단계: 허수아비 (stage 0: strawman)

    TC39 프로세스에 프로포절을 내놓기 위해선 기본적으로 별다른 제약이 없다. 라이센스 관련 조항에 동의하고 TC39의 컨트리뷰터로 등록한 누구라도 프로포절을 내놓을 수 있다. 해당 프로포절 중 어떤 경로로든 TC39의 회의의 안건으로 상정되고 앞서 언급된 0단계 문서에 등재되면 0단계 제안이 된다.

    1단계: 제안 (stage 1: proposal)

    1단계에 들어오기 위해선 가장 먼저 챔피언(champion) 을 구해야 한다. 챔피언이란 해당 제안을 책임지고 다음 단계로 끌고 나아갈 TC39 구성원을 일컫는다. 또한, 1단계 프로포절은 풀고자 하는 문제와 하이 레벨 API 및 잠재적 장애물을 제시해야 한다. 구현상으로는 폴리필, 데모 등을 필요로 한다.

    위에서 살펴보았듯 0단계는 기본적으로 TC39 회의에서 안건으로 논의되어야 한다는 것 이외에는 제약이 전무하다시피 하다. 어떤 프로포절이 1단계에 진입한다는 것은 본격적으로 위원회 수준에서 시간과 노력을 투자해 해당 프로포절에 관해 논의할 의사를 표명한 것으로 해석할 수 있다. 1단계 제안은 추후 단계를 거치며 많은 부분 변화할 수 있다.

    2단계: 초고 (stage 2: draft)

    2단계에 올라오기 위해선 ECMAScript 표준의 형식 언어(formal description)로 작성 된 형식적인 서술(formal description) 초안이 필요하다. 이 초안은 만약 프로포절이 실제로 표준에 편입 될 경우 사용할 명세의 초기 버전이다. 2단계까지는 앞으로 해야 할 일 등을 TODO 마크 등으로 표시해 놓는 등의 일부 불완전한 명세가 허용된다. 또한 실험적인(플래그에 의해 켜지고 꺼지는) 구현이 요구된다.

    어떤 프로포절이 2단계에 올라왔다는 것은 위원회가 이 프로포절을 발전시켜 궁극적으로는 표준에 포함시키고자 하는 의지가 있다고 해석할 수 있다. 2단계 이후로는 상대적으로 적은 변경만이 허용된다.

    3단계: 후보 (stage 3: candidate)

    3단계 프로포절은 대부분 완성에 가깝고, 구현 주체나 사용자들로부터 피드백을 좀 더 받아보는 일만이 남은 상태다. 3단계에 들어오기 위해서는 2단계의 초안과는 다르게 빈칸 없이 문법, 동작, 그리고 API까지 모든 부분이 기술되어 있도록 마무리 된 명세가 필요하다.

    3단계까지 올라온 프로포절은 이후 구현상 심각한 문제가 발견되지 않는 이상 변경이 허용되지 않는다. 이 시점에서는 실제로 ECMA-262 표준에 편입시키고자 하는 해당 표준의 명세가 거의 마무리 된 상태여야 한다.

    4단계: 완료됨 (stage 4: finished)

    마지막 4단계는 모든 단계를 거치고 마침내 제안이 수락되고 다음 표준에 포함되어 발표되기만을 기다리는 단계이다. 3단계의 프로포절이 ECMA-262의 단위 테스트 슈트인 Test262에 관련 테스트가 작성되고, 최소 2개 이상의 구현이 제공되는 등의 까다로운 추가 조건을 모두 만족하면 마침내 4단계로 올라올 수 있다.

    4단계까지 올라온 프로포절은 별다른 이변이 없는 이상 다가오는 새 표준에 포함되어 발표된다. 2015년을 기점으로 매년 6월 새로운 ECMAScript 표준이 발표되는데, 당해 3월 전까지 4단계를 달성하고 3월 회의에서 최종 승인된 제안들이 새 표준에 포함된다.

    각 과정에 대한 보다 자세한 설명은 공식 문서에 기재되어 있다. 또한, 언제든지 앞서 언급한 proposals 저장소에서 현재 진행중인 모든 ECMAScript 표준에 관한 프로포절과 그 상태를 확인할 수 있다.


    실제 예시 – Array.prototype.includes

    TC39 프로세스가 구체적으로 어떻게 진행되는지 좀 더 구체적인 감각을 갖기 위해, 실제 예시를 들어 살펴보자. 오늘의 초대 손님은 Array.prototype.includes 메소드다. 이 메소드는 이름이 암시하듯 배열에 어떤 원소가 들어있는지 검사한다.

    매우 흔한 요구사항인 것을 감안하면 놀랍게도 이 메소드는 2016년이 되어서야 표준 – ECMAScript 2016 – 에 추가되었다. 이 프로포절의 챔피언은 Google의 Domenic Denicola이 맡았고, 2014년 4월 9일 회의에서 처음 언급되었다.

    0단계: 허수아비 (stage 0: strawman)

    앞서 언급된 2014년 4월 9일 회의록에서 Rick Waldron은 ES6에 추가될 예정인 String.prototype.contains 와 비슷한 메소드 Array.prototype.contains 를 배열 프로토타입에 추가하는 것이 어떻겠냐는 제안을 제시한다. 메일링 리스트에서 논의되던 이 프로포절은 이로서 0단계 프로포절이 된다.

    1단계: 제안 (stage 1: proposal)

    이 프로포절은 2014년 7월 31일 회의에서 다음으로 등장한다. 동작에 대한 간단한 논의 (인자로 받는 게 배열의 원소여야 하는지 서브 배열이어야 하는지)와 네이밍에 대한 논의 후에 1단계 승격이 결정된다. 이후 논의에서 상대적으로 간단한 제안인 만큼 프로세스를 TC39 회의 밖에서 비동기적으로 진행하고 싶다는 의견이 나오는데, Allen Wirfs-Brock와 Mark Miller에 의해 기각된다.

    1단계 프로포절로 승격된 시점의 저장소를 보면, 이 프로포절이 필요한 이유와 API, 그리고 많이들 궁금해 할 법한 질문과 사용 예시 모두가 README.md 에 정리되어 있으며, 데모 구현 또한 저장소에 포함되어 있다. 승격에 필요한 요건의 체크리스트는 6번 이슈에서 볼 수 있다.

    이후 이 제안은 2014년 11월 18일 회의의 안건으로 올라온다. 이 안건에서는 Array.prototype.contains 가 표준에 포함되면 이를 구현한 브라우저에서 Mootools라는 라이브러리를 사용하고 있는 기존 웹사이트가 깨질 것이라는 문제가 제기된다. 당일 챔피언이 도착하고 이어진 논의에서 결국 String.prototype.containsArray.prototype.contains 의 메소드 명을 includes 로 변경하는 결정이 난다. 회의 전에 이루어진 관련 대화 쓰레드를 읽어보면 설령 유용한 새 기능을 포기하더라도 (그리고 그것이 TC39나 브라우저의 잘못으로 인한 상황이 아니더라도) 이미 존재하는 웹을 깨트리지 않겠다는 참여자들의 의지를 엿볼 수 있어 흥미롭다.

    2단계: 초고 (stage 2: draft)

    이름을 바꾸기로 결정한 논의의 이틀 후인 2014년 11월 20일, 이 프로포절을 2단계로 승격시키는 안건이 올라오고, 통과된다. 1단계와 마찬가지로 2단계로 승격된 시점의 저장소체크리스트를 담은 이슈를 깃헙 저장소에서 확인할 수 있다.

    저장소를 확인해보면 스펙 초안은 사실 1단계가 되는 시점에서 이미 준비되어 있다. 2단계의 또다른 요구사항인 (예를 들어 V8에서 --harmony-array-includes 등의 플래그에 의해 제어되는) 실험적인 구현이 완성된 시점에서 안건에 올라온 것으로 보인다. 앞으로 패치가 좀 더 있을 예정이므로 3단계로 올릴 수는 없다는 내용이 언급된다.

    3단계: 후보 (stage 3: candidate)

    2단계로 승격된 지 여덟 달이 지난 2015년 7월 28일, 이 제안은 3단계로 승격된다. (저장소, 이슈)

    각종 엣지 케이스들에 대한 디자인 문제를 해결한 후 명세 문서가 완전히 정리된 상태다. 또한 지명된 리뷰어와 ECMAScript 편집자의 승인도 받은 것을 볼 수 있다. 실제로 명세를 담고 있는 spec.html 파일의 히스토리를 보면 3단계로 승격된 이후에는 명세를 적은 마크업의 문법 버전 변경을 제외하면 변경 사항이 거의 전무하다.

    4단계: 완료됨 (stage 4: finished)

    2015년 11월 17일 회의에서 Array.prototype.includes 메소드 프로포절은 최종적으로 4단계로 승격된다. 이 프로포절은 2016년 6월에 발표된 ECMAScript 2016 표준에 거듭제곱 연산자(**)와 함께 언어의 표준 기능으로 포함되어 배포된다.


    맺으며

    이렇게 ECMA-262 표준과 TC39, 그리고 TC39 프로세스에 대해 다루어보았다. 글을 끝맺기 전 마지막으로 이 모든 과정은 TC39의 구성원인 큰 기업만 참가할 수 있는 ‘그들만의 리그’가 아니라는 점을 강조하고 싶다. 앞서 언급했듯 모든 회의록과 프로포절의 진행상황은 전부 깃헙을 통해 언제든 조회할 수 있다. 누구든 챔피언을 구해 프로포절을 제출할 수 있으며, 진행중인 프로포절/현 표준에 대한 의견을 저장소, 메일링 리스트 또는 포럼를 통해 밝힐 수 있다.

    자바스크립트는 매우 명백한 결점과 고유의 매력을 동시에 가진 언어로 출발했다. 그 후 지난 20여년 간 꾸준하고 빠르게 더 나은 방향을 향해 발전해왔다. 이 애증의 언어의 결점을 고치고 더 매력적인 모습으로 바꾸어 낼 기회는 생태계의 모든 참여자에게 열려 있다. (물론 Array.prototype.includes의 사례에서 보았듯 그 길은 험난하고 굴곡져 있는 경우가 많다.) 이 언어와 웹에 애착을 가진 한 개발자로서, 그건 굉장히 멋진 일이라 생각한다.