Community연구 & 데이터 분석github.com

alii13/overfetch: 요청 감사

프론트엔드 앱이 백엔드와 통신하는 방식을 감사하고, 요청 증폭(N+1 읽기, 중복 요청, 폴링 스택, 직렬 워터폴 등)에 대한 증거 기반의 순위별 보고서와 구체적인 수정 방안을 생성합니다.

overfetch: 요청 감사란 무엇인가요?

overfetch는 프론트엔드 애플리케이션이 백엔드에 과도한 요청을 보내는 원인을 분석하고, 증거 기반의 실행 가능한 감사 보고서를 생성하는 AI 에이전트 스킬입니다. TanStack Query, SWR, Apollo, RTK Query와 같은 주요 데이터 페칭 라이브러리를 지원하며, 정적 코드 스캔과 라이브 네트워크 캡처(HAR)를 결합하여 N+1 쿼리, 중복 페치, 폴링 타이머 중복, 직렬 워터폴, 과도한 페칭, 잘못된 캐시 무효화 등 9가지 이상의 요청 증폭 패턴을 탐지합니다. 감사는 실제 코드와 캡처 데이터를 기반으로 하며, 각 발견 사항에 대해 파일:라인 위치, 근본 원인, 구체적인 수정 패턴, 예상되는 요청 감소량, 구현 노력을 포함한 순위별 보고서를 제공합니다. 이 스킬은 단순히 문제를 나열하는 것에 그치지 않고, 감사가 커버한 범위와 확인하지 못한 부분을 명확히 표시하여 신뢰성을 높이며, 감사 후에는 가장 심각한 문제부터 순차적으로 PR을 통해 수정을 제안할 수 있습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/alii13/overfetch/tree/HEAD

Installed? Explore more 연구 & 데이터 분석 skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

overfetch: 요청 감사은(는) 무엇을 하나요?

당신은 누군가가 실행할 보고서를 생성합니다: 이 앱이 화면에 필요한 것보다 더 많은 요청을 만드는 방식을 순위별로 나열하고, 각각에 증거, 수정 방법, 그리고 목표로 삼아야 할 숫자를 제시합니다. 보고서는 모든 발견이 회의적인 독자를 견딜 수 있을 때만 유용하므로, 아래 방법은 대부분의 노력을 검증과 무엇을 확인했고 확인하지 않았는지를 명확히 말하는 데 사용합니다.

제공하는 것

references/report-template.md 템플릿을 기반으로 한 하나의 마크다운 보고서:

  1. 범위와 증거: 어떤 트리, 어떤 커밋, 어떤 캡처인지.
  2. 커버리지: 모든 라우트, 지연 청크 및 게이트된 데이터 사이트, 그리고 이 중 어떤 것이 코드로만 읽혔고 어떤 것이 캡처에서 실행되었는지.
  3. 발견 사항: 요청 수가 증가하는 방식에 따라 순위가 매겨지며, 각각 file:line 또는 캡처 증거, 근본 원인, 수정 패턴, 예상 델타, 노력이 포함됩니다.
  4. 비발견 사항: 확인했지만 배제된 패턴과 그 이유. 이는 다음 사람이 다시 조사하는 것을 막습니다.
  5. 공개된 제품 결정 및 백엔드 요청 사항: 사람이나 API 변경이 필요하고 클라이언트 패치가 아닌 것들.
  6. 한계: 감사가 측정할 수 없었던 것.

이후에 발견당 하나의 PR로, 가장 심각한 것부터 수정을 제안하십시오. 감사 중에는 수정을 시작하지 마십시오.

원칙

정규식 히트는 후보일 뿐, 발견이 아닙니다. scripts/static_scan.py는 텍스트를 읽습니다. 3행 탭 스트립과 3,000행 테이블을 구분할 수 없고, 대량 가져오기 후 의도적인 루트 무효화와 게으른 무효화를 구분할 수 없습니다. 보고하려는 모든 후보 뒤에 있는 코드를 읽으십시오. 읽은 내용을 말하십시오.

측정된 것이 주장보다 낫습니다. 실행 중인 앱의 캡처는 요청 수에 대한 진실이고, 코드는 이유에 대한 진실입니다. 주석, 문서 및 이전 감사 기록은 주장입니다. 문서에 "60초 동안 신선함"이라고 되어 있고 코드에 staleTime: Infinity가 있으면, 코드를 보고, 모순을 기록하고, 읽은 커밋 해시를 기록하십시오.

비난하기 전에 라이브러리의 실제 의미를 알아야 합니다. 가장 비용이 많이 드는 실수는 잘못된 확신입니다: "캐시가 이것을 중복 제거한다"고 하지만 키가 다르고, "폴링이 유휴 상태일 때 일시 중지된다"고 하지만 숨겨졌을 때만 일시 중지되고, "세 명의 호출자, 분당 세 번의 페치"라고 하지만 라이브러리가 동일한 키 타이머를 재동기화하고 페치를 공유합니다. references/library-facts.md에는 TanStack Query, SWR, Apollo 및 RTK Query에 대한 사실이 포함되어 있으며, 각각 확인된 소스 경로가 있습니다. 사용 중인 라이브러리에 대한 섹션을 읽고 나서 캐싱이나 폴링에 관한 문장을 작성하고, 주장이 발견을 결정할 때는 설치된 라이브러리의 소스를 열고 확인하십시오.

개수가 아닌 성장에 따라 순위를 매기십시오. 행, 마운트된 구성 요소 또는 시간에 따라 확장되는 읽기는 고정된 중복보다 더 나쁩니다. 아래 심각도 기준은 성장 클래스에 관한 것입니다.

커버리지에는 분모가 있습니다. 캡처는 실행되는 동안 로드된 코드만 봅니다: 누군가 방문한 라우트, 누군가 연 대화 상자와 탭, 켜져 있던 플래그, 백엔드가 반환한 상태. 지연 청크, 게이트된 화면 및 오류 경로는 정확히 요청 버그가 숨는 곳입니다. 개발 중에는 아무도 보지 않기 때문입니다. 따라서 모든 감사는 전체 표면(coverage_map.py)에서 시작하고, 모든 "문제 없음"은 커버된 범위로 한정되며, 보고서는 어떤 부분이 실제로 실행되었고 어떤 부분이 읽기만 되었는지 말합니다.

괜찮은 것도 말하십시오. 행당 하나의 중복 제거된 읽기인 호버 프리페치는 비발견 사항입니다. 그것을 하나로 기록하십시오. 문제만 나열하는 보고서는 독자가 다른 것을 놓쳤는지 궁금하게 만듭니다.

숫자는 어디에서 오는가. 보고서의 모든 카운트는 캡처 파일 또는 코드 경로로 추적됩니다. 직감으로 "6+" 또는 "대략 100"을 만들지 마십시오; 측정할 수 없으면 "측정되지 않음"이라고 말하고 공식(행 × 행당 읽기)을 제시하십시오.

워크플로우

이 작업에 소요되는 시간을 미리 사용자에게 알리십시오. 중간 규모 앱의 정적 전용 감사는 읽는 데 1530분이 걸립니다. 라이브 캡처를 추가하면 얼마나 많은 여정이 중요한지에 따라 1545분이 추가됩니다.

1. 범위

  • package.json에서 앱 루트와 데이터 라이브러리를 찾으십시오(스캔이 둘 다 출력합니다). 모노레포: 각 앱을 개별적으로 스캔하십시오.
  • 데이터 계층을 찾으십시오: 쿼리 키 팩토리, 전송/서비스 모듈, QueryClient 생성(SWR 구성, Apollo 클라이언트, RTK createApi). 먼저 기본값을 읽으십시오; 모든 발견이 측정되는 기준선을 설정합니다.
  • 중요한 화면을 나열하십시오: 일반적으로 로그인 후 랜딩 라우트, 가장 바쁜 목록, 그리고 몇 시간 동안 열려 있는 화면(셸, 모니터). 명확하지 않으면 사용자에게 물어보고; 그렇지 않으면 이 세 가지를 선택하고 그렇게 말하십시오.
  • 커밋을 기록하십시오: git rev-parse HEAD. 모든 보고서 행은 이 리비전을 참조합니다.
  • 라이브 캡처가 가능한지 결정하십시오: 실행 중인 개발 서버와 구동할 수 있는 브라우저, 또는 사용자가 이미 가지고 있는 HAR. 둘 다 없으면 감사는 정적 전용이며, 보고서는 첫 번째 문단에 명시해야 합니다.

2. 커버리지 맵

python3 <skill-dir>/scripts/coverage_map.py <app-root> --format md --out coverage.md

이것이 분모입니다. 모든 라우트(TanStack Router, Next.js, Remix, SvelteKit, SolidStart용 파일 기반 라우터; 경로 리터럴로 코드 정의된 라우터; 그렇지 않으면 항목 파일), 모든 동적 import() 경계와 그 뒤의 읽기, 플래그, 플랫폼, 권한 또는 환경 검사로 게이트된 모든 데이터 모듈, 소스의 모든 엔드포인트 경로 리터럴, 그리고 어떤 라우트도 도달하지 않는 데이터 모듈을 나열합니다. 2,000개 파일 앱에서 몇 초 안에 실행됩니다.

세 가지 방법으로 사용하십시오:

  • 계획을 세우기 위해. 하단의 캡처 계획은 가장 많은 읽기 사이트가 있는 라우트, 트리거할 지연 청크, 토글할 게이트를 지정합니다. 추측하는 대신 6단계의 여정을 선택하는 데 사용하십시오.
  • 스캔 범위를 지정하기 위해. 어떤 라우트도 도달하지 않는 모듈의 발견은 죽은 코드이거나 맵이 해결할 수 없는 것에 의해 도달된 것입니다. 라이브라고 부르기 전에 확인하십시오.
  • 루프를 닫기 위해. 캡처 후 캡처와 함께 다시 실행하십시오. 방문한 라우트, 로드된 모듈과 지연 청크(개발 서버 캡처의 경우 정확히), 실행된 게이트된 모듈, 나타난 엔드포인트 경로를 표시합니다:
python3 <skill-dir>/scripts/coverage_map.py <app-root> --har home.har --har library.har --visited home.har.visited.txt --format md

가장 많은 읽기 사이트가 있는 라우트와 지연 청크가 커버될 때까지 캡처를 반복하거나, 그렇지 않은 이유를 기록하십시오(피xtures 데이터 없음, 가지고 있지 않은 역할 필요, 실행할 수 없는 플랫폼).

3. 정적 스캔

python3 <skill-dir>/scripts/static_scan.py <app-root> --format md --out scan.md
python3 <skill-dir>/scripts/static_scan.py <app-root> --format json --out scan.json

스캔은 빠르며(2,000개 파일에 약 10초) Python 3.9+만 필요합니다. 심각도, 신뢰도, 실행된 탐지기, file:line, 중요한 이유, 수정 패턴 및 "먼저 확인" 지침과 함께 후보를 내보냅니다. scan.md 전체를 읽으십시오; JSON은 스크립팅 및 평가 도구용입니다.

기본값이 놓친 생성된 트리에 대해 --exclude, 목록이 길고 첫 번째 패스를 좁히려면 --min-confidence medium을 추가하십시오.

4. 후보 확인

다음 순서로 후보를 처리하십시오: 신뢰도별 P0, 그다음 P1, 그다음 나머지. 유지하는 각 후보에 대해 파일을 열었고 다음 질문에 답할 수 있어야 합니다:

  • 행당 또는 관찰자당 승수는 무엇이며, 무엇이 그것을 제한합니까? (고정 열거형에 대한 .map은 N+1이 아닙니다. 페이지네이션된 목록의 행 수는 그렇습니다.)
  • 캐시가 이미 그것을 흡수합니까? (동일한 키, 웜 엔트리, enabled: false 읽기, 이미 객체를 페치한 부모.)
  • 클라이언트가 대신 사용할 수 있는 배치 또는 프로젝션 엔드포인트가 있습니까? API 클라이언트 또는 OpenAPI 사양을 읽으십시오. 없으면 수정은 백엔드 요청이며, 발견은 "백엔드 차단"으로 유지됩니다.
  • references/catalog.md에서 이름별로 수정 패턴은 무엇입니까?

이러한 검사에 실패한 후보는 삭제하고, 삭제했지만 독자가 그럴듯하게 제기할 수 있는 후보는 한 줄짜리 이유와 함께 비발견 사항 테이블에 보관하십시오.

각 탐지기에 대한 카탈로그 항목은 특정 비발견 사항 조건을 나열합니다. 스캔에 나타나는 모든 탐지기 ID에 대해 읽으십시오; 동일한 ID로 구성되어 있습니다.

5. 스캐너가 할 수 없는 교차 확인

이것들은 읽기가 필요하며, 그렙이 아닙니다. 모두 수행하십시오; 대부분의 감사에서 적어도 하나를 찾습니다.

  • 키 정규성. 가장 많이 읽힌 다섯 개의 엔드포인트를 선택하고 각각을 읽는 모든 쿼리 키를 찾으십시오. 하나의 읽기에 두 개의 키는 두 개의 캐시 엔트리와 두 개의 페치를 의미합니다. 특히 다른 프로젝션(전체 vs 이름만) 아래의 목록 읽기와 실제로 다른 데이터가 아닌 범위 차이(조직 vs 작업 공간)를 찾으십시오.
  • 공유된 진행 중인 읽기. 동일한 키로 동일한 프레임에 마운트되는 두 구성 요소는 해당 순간에 키가 동일한 경우에만 하나의 요청을 공유합니다. 한 틱 후에 안정되는 상태(다른 쿼리에서 도착하는 ID)로 구축된 키는 두 개의 페치를 생성합니다: 하나는 undefined로, 하나는 실제입니다. 종속 키에 대한 enabled 게이트를 확인하십시오.
  • 표면별 신선도. 데이터 패밀리(아이덴티티, 목록, 세부 정보, 라이브 상태)별로 staleTime 표를 만들고 각각이 실제로 얼마나 빨리 변경되는지 비교하십시오. 일반적인 버그는 모든 것에 대해 옳지 않은 하나의 전역 값입니다.
  • 폴링 소유권. 공유 훅 또는 옵션 팩토리의 모든 폴링 옵션에 대해 한 번에 마운트될 수 있는 구성 요소와 각각이 사용하는 키를 나열하십시오. SWR 및 Apollo에서 각 인스턴스는 자체 타이머를 실행하고 페치는 중복 제거 창에 들어가지 않으면 곱해집니다. TanStack Query에서 타이머는 모든 쿼리 업데이트 시 다시 시작되고 하나의 페치를 공유하므로, 동일한 키 관찰자는 최단 간격당 하나의 페치 비용이 듭니다; 스태킹은 키 또는 클라이언트 간에 나타나며, 발견은 케이던스 소유권입니다. RTK Query에서 캐시 엔트리당 하나의 타이머가 최단 간격으로 실행됩니다.
  • 포커스 및 가시성. 이 플랫폼에서 포커스 리페치를 트리거하는 것은 무엇입니까? 데스크탑 셸(Tauri, Electron)은 종종 OS 창 포커스를 연결하여 탭 가시성보다 훨씬 더 자주 실행됩니다. 숨겨졌을 때 어떤 폴링이 일시 중지되고, 사용자가 보이는 화면에서 유휴 상태일 때 어떤 폴링이 계속 실행됩니까?
  • 동시성 제한. 팬아웃 읽기에 대한 제한기가 있으며, 무엇입니까? 진행 중인 6개 제한기는 초당 6개 요청 제한이 아닙니다; 하나를 다른 것으로 쓰지 마십시오.
  • 페이지네이션 계약. 알 수 없는 총 컬렉션의 경우, 클라이언트가 페이지가 짧게 돌아올 때 중지합니까, 아니면 빈 페이지까지 계속 요청합니까? 화면이 표시할 수 있는 것과 페이지 크기를 확인하십시오.
  • 재시도. 클라이언트는 403/404/422에서 무엇을 합니까? 라이브러리 기본값은 세 번 재시도합니다; 금지된 청크가 있는 100행 N+1은 400개의 요청이 됩니다.
  • 지속성. 캐시가 지속되면(IndexedDB, localStorage, 네이티브 스토어), maxAge는 무엇이며, 배포 시 무엇이 그것을 파괴하며, 스토어는 플랫폼별입니까? 지속된 캐시는 캡처에서 "콜드 로드"의 의미를 변경합니다; 측정한 것을 말하십시오.
  • 뮤테이션. 가장 일반적인 다섯 개의 쓰기에 대해 무엇이 무효화됩니까? 작은 쓰기 후 루트 무효화가 일반적인 발견입니다.

6. 라이브 캡처

앱을 실행할 수 있거나 사용자가 캡처를 제공했다면 숫자를 얻으십시오. references/capture.md에는 실행할 여정, 상태 매트릭스(비어 있음, 채워짐, 오류, 느림, 오프라인, 유휴, 숨김, 게이트됨, 콜드 및 웜 캐시), 캡처 방법(DevTools HAR, Playwright, 번들된 scripts/capture.mjs 또는 앱 자체 요청 로그), 그리고 캡처를 비교 가능하게 유지하는 방법이 있습니다.

습관이 아닌 커버리지 맵의 계획에서 여정을 선택하십시오. 실행할 수 있을 때는 개발 서버를 선호하십시오: 캡처는 로드된 모든 모듈의 이름을 지정하므로 맵이 어떤 지연 청크와 게이트된 모듈이 실행되었는지 정확히 말할 수 있습니다. 그런 다음 캡처와 함께 맵을 다시 실행하고(2단계) 간격을 캡처하거나 한계 아래에 나열하십시오.

캡처는 일어난 일을 보여주고, 결코 이유를 보여주지 않습니다. 캡처 전용 감사에서는 각 인과 절을 그것이 있는 곳에서 헤지하십시오("두 개의 쿼리 키와 일치", "리마운트 가능성 높음"), 상단의 면책 조항에서 한 번이 아닙니다: 독자는 한 문장을 인용하며, 헤지되지 않은 "왜냐하면"은 면책 조항 없이 전달됩니다.

다른 사람이 찍은 캡처만 있을 때는 캡처만으로 무엇을 놓쳤는지 알 수 없습니다. 그렇게 말하고, 단일 세션이 일반적으로 놓치는 것(방문하지 않은 라우트, 열지 않은 대화 상자와 탭, 플래그 및 역할 변형, 오류 및 빈 상태, 유휴 및 숨겨진 탭 동작)을 나열하고, 이를 해결할 캡처를 권장하십시오.

python3 <skill-dir>/scripts/har_analyze.py capture.har --format md --out capture.md

페이지당 API 요청, 하나의 경로 템플릿에 대한 행당 버스트, 키당 누적 타이머 수를 포함한 폴링, 창 내 중복(POST의 경우 본문 해시 포함), 직렬 체인, 반복된 오류 및 가장 큰 응답을 보고합니다. 정적 자산은 제외됩니다. 텔레메트리 호스트에 대해 --ignore를 사용하십시오.

읽을 때 주의할 두 가지 사항:

  • 동일한 URL에 대한 POST는 본문 해시가 일치하는 경우에만 중복입니다. 본문이 캡처되지 않은 경우 도구는 "미확인"이라고 말합니다; 그렇게 보고하십시오.
  • 직렬 체인은 이후 요청이 이전 요청에서 아무것도 필요하지 않은 경우에만 워터폴입니다. 도구는 모양을 찾습니다; 코드에서 종속성을 확인합니다.

7. 조정

해당 화면을 커버하는 캡처 증거가 있는 모든 정적 발견을 짝짓습니다. 불일치하는 경우, 캡처는 개수에서 승리하고 코드는 원인에서 승리합니다. 캡처가 어떤 후보도 설명하지 못하는 증폭을 보여주면, 코드가 설명할 때까지 읽으십시오. 이것은 일반적으로 4단계의 키 정규성 또는 종속 키 문제입니다.

리포지토리가 이전 감사 또는 성능 문서를 가지고 있으면, 해당 발견에 영향을 미치는 각 주장을 이 커밋의 코드와 비교하고 보고서에 모순점을 나열하십시오. 오래된 주장은 동일한 버그가 두 번 "수정"되는 방법입니다.

8. 순위 매기기 및 작성

기준 사용:

심각도성장 클래스일반적인 형태
P0행, 마운트된 관찰자 또는 시간에 따라 무제한으로 증가페이지네이션된 목록에 대한 행당 쿼리, 공유 훅(SWR, Apollo, 수동)의 인스턴스당 폴 타이머, 키 입력마다 무효화, 지워지지 않은 간격
P1핫 경로에 대한 고정 승수모든 화면이 읽는 목록에 대한 staleTime 0, 모든 포커스에서 리페치, 캐시 없이 효과 기반 페치, 연결되지 않은

...

[번역을 위해 잘림]

관련 스킬