요즘 개발 이모저모 #1

ADE 무한 경쟁 시대

AI로 작업할 때 보통 cmux를 사용하고 있었는데, 최근 Orca라는 좋은 녀석을 알게 됐다.
Orca는 AI 에이전트를 병렬로 실행하고 관리할 수 있도록 도와주는 ADE(Agent Development Environment)다.
처음 봤을 때는 "이건 또 뭐지?" 싶었지만, 직접 사용해보니 생각보다 정말 편리했다.
각 작업을 워크트리로 쉽게 분리할 수 있고, 여러 에이전트가 어떤 작업을 진행하고 있는지도 한눈에 확인할 수 있다. 사용하지 않는 에이전트와 Worktree는 Sleep 기능을 통해 프로세스를 일시 중지시켜 메모리 사용량을 줄일 수도 있다.
Jira, GitHub, GitLab, Linear 같은 도구들과도 연동할 수 있어 이슈나 PR을 ADE 안에서 바로 확인할 수 있다.
그 외에도 자동화 등 여러 편의 기능을 제공하고 있다.
아직 모든 기능을 사용해본 것은 아니지만, 지금까지는 꽤 만족스럽게 사용하고 있다.
요즘은 또 Paseo라는 녀석이 Orca의 대항마로 떠오르고 있다고 한다.
AI 에이전트 자체의 경쟁도 치열한데, 이제는 에이전트를 어떻게 동시에 실행하고 관리할 것인가를 두고 ADE까지 경쟁하기 시작한 걸 보면 정말 무한 경쟁 시대에 들어온 것 같다.
우선은 Orca를 조금 더 진득하게 사용해보고, 시간이 날 때 Paseo도 한번 사용해봐야겠다.

Next.js 16.3 등장

Next.js 16.3 업데이트가 나왔다.
이번 업데이트에서는 개발 환경부터 빌드, 타입 체크, 서버 렌더링까지 꽤 많은 부분이 개선됐다.
  • Less memory usage in dev
  • Faster builds
  • Faster type checking with TypeScript 7
  • Faster server-side rendering
  • Custom error boundaries
  • Root params
  • Instant Insights
전반적으로 개발 경험과 성능을 개선하는 업데이트라 반가웠지만, 개인적으로 가장 눈에 들어온 것은 Root paramsInstant Insights였다.
둘 다 처음 봤을 때 약간 이런 느낌이었다.
아, 드디어 이게 해결됐네.
오랫동안 조금씩 불편했던 부분이 한 번에 뻥 뚫린 느낌이었다.

Root params

기존에는 서버 컴포넌트에서 params를 통해 동적 파라미터를 가져온 뒤, 하위 컴포넌트에서 필요하다면 props를 통해 전달해야 했다.
하지만 이제 next/root-params를 통해 Root Layout의 동적 파라미터를 하위 서버 컴포넌트에서도 직접 가져올 수 있게 됐다.
이게 왜 좋냐고 한다면, 대표적으로 다국어 라우팅을 생각해볼 수 있다.
다국어 페이지를 구성할 때 언어별 페이지를 제공하기 위해 최상단에 [locale] 폴더를 두고 다음과 같은 구조를 사용하는 경우가 많다.
이 구조에서 깊은 곳에 위치한 서버 컴포넌트가 locale 정보를 필요로 한다면 기존에는 몇 가지 불편함이 있었다.
  • Props Drilling
    • 최상위 Page/Layout에서 받은 locale을 필요한 컴포넌트까지 계속 props로 전달해야 했다.
      실제로 locale은 페이지 전반에서 필요한 값인데도 컴포넌트 계층이 깊어질수록 이를 전달하기 위한 코드가 계속 추가된다.
  • 요청 단위 API에 의존할 가능성
    • Props Drilling을 피하기 위해 locale 정보를 headers()cookies() 같은 요청 단위 API를 통해 가져오는 방식을 사용할 수도 있다.
      하지만 이런 API에 의존하게 되면 정적으로 생성할 수 있었던 페이지의 렌더링 전략에도 영향을 줄 수 있기 때문에, generateStaticParams를 이용해 언어별 페이지를 정적으로 생성하려는 경우에는 신경 써야 할 부분이 생긴다.
새롭게 도입된 Root params를 사용하면 URL의 Root Layout 파라미터를 하위 서버 컴포넌트에서 직접 가져올 수 있다.
즉, 이런 구조가 가능해진 것이다.
locale을 전달하기 위해 중간 컴포넌트들이 의미 없는 props를 받을 필요도 없고, 단순히 locale을 얻기 위해 요청 헤더나 쿠키에 의존할 필요도 없다.
특히 generateStaticParams와 함께 사용하면 URL에 이미 존재하는 locale 정보를 활용하면서 언어별 페이지를 정적으로 생성하는 구조를 유지하기도 훨씬 자연스러워졌다.
개인적으로 다국어 서비스를 자주 다루다 보니 이번 기능이 굉장히 반가웠다.

Instant Insights

이것도 정말 기다렸던 개선이다.
Next.js App Router를 사용하다 보면 <Link>를 클릭했는데도 화면이 바로 바뀌지 않는 것처럼 느껴지는 경우가 있었다.
사용자는 분명 링크를 클릭했는데 서버에서 다음 페이지를 렌더링하기 위한 작업이 끝날 때까지 현재 화면이 그대로 유지되면서,
내가 클릭을 안 했나??
싶은 순간이 생긴다.
특히 네트워크가 느리거나 서버에서 처리해야 할 작업이 많은 페이지에서는 이런 느낌이 더욱 크게 다가온다.
물론 loading.tsxSuspense를 통해 로딩 UI를 제공할 수 있었지만, 결국 다음 라우트로 전환하기 위해 필요한 정보가 준비되는 시점에 따라 클릭 이후 피드백이 늦어지는 경우가 있었다.
Next.js 16.3의 Instant Insights는 이 부분을 개선한다.
컴포넌트 내부에 Suspense를 통해 로딩 상태를 정의하거나 재사용 가능한 영역에 use cache를 적용하면 Next.js가 라우팅 전에 재사용 가능한 부분과 Loading Shell을 미리 준비할 수 있다.
덕분에 사용자가 링크를 클릭했을 때 서버의 모든 작업이 끝날 때까지 현재 페이지에 머무르는 대신, 준비된 Loading Shell로 빠르게 전환할 수 있다.
결과적으로 사용자 입장에서는
과 비슷한 경험을 하게 된다.
실제 데이터가 더 빨리 도착하는 것은 아니지만, 사용자가 느끼는 반응 속도는 훨씬 빨라질 수 있다.
개인적으로 이 차이가 꽤 중요하다고 생각한다.
웹 성능에서 중요한 것은 단순히 "몇 ms 빨라졌는가"뿐만 아니라 사용자의 행동에 애플리케이션이 얼마나 빠르게 반응하는지도 중요하기 때문이다.
하지만
그렇다고 Instant Insights를 적용한다고 해서 모든 페이지 이동이 마법처럼 즉시 이루어지는 것은 아니다.
결국 Next.js가 미리 준비할 수 있는 영역과 실제 요청 시점에 처리해야 하는 영역을 적절히 분리해야 한다.
페이지 전체가 동적 데이터에 의존하고 있거나 Suspense Boundary 없이 하나의 큰 서버 컴포넌트에서 모든 데이터를 기다리는 구조라면 Instant Insights가 제공하는 이점을 충분히 활용하기 어렵다.
결국 중요한 것은 어디까지 미리 준비할 수 있고, 어디부터 실제 요청 시점에 처리해야 하는지를 구분하는 것이라고 생각한다.
오히려 이번 기능을 보면서 Suspense Boundary와 캐시 전략이 단순한 성능 최적화를 넘어 페이지의 로딩 경험을 설계하는 요소가 되어가고 있다는 느낌을 받았다.
이번 Next.js 16.3 업데이트를 보면서 개인적으로는 새로운 API가 대거 추가됐다는 느낌보다는, 기존 App Router를 사용하면서 조금씩 불편했던 부분들을 다듬었다는 느낌을 더 많이 받았다.
특히 Root params와 Instant Insights 모두 완전히 새로운 문제를 해결한다기보다는,
"원래 이렇게 됐으면 좋겠는데..." 라고 생각했던 부분을 자연스럽게 만들어주는 업데이트에 가깝다.
Next.js가 App Router를 처음 공개했을 때와 비교하면 이제는 새로운 패러다임을 계속 추가하기보다는, 실제 서비스에서 사용하면서 발생했던 불편함과 개발 경험을 하나씩 개선하는 단계로 들어가고 있는 것 같다.
물론 업데이트가 나올 때마다 새로운 개념을 공부해야 하는 건 여전하지만 말이다.

Typescript7

MS에서 기존 코드를 완전히 go 기반 코드로 이식한 TypeScript7 정식으로 발표했다. 이전 버전인 6.0보다 약 10배 더 빠른 성능을 제공하게 되었다.
가장 눈에 띄는 변화는 역시 성능이다.
기존 TypeScript 6과 비교했을 때 프로젝트에 따라 약 8~12배 빠른 빌드 성능을 보여주며, 단순히 컴파일러만 빨라진 것이 아니라 에디터의 Language Server 역시 새로운 네이티브 구현을 사용하면서 개발 과정 전반에서 성능 향상을 기대할 수 있게 됐다.
실제 대규모 프로젝트에서도 꽤 인상적인 결과가 나왔다.
  • VS Code: 에러가 포함된 파일을 열었을 때 첫 번째 에러가 표시되기까지 약 17.5초가 걸렸지만, TypeScript 7에서는 1.3초 미만으로 단축됐다.
  • Slack: CI에서의 타입 검사 시간이 약 7.5분에서 1.25분으로 단축됐으며, Merge Queue 대기 시간 역시 약 40% 줄었다.
단순 벤치마크 숫자가 아니라 실제 대규모 프로젝트의 개발 경험과 CI 시간까지 줄였다는 점에서 꽤 의미 있는 변화라고 생각한다.
기존 Typescript 컴파일러는 Typescript로 작성되고 Javascript로 실행되는 구조였다. 하지만 프로젝트 규모가 커지면서 타입 체크할 코드 역시 많아지고 Javascript 런타임 위에서 작동한다는 구조적 한계가 존재했다.
Typescript7.0은 이를 네이티브 코드로 실행 할 수 있도록 Go로 포팅했고 Shared Memory 기반의 멀티스레딩을 활용하면서 여러 타입 체커가 병렬로 작업 할 수 있게 됐다.
그냥 순전히 Go가 Javascript 보다 빨라서가 아니라 대규모 코드내에서 타입 검사를 어떻게 병렬화하고 더 효율적으로 처리할것인가 라는 문제를 해결하기 위해 바꾼것으로 볼 수 있다.

지금 바로 적용하면 해도 될까?

성능만 보면 당장 TypeScript 7으로 넘어가고 싶어진다. 하지만 아직은 프로젝트의 모든 Typescript 관련 도구를 7.0으로 완전히 교체하기에는 조금 주의가 필요하다.
가장 큰 이유는 Compiler API다.
TypeScript 생태계에는 단순히 tsc를 실행하는 것뿐만 아니라 TypeScript Compiler API를 직접 사용하는 도구들이 굉장히 많다. 대표적으로 typescript-eslint 같은 도구가 여기에 해당한다.
문제는 TypeScript 7.0은 기존에 제공되던 프로그래밍 API를 제공하고 있지 않다는 점이다. 새로운 Compiler API는 7.1 버전 부터 제공될 예정이기 때문에 기존 Compiler API에 의존하는 도구들 사용중인 경우 바로 전환하기는 어렵다.
공식문서에서는 npm alias를 활용하여 TypeScript6 과 TypeScript7을 함께 사용 할 수 있는 방법을 안내하고 있다.
즉 TypeScript 7을 타입 체크 등에 사용하면서, 기존 Compiler API가 필요한 도구에서는 TypeScript 6을 사용하는 방식이다.
기존 Compiler API에 의존하고 있는 경우 TypeScript 7.1에서 새로운 Compiler API를 제공하고 주변 생태계가 이에 맞춰 업데이트 되기 전까지 지금 당장은 이런식으로 함께 사용하도록 하는 방식이 현실적인 선택으로 보이지만.
반면 일반적인 tsc를 통해 타입 체크만 하고 있는 프로젝트라면 Typescript7으로 전환해도 충분해 괜찮아 보인다.
 

© 2026 dan.dev.log, All right reserved.

Built with NextJS