5P by GN⁺ | ★ favorite | 댓글 1개
  • Figma는 모바일 렌더링과 프로토타입 뷰어에 쓰던 자체 언어 Skew가 온보딩·통합·생태계 측면에서 한계에 부딪히자 전체 Skew 코드를 TypeScript로 이전함
  • 전환의 전제는 모바일 브라우저의 WebAssembly 지원 확대, 핵심 경로의 C++ 엔진 대체, 프로토타이핑·모바일 팀 성장으로 마련됨
  • 마이그레이션은 Write Skew, build SkewWrite Skew, build TypeScriptWrite TypeScript, build TypeScript의 3단계로 진행됐고, Skew-to-TypeScript 트랜스파일러가 개발 흐름을 유지함
  • 실제 이전 과정에서는 배열 구조 분해 성능, 가상 호출 제거(devirtualization) 차이, 초기화 순서, 소스맵 연결, 조건부 컴파일 부재 같은 호환성 문제가 드러남
  • 최종적으로 단위 테스트를 통과하고 Skew와 비슷한 성능의 TypeScript 코드베이스를 확보했으며, Figma는 내부·외부 코드 통합과 패키지 관리, TypeScript 생태계 활용을 다음 과제로 보고 있음

Skew에서 TypeScript로 옮긴 이유

  • Skew는 Figma 초기의 사이드 프로젝트에서 시작됐고, 웹과 모바일을 모두 지원하는 프로토타입 뷰어를 빠르게 만들기 위한 요구를 충족함
  • JavaScript로 컴파일되는 언어로 발전하면서 고급 최적화와 빠른 컴파일 시간을 제공했지만, 프로토타입 뷰어에 코드가 누적될수록 유지 비용이 커짐
    • 신규 입사자가 익히기 어려움
    • 나머지 코드베이스와 쉽게 통합되지 않음
    • Figma 밖의 개발자 생태계가 없음
  • TypeScript 전환으로 기대한 효과는 개발 속도와 협업 범위 확대였음
    • 정적 import와 네이티브 패키지 관리로 내부·외부 코드 통합 간소화
    • 린터, 번들러, 정적 분석기 등 대규모 개발자 커뮤니티가 만든 도구 활용
    • async/await 같은 최신 JavaScript 기능과 더 유연한 타입 시스템 사용
    • 신규 개발자 온보딩과 다른 팀의 참여 장벽 완화

전환이 최근에야 가능해진 조건

  • Figma가 모바일 코드베이스를 처음 만들 당시에는 모바일 브라우저가 WebAssembly를 지원하지 않았고, 큰 번들을 성능 좋게 로드하기도 어려웠음
  • TypeScript도 초기 단계였기 때문에, 정적 타입과 더 엄격한 타입 시스템을 갖춘 Skew가 당시에는 더 현실적인 선택지였음
  • WebAssembly는 2018년까지 모바일에서 광범위한 지원을 얻었고, Figma 테스트 기준으로 2020년에는 모바일 성능이 신뢰 가능한 수준에 도달함
  • Skew의 초기 강점은 상수 접기, 가상 호출 제거 같은 전통적 컴파일러 최적화와 실제 정수 연산을 쓰는 JavaScript 생성 같은 웹 특화 최적화였음
  • 2020년 벤치마크에서는 Safari에서 TypeScript로 Figma 프로토타입을 로드하면 거의 2배 느려질 수 있음이 확인됐고, iOS에서 Safari가 유일하게 허용된 브라우저 엔진이라는 점이 전환을 막는 요인이었음
    • iOS 17.4에서 Apple은 EU 사용자에게 다른 브라우저 엔진을 열었지만, 그 외 지역 사용자에게는 WebKit이 계속 유일한 브라우저 엔진임
  • 이후 Skew 엔진의 핵심 구성요소 다수가 C++ 엔진의 대응 구성요소로 대체되면서 TypeScript 이전의 성능 위험이 줄어듦
    • 파일 로딩 같은 가장 뜨거운 코드 경로가 포함됨
    • TypeScript로 옮겨도 성능 손실을 감당할 수 있다는 확신을 얻음
  • 프로토타이핑·모바일 팀이 더 큰 조직으로 성장하면서 자동 마이그레이션과 개발자 경험 개선에 자원을 투입할 수 있게 됨

3단계 코드베이스 전환

  • 2020년 첫 마이그레이션 프로토타입에서는 TypeScript 성능이 거의 2배 느렸음
  • WebAssembly 지원과 모바일 엔진의 C++ 전환이 충분해진 뒤, Figma는 Maker Week 동안 기존 프로토타입을 고쳐 모든 테스트를 통과하는 작동 마이그레이션을 시연함
  • 목표는 전체 코드베이스를 TypeScript로 바꾸는 것이었지만, 수동 재작성은 개발 속도 저하와 런타임 오류, 성능 저하 위험을 만들 수 있었음
  • Skew와 TypeScript는 단순한 “타입 있는 JavaScript” 계열 간 전환보다 의미 차이가 컸음
    • TypeScript는 파일을 import한 뒤에야 namespace와 class가 초기화됨
    • import 순서가 예상과 다르면 런타임 오류가 날 수 있음
    • Skew는 로딩 시 모든 심볼을 런타임에서 코드베이스 전체에 사용할 수 있게 함
  • Figma는 Evan Wallace가 과거 시작한 작업을 바탕으로 Skew-to-TypeScript 트랜스파일러를 개발함
  • Phase 1: Skew를 작성하고 Skew를 빌드

    • 기존 빌드 프로세스를 유지한 채 트랜스파일러를 개발함
    • 생성된 TypeScript 코드를 GitHub에 체크인해 개발자들이 새 코드베이스 형태를 확인할 수 있게 함
  • Phase 2: Skew를 작성하고 TypeScript를 빌드

    • 단위 테스트를 모두 통과하는 TypeScript 번들이 생성된 뒤, 프로덕션 트래픽을 TypeScript 코드베이스 빌드로 점진 배포함
    • 개발자는 여전히 Skew를 작성했고, 트랜스파일러가 Skew 코드를 TypeScript로 변환해 GitHub의 TypeScript 코드를 갱신함
    • 생성 코드의 타입 오류도 계속 수정함
    • TypeScript는 타입 오류가 있어도 유효한 번들을 생성할 수 있었음
  • Phase 3: TypeScript를 작성하고 TypeScript를 빌드

    • 모든 사용자가 TypeScript 빌드 프로세스를 거친 뒤, TypeScript 코드를 개발의 단일 진실 공급원으로 전환함
    • 코드 병합이 없는 시점을 찾아 자동 생성 프로세스를 중단하고, 코드베이스에서 Skew 코드를 삭제함
    • 금요일 밤에 자동 생성 제거와 CI 작업의 TypeScript 파일 직접 실행 변경을 병합함
    • 점진 배포 중 Smart Animate 기능의 파손을 내부에서 발견했고, 게이트 방식 배포 덕분에 롤아웃을 끄고 수정한 뒤 계획을 재검토할 수 있었음

트랜스파일러에서 드러난 문제

  • 컴파일러는 보통 프런트엔드와 백엔드로 구성됨
    • 프런트엔드는 입력 코드를 파싱하고 타입 검사·문법 검사를 수행한 뒤 중간 표현(IR)으로 변환함
    • 백엔드는 IR을 다른 언어로 변환함
    • Skew 컴파일러의 백엔드는 난독화·축소된 JavaScript를 생성함
  • 트랜스파일러는 백엔드가 사람이 읽을 수 있는 코드를 생성하는 특수한 컴파일러이며, Figma는 Skew IR에서 사람이 읽을 수 있는 TypeScript를 생성해야 했음
  • 초기 구현은 Skew의 JavaScript 백엔드에서 많은 영감을 얻어 비교적 수월했지만, 후반에는 추적과 처리가 어려운 문제가 여럿 발생함
  • 배열 구조 분해 성능

    • 샘플 프로토타입에서 Skew와 TypeScript의 오프라인 성능 차이를 조사하던 중 TypeScript의 프레임률이 낮게 나옴
    • 원인은 JavaScript의 배열 구조 분해였음
    • const [a, b] = function_that_returns_an_array() 같은 연산에서 JavaScript는 배열을 직접 인덱싱하지 않고 iterator를 구성해 순회함
    • Figma는 JavaScript의 arguments 키워드에서 인자를 가져오기 위해 이 방식을 사용했고, 특정 테스트 케이스에서 성능이 느려짐
    • 구조 분해 대신 arguments 배열을 직접 인덱싱하는 코드를 생성해 프레임당 지연 시간을 최대 25% 개선함
  • Skew의 가상 호출 제거 최적화

    • Skew 컴파일러는 특정 조건에서 class 내부 함수를 밖으로 빼 전역 함수로 올리는 devirtualization 최적화를 수행함
    • myObject.myFunc(a, b)myFunc(myObject, a, b) 형태가 될 수 있음
    • TypeScript는 이 최적화를 하지 않음
    • Smart Animate 파손은 myObject가 null인 상황에서 발생함
    • devirtualized 호출은 정상 실행됐지만, non-devirtualized 호출은 null 접근 예외를 냄
    • Figma는 같은 문제가 있는 호출 지점을 찾기 위해 devirtualization에 참여할 수 있는 모든 함수에 로깅을 추가함
    • 짧은 기간 로깅을 켠 뒤 프로덕션 로그를 분석하고 문제 호출 지점을 수정함
  • 초기화 순서 차이

    • Skew에서는 변수, class, namespace, 함수 정의를 코드 어디에 선언해도 선언 순서를 신경 쓰지 않음
    • TypeScript에서는 전역 변수나 class 정의의 초기화 순서가 중요함
    • class 정의보다 static class 변수를 먼저 초기화하면 컴파일 타임 오류가 됨
    • 초기 트랜스파일러는 namespace를 쓰지 않고 모든 함수를 전역 스코프로 평탄화해 Skew와 비슷한 동작을 유지함
    • 결과 코드는 읽기 어려웠고, 이후 트랜스파일러를 고쳐 올바른 순서로 TypeScript 코드를 출력하고 가독성을 위해 namespace를 다시 추가함
    • 최종적으로 단위 테스트를 통과하고 Skew 성능과 맞는 TypeScript 코드를 컴파일할 수 있는 트랜스파일러를 만들었음
    • 일부 작은 문제는 트랜스파일러에 새 수정을 넣기보다 Skew 원본 코드에서 수동 수정하거나 TypeScript 전환 이후 수정함

소스맵으로 디버깅 경험 유지

  • Figma는 TypeScript 전환 중에도 개발자가 중단 없이 디버깅할 수 있도록 소스맵을 중요하게 다룸
  • 브라우저 디버거는 JavaScript만 이해하지만, 개발자는 Skew나 TypeScript 소스에 breakpoint를 설정함
  • 소스맵은 컴파일된 JavaScript 위치와 원본 소스 위치를 연결함
    • 예시로 helper → c, myInt → a, arrayOfInts → b 같은 매핑이 가능함
  • 일반적으로 .map 확장자의 소스맵 파일 하나가 최종 JavaScript 번들과 연결됨
  • 기존 인프라는 Skew → JavaScript 소스맵을 생성했지만, Phase 2에서는 Skew → TypeScript → esbuild 번들링 흐름으로 파이프라인이 바뀜
  • 기존 소스맵을 그대로 쓰면 JavaScript와 Skew 코드 사이 매핑이 틀어지고, 개발자가 디버깅할 수 없게 됨
  • 새 빌드 프로세스는 3단계로 소스맵을 구성함
    • Step 1: esbuild가 TypeScript → JavaScript 소스맵 ts-to-js.map 생성
    • Step 2: 트랜스파일러가 각 Skew 파일에 대해 Skew → TypeScript 소스맵 생성
    • Step 3: 두 소스맵을 합성해 Skew → JavaScript 최종 소스맵 생성
  • 최종 소스맵으로 새 JavaScript 번들을 Skew 코드에 매핑할 수 있어 Phase 2에서도 개발자 경험을 유지함

TypeScript에서 조건부 컴파일 처리

  • Skew는 최상위 if 문과 컴파일러에 전달하는 defines 옵션으로 조건부 컴파일을 지원함
  • 이 기능으로 같은 코드베이스에서 서로 다른 번들을 만들 수 있었음
    • 사용자에게 배포되는 실제 번들
    • 단위 테스트 전용 번들
    • debug 또는 release 빌드에서 다른 구현을 쓰는 함수나 class
  • TypeScript에는 조건부 컴파일이 없기 때문에, Figma는 타입 검사 이후 esbuild의 defines와 dead code elimination 기능을 사용해 번들링 단계에서 조건부 컴파일을 수행함
  • 이 방식에서는 defines가 타입 검사에 영향을 줄 수 없음
    • BUILD == "TEST"일 때만 존재하는 testOnlyFunction 같은 코드는 TypeScript에서 그대로 존재할 수 없음
  • 해결책은 class와 method를 항상 정의하고, method 내부에서 BUILD 값에 따라 분기하는 형태로 변환하는 것이었음
    • 테스트 전용이 아닌 빌드에서 testOnlyFunction이 호출되면 Unexpected call to test-only function 오류를 던짐
  • 최종 JavaScript는 원래 Skew 코드가 생성하던 JavaScript와 같게 컴파일될 수 있었음
  • 다만 일부 심볼이 원래는 특정 컴파일 모드에만 존재했지만 변경 뒤 모든 모드에 존재하게 되어 최종 번들이 약간 커짐
  • 테스트에서 번들 크기 증가는 수용 가능한 수준이었고, export되지 않은 최상위 심볼은 tree-shaking으로 제거할 수 있었음

전환 이후의 방향

  • 모든 Skew 코드를 TypeScript로 옮기면서 Figma의 핵심 코드베이스 하나가 현대화됨
  • 내부·외부 코드와의 통합이 쉬워졌고, 개발자는 더 효율적으로 작업할 수 있게 됨
  • 당시 Figma의 요구와 역량에서는 Skew로 코드베이스를 시작한 결정이 적절했음
  • 기술이 성숙하면서 과거에는 적절하지 않았던 TypeScript가 현재는 적절한 선택지가 됨
  • Figma는 이후 작업으로 다음 가능성을 탐색 중임
    • 나머지 코드베이스와의 통합
    • 훨씬 쉬운 패키지 관리
    • 활발한 TypeScript 생태계의 새 기능 직접 사용
  • 전환 과정에서 import 해석, 모듈 시스템, JavaScript 코드 생성 등 TypeScript의 여러 측면을 학습함

댓글과 토론

Hacker News 의견들
  • Figma가 JS용 커스텀 언어를 갖고 있었다는 것도 놀랍고, 그게 TS보다 빨랐다는 건 더 놀라움
    그런데 결국 더 느린 TS로 옮겼다는 점도 흥미로움
    이런 일은 꽤 자주 보이는데, 회사가 초기에 자체 기술을 만들고 커진 뒤에는 더 “표준적인” 것으로 이전하게 됨

    • 꽤 전형적인 흐름으로 보임. 초기에 Evan 같은 뛰어난 개인이 전체 도구 체인과 제품 핵심을 세팅하고, 이후 떠나거나 밀려나거나 흥미를 잃음
      팀과 제품이 훨씬 커지면 더 익숙하고 널리 쓰이는 스택으로 다시 플랫폼을 옮기게 됨
      이런 전환의 성공은 조직의 엔지니어링 문화가 얼마나 탄탄한지에 크게 달려 있음. 근거는 없지만 Evan과 창업자들이 Figma에 훌륭한 엔지니어링 문화를 만들어둔 것 같고, 실수가 생겨도 고칠 회복력이 충분해 보임
    • 자세히 읽어보면 성능에 민감한 부분은 전부 C++/WASM으로 옮겼음
      그 시점에는 접착 코드만 남았고, 커스텀 언어가 더 이상 존재할 이유가 없어진 것임
    • PHP 커뮤니티에서도 비슷한 일이 있었음. Facebook이 대표 사례지만 Yahoo도 내부 최적화가 꽤 있었고, 다른 회사들도 성능이나 보안을 위해 자체적으로 손본 경우를 봤음
      그러다 커뮤니티가 따라잡고 회사보다 더 큰 추진력을 갖게 되는 시점이 오면, 표준 구현으로 옮기는 게 합리적이 됨
      Google의 Borg에서 k8s로 이어지는 흐름도 약간 비슷하게 봄. 다만 Google은 자신들이 만든 표준 주변으로 커뮤니티를 초대한 쪽임
    • 좁은 용도에서 TS보다 빠르다는 건 비교적 낮은 기준임. 하지만 규모가 커질수록 그 기준은 시장에서 구할 수 있는 개발자 풀과 함께 따져야 함
      완전히 새로운 프레임워크를 처음 보고도 익힐 수 있는 개발자의 비용과, 이미 쓰는 플랫폼이나 기술에 문서화된 경험이 있는 개발자의 가치를 비교해야 함
      완전한 자체 개발로 가면 어떤 언어나 프레임워크에서도 엄청난 성능을 끌어낼 수 있지만, 프로젝트가 더 많은 상황을 처리해야 할수록 유지보수에 필요한 개발자 수가 늘고, 결국 느리고 요구사항에 딱 맞지 않더라도 기성 소프트웨어가 더 나아지는 지점이 옴
      장기적으로 유니콘급 채용 기준을 유지할 수 있다면 완전 커스텀 스택도 유지 가능할 수 있음. 하지만 대부분 조직은 평균적인 신규 채용자가 앞으로 유지할 수 있는 쪽으로 옮겨야 하고, 대체로 유명하고 지루한 소프트웨어 벤더 제품을 뜻함
    • 커스텀 언어 같은 특이하고 별난 것은 구현자가 아니라 단순 사용자, 예컨대 그 언어를 쓰는 개발자라면 이력서에 불리함
      야심 있는 사람에게는 떠날 이유가 될 수 있고, 채용도 어려워지며 온보딩도 길어짐. 나중에 커스텀 언어를 버릴 때 큰 전환 프로젝트도 필요함
      성능 향상이 엄청나거나, 더 안전한 코드를 쓸 수 있거나, 새 언어 배우기를 좋아하는 사람만 채용하려는 의도가 있다면 가끔은 그럴 가치가 있음
  • 이 프로젝트에서 일했음. Twitter에 조금 더 적어둠: https://twitter.com/andrew_k_chan/status/1786769203912925477
    글 제목은 오해의 소지가 있음. Figma에서는 코드베이스의 다른 부분에서 거의 10년 동안 Typescript를 썼고, 그 기간 거의 내내 Skew보다 Typescript 코드가 더 많았음
    블로그 글에서 설명하듯 Skew는 모바일 엔진, 이후 프로토타이핑 플레이어, 미러링 기능, 그리고 기억나지 않는 한두 제품 영역에서 쓰였음

  • Skew는 TypeScript보다 조금 빠른 정도가 아니었음
    Evan Wallace 전 Figma CTO에 따르면, 더 엄격한 타입 시스템이 가능하게 한 최적화 덕분에 1.5~2배 더 빨랐음

    • 브라우저가 JS의 "use strong" 모드 개발을 계속했으면 좋았을 텐데 아쉬움
      꽤 큰 난제가 있었던 것 같지만, 더 예측 가능한 최적화를 위해 동적성을 일부 줄이는 건 프로덕션급 앱에 좋은 절충으로 들림
    • “더 엄격한 타입 시스템 덕분에 1.5~2배 빨랐다”는 말은 그렇게 단순하지 않을 가능성이 큼
      뜨거운 실행 경로를 최적화하면 2배 이점은 사라질 가능성이 꽤 높음
      물론 그러면 여러 곳에서 최적화된 JS를 강제로 작성해야 하고 가독성에 영향을 준다고 말할 수 있음. 맞지만, 그 대안은 도구 지원과 인지도가 낮은 완전히 새로운 JS 컴파일 언어를 쓰는 것이었음
      지금 보면 그만한 가치가 없었던 듯하고, 블로그 글은 논쟁적이었던 이전 기술 선택을 약간 좋게 포장하는 느낌임
    • 전체 글에서 2배 속도 차이가 가장 놀라웠음
      TypeScript 사용을 그 성능을 내는 하위 집합으로 제한할 수 있는지 궁금함
  • const [a, b] = function_that_returns_an_array() 같은 작업을 완료할 때 JavaScript가 배열에서 직접 인덱싱하지 않고 배열을 순회하는 반복자를 만든다는 점이 흥미로움
    JS는 왜 구조 분해 할당에서 배열을 그냥 직접 인덱싱하지 않는 걸까?

    • 어떤 객체든 Symbol.iterator를 추가하면 반복 가능 객체가 될 수 있고, 구조 분해는 그런 객체에서도 동작해야 함. 심지어 배열 자체의 Symbol.iterator도 패치할 수 있어서 VM이 처리해야 함
      Array.prototype[Symbol.iterator] = function*() { yield 1; yield 2; yield 3; }
      [...[4, 5, 6]]
      [1, 2, 3]
      반복자 프로토콜의 끔찍한 성능은 당시에도 논의됐지만, 탈출 분석이 해결할 거라며 무시됐음 [0]. 거의 10년이 지난 지금도 탈출 분석은 해결하지 못했고, GC를 매우 많이 쓰며 여전히 별로임. 성능을 의식하지 않는 사람들이 설계한 나쁜 명세임
      사용자가 Symbol.iterator를 패치하지 않았다면 엔진이 배열의 구조 분해 할당과 스플라이싱을 특수화해 반복자 프로토콜 오버헤드를 없애는 것도 말이 될 수 있지만, 그건 또 다른 골치 아픈 문제임
      [0] https://esdiscuss.org/topic/performance-of-iterator-next-as-...
    • 프록시 같은 것이 존재하기 때문인 듯함
      더 이상한 건, 일부 JavaScript 엔진에서는 원소가 두세 개인 배열을 구조 분해할 때 {0: foo, 1: bar} 식의 객체 구조 분해가 더 빠를 수 있다는 점임
  • Skew의 편의 기능을 잃으면서 생기는 지속적인 개발자 경험 영향은 별로 다루지 않고, 코드베이스 이전 때 한 번 수행한 변환만 이야기함
    예를 들어 TypeScript에서는 파일을 올바른 순서로 가져와야만 하는 경우가 쉽게 생기고, 그렇지 않으면 깨질 수 있음. 또 구조 분해는 느려서 성능이 조금이라도 중요하면 쓰면 안 됨
    TypeScript를 몇 년 써보니 이런 함정이 수십 개 있고, 일부는 JavaScript에서 물려받았고 일부는 그렇지 않음. 엔지니어가 많다면 적어도 방대한 스타일 가이드가 필요함
    Skew가 사라지는 걸 아쉬워한 엔지니어도 있었을지 궁금함

    • 결과에 개발자들이 만족하도록 하는 건 확실히 중요했음. 그래서 롤아웃에 개발자들이 계속 Skew를 작성하되 변경 사항이 생성된 TS로 자동 체크인되는 단계 같은 것을 넣었음
      이렇게 하면 개발자들이 PR 리뷰에서 결과가 어떻게 보일지 확인하고 문제를 보고할 수 있었음
      성능과 런타임 정확성 측면에서는 TS에 몇 가지 함정이 있는 게 맞음. 배열 구조 분해 같은 문제는 계측과 엄격한 모니터링으로 잡아냈음
      Skew의 일부 기능, 예컨대 연산자 오버로딩과 정수 타입이 사라지는 건 확실히 아쉬웠음. 하지만 이전은 결국 팀 전체가 내린 결정이었고, 나도 그게 맞는 결정이었다고 봄
  • “async/await 같은 현대적 JavaScript 기능과 더 유연한 타입 시스템”이라고 되어 있는데, 그럼 Skew에는 콜백만 있었던 건가?

    • 아마 Promise는 있었을지도?
  • Figma를 잘 모르는 입장에서, 왜 WebAssembly를 쓰는지 궁금함

    • Figma가 UX 디자인 소프트웨어라는 건 아마 알 것임. 즉 기본적으로 그래픽 프로그램임. 도형을 그리고, 스크롤하고, 확대/축소함
      Figma는 그걸 극도로 잘함. 복잡한 UI 화면이 많이 있는 아주 큰 캔버스에서도 믿기 어려울 정도로 빠릿함
      요즘 데스크톱 애플리케이션 중에서도 이 정도로 잘 도는 것은 거의 없음. 이런 최적화가 Figma 성공의 중요한 일부라고 확신함
    • 벡터 편집에는 CPU에 묶이는 작업이 많음. Evan이 WASM 전환에 대해 쓴 글이 있음: https://medium.com/figma-design/webassembly-cut-figmas-load-...
    • 처음 목표가 브라우저 안의 Photoshop이었음
  • Figma가 보안 문제, 즉 권한을 해결하기 위해 커스텀 TypeScript DSL + 컴파일러를 만든 방식에 대한 흥미로운 세부 내용은 다른 블로그 글에도 있음
    https://www.figma.com/blog/how-we-rolled-out-our-own-permiss...

  • 조금 아프게 느껴짐. 큰 회사마다 자체 내부 도구, 언어, Kubernetes 같은 것이 있음. 왜 공유하지 않는 걸까
    Skew가 오픈소스였다면 더 나은 TypeScript가 됐을 수도 있음

    • Skew는 오픈소스지만 더 이상 유지보수되지 않음: https://github.com/evanw/skew
    • 이런 관점은 별로 좋아하지 않고, 보통 오픈소스 경험 부족에서 나옴
      오픈소스라고 해서 공짜 기여가 생기는 건 아님. 사소하지 않은 PR마다 긴 리뷰, 논의, 어쩌면 재작성까지 따라와야 함
  • TypeScript를 좋아하고 TypeScript로 풀스택 시스템도 갖고 있지만 완벽하진 않음. 모노레포에서 TypeScript를 설정하는 건 악몽임
    pnpm 모노레포 아래 내부 패키지들과 함께 이해 가능하게 만들려면 모든 경로가 서로 맞도록 tsconfig.json을 많이 수작업해야 함
    그리고 훌륭한 tsx 패키지가 나오기 전까지는 프로덕션 도구 체인이 사실상 유지보수 불가능했음
    또한 말도 안 되게 느림. Zod 때문에 TypeScript 언어 서버 성능이 크게 느려지는 문제가 있어서, 결국 프로젝트 참조를 도입하고 프로젝트 참조 리디렉션을 꺼야 했음
    종합하면 TypeScript를 더 좋게 만들 여지는 많음. 특히 모노레포와 성능 면에서 그렇음

    • Zod는 타입 검사 속도를 얼마나 느리게 만들 수 있는지에서 꽤 예외적인 사례라는 점은 감안해야 함. 예를 들어 https://dev.to/nicklucas/typescript-runtime-validators-and-d...에서 한 테스트는 거의 300ms까지 가지만, 다른 라이브러리는 100ms에도 거의 닿지 않음
    • Zod는 느린 것으로 알려져 있음. 예를 들어 Typebox는 훨씬 빠름. 바꾸라는 뜻은 아니고, 이건 TypeScript 문제이거나 TypeScript가 해결해야 할 문제가 아니라는 뜻임
      모노레포 문제는 모든 패키지에 같은 설정을 쓰지 않은 것처럼 들림. 그렇다면 같은 설정과 코딩 표준을 강제하는 걸 먼저 고치겠음. 이것도 TypeScript 문제가 아님
      혹시 tsx 전에 ts-node를 썼던 건가? 맞다면 tsx가 훨씬 견고함. 그냥 잘 동작함
    • 특정 도구와 라이브러리 선택 조합을 TypeScript가 지원해야 하는 게 아니라, 반대로 도구와 라이브러리 쪽이 맞춰야 함
      중간 규모 모노레포, 여러 앱과 많은 서비스를 대부분 TypeScript로 운영하고 있는데, 지루한 npm workspaces 기반 설정으로도 괜찮게 동작함
    • Zod가 느리니까 TypeScript가 느리다고 하는 건, JavaScript가 느리니까 C++이 느리다고 하는 것과 비슷함
      TypeScript가 빠르다는 뜻은 전혀 아니지만, JavaScript로 작성된 것이니 빠르기 어렵기도 함
      다만 대규모 애플리케이션에서 타입 추론을 위해 TypeScript가 코드를 실행하게 두는 건 스스로 만든 문제처럼 보임