Skip to content

Latest commit

 

History

History
389 lines (224 loc) · 45.3 KB

File metadata and controls

389 lines (224 loc) · 45.3 KB

2025-11

📚 링크 & 읽을거리

지난 10월 7~8일, 양일간 React 콘퍼런스가 진행되었다.

React 19 RC에서 커뮤니티 피드백을 반영해 sibling pre-warming 기능을 추가했고, 19.1에서는 개발 환경에서 오류 추적을 개선하는 Owner Stack 기능을 지원한다. React 19.2 (10/1 공개됨)에서는 UI 상태를 숨기거나 복원할 수 있는 컴포넌트와 이펙트를 세밀하게 제어하는 useEffectEvent() 훅이 도입된다. 또한 부분 사전 렌더링으로 초기 로딩 속도를 크게 개선하고, 크롬 개발자 도구에서 React 작업을 시각적으로 분석할 수 있는 성능 트랙 기능도 추가된다.

View Transition API는 React 최초의 내장 애니메이션 API로 UI 변화를 부드럽게 연결할 수 있게 해 준다. React Compiler 1.0이 정식 출시되어 모든 플랫폼에서 컴포넌트와 훅을 자동 최적화한다. React Foundation 설립을 통해 커뮤니티 중심의 거버넌스 시스템을 구축할 계획이다.

[참고] 콘퍼런스 한글 요약본은 다음 링크를 참고하라.

React 팀이 React와 React Native를 Meta에서 새로운 React Foundation으로 이전하고, 독립적인 기술 거버넌스 구조를 구축할 계획을 발표했다. React는 10여 년 전 오픈소스화된 이후 Meta 외부 기여자들의 참여가 크게 증가했으며, 이제 단일 회사의 범위를 넘어선 프로젝트로 성장했다.

React Foundation은 React, React Native, JSX 등의 프로젝트를 관리하며, GitHub 및 CI 같은 인프라 유지보수, React Conf 조직, 생태계 프로젝트 재정 지원 및 보조금 프로그램 운영을 담당한다. 이사회가 Foundation을 관리하며 Seth Webster가 이사장을 맡는다. 창립 기업 멤버로는 Amazon, Callstack, Expo, Meta, Microsoft, Software Mansion, Vercel이 참여한다.

기술적 방향은 React 기여자와 메인테이너들이 결정하도록 새로운 기술 거버넌스 구조를 만들 예정이며, 단일 회사나 조직이 과대 대표되지 않도록 설계한다. 이러한 변화는 React가 벤더 중립적이며 커뮤니티의 최선의 이익을 반영하도록 하고, React 생태계 프로젝트에 더 많은 리소스를 제공할 수 있게 한다.

RSC(React Server Components) 라우터가 워터폴(waterfall) 문제를 어떻게 해결하는지 설명하는 기술 깊이 있는 글이다. 워터폴은 부모 컴포넌트가 데이터를 가져와 렌더링 한 후 자식 컴포넌트가 또 데이터를 가져오는 순차적 패턴으로, 자식은 부모가 완료될 때까지 대기해야 하므로 렌더링 시간이 각 컴포넌트의 합이 되어 성능이 저하된다.

해결책은 서버에서 라우트를 병렬로 렌더링 하고 클라이언트에서 재귀적으로 조합하는 것이다. React의 renderToReadableStream은 컴포넌트 트리뿐 아니라 배열이나 객체도 렌더링 할 수 있다. 중첩된 컴포넌트 대신 컴포넌트 배열을 렌더링 하면 모든 컴포넌트가 동시에 렌더링을 시작하여 워터폴을 피할 수 있다. 각 레이아웃은 <Placeholder /> 컴포넌트를 children으로 받고, 서버에서 생성된 스택은 클라이언트에서 createFromReadableStream으로 재구성된다.

클라이언트의 <StackReader> 컴포넌트는 스택의 첫 항목을 꺼내 렌더링 하고 나머지는 context에 저장한다. <Placeholder />가 렌더링 될 때마다 다시 <StackReader>를 호출하여 다음 항목을 꺼내는 재귀 패턴을 사용한다. 이렇게 병렬로 렌더링 된 컴포넌트들을 중첩 구조로 재구성하여 모든 라우트가 동시에 실행되므로 워터폴이 발생하지 않는다.

React Conf 2025와 Remix Jam 2025에서 발표된 내용을 비교 분석한 글이다. 두 프레임워크가 서로 다른 가치와 방향을 선택하면서 점점 멀어지고 있다는 점을 지적한다.

React는 안정성(Stability), 조합성(Composability), 기능성(Capability)을 핵심 가치로 삼는다. React 컴파일러는 개발자를 대신해 복잡성을 감수하며, Meta의 Quest 스토어 앱에서 로드 시간 12% 개선과 2배 빠른 인터랙션을 달성했다. 반면 Remix 3는 단순성(Simplicity)을 최우선 가치로 선택하며 React와 완전히 결별했다. use client와 Server Components의 복잡성을 거부하고 명시적인 this.update() API를 도입했다.

// Remix 3의 명시적 업데이트 방식
class Component {
  render() {
    return <button on:click={() => {
      this.state.count++;
      this.update(); // 명시적으로 업데이트 호출
    }}>Count: {this.state.count}</button>
  }
}

Remix 2에서 Remix 3로의 마이그레이션 방법은 제공되지 않으며, Remix 2 사용자는 react-router v7로 전환해야 한다. 이는 단순성을 위해 안정성을 희생한 선택이다. 글은 두 프레임워크의 방향이 기술적 우월성이 아닌 가치의 차이에서 비롯되었으며, 개발자는 자신의 가치에 따라 도구를 선택해야 한다고 강조한다.

JavaScript 생태계에서 프레임워크들이 use client, use server, use cache, use workflow 같은 독자적인 directive를 만들고 있다. 이들은 파일 상단에 위치해 언어 기능처럼 보이지만, 실제로는 표준화되지 않은 프레임워크별 기능이다.

이러한 directive는 여러 문제를 야기한다. 개발자들이 이를 공식 JavaScript 기능으로 오해하고, 프레임워크 간 의미가 달라 혼란을 겪으며, 툴링 지원과 디버깅이 어려워진다. 또한 directive가 옵션이나 파라미터를 필요로 할 때 한계가 드러나는데, use cache:remote 같은 변형이나 cacheLife(...) 같은 헬퍼 함수가 필요해지면서 일관성이 떨어진다. 명시적인 import를 통한 API는 출처, 버저닝, 옵션 전달, 테스트 가능성 측면에서 더 우수하다.

// directive 방식 (출처가 불명확)
'use cache'
const fn = () => 'value'

// 명시적 API 방식 (출처와 옵션이 명확)
import { cache } from 'next/cache'
export const fn = cache(() => 'value', {
  strategy: 'remote',
  ttl: 60,
})

글은 프레임워크가 혁신을 추구하되, 플랫폼 기능과 프레임워크 동작을 명확히 구분해야 한다고 강조한다. 공유 primitive가 필요하다면 표준화 작업을 통해 진행하고, 비표준 기능은 언어 공간이 아닌 API 공간에 명확히 두어 생태계 혼란을 줄여야 한다는 것이다.

프런트엔드와 백엔드 사이의 책임을 어떻게 나눌 것인가? 저자는 전통적인 관습에 의문을 제기하며, 가능한 한 많은 작업을 프런트엔드에서 처리하고 백엔드는 최소화하는 "프런트엔드 최대주의" 접근법을 제안한다. 제품 목록을 보여줄 때 선택된 제품만 가져오는 대신 모든 제품 정보를 미리 가져와 로컬 상태로 관리하거나, 대시보드에서 필터링된 데이터를 백엔드에 요청하는 대신 모든 관련 데이터를 프런트엔드에서 처리하는 방식이 그 예다.

저자는 이 접근법이 사용자 경험 속도 향상, 페이지네이션과 쿼리 구성 관련 버그 제거, 새 기능 추가 비용 감소, API 호출 감소, 개인정보 보호 개선 등의 장점을 제공한다고 주장한다. 불안정한 네트워크 환경에서는 더 많은 데이터를 한 번에 보내더라도 API 호출 횟수가 줄어드는 이점이 더 클 수 있다는 것이다. 다만 데이터가 너무 많거나 보안상 사용자에게 보내서는 안 되는 경우는 예외로 둔다.

글은 Gall's Law를 인용하며 단순함의 가치를 강조한다. "작동하는 복잡한 시스템은 언제나 작동했던 단순한 시스템에서 진화한 것이다." 현대의 도구들(React, TypeScript, Jest, DuckDB 등)은 프런트엔드 최대주의를 실현 가능하게 만들었지만, 시스템 설계 관습은 이러한 도구들이 등장하기 전에 형성되었다는 점을 지적한다. 저자는 습관적으로 책임을 나누기보다 프런트엔드 중심 설계를 고려해 볼 것을 제안한다.

[참고] Gall's Law에 대해서는 다음 문서를 참고하라.

NodeSource가 최근 Node.js에 추가된 15가지 기능을 소개하며, 이들이 기존 인기 npm 패키지를 대체할 수 있음을 설명했다. 이러한 내장 기능들은 의존성 감소, 보안 향상, 성능 개선 등의 이점을 제공한다.

주요 기능으로는 Node.js 18부터 제공되는 글로벌 fetch() API(node-fetch 대체), 내장 테스트 러너(jest/mocha 대체), 웹 스트림 API, AbortController, structuredClone() 등이 있다. 또한 새로운 모듈 시스템 개선사항과 성능 최적화 기능들도 포함되어 있다.

이러한 변화는 Node.js 생태계의 성숙도를 보여주며, 개발자들이 더 적은 의존성으로 안정적인 애플리케이션을 구축할 수 있게 한다. 최신 Node.js 기능을 활용하면 번들 크기 감소와 보안 위험 최소화라는 두 가지 이점을 동시에 얻을 수 있다.

JSON이 다양한 프로그래밍 언어에서 일관되게 해석되지 않는 문제를 다룬 글이다. JSON은 범용 데이터 교환 포맷으로 널리 사용되지만, 각 언어의 구현 차이로 인해 예상치 못한 문제가 발생할 수 있다.

대표적인 문제로는 숫자 정밀도 손실이 있다. JavaScript는 모든 숫자를 64비트 부동소수점으로 처리하므로 Number.MAX_SAFE_INTEGER(2^53 - 1)를 초과하는 정수는 정밀도를 잃는다. 예를 들어 90071992547409939007199254740992로 변환되지만, Python은 이를 정확하게 처리한다. 문자열 인코딩도 언어마다 다르게 처리되어 특수 문자나 이모지 표현이 일관되지 않을 수 있다. 객체 키 순서는 JSON 사양에서 보장하지 않지만 일부 언어는 순서를 유지하고 다른 언어는 그렇지 않아 해시 충돌이나 직렬화 문제를 야기한다.

날짜와 시간 처리도 까다롭다. JSON에는 기본 날짜 타입이 없어서 ISO 8601 문자열, Unix 타임스탬프 등 다양한 형식으로 표현하는데, 각 언어가 이를 해석하는 방식이 달라 시간대 변환이나 파싱 오류가 발생한다. 이러한 문제를 해결하려면 명확한 데이터 스키마 정의, 철저한 테스트, 크로스-플랫폼 호환성을 고려한 개발이 필요하다.

올해 JSON 모듈 import가 모든 브라우저 엔진에서 baseline 'newly available'로 지원되기 시작했다. Jake Archibald는 이 기능이 유용하지만 브라우저 환경에서는 제한적으로 사용해야 한다고 주장한다. 번들러가 처리하는 프런트엔드 소스 코드에서는 사용하겠지만, 브라우저에 직접 전달되는 경우 fetch()가 더 나은 선택이라는 것이다.

첫 번째 이유는 에러 처리다. 정적 import는 실패 시 전체 모듈 그래프가 무너지므로 서드파티 JSON에는 사용하기 어렵다. import()는 try-catch로 폴백을 제공할 수 있지만, fetch()response.statusresponse.text()로 훨씬 상세한 실패 정보를 확인할 수 있다. 더 중요한 문제는 캐싱과 가비지 컬렉션이다. 모듈 import는 페이지 생명주기 동안 결과가 캐시 되므로 검색 결과 같은 동적 데이터를 import 하면 메모리 누수가 발생한다. 큰 데이터의 일부만 사용하고 나머지를 null로 설정해도 import 한 전체 객체는 메모리에 남는다. 반면 fetch()로 가져온 데이터는 참조가 없어지면 가비지 컬렉션 된다.

JSON 모듈 import는 로컬의 정적 JSON 리소스를 대부분 사용하는 경우에 적합하다. 번들러가 JSON import를 이해하고 다른 모듈과 함께 번들링 할 수 있기 때문이다. 다만 esbuild, Vite, Rollup 같은 번들러는 비표준 문법(import { version } from './package.json')을 사용하면 최상위 키만 tree-shaking 할 수 있다. 저자는 일반적으로 "fetch-and-process" 로직을 Vite/Rollup 플러그인으로 변환해 빌드 타임에 처리하도록 한다고 밝혔다.

Evan You가 만든 Vite의 탄생과 성장 과정을 다룬 다큐멘터리다. "JavaScript 프레임워크를 사용한다면 아마도 Vite를 사용하고 있을 것"이라는 문구로 시작하는 이 영상은 Webpack의 느린 빌드 시간에 대한 좌절에서 시작된 Vite의 여정을 보여준다.

처음에는 Vue 사용자를 위한 개인 사이드 프로젝트였던 Vite가 어떻게 React, Svelte, Astro, Remix 등 다양한 프레임워크에서 채택되는 범용 생태계로 성장했는지를 다룬다. 이 과정에서 벌어진 경쟁, 재작성, 그리고 커뮤니티 주도의 혁신들이 프런트엔드 환경을 어떻게 변화시켰는지를 보여준다.

JavaScript 생태계의 저명한 개발자들이 출연하여 Vite가 언더독 프로토타입에서 현대 웹 도구의 새로운 표준이 되기까지의 혁신, 경쟁, 협력의 이야기를 전한다. 현대 프런트엔드 개발 도구의 진화 과정을 이해하는 데 유용한 자료다.

Evan You가 ViteConf의 Vite Beyond a Build Tool 세션을 통해 JavaScript 개발을 위한 통합 도구 체인인 Vite+를 발표했다. 이는 기존 Vite의 기능을 확장하여 프로젝트의 전체 개발 라이프사이클을 지원하는 포괄적인 도구이다.

Vite+는 프로젝트 스캐폴딩(vite new), 테스트 실행(vite test), 코드 린팅(vite lint), 포맷팅(vite fmt), 라이브러리 번들링(vite lib), 모노레포 작업 실행(vite run), GUI 개발 도구(vite ui) 등의 기능을 단일 CLI로 제공한다. 모든 기능은 Rust로 구현된 고성능 컴파일러 툴체인을 기반으로 한다.

이러한 통합 접근법은 JavaScript 개발 환경의 복잡성을 크게 줄이고, 도구 간 호환성 문제를 해결한다. 개발자들은 여러 도구를 개별적으로 설정하고 관리할 필요 없이 일관된 개발 경험을 얻을 수 있다.

Prettier의 창시자인 Vjeux가 코드 포맷터 개발의 상세한 전체 여정의 글을 공유했다.

그는 대학 시절부터 코드 포맷팅 규칙의 자동화 필요성을 느꼈으며, Facebook에서의 경험을 통해 이 문제를 본격적으로 해결하고자 했다. 기존 Linter와 포맷터의 한계를 분석한 후, Go 포맷터인 gofmt와 Dart 포맷터인 dartfmt에서 영감을 받아 JavaScript를 위한 완전 자동화된 코드 포맷터를 개발하게 되었다고 한다. 그는 코드 스타일 논쟁을 기술적 혁신으로 해결하려는 철학을 바탕으로 Prettier를 설계했다.

이 글은 Prettier가 어떻게 JavaScript 생태계의 표준 도구가 되었는지, 그리고 개발자 경험 개선에 어떤 영향을 미쳤는지를 보여주는 귀중한 기록이다. 오픈소스 프로젝트의 탄생과 성장 과정을 이해하는 데 도움이 된다.

Biome 메인테이너인 Emanuele Stoppa가 툴체인 개발의 어려운 부분들과 개발자 경험(DX) 개선 방안을 분석했다. 툴체인은 컴파일러, 에디터 지원, 린터, 포매터 등 프로젝트 라이프사이클 전체를 관리하는 통합 도구를 의미한다.

가장 큰 도전은 의미 있는 에러 메시지와 실행 가능한 피드백 제공이다. 기존 도구들(ESLint 등)과 달리 Biome, oxlint 같은 새로운 도구들은 초보자 친화적인 메시지와 구체적인 해결 방안을 제시한다. 흥미롭게도 컴파일러보다 포매터가 구현하기 가장 어려운 도구라고 밝혔다.

JavaScript 생태계는 분산된 도구들로 인한 복잡성을 겪고 있지만, Rust의 cargo나 Deno처럼 통합된 툴체인으로 발전하고 있다. 이러한 변화는 개발자 경험을 크게 개선하고 설정 복잡성을 줄이는 데 기여한다.

Lodash 미래 계획과 지속 가능한 유지보수 전략에 대한 내용이다. Lodash는 현재 930만 개 웹사이트에서 사용되고 있으며, npm에서 주간 24억 다운로드를 기록하는 JavaScript 생태계의 핵심 라이브러리다.

새로운 계획은 기능 완성된 라이브러리로서 지속 가능성에 초점을 맞춘다. 주요 변화로는 John-David Dalton의 BDFL 모델에서 Technical Steering Committee(TSC) 기반의 복수 거버넌스로 전환, 다양한 변형 패키지 통합, 보안 위협 모델 도입 등이 있다. 또한 현대 JavaScript 네이티브 함수를 활용한 점진적 재작성을 통해 성능을 최적화할 예정이다.

이러한 변화는 Express 5.0 성공 사례를 바탕으로 하며, OpenJS Foundation의 지원을 받는다. 오픈소스 생태계의 지속 가능성 문제를 해결하고, 차세대 메인테이너들에게 영감을 주는 모델이 될 것으로 기대된다.

XSS 공격으로부터 안전한 방식으로 HTML 문자열을 파싱하고 정화하여 DOM에 삽입할 수 있는 실험적 웹 API인 HTML Sanitizer API의 핵심 메서드인 Element.setHTML()을 설명하는 문서다.

setHTML() 메서드는 입력된 HTML 문자열에서 XSS 위험 요소를 자동으로 제거하고, 사용자 정의 Sanitizer 설정을 통해 허용할 요소와 속성을 세밀하게 제어할 수 있다. 기존의 innerHTML과 달리 신뢰할 수 없는 HTML 콘텐츠를 안전하게 처리하며, setHTMLUnsafe()보다 보안성이 뛰어나다.

이 API는 현재 실험적 단계로 브라우저 호환성이 제한적이지만, 웹 보안의 새로운 표준을 제시한다. 특히 사용자 생성 콘텐츠나 외부 데이터를 다루는 웹 애플리케이션에서 XSS 공격 방지를 위한 강력한 도구로 활용될 수 있다.

보다 자세한 내용은 다음 문서를 참고하라.

Cloudflare가 웹에서 JavaScript 암호화의 신뢰성 문제를 해결하기 위한 새로운 시스템을 소개했다. 웹 애플리케이션은 강력한 플랫폼이지만, 2011년부터 지금까지 JavaScript 암호화는 위험한 것으로 간주되어 왔다. 주된 문제는 코드 배포 과정에서 발생하는데, 악의적인 공격자가 JavaScript를 수정하여 암호화된 메시지를 탈취할 수 있기 때문이다.

이 문제를 해결하기 위해 W3C를 중심으로 브라우저 벤더, 클라우드 제공업체, 암호화 통신 개발자들이 협력하여 WAICT(Web Application Integrity, Consistency, and Transparency)를 개발하고 있다. WAICT는 앱스토어처럼 무결성(integrity), 일관성(consistency), 투명성(transparency)을 제공하되, 중앙화된 권한 없이 이를 달성한다. 시스템의 핵심 요소로는 Subresource Integrity(SRI), Integrity Manifest, 그리고 공개 투명성 로그가 있다.

이 시스템은 end-to-end 암호화 메시징, 웹 기반 기밀 LLM, 암호화폐 지갑, 투표 시스템 등 브라우저 내 암호화를 사용하는 모든 애플리케이션에 이점을 제공한다. Cloudflare는 transparency service와 witness 역할을 수행할 계획이며, Tor 생태계와 같은 대안적 환경도 지원할 예정이다. 현재 표준화 초기 단계이며, 곧 베타 버전을 공개할 계획이다.

Andrej Karpathy가 "$100로 살 수 있는 최고의 ChatGPT"라는 슬로건으로 공개한 완전한 LLM 구현 프로젝트다. 이는 ChatGPT와 같은 대화형 AI를 단일 8XH100 노드에서 처음부터 끝까지 구축할 수 있는 최소한이면서도 해킹 가능한 코드베이스를 제공한다.

nanochat은 토큰화, 사전 훈련, 파인튜닝, 평가, 추론, 웹 서빙까지 전체 파이프라인을 포함하며, speedrun.sh 스크립트를 통해 3시간 51분 만에 완전한 ChatGPT 클론을 생성할 수 있다. 현재 공개된 d32 모델(32개 레이어로 구성된 트랜스포머 신경망, 19억 개 매개변수)은 38B 토큰으로 훈련되었으며, 다양한 벤치마크에서 측정 가능한 성능을 보여준다.

이 프로젝트는 Eureka Labs의 LLM101n 과정의 캡스톤 프로젝트로 설계되었으며, 복잡한 설정 객체나 조건문 없이 단일하고 일관된 코드베이스를 유지한다. 1천 달러 미만의 예산으로 접근 가능한 마이크로 모델의 최신 기술 발전을 목표로 하며, 인지적 복잡성과 전체 비용 모두에서 접근성을 추구한다.

Anthropic이 UK AI Security Institute, Alan Turing Institute와 공동으로 진행한 연구에서 놀라운 사실을 발견했다. 단 250개의 악의적 문서만으로 LLM에 백도어 취약점을 만들 수 있으며, 이는 모델 크기나 훈련 데이터 양과 무관하다는 것이다. 13B 파라미터 모델은 600M 모델보다 20배 이상 많은 훈련 데이터를 사용하지만, 동일한 소량의 중독된 문서로 백도어 공격이 가능했다.

연구진은 600M부터 13B 파라미터까지 다양한 크기의 모델을 훈련하며 denial-of-service 공격을 테스트했다. 이 공격은 특정 트리거 문구(예: <SUDO>)를 보면 모델이 무작위 gibberish 텍스트를 생성하도록 만든다. 실험 결과, 250개 이상의 중독된 문서면 모든 크기의 모델에서 공격이 성공했으며, 공격 성공률은 훈련 데이터의 비율이 아닌 중독된 문서의 절대 개수에 의존했다. 이는 기존 가정(공격자가 훈련 데이터의 일정 비율을 통제해야 함)을 완전히 뒤집는 결과다.

250개의 악의적 문서는 약 420k 토큰으로, 13B 모델 전체 훈련 토큰의 0.00016%에 불과하다. 이는 공격자에게 수백만 개가 아닌 수백 개의 문서만 만들면 되므로, 데이터 중독 공격이 기존에 생각했던 것보다 훨씬 실행 가능함을 의미한다. 연구진은 이 결과를 공개함으로써 방어자들이 적절한 대응을 준비할 수 있도록 하고, 더 강력한 방어 기법 개발을 장려하고자 한다.

Anthropic은 AI 에이전트가 특정 작업에 특화될 수 있도록 돕는 'Agent Skills' 시스템을 공개했다. 이 시스템은 파일과 폴더를 활용하여 에이전트에 전문 지식을 동적으로 로드할 수 있게 한다.

Agent Skills는 SKILL.md 파일과 관련 리소스를 포함하는 디렉터리로 구성되며, 에이전트는 필요에 따라 이 정보를 자동으로 로드한다. 각 스킬은 특정 도메인의 지침, 스크립트, 예제 코드 등을 포함하여 에이전트의 성능을 향상한다.

이러한 접근 방식은 일반 목적의 에이전트를 특정 업무에 특화된 전문 에이전트로 변환할 수 있게 하며, 에이전트의 유연성과 확장성을 크게 높인다. 개발자들은 자신만의 스킬을 만들어 에이전트를 커스터마이징 할 수 있다.

[참고]

AI를 활용한 소프트웨어 개발의 두 가지 접근 방식을 비교 분석한 글이다. 'Vibe Coding'은 빠르고 즉흥적인 AI 활용 방식이며, 'Vibe Engineering'은 숙련된 엔지니어가 AI를 도구로 활용하여 책임감 있게 개발하는 방식이다.

Vibe Engineering은 자동화된 테스트, 사전 계획, 포괄적인 문서화, 효과적인 버전 관리, 자동화된 배포, 코드 리뷰 문화 등의 엔지니어링 모범 사례를 유지하면서 AI의 생산성 이점을 활용한다. 이는 단순히 빠른 코드 생성을 넘어서 지속 가능한 소프트웨어 개발을 추구한다.

이 개념은 AI 시대의 소프트웨어 개발에서 기술적 역량과 엔지니어링 원칙의 균형을 맞추는 방법을 제시한다. 개발자들이 AI를 효과적으로 활용하면서도 코드 품질과 유지보수성을 보장할 수 있는 실용적인 가이드를 제공한다.

LLM 코딩 에이전트를 사용하면서 느끼는 어색함의 원인을 분석한 글이다. 저자는 LLM이 인간 개발자와 다르게 작동하는 두 가지 근본적인 문제를 지적한다.

첫째, LLM은 코드를 복사-붙여 넣기 하지 않는다. 대용량 파일을 여러 작은 파일로 리팩터링 할 때, 인간은 복사-붙여 넣기를 통해 코드가 정확히 동일하게 옮겨졌다는 확신을 얻는다. 하지만 LLM은 코드 블록을 "기억"한 후 delete와 write 도구를 사용해 메모리에서 재작성한다. 실제 cut이나 paste 도구가 없고, 모든 수정이 메모리에서 write 명령을 실행하는 방식이다. Codex가 가끔 sedawk로 복사-붙여 넣기를 흉내 내려 하지만 항상 작동하지는 않는다.

둘째, LLM은 질문을 잘 못한다. 숙련된 개발자는 큰 변경을 하기 전이나 불확실할 때 항상 질문한다("나쁜 질문은 없다"는 격언). 하지만 LLM은 여러 가정을 세우고 그에 기반해 무작정 시도하며, 막혀도 계속 같은 벽에 머리를 부딪힌다. 프롬프트를 정교하게 작성하면(Roo가 좋은 예) 질문을 더 많이 하게 할 수 있지만, 여전히 질문하지 않을 가능성이 높다. 저자는 LLM이 인간 개발자를 대체한다는 생각에 반대하며, LLM을 "이상하고 과신하는 인턴"에 비유한다.

코딩 에이전트의 성능을 향상하기 위한 고급 콘텍스트 엔지니어링 기법을 다루는 GitHub 문서다. 코딩 에이전트가 복잡한 소프트웨어 개발 작업을 효율적으로 수행하려면 올바른 콘텍스트를 제공하는 것이 핵심이다.

문서는 콘텍스트 설계, 조정, 최적화 세 가지 영역을 다룬다. 콘텍스트 설계는 에이전트가 작업 수행에 필요한 정보를 효과적으로 수집하고 구성하는 방법을 설명한다. 콘텍스트 조정은 에이전트의 성능을 최적화하기 위해 콘텍스트를 동적으로 조정하는 전략을 제시한다. 콘텍스트 최적화는 에이전트가 불필요한 정보를 배제하고 중요한 정보에 집중할 수 있도록 하는 기법을 소개한다.

이 문서는 코딩 에이전트의 효율성과 정확성을 높이고자 하는 개발자와 연구자에게 실용적인 지침을 제공한다. 콘텍스트 엔지니어링은 AI 코딩 어시스턴트의 성능을 좌우하는 중요한 요소이며, 적절한 콘텍스트 관리를 통해 에이전트의 작업 품질을 크게 향상할 수 있다.

Microsoft가 GitHub과 협력하여 AI 기반 소프트웨어 개발을 위한 새로운 접근법인 'Spec-Driven Development(SDD)'와 GitHub Spec Kit을 소개했다. 이는 AI 에이전트가 정확한 결과를 생성할 수 있도록 명확한 콘텍스트와 요구사항을 사전에 정의하는 개발 방법론이다.

SDD는 코드 작성 전에 프로젝트의 요구사항, 동기, 기술적 측면을 명시적으로 문서화하여 AI 에이전트가 정확히 필요한 것을 구축할 수 있게 한다. GitHub Spec Kit은 Specify CLI와 템플릿 세트를 제공하며, /specify, /plan, /tasks 세 가지 슬래시 명령어를 통해 순차적으로 사양 정의, 기술 계획 수립, 작업 분해를 수행한다.

이 접근법은 기존의 'vibe coding' 방식을 넘어서 체계적이고 검토 가능한 개발 프로세스를 제공한다. 특히 AI 에이전트와의 협업에서 공유된 콘텍스트의 중요성을 강조하며, 다중 구현 변형 생성이나 다양한 기술 스택 실험을 쉽게 할 수 있게 한다.

저명한 UX 에이전시인 Nielsen Norman Group이 iOS 26의 새로운 디자인 언어인 'Liquid Glass'의 사용성 문제를 분석한 글을 공유했다. 이 디자인은 시각적으로 매력적이지만 실제 사용자 경험에서는 여러 단점을 보인다.

투명도와 반사 효과로 인해 텍스트 가독성이 저하되고, 인터페이스 요소 간의 구분이 어려워진다. 특히 저시력 사용자나 밝은 환경에서 사용할 때 문제가 더욱 심각해진다. 또한 동적인 배경 효과가 인지적 부담을 증가시켜 사용자의 집중력을 방해한다.

이 분석은 디자인과 사용성 간의 균형이 얼마나 중요한지를 보여준다. 시각적 혁신이 사용자 경험을 해치지 않도록 하는 것이 UI/UX 디자인의 핵심 과제임을 강조한다. 개발자와 디자이너들에게 기능성을 우선시하는 디자인 철학의 중요성을 일깨워준다.

반응형 웹 디자인에서 유동적인 헤딩 크기를 구현하는 고급 기법을 소개하는 글이다. 기존의 미디어 쿼리 기반 접근법을 넘어서 더 부드럽고 자연스러운 타이포그래피 스케일링을 구현하는 방법을 다룬다.

CSS의 clamp() 함수와 뷰포트 단위(vw, vh)를 조합하여 화면 크기에 따라 연속적으로 변화하는 헤딩 크기를 만드는 기법을 설명한다. 또한 최소/최대 크기 제한을 통해 가독성을 보장하면서도 시각적 일관성을 유지하는 방법도 제시한다.

이러한 기법은 다양한 디바이스에서 일관된 사용자 경험을 제공하며, 특히 모바일과 데스크톱 간의 자연스러운 전환을 가능하게 한다. 현대 웹 디자인에서 요구되는 반응형 타이포그래피의 새로운 표준을 제시한다.

JavaScript에서 typeof NaN'number'를 반환하지만, 모든 수학 연산은 다시 NaN을 반환한다. 더 흥미로운 점은 NaN !== NaNtrue를 반환한다는 것이다. 이 독특한 동작은 JavaScript의 버그가 아니라 1985년 제정된 IEEE 754 표준에서 의도적으로 설계된 것이다.

Firefox와 V8의 소스 코드를 살펴보면 std::isnan이라는 표준 라이브러리 메서드를 사용하는데, 이는 NaN이 JavaScript 이전부터 존재했음을 보여준다. x86 아키텍처의 ucomisd 명령어는 하드웨어 레벨에서 NaN을 감지하여 PF(Parity Flag)를 설정한다. C, Python, C++, Rust 등 모든 언어에서 동일한 동작을 보이는 이유는 CPU 레벨에서 NaN이 구현되어 있기 때문이다.

// JavaScript에서 NaN의 특성
console.log(typeof NaN);        // 'number'
console.log(NaN + 1);            // NaN
console.log(NaN !== NaN);        // true
console.log(Number.isNaN(NaN));  // true (올바른 확인 방법)

// NaN이 발생하는 경우들
console.log(0 / 0);              // NaN
console.log(Math.sqrt(-1));      // NaN
console.log(Infinity - Infinity); // NaN

IEEE 754 이전에는 0/0 같은 연산이 프로그램을 크래시 시켰고, 개발자들은 모든 연산 전에 방어적 코딩을 해야 했다. NaN은 에러 전파를 통해 프로그램이 계속 실행되도록 하며, 최종 결과에서 문제를 확인할 수 있게 한다. NaN !== NaN이라는 특성은 isNaN() 함수가 없던 시절 개발자들이 x != x 테스트로 NaN을 감지할 수 있게 하기 위한 것이었다. 이는 수백만 개의 프로세서를 교체하게 만든 1994년 Pentium FDIV 버그($475 million 손실)가 보여주듯, 부동소수점 연산의 정확한 표준화가 얼마나 중요한지를 증명한다.

한빛미디어가 주최한 개발자 중심 기술 콘퍼런스인 데브그라운드 2025가 지난 9월 18일 홍대입구역 인근 한빛미디어에서 성황리에 개최되었다. "Vibe Up, Next Stage"를 주제로 AI와 개발의 미래를 탐구하고, 실전 경험으로 풀어낸 개발자들의 이야기를 통해 Next Stage로 도약할 인사이트와 노하우를 나누는 자리였다.

행사는 AI 트랙과 Vibe Coding 트랙으로 구성되었다. AI 트랙에서는 Upstage 연구진을 포함한 전문가들이 최신 AI 트렌드를 짚어보고, LLM을 어떻게 설계하고 서비스에 적용했는지 실전 사례를 공유했다. 주요 세션으로는 "LLM, 믿고 쓸 수 있을까요? 지표 중심 LLM 모니터링", "한눈에 알아보는 LLM post-training", "Document AI 서비스 성장스토리" 등이 있었다. Vibe Coding 트랙에서는 새로운 개발 방식인 '바이브코딩'을 체험하며 Cursor AI, Figma MCP 등 AI 도구로 만든 산출물을 중심으로 탐구하고, 현업 프로젝트에서 얻은 노하우와 사례를 나누었다.

박태웅 녹서포럼 의장의 "2030년에 우리는 어떻게 일하고 있을까?"와 하용호 데이터오븐 CEO의 "AI 시대, 개발자가 반드시 알아야 할 속도 향상 비법" 키노트를 비롯해 다양한 세션이 진행되었다. 각 세션별 발표자료와 영상은 행사 종료 후 한빛+ 홈페이지에서 다시보기 형태로 제공될 예정이다.

삼성전자가 2025년 10월 30일 '삼성 인터넷 PC 브라우저'를 새롭게 공개하고 베타 프로그램을 운영한다. 이 브라우저는 갤럭시 스마트폰에서 제공되던 삼성 인터넷의 PC 버전으로, 모바일과 PC 간의 원활한 연동을 목표로 한다.

주요 기능으로는 모바일과 PC 간 북마크와 방문 기록 등의 브라우저 데이터를 실시간으로 동기화할 수 있으며, 삼성패스(Samsung Pass)에 저장된 개인 정보의 연동을 통해 PC에서도 간편한 로그인과 자동완성이 가능하다. 스마트 추적 방지(Smart Anti-tracking) 기능이 적용되어 개인 정보 유출을 방지하며, 갤럭시 AI의 '브라우징 어시스트(Browsing Assist)'를 통해 웹 페이지의 번역과 요약 기능을 제공한다.

베타 프로그램은 한국과 미국에서 먼저 시작되며, 향후 다른 지역으로 확대될 예정이다. 삼성은 이번 PC 브라우저를 통해 갤럭시 생태계를 PC까지 확장하고, 모바일과 데스크톱 간의 매끄러운 사용자 경험을 제공하고자 한다.

🕹 튜토리얼

모두가 <input> 태그는 알지만, <output> 태그는 대부분의 개발자가 존재조차 모른다. HTML5 스펙에서 "계산 결과나 사용자 액션의 결과"를 나타내기 위해 설계된 이 태그는, 접근성 트리에서 자동으로 role="status"로 매핑되어 값이 변경될 때 스크린 리더가 자동으로 읽어준다. ARIA 속성 없이도 aria-live="polite" aria-atomic="true"와 동일한 효과를 제공한다.

<output> 태그는 for 속성을 통해 관련된 input 요소들과 의미론적으로 연결할 수 있다. 간단한 계산기부터 범위 슬라이더 값 포맷팅, 비밀번호 강도 표시, 실시간 폼 검증까지 다양하게 활용 가능하다. 서버에서 계산된 값(배송비, 세금 등)도 표시할 수 있으며, React나 Vue 같은 프레임워크와도 완벽하게 호환된다.

// React에서 범위 슬라이더와 함께 사용하는 예시
<div role="group" aria-labelledby="mileage-label">
  <label id="mileage-label" htmlFor="mileage">Annual mileage</label>
  <input
    id="mileage"
    type="range"
    value={mileage}
    onChange={(e) => setMileage(Number(e.target.value))}
  />
  <output name="formattedMileage" htmlFor="mileage">
    {mileage.toLocaleString()} miles/year
  </output>
</div>

2008년부터 스펙에 포함되어 있어 브라우저 지원도 훌륭하다. <div>와 ARIA live region으로 해결해 왔던 동적 결과 표시를 네이티브 HTML로 더 간단하고 접근성 있게 구현할 수 있다. 토스트 메시지 같은 전역 알림이 아닌, 사용자 입력에 연결된 결과 표시에 사용하는 것이 적절하다.

JavaScript에서 비동기 루프를 다룰 때 await의 사용 방식에 따라 성능과 동작이 크게 달라진다. Matt Smith는 비동기 루프의 일반적인 문제점과 해결 방안을 제시한다.

가장 흔한 실수는 for 루프 안에서 await를 사용하는 것이다. 각 fetchUser 호출이 이전 호출이 완료될 때까지 대기하므로 독립적인 네트워크 호출을 순차적으로 실행하게 된다. map() 내에서 await를 사용하면 프로미스 배열을 반환하지만 프로미스가 해결될 때까지 기다리지 않는다. 모든 요청을 병렬로 실행하고 최종 결과를 얻으려면 await Promise.all(users.map(id => fetchUser(id)))를 사용해야 한다.

Promise.all()의 문제는 하나의 프로미스가 거부되면 전체 연산이 실패하고 성공한 결과도 반환되지 않는다는 것이다. 안전한 대안으로 Promise.allSettled()를 사용하면 일부가 실패하더라도 모든 결과를 처리할 수 있다. 또는 매핑 함수 내에서 try...catch로 개별적으로 오류를 처리할 수 있다.

// 순차 실행 (이전 작업의 결과에 의존하거나 API 속도 제한이 있을 때)
for (const id of users) {
  const user = await fetchUser(id);
}

// 병렬 실행 (작업이 독립적일 때)
const usersData = await Promise.all(users.map(id => fetchUser(id)));

// 제어된 동시성 (API 제한을 준수하면서 속도 향상)
import pLimit from 'p-limit';
const limit = pLimit(2); // 한 번에 2개의 fetch 실행
const results = await Promise.all(users.map(id => limit(() => fetchUser(id))));

상황에 따라 순차 실행, 병렬 실행, 제어된 동시성 중 적절한 패턴을 선택하는 것이 중요하다.

NPM 패키지 관리 시 보안을 강화하기 위한 포괄적인 모범 사례 가이드다. 이 저장소는 패키지 설치부터 배포까지 전 과정에서 고려해야 할 보안 요소들을 체계적으로 정리했다.

주요 내용으로는 의존성 취약점 스캔, 패키지 무결성 검증, 자동화된 보안 업데이트, 최소 권한 원칙 적용, 공급망 공격 방지 등이 포함되어 있다. 또한 npm audit, npm ci, .npmrc 설정 최적화 등 실무에서 바로 적용할 수 있는 구체적인 명령어와 설정 방법도 제시한다.

이 가이드는 Node.js 프로젝트의 보안 수준을 크게 향상할 수 있는 실용적인 지침을 제공한다. 특히 오픈소스 패키지에 의존하는 현대 JavaScript 개발 환경에서 필수적인 보안 지식을 습득할 수 있다.

WebKit 팀이 CSS Grid의 개념적 이해를 돕는 정신 모델과 그리드 라인의 강력한 활용법을 소개한다. 복잡한 Grid 레이아웃을 더 직관적으로 이해하고 구현할 수 있는 방법을 제시한다.

그리드 라인을 중심으로 한 사고방식을 통해 요소 배치를 더 정확하게 제어할 수 있으며, 명명된 그리드 라인을 활용하면 코드의 가독성과 유지보수성이 크게 향상된다. 또한 암시적 그리드와 명시적 그리드의 차이점과 활용 방안도 상세히 다룬다.

이 글은 CSS Grid를 단순한 레이아웃 도구가 아닌 강력한 디자인 시스템 구축 도구로 활용하는 방법을 보여준다. 복잡한 반응형 레이아웃을 효율적으로 구현하고자 하는 개발자들에게 실용적인 인사이트를 제공한다.

📦 코드와 도구

ESLint 팀이 프로젝트의 ESLint 설정을 시각적으로 분석하고 검증할 수 있는 Config Inspector 도구를 공개했다. 이 도구는 복잡한 ESLint 설정의 구조를 이해하고 잠재적 문제를 식별하는 데 도움을 준다.

# eslint.config.js 설정 파일이 위치한 프로젝트 루트에서 다음을 실행
$ npx @eslint/config-inspector@latest

Inspector는 설정 파일의 구조를 시각적으로 표현하고, 각 규칙의 적용 범위와 우선순위를 명확히 보여준다. 또한 설정 충돌이나 중복을 감지하여 최적화 방안을 제시한다.

이 도구는 특히 대규모 프로젝트나 복잡한 모노레포 환경에서 ESLint 설정을 관리할 때 유용하다. 팀 내 코드 스타일 일관성을 유지하고 린팅 성능을 최적화하는 데 실질적인 도움을 제공한다.