
웹 애플리케이션에서 전환 품질은 기능 완성도와 동등한 수준으로 중요하다. 사용자가 목록에서 항목을 선택해 상세 화면으로 이동할 때, 화면이 자연스럽게 이어지면 서비스는 빠르고 안정적으로 느껴진다. 반대로 동일한 기능이라도 전환이 끊기면 체감 성능과 신뢰도는 동시에 하락한다. 전환은 부가적인 장식이 아니라, 사용자가 시스템을 인지하는 방식에 직접적인 영향을 미치는 요소다.
과거에는 이러한 전환을 구현하기 위해 DOM을 측정하고, 좌표를 계산하고, 엔터·엑시트 타이밍을 정교하게 동기화하며, z-index를 조정하는 작업을 수동으로 수행해야 했다. 작은 화면이나 단순한 상태 구조에서는 관리가 가능했지만, 화면 수와 상태 수가 늘어나는 순간 애니메이션 코드는 여러 계층으로 흩어지고 로직과 표현이 서로 얽히기 시작한다. 그 결과 변경 비용은 기하급수적으로 증가하고, 전환은 점점 유지보수하기 어려운 영역이 된다.
View Transition API는 이 문제를 다른 관점에서 정의한다. 핵심은 “브라우저가 전환 스냅샷을 관리한다”는 전제다. 개발자는 상태 변경 시점을 명시하고, 브라우저는 변경 전후의 DOM을 캡처한 뒤 의사 요소 레이어를 생성해 전환을 수행한다. 전환의 물리적 구현은 브라우저가 책임지고, 개발자는 전환의 의미와 맥락을 설계하는 데 집중한다. 구현 세부를 직접 제어하는 방식에서, 전환을 선언적으로 정의하는 방식으로 책임이 이동한 셈이다.
화면 전환 문제는 대체로 아래와 같은 세 가지 유형에서 발생한다. 형태는 다르지만 세 경우의 공통 요구는 하나다. 사용자는 결과 자체보다 “무엇이 무엇으로 이어졌는가”를 먼저 파악하고 싶어 한다는 점이다. 맥락이 보존되어야 변화가 이해된다.
같은 문서 내부에서 상태만 바뀌는 전환
라우트 이동처럼 문서 맥락이 바뀌는 전환
같은 화면에서 요소 배치가 재구성되는 전환
개별 컴포넌트에 독립적인 애니메이션을 부여하는 방식은 국소적으로는 화려할 수 있다. 그러나 전체 화면 차원에서의 연속성을 보장하지 못하면, 사용자에게는 단절된 효과들의 집합으로 인식될 뿐이다. 전환은 개별 요소의 움직임이 아니라, 상태 간 관계를 드러내는 설계 문제다.
실무에서 더 자주 마주하는 문제는 전환 규칙의 불일치다. 어떤 화면은 페이드, 어떤 화면은 슬라이드, 어떤 화면은 즉시 전환된다면 인터랙션 모델 자체가 예측 불가능해진다. 사용자는 매번 새로운 규칙을 학습해야 하고, 그 과정에서 피로가 누적된다. 결국 전환의 목표는 “예쁜 효과”가 아니라 “일관된 정보 전달”이다. 시각적 효과는 수단일 뿐이며, 핵심은 맥락을 유지한 채 변화를 설명하는 데 있다.
View Transition의 동작 모델
View Transition의 핵심은 document.startViewTransition()이다. 이 메서드를 호출하면 브라우저는 현재 DOM 상태를 스냅샷으로 캡처한다. 이후 콜백 내부에서 수행된 DOM 업데이트가 완료되면 변경 이후 상태를 다시 캡처하고, 두 스냅샷 사이를 전환 전용 레이어로 구성해 애니메이션한다. 개발자가 직접 이전·이후 상태를 계산하는 것이 아니라, 상태 변경의 경계를 선언하면 브라우저가 그 사이를 연결한다는 점이 핵심이다.
function updateLayout() {
const app = document.querySelector('#app');
if (!app) return;
app.classList.toggle('is-detail');
}
export function transitionLayout() {
if (!document.startViewTransition) {
updateLayout();
return;
}
document.startViewTransition(() => {
updateLayout();
});
}이 코드에서 가장 중요한 부분은 폴백 처리다. View Transition은 기능의 전제 조건이 아니라 점진적 향상의 수단이어야 한다. API를 지원하지 않는 환경에서도 상태 변경은 동일하게 수행되어야 하며, 전환은 사용자 경험을 강화하는 추가 계층으로 동작해야 한다. 전환이 사라지더라도 기능은 깨지지 않아야 한다는 원칙을 지켜야 한다.
startViewTransition은 전환 객체를 반환한다. 이 객체를 통해 전환의 생명주기를 관측할 수 있으며, 이는 운영 관점에서 의미 있는 신호가 된다.
export function transitionWithTelemetry(updateDOM: () => void) {
if (!document.startViewTransition) {
updateDOM();
return;
}
const transition = document.startViewTransition(() => {
updateDOM();
});
transition.ready
.then(() => {
console.info('[vt] ready');
})
.catch((error) => {
console.warn('[vt] ready rejected', error);
});
transition.finished.then(() => {
console.info('[vt] finished');
});
}ready는 브라우저가 두 상태의 스냅샷을 성공적으로 준비했을 때 resolve된다. 반대로 거절되는 경우는 전환 이름 충돌과 같이 브라우저가 전환을 구성하지 못한 상황이다. 이 시점을 로깅해두면 특정 화면에서 전환이 보이지 않는 문제를 빠르게 진단할 수 있다. finished는 애니메이션이 완전히 종료된 시점을 나타낸다. 이를 활용하면 전환 완료 이후 후속 작업을 안전하게 연결할 수 있다.
전환을 단순한 시각 효과로 취급하지 않고, 생명주기를 갖는 상태 변화 과정으로 다루면 운영과 디버깅의 관점에서도 통제 가능한 영역이 된다. 이는 선언적 전환 모델이 제공하는 또 하나의 이점이다.
view-transition-name과 의사 요소 트리
shared element 전환의 핵심은 view-transition-name이다. 전환 전후 화면에서 동일한 의미를 갖는 요소에 같은 이름을 지정하면, 브라우저는 이를 하나의 연속된 객체로 인식한다. 그 결과 위치 이동, 크기 변화, 불투명도 전환이 개별 애니메이션의 조합이 아니라 하나의 맥락 있는 변화로 연결된다.
<!-- 목록 화면 -->
<img src="cover.jpg" alt="표지" style="view-transition-name: book-cover" />
<!-- 상세 화면 -->
<img src="cover.jpg" alt="표지 상세" style="view-transition-name: book-cover" />이처럼 동일한 view-transition-name을 부여하면, 브라우저는 전환 시점에 내부적으로 의사 요소 트리를 구성해 애니메이션을 수행한다.
::view-transition
└─ ::view-transition-group(<pt-name-selector>[.<pt-class-selector>]?)
├─ ::view-transition-image-pair(<pt-name-selector>[.<pt-class-selector>]?)
│ ├─ ::view-transition-old(<pt-name-selector>[.<pt-class-selector>]?)
│ └─ ::view-transition-new(<pt-name-selector>[.<pt-class-selector>]?)
└─ ... (other groups)<pt-name-selector>는 view-transition-name으로 연결된 개별 대상 식별자다. 전환의 “동일성”을 판단하는 기준이 바로 이 값이다. 반면 <pt-class-selector>는 view-transition-class로 지정한 공통 스타일 훅이다. 매칭과 스타일 재사용을 분리하는 구조라고 이해하면 된다.
실무에서는 “매칭은 name, 스타일 재사용은 class”라는 원칙으로 설계하면 복잡도가 크게 낮아진다.
.card--a {
view-transition-name: card-a;
view-transition-class: card-featured;
}
.card--b {
view-transition-name: card-b;
view-transition-class: card-featured;
}
::view-transition-group(.card-featured) {
animation-duration: 280ms;
}
::view-transition-old(card-a),
::view-transition-new(card-a),
::view-transition-old(card-b),
::view-transition-new(card-b) {
border-radius: 16px;
}이 구조에서는 각 카드가 고유한 view-transition-name으로 개별 매칭을 보장하고, view-transition-class를 통해 공통 전환 규칙을 묶는다. 이름은 동일성의 기준이고, 클래스는 스타일 전략의 단위다.
주의할 점도 분명하다. view-transition-class는 매칭 키가 아니다. 브라우저는 오직 view-transition-name을 기준으로 전환 대상을 연결한다. 동일한 시점에 같은 이름이 중복되면 전환이 스킵되거나 ready가 reject될 수 있다. shared element 전환의 안정성은 결국 고유하고 충돌 없는 이름 설계에 달려 있다.
CSS 의사 요소로 전환 효과 커스터마이징
기본 전환은 크로스 페이드다. 변경 전 스냅샷과 변경 후 스냅샷을 겹쳐 놓고 불투명도를 교차시키는 방식이다. 이 기본값만으로도 충분히 자연스러운 전환을 만들 수 있지만, 의사 요소를 직접 스타일링하면 슬라이드, 스케일, 마스크, 블러와 같은 효과를 CSS만으로 확장할 수 있다.
::view-transition {
isolation: isolate;
}
::view-transition-group(root) {
overflow: hidden;
animation-duration: 320ms;
}
::view-transition-image-pair(root) {
mix-blend-mode: normal;
}
::view-transition-old(root) {
animation: slide-out 0.32s ease-in-out both;
}
::view-transition-new(root) {
animation: slide-in 0.32s ease-in-out both;
}
@keyframes slide-out {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(-40px);
opacity: 0;
}
}
@keyframes slide-in {
from {
transform: translateX(40px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}::view-transition-old(root)와 ::view-transition-new(root)는 각각 이전 화면과 다음 화면의 스냅샷을 나타낸다. 이 레이어에 직접 애니메이션을 적용함으로써 전환의 물리적 움직임을 정의할 수 있다. ::view-transition-group(root)는 해당 전환 단위를 감싸는 컨테이너로, duration이나 overflow 같은 전역 규칙을 제어하는 지점이다.
중요한 점은 전환을 “효과 추가”의 관점이 아니라 “리듬 설계”의 관점에서 다루는 것이다. 과도한 이동 거리, 긴 duration, 복합적인 easing은 주목도를 높일 수 있지만 동시에 인지 부담도 증가시킨다. 실무에서는 180~320ms 범위의 짧은 전환을 기본값으로 두고, 정보 구조상 강조가 필요한 구간에서만 차별화된 효과를 적용하는 편이 안정적이다.
전환의 목적은 화면을 화려하게 만드는 것이 아니다. 사용자가 상태 변화를 빠르게 이해하도록 돕는 것이다. CSS 커스터마이징은 그 목적을 보조하는 수단이어야 하며, 일관된 타이밍과 움직임 패턴을 유지하는 것이 전체 인터랙션 품질을 좌우한다.
same-document 전환: SPA에서의 적용 전략
SPA에서 자주 마주하는 장면은 목록 재정렬, 필터링, 선택 상태 변경과 같은 동일 문서 내부의 상태 변화다. 이 경우 각 요소에 고유한 이름을 일일이 부여하지 않더라도 view-transition-name: match-element를 활용하면 자동 매칭 기반 전환을 구성할 수 있다.
.sortable-list > li {
view-transition-name: match-element;
}
::view-transition-group(*) {
animation-duration: 0.5s;
}
html::view-transition-old(*),
html::view-transition-new(*) {
height: 100%;
}match-element는 브라우저가 동일 문서 내에서 이전·이후 DOM을 비교해 대응 요소를 추론하도록 위임하는 방식이다. 특히 리스트 재정렬처럼 “같은 항목이 다른 위치로 이동하는” 상황에서 선언적이고 간결한 해법이 된다.
다만 이 값은 same-document 전환에서만 안전하다. 문서 간 전환(MPA)에서는 내부 식별자가 유지된다는 보장이 없기 때문에 동일한 기대를 전제해서는 안 된다. 문서 경계를 넘는 경우에는 명시적인 view-transition-name 설계가 필요하다.
또 하나의 실무적 주의점은 전환 콜백 내부의 작업량이다. startViewTransition 콜백에서 무거운 연산이나 비동기 흐름 제어를 수행하면, 이전 상태와 다음 상태 스냅샷 사이의 간격이 길어진다. 이는 부드러운 전환으로 이어지지 않고 오히려 지연으로 체감될 수 있다. 전환 콜백은 가능한 한 “상태 변경만 수행하는 얇은 경계”로 유지하는 것이 안정적이다.
React에서의 View Transition
리액트 환경에서는 상태 업데이트 타이밍이 핵심 변수다. startViewTransition 콜백 안에서 setState를 호출하더라도, 실제 커밋 시점이 지연되면 브라우저의 스냅샷 캡처 타이밍과 어긋날 수 있다. 그 결과 전환이 생략되거나 기대와 다른 방식으로 보일 수 있다.
이 문제를 완화하기 위해 제한적으로 flushSync를 사용할 수 있다.
import { useState } from 'react';
import { flushSync } from 'react-dom';
type Book = { id: number; title: string };
const books: Book[] = [
{ id: 1, title: '책 1' },
{ id: 2, title: '책 2' },
{ id: 3, title: '책 3' },
];
export default function App() {
const [selectedId, setSelectedId] = useState<number | null>(null);
function selectBook(id: number) {
if (!document.startViewTransition) {
setSelectedId(id);
return;
}
document.startViewTransition(() => {
flushSync(() => {
setSelectedId(id);
});
});
}
function goBack() {
if (!document.startViewTransition) {
setSelectedId(null);
return;
}
document.startViewTransition(() => {
flushSync(() => {
setSelectedId(null);
});
});
}
if (selectedId === null) {
return (
<ul>
{books.map((book) => (
<li
key={book.id}
style={{ viewTransitionName: `book-${book.id}` }}
onClick={() => selectBook(book.id)}
>
{book.title}
</li>
))}
</ul>
);
}
return (
<section style={{ viewTransitionName: `book-${selectedId}` }}>
<h2>{books.find((book) => book.id === selectedId)?.title}</h2>
<button onClick={goBack}>뒤로가기</button>
</section>
);
}flushSync는 상태 업데이트를 즉시 커밋해 브라우저 스냅샷 시점과 정렬시키는 역할을 한다. 전환의 안정성을 확보하는 데는 효과적이지만, 리액트의 동시성 이점을 일부 포기하는 선택이기도 하다. 메인 스레드 점유 시간이 늘어날 수 있고, 렌더링 유연성이 감소할 수 있다.
따라서 이 기법은 “전환 품질이 실제로 깨지는 구간”에 한정해 최소 범위로 적용하는 것이 바람직하다. 전환을 위해 전체 렌더링 전략을 동기화하는 것은 과도한 대응일 수 있다. 전환은 상태 변화의 표현 계층이며, 애플리케이션의 렌더링 모델 전체를 흔들어서는 안 된다.
선언적 ViewTransition 컴포넌트
리액트는 선언적 ViewTransition 컴포넌트를 제공한다. 다만 이 기능은 현재 canary/experimental 채널 중심으로 제공되므로, 프로덕션 도입 전에는 채널 정책과 업그레이드 전략을 먼저 점검해야 한다. API 자체보다 “언제 안정화되는가”가 운영 리스크에 더 직접적인 변수다.
선언적 접근의 장점은 전환 시점을 리액트가 내부적으로 조율한다는 점이다. 직접 document.startViewTransition()을 호출하는 대신, **트리거 유형(enter, exit, update, share)**에 따라 전환 클래스를 선언적으로 부여할 수 있다. 전환을 명령형 이벤트로 다루기보다, 상태 변화의 한 표현으로 편입시키는 방식이다.
import { ViewTransition, startTransition, useState } from 'react';
export default function Example() {
const [open, setOpen] = useState(false);
return (
<>
<button
onClick={() => {
startTransition(() => {
setOpen((prev) => !prev);
});
}}
>
토글
</button>
{open ? (
<ViewTransition
enter="slide-in"
exit="slide-out"
default="fade-default"
>
<div>내용</div>
</ViewTransition>
) : null}
</>
);
}이 방식에서는 리액트의 startTransition과 결합해 상태 변경을 전환 경계 안에 포함시킨다. 전환 클래스는 CSS 설계의 문제로 분리되고, 전환 트리거는 렌더링 흐름과 자연스럽게 맞물린다. 아래는 실무에서 자주 마주하는 props를 중심으로 축약한 개념 타입이다.
type ViewTransitionClass = string | Record<string, string>;
type ViewTransitionProps = {
children?: React.ReactNode;
default?: ViewTransitionClass;
enter?: ViewTransitionClass;
exit?: ViewTransitionClass;
update?: ViewTransitionClass;
share?: ViewTransitionClass;
name?: string;
onEnter?: (element: Element, types: string[]) => void;
onExit?: (element: Element, types: string[]) => void;
onUpdate?: (element: Element, types: string[]) => void;
onShare?: (element: Element, types: string[]) => void;
};share 트리거는 동일 name을 가진 전환 경계를 공유 요소로 연결할 때 동작한다. 다만 한쪽이 뷰포트 바깥에 존재하면 공유 쌍이 형성되지 않고 일반 enter/exit로 처리될 수 있다. 또한 동일 name이 동시에 여러 개 마운트되면 오류의 원인이 되므로, 네임스페이스 기반 이름 전략을 초기에 정의해두는 편이 안전하다.
cross-document 전환: MPA에서의 적용
MPA 전환은 @view-transition으로 문서 참여를 선언하는 것에서 시작한다. same-document와 달리 탐색 조건, 출처 제약, 브라우저 구현 차이에 영향을 받는다. 따라서 점진적 향상 설계가 전제 조건이다.
@view-transition {
navigation: auto;
}
::view-transition-old(root) {
animation: 180ms ease-out both fade-out;
}
::view-transition-new(root) {
animation: 220ms ease-in both fade-in;
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}실무에서 자주 놓치는 부분은 “양쪽 문서 동시 설계”다. 진입 문서에만 전환 스타일이 정의되어 있고 출발 문서에 누락이 있으면, 전환이 의도와 다르게 보이거나 일부만 적용될 수 있다. 공통 레이아웃 또는 베이스 스타일 레이어에 전환 규칙을 배치하는 편이 운영상 안정적이다.
실무 안티패턴과 해결책
View Transition은 강력하지만, 적용 방식이 잘못되면 오히려 UX를 해칠 수 있다. 반복적으로 발생하는 대표적 안티패턴은 전환 콜백 내부에 과도한 작업을 넣는 것이다.
document.startViewTransition(() => {
expensiveSynchronousComputation();
runHeavyParser();
updateScreen();
});이 구조는 스냅샷 사이 간격을 불필요하게 늘려 전환 지연을 유발한다. 콜백은 “두 스냅샷 사이의 DOM 반영”에만 집중해야 한다. 무거운 계산은 사전 준비하거나, 전환 이후 단계로 분리하는 것이 바람직하다.
const prepared = precomputeData();
document.startViewTransition(() => {
applyPreparedDOM(prepared);
});또 다른 안티패턴은 전환 남용이다. 모든 상태 변화에 전환을 적용하면 반응성이 떨어지고, 사용자는 오히려 앱이 느리다고 인지한다. 전환은 목록→상세, 레이아웃 대전환, 라우트 이동처럼 맥락 변화가 큰 구간에 집중해야 한다.
세 번째는 이름 전략의 부재다. 공유 요소 전환에서 view-transition-name 충돌이 발생하면 전환이 스킵되고 원인 파악이 어려워진다. “전역 고유 네임스페이스 + 도메인 ID” 규칙을 초기에 합의해두는 편이 장기 운영에 유리하다.
네 번째는 접근성 대응 누락이다. 전환이 시각적으로 매력적일 수는 있지만, 모션 민감 사용자에게는 피로를 유발할 수 있다.
@media (prefers-reduced-motion: reduce) {
::view-transition-group(root),
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 1ms;
}
}실무에서는 “완전 비활성화”와 “최소 모션 유지” 정책 중 하나를 먼저 확정해야 한다. 화면마다 대응 방식이 다르면 접근성 일관성이 무너진다.
운영 체크리스트
2026년 기준 same-document 전환의 활용 범위는 넓어졌지만, cross-document 전환은 브라우저별 편차가 여전히 존재한다. 따라서 도입 전략은 전면 적용이 아니라 “핵심 플로우 우선 + 폴백 보장”이 안전하다. 운영 전에는 다음을 점검하는 것이 좋다.
전환 미지원 환경에서도 기능 흐름이 완전한가.
view-transition-name 네이밍 규칙이 문서화되어 있는가.
prefers-reduced-motion 대응이 전역 정책으로 적용되어 있는가.
전환 콜백 내부에서 무거운 작업이 제거되었는가.
전환 실패(ready reject) 로그를 수집하고 있는가.
간단한 로깅 훅은 다음과 같이 구성할 수 있다.
export function runVT(updateDOM: () => void) {
if (!document.startViewTransition) {
updateDOM();
return;
}
const vt = document.startViewTransition(updateDOM);
vt.ready.catch((error) => {
reportError('view-transition-ready-rejected', {
message: String(error),
});
});
}트레이드오프와 적용 기준
View Transition의 이점은 분명하다. 화면 전환의 맥락을 자연스럽게 연결하고, 전환 로직을 브라우저 모델에 맞춰 단순화하며, 컴포넌트 단위 애니메이션의 난립을 줄일 수 있다. 특히 shared element 전환이 핵심 UX인 서비스에서는 체감 품질을 빠르게 끌어올릴 수 있다.
반면 비용도 명확하다. 브라우저 지원 편차를 고려한 점진적 향상 설계가 필요하고, 이름 충돌·캡처 타이밍·뷰포트 제약 같은 고유 함정을 이해해야 한다. 리액트와 결합할 경우에는 렌더링 타이밍 모델까지 함께 고려해야 한다.
실무 도입은 단계적으로 접근하는 편이 안전하다.
same-document 전환을 핵심 플로우 한두 곳에만 적용한다.
네이밍 규칙, 접근성 정책, 폴백 전략을 먼저 고정한다.
shared element 전환을 선택 구간에 확장한다.
cross-document 전환을 브라우저 행태 검증 후 확대한다.
리액트의 선언형 ViewTransition을 채널 안정성 확인 이후 도입한다.
결국 기준은 화려함이 아니다. 사용자가 이동 과정에서 맥락을 잃지 않도록 돕는가, 그리고 팀이 예측 가능한 규칙으로 이를 유지할 수 있는가. 그 두 질문에 명확히 답할 수 있을 때 View Transition API는 장기적으로 가치 있는 선택이 된다.
더 읽어보기
2026.04.11
Trie 자료구조
문자열 데이터를 다룰 때 단순히 “이 단어가 있나?”만으로는 부족한 순간이 있다. 자동 완성처럼 특정 접두사로 시작하는 후보를 모아야 할 때도 있고, 어떤 키에 값을 두고 빠르게 찾고 싶을 때도 있다. 이럴 때 가장 자연스럽게 떠올릴 수 있는 자료구조가 바로 Trie이다. Trie는 무…
2026.03.19
Streams API 부록 2. 왜 이미지는 위에서 아래로 나타날까
느린 네트워크에서 큰 이미지를 열면 가끔 화면이 위에서 아래로 채워진다. 마치 누군가 아주 성실하게 롤러로 이미지를 칠하는 것처럼 보인다. 물론 브라우저 안에 그런 직원은 없다. 있다면 우리보다 야근을 더 많이 하고 있을 것이다. 이 현상은 단순한 시각 효과가 아니라 네트워크 전송, 브…
2026.03.19
Streams API 부록 1. HTTP 다운로드 진행률은 어떻게 계산될까
다운로드 화면에서 진행 막대가 조금씩 차오르면 이상하게 안심된다. 반대로 스피너만 계속 돌면 파일이 오는 중인지, 서버가 고민 중인지, 내 인생이 잠깐 멈춘 건지 알 수 없다. 사용자는 둘 다 “다운로드 중”이라고 느끼지만, 내부적으로는 꽤 다른 상황일 수 있다. 진행률 계산 자체는 복…
2026.03.13
Streams API 4. 왜 모든 언어에는 Stream API가 존재할까
Streams API를 공부하다 보면 묘한 기시감이 온다. JavaScript에서 ReadableStream, WritableStream, TransformStream을 보고 있는데, Java의 InputStream, Go의 io.Reader, Rust의 Read와 Write가 멀리서…
2026.06.07
AI 에이전트의 비밀값을 macOS Keychain에 맡기기
AI 에이전트나 스킬을 만들다보면 비밀값을 어떻게 관리하면 좋을지 하는 생각을 자주 하게 된다. API를 호출하려면 API Key가 필요하고, 특정 기능을 자동화하는 과정에서 아이디와 비밀번호가 필요할 수도 있다. 그런데 그 값을 프롬프트에 박아버리면 대화 기록에 남고, 명령어 인자로…
2026.06.01
React Server Components를 위한 컴포넌트 아키텍처
이 포스트는 Vercel의 Next.js 팀 소속 개발자 Aurora Scharff가 자신의 블로그에 올린 Component Architecture for React Server Components 게시글을 번역한 것이다. 번역하는 과정에서 다소 의역이 있을 수 있으며, 일부 번역에는…
2026.05.26
차트는 멈췄는데 윈도우가 움직인다
상황 어느날 서비스를 살펴보시던 팀장님께서 이런 말씀을 slack에 남기셨다. 진호님, 예측 차트에서 zoom을 계속하면 어느 순간 라인 차트가 아니라 단일 스캐터 차트처럼 보이는 데, 이거 수정하면 좋을 거 같아요. 어느정도 zoom을 하면 그 이후로는 zoom이 안 되도록 할 수 없…
2026.05.21
피자가게로 이해하는 디자인 패턴
에이든 피자는 처음부터 복잡한 시스템을 만들 생각이 없었다. 처음에는 메뉴 몇 개만 만들면 됐다. 그런데 손님은 커스텀 주문을 넣기 시작했고, 주방은 상태를 나눠야 했고, 결제와 배달앱과 알림이 하나씩 붙었다. 코드도 가게를 닮는다. 장사가 잘될수록 이상하게 더 쉽게 망가진다. 디자인…
댓글
댓글을 불러오는 중...