현록

TTV와 TTI 차이

웹 성능을 공부하다 보면 TTVTTI라는 표현을 만난다.
둘 다 사용자가 느끼는 속도와 관련이 있지만 같은 의미는 아니다.

TTV는 보통 Time to View로 설명한다.
사용자가 화면에서 의미 있는 콘텐츠를 보기 시작하는 시점을 말할 때 쓰인다.

TTI는 Time to Interactive다.
페이지가 보여지는 것을 넘어 사용자가 클릭, 입력, 탭 같은 동작을 할 수 있는 상태가 되는 시점을 말한다.

초보자 기준으로는 이렇게 구분하면 된다.
보이는 속도는 TTV에 가깝다.
눌렀을 때 반응하는 속도는 TTI에 가깝다.

TTV의 기준

TTV는 표준화된 단일 Web API 지표라기보다 경험을 설명하는 표현에 가깝다.
사용자가 빈 화면이 아니라 실제 콘텐츠를 보기 시작하는 시점을 말할 때 사용한다.

예를 들어 블로그 글 페이지를 연다고 해보자.
상단 헤더와 글 제목이 먼저 보이고, 나머지 이미지가 조금 늦게 로드될 수 있다.
이때 사용자는 이미 페이지가 열렸다고 느낄 수 있다.

이 감각은 First Contentful Paint, Largest Contentful Paint 같은 지표와 연결해서 보는 편이 좋다.
FCP는 첫 텍스트나 이미지 같은 콘텐츠가 화면에 처음 그려지는 시점을 본다.
LCP는 뷰포트 안의 가장 큰 주요 콘텐츠가 그려지는 시점을 본다.

그래서 TTV를 엄밀히 측정해야 한다면 서비스의 기준을 정해야 한다.
글 제목이 보이면 볼 수 있다고 할지, 대표 이미지까지 보여야 볼 수 있다고 할지 정해야 한다.

TTI의 기준

TTI는 Time to Interactive의 약자다.
페이지가 사용자 입력에 안정적으로 반응할 수 있는 시점을 설명하는 지표다.

예를 들어 화면은 이미 보이는데 버튼을 눌러도 아무 반응이 없다면 사용자는 페이지가 느리다고 느낀다.
JavaScript를 아직 다운로드하거나 실행하는 중이라면 이런 일이 생길 수 있다.

TTI는 이런 상황을 설명하기 위해 사용됐다.
페이지가 보이는 것과 실제로 사용할 수 있는 것은 다르기 때문이다.

다만 TTI는 요즘 성능 관리의 중심 지표로 쓰기에는 한계가 있다.
Lighthouse에서도 TTI는 과거에 중요하게 다뤄졌지만, 현재 사용자 상호작용 품질을 볼 때는 INP를 더 직접적으로 보는 흐름이다.

FCP와 LCP의 관계

FCP는 First Contentful Paint다.
사용자가 페이지에 진입한 뒤 텍스트, 이미지, SVG, canvas 같은 콘텐츠가 처음 화면에 렌더링되는 시점을 측정한다.

페이지 요청 -> HTML 수신 -> 첫 텍스트나 이미지 표시

FCP가 빠르면 사용자는 “무언가 뜨고 있다”고 느낀다.
하지만 FCP만 빠르다고 해서 중요한 콘텐츠가 다 보였다는 뜻은 아니다.

LCP는 Largest Contentful Paint다.
뷰포트 안에서 가장 큰 주요 콘텐츠가 렌더링되는 시점을 측정한다.
블로그라면 제목, 대표 이미지, 본문 첫 영역 같은 것이 영향을 줄 수 있다.

첫 콘텐츠 표시 -> 주요 콘텐츠 표시

TTV를 실제 지표로 연결한다면 FCP와 LCP를 함께 보는 편이 좋다.
FCP는 첫 신호이고, LCP는 주요 콘텐츠가 보이는 시점에 더 가깝다.

INP의 관계

INP는 Interaction to Next Paint다.
사용자의 클릭, 탭, 키보드 입력 같은 상호작용에 페이지가 얼마나 빨리 시각적으로 반응하는지 본다.

Core Web Vitals에서 현재 상호작용 품질을 볼 때는 INP가 중요하다.
web.dev 문서 기준으로 INP는 안정적인 Core Web Vital이며, 페이지 생명주기 동안 발생한 상호작용 지연을 관찰한다.

TTI가 “언제부터 상호작용 가능해지는가”에 가까운 지표라면, INP는 “실제 상호작용들이 얼마나 빨리 반응하는가”에 가깝다.
그래서 최신 성능 개선에서는 TTI만 보기보다 INP를 함께 보는 편이 더 실용적이다.

예를 들어 초기 로딩 후 버튼을 눌렀는데 화면 반응이 600ms 뒤에 나타난다면 INP가 나빠질 수 있다.
사용자는 페이지가 이미 보이는 상태에서도 답답함을 느낀다.

TTV와 TTI의 차이

TTV와 TTI는 사용자가 느끼는 두 순간을 나눠서 설명한다.

구분관심사관련 지표
TTV화면에서 콘텐츠를 볼 수 있는 시점FCP, LCP
TTI페이지를 조작할 수 있는 시점TTI, INP, TBT
TTV
관심사
화면에서 콘텐츠를 볼 수 있는 시점
관련 지표
FCP, LCP
TTI
관심사
페이지를 조작할 수 있는 시점
관련 지표
TTI, INP, TBT

TTV가 빠르면 사용자는 빈 화면을 오래 보지 않는다.
TTI가 빠르면 사용자는 버튼이나 입력창을 눌렀을 때 바로 반응을 얻는다.

둘 중 하나만 좋아서는 충분하지 않다.
화면은 빨리 보이지만 클릭이 안 되면 답답하다.
반대로 상호작용 준비는 빨라도 화면이 늦게 뜨면 첫인상이 나쁘다.

개선 방향

TTV를 개선하려면 먼저 화면에 필요한 리소스를 빨리 가져오고 렌더링해야 한다.
서버 응답 시간을 줄이고, 렌더링을 막는 CSS와 JavaScript를 줄이고, 핵심 이미지를 최적화하는 방식이 도움이 된다.

HTML 응답 빠르게 만들기
중요 CSS 우선 처리
초기 JavaScript 줄이기
대표 이미지 최적화

TTI와 INP를 개선하려면 JavaScript 실행 시간을 줄이는 것이 중요하다.
큰 번들을 나누고, 필요 없는 코드를 늦게 불러오고, 긴 작업을 쪼개는 식으로 메인 스레드가 오래 막히지 않게 해야 한다.

초기 번들 줄이기
코드 스플리팅
긴 task 쪼개기
이벤트 핸들러 가볍게 유지
불필요한 hydration 줄이기

Next.js나 Nuxt 같은 프레임워크를 쓴다면 서버 렌더링, 이미지 최적화, 라우트 단위 코드 분리 같은 기능도 함께 본다.
성능 지표는 하나의 숫자보다 병목을 찾기 위한 단서로 보는 편이 좋다.

측정 도구

가장 쉽게 시작하려면 PageSpeed Insights나 Lighthouse를 사용한다.
PageSpeed Insights는 실제 사용자 데이터가 있으면 field data를 보여주고, Lighthouse는 실험실 환경에서 진단 정보를 제공한다.

Chrome DevTools Performance 패널도 유용하다.
초기 로딩 중 어떤 JavaScript가 오래 실행되는지, 어떤 작업이 렌더링을 막는지 확인할 수 있다.

실제 서비스에서는 field data가 중요하다.
사용자의 기기, 네트워크, 브라우저 상태가 다르기 때문이다.
web-vitals 라이브러리를 사용하면 FCP, LCP, INP 같은 지표를 JavaScript로 수집하는 흐름을 만들 수 있다.

정리

TTV는 사용자가 콘텐츠를 보기 시작하는 시점에 가깝다.
실제 측정에서는 FCP와 LCP를 함께 보면 좋다.

TTI는 사용자가 페이지를 조작할 수 있는 시점에 가깝다.
현대적인 상호작용 품질 관리는 TTI만 보기보다 INP를 함께 보는 편이 좋다.

웹 성능을 볼 때는 “보이는가”와 “반응하는가”를 나눠서 생각한다.
화면이 빨리 보이는 것과 사용자가 바로 조작할 수 있는 것은 다른 문제다.

참고 자료

관련 포스트
HTTP GET과 POST 차이 thumbnail
HTTP GET과 POST 차이
HTTP GET과 POST의 차이를 초보자 기준으로 정리합니다. 조회와 변경, query string과 request body, 캐시, safe, idempotent, form과 fetch 사용 기준을 함께 봅니다.
npm outdated와 npm update 차이 thumbnail
npm outdated와 npm update 차이
npm outdated와 npm update의 차이를 초보자 기준으로 정리합니다. Current, Wanted, Latest의 의미와 semver 범위 안에서 업데이트되는 방식, package-lock.json 변화까지 함께 봅니다.
npm install -g와 npx 차이 thumbnail
npm install -g와 npx 차이
npm install -g와 npx의 차이를 초보자 기준으로 정리합니다. 전역 설치, 로컬 설치, 일회성 실행, 프로젝트 scripts에 넣는 기준까지 함께 봅니다.
package.json에서 ^와 ~ 차이 thumbnail
package.json에서 ^와 ~ 차이
package.json 의존성 버전 앞에 붙는 ^와 ~의 차이를 초보자 기준으로 정리합니다. semantic versioning, 버전 범위, 0.x 예외, package-lock.json과의 관계까지 함께 봅니다.
npx와 npm exec 차이 thumbnail
npx와 npm exec 차이
npx와 npm exec가 어떤 명령어인지 초보자 기준으로 정리합니다. 로컬 패키지 실행, 원격 패키지 임시 실행, --package 옵션, -- 인자 전달 차이까지 함께 봅니다.
npm scripts와 npm run 정리 thumbnail
npm scripts와 npm run 정리
npm scripts란 무엇인지, package.json scripts와 npm run의 관계를 초보자 기준으로 정리합니다. npm run dev, npm start, npm test, node_modules/.bin, -- 인자 전달 방식까지 함께 봅니다.
dependencies와 devDependencies 차이 thumbnail
dependencies와 devDependencies 차이
package.json의 dependencies와 devDependencies 차이를 초보자 기준으로 정리합니다. npm install과 npm install -D, 배포 환경 설치, package-lock.json과의 관계까지 함께 봅니다.
npm ci와 npm install 차이 thumbnail
npm ci와 npm install 차이
npm ci와 npm install의 차이를 초보자 기준으로 정리합니다. clean install의 의미, package-lock.json 조건, CI에서 npm ci를 쓰는 이유, .npmrc 플래그 주의점까지 함께 봅니다.
.npmrc 파일이란? thumbnail
.npmrc 파일이란?
storybook을 사용해보려고 하다 마주한 이슈의 해결법을 알아보다가 등장한 .npmrc라는 파일에 대해 공부해보았다. .npmrc 파일이란? .npmrc 파일은 npm에 대한 config 파일이다. (npm에 대한 rc 파일) 프로젝트별 registry, install 옵션, 인증 토큰처럼 npm CLI가 읽는 설정을 관리할 때 사용한다.
스토리북이란? thumbnail
스토리북이란?
Storybook은 UI 컴포넌트를 독립적으로 개발하고, 문서화하고, 테스트하기 위한 프론트엔드 워크샵입니다. Storybook 10.4 기준 설치 흐름과 stories, 문서화, 테스트 활용 방식을 정리합니다.
Maria DB 외부 접속 설정하기 thumbnail
Maria DB 외부 접속 설정하기
안녕하세요. 오늘은 Maria DB 초기 세팅 시, 외부에서 접속이 안될 때 매뉴얼을 작성해보겠습니다. dotenv 패키지를 통해서 환경변수로 관리한다면, 별도의 추가 작업을 할 일이 없으실 겁니다.
package-lock.json 파일의 역할 thumbnail
package-lock.json 파일의 역할
안녕하세요. 오늘은 node 환경의 개발자라면 한번쯤 궁금했을만한 package-lock.json의 역할에 대해 알아보겠습니다. 우리는 node 환경에서 개발을 할 때 다양한 패키지들을 설치하여 활용하곤 합니다. 우리가 설치하는 패키지 또한 다른 npm 패키지를 활용하여 만든 패키지들이고 이들 또한 설치를 하게 됩니다. 이렇게 직간접적으로 설치된 패키지들은 대부분 호환성을 "^1.1.5"와 같이 표현하여, 범위로 지정해두고 있습니다.
Linux 환경 배포 자동화 체험해보기 thumbnail
Linux 환경 배포 자동화 체험해보기
안녕하세요. 요즘 포트폴리오를 만들면서 서버 상에 자주 반영할 일이 생겼는데, 매번 명령어들을 타이핑하는 것이 비효율적이라 생각이 들어 배포 자동화를 생각해보게 되었습니다. 현재 레벨에서는 단순히 명령어들만 단축시켜도 효율적이라 생각이 들어 간단한 쉘 스크립트만 작성하였습니다. 정말 간단하니 여러분도 도전해보시길 바랍니다.
협업 필수품. Prettier thumbnail
협업 필수품. Prettier
안녕하세요. 오늘은 Prettier이라는 도구에 대해 알려드리고자 합니다. 개발자는 각자의 코딩스타일이 존재합니다. 그러다보니 같은 프로젝트에서도 작성하는 소스마다 스타일이 제각기 다르기 일쑤입니다. 그럴 때 도입하면 좋은 것이 Prettier입니다. 프로젝트 root 폴더에 .prettierrc 라는 파일을 생성한 뒤, 위 예시와 같이 원하는 옵션을 JSON 형식으로 작성해주면 됩니다.