Part 3.3 코드 읽는 법 - 간단한 것부터 시작
Cursor가 생성한 코드를 다 보시나요? 저는 개발자로 오래 지내다보니, 그냥 습관적으로 남이 쓴 코드를 읽긴 합니다. 그치만, 저도 바이브코딩을 하면서 '굳이?', '꼭 전체를 읽을 거 까지는?' 이란 생각이 들더라구요. 바이브코딩의 정의도 코드를 안 보고 '프롬프트'만으로 명령을 해 나가는 거 잖아요?
바이브코딩에서 필요한 건 딱 세 가지입니다:
-
이 파일이 뭘 하는 파일인지 파악하기
-
내가 수정하고 싶은 부분이 어디에 있는지 찾기
-
AI에게 정확한 위치를 알려주기
이번 챕터에서는 코드를 "읽는" 게 아니라 "훑어보는" 방법을 알려드립니다. 마치 책을 읽기 전에 목차와 소제목을 훑어보는 것처럼요.
코드를 훑어보는 5가지 포인트
1. 주석: 개발자가 남긴 메모
주석(Comment)은 코드 실행에 영향을 주지 않는 설명 메모입니다. AI도 주석을 많이 남기는 편이라, 주석만 읽어도 코드가 뭘 하는지 대충 파악됩니다.
프롬프트를 입력할 때 '주석도 잘 넣어라' 이 한마디만 추가해주세요. 그러면 AI가 코드를 짤 때, 주석도 잘 넣어줄거에요. 코딩에 익숙하지 않은 사람은 주석을 최대한 활용하면서 각 클래스, 함수, 파일, 폴더를 이해하는 시도를 하면 좋습니다.
주석의 두 가지 형태:
// 한 줄 주석: 슬래시 두 개 뒤에 작성
// 이 함수는 사용자 로그인을 처리합니다
/*
여러 줄 주석: 슬래시+별표로 시작, 별표+슬래시로 끝
이 컴포넌트는 메인 대시보드를 렌더링합니다.
- 사용자 정보 표시
- 최근 활동 목록
- 통계 차트
*/
Cursor에서 실제로 보이는 예시:
// components/LoginForm.tsx
import { useState } from "react";
// 로그인 폼 컴포넌트
// - 이메일과 비밀번호 입력 받음
// - 유효성 검사 후 서버에 로그인 요청
export default function LoginForm() {
// 입력값을 저장하는 상태
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
// 로그인 버튼 클릭 시 실행되는 함수
const handleLogin = async () => {
// TODO: 서버에 로그인 요청 보내기
};
return (
// ... 생략
);
}
주석만 읽으면:
-
이 파일은 "로그인 폼 컴포넌트"구나
-
이메일/비밀번호 입력을 받는구나
-
handleLogin이 로그인 처리하는 함수구나
실전 팁: TODO 주석 찾기
// TODO:는 "나중에 해야 할 일"을 표시하는 관례입니다. AI가 코드를 생성할 때 완성하지 않은 부분에 TODO를 남기기도 합니다. 저는 TODO를 '메모'용도로도 많이 사용합니다. TODO로 코멘트를 남기면 이건 comment중에서도 특별히 취급이 되서 TODO comment만 하이라이팅도 됩니다.
// TODO: 에러 처리 추가하기
// TODO: 로딩 상태 표시하기
// FIXME: 이 부분 버그 있음
Cursor에서 Ctrl+Shift+F (전체 검색)로 TODO를 검색하면 미완성 부분을 찾을 수 있습니다.
2. 함수명: 코드의 목차
함수 이름은 그 함수가 뭘 하는지 설명합니다. 영어지만 패턴을 알면 읽을 수 있습니다.
자주 보는 함수명 패턴:
| 접두사 | 의미 | 예시 |
|---|---|---|
| handle | 이벤트 처리 | handleClick, handleSubmit, handleChange |
| get | 데이터 가져오기 | getUser, getProducts, getData |
| set | 데이터 설정하기 | setUser, setLoading, setError |
| fetch | 서버에서 가져오기 | fetchUsers, fetchPosts |
| create | 새로 만들기 | createUser, createPost |
| update | 수정하기 | updateProfile, updateSettings |
| delete | 삭제하기 | deleteItem, deleteUser |
| is/has | 확인하기 (true/false) | isLoggedIn, hasPermission |
| on | 이벤트 발생 시 | onClick, onChange, onSubmit |
실제 예시 해석:
// "사용자 데이터 가져오기" 함수
async function fetchUserData(userId) { ... }
// "폼 제출 처리" 함수
function handleFormSubmit(event) { ... }
// "로그인 상태인지 확인" 함수
function isUserLoggedIn() { ... }
// "장바구니에 상품 추가" 함수
function addToCart(product) { ... }
함수 이름만 봐도 뭘 하는 함수인지 대충 감이 옵니다.
AI에게 요청할 때 활용:
❌ "저기 그 함수 수정해줘"
✅ "handleSubmit 함수에서 로딩 상태 추가해줘"
✅ "fetchUserData가 실패했을 때 에러 메시지 표시하게 해줘"
3. 들여쓰기: 코드의 계층 구조
들여쓰기(Indentation)는 코드의 소속 관계를 보여줍니다.
function LoginForm() { // 레벨 0: 함수 시작
const [email, setEmail] = useState(""); // 레벨 1: 함수 안에 있음
const handleSubmit = () => { // 레벨 1: 함수 안의 함수
if (email === "") { // 레벨 2: handleSubmit 안에 있음
alert("이메일을 입력하세요"); // 레벨 3: if 안에 있음
} // 레벨 2: if 끝
}; // 레벨 1: handleSubmit 끝
return ( // 레벨 1: return 시작
<form> // 레벨 2: form 안
<input /> // 레벨 3: form 안의 input
<button>로그인</button> // 레벨 3: form 안의 button
</form> // 레벨 2: form 끝
); // 레벨 1: return 끝
} // 레벨 0: 함수 끝
들여쓰기로 파악할 수 있는 것:
-
같은 레벨 = 같은 "그룹"에 속함
-
더 들어간 코드 = 위 코드에 "소속"됨
-
중괄호
{}나 괄호()가 열리면 → 들여쓰기 증가 -
닫히면 → 들여쓰기 감소
실전 팁: 접기(Folding) 기능 활용
Cursor 뿐 아니라, 코드 에디터에서 코드 라인의 왼쪽에서 마우스를 올리면 ▼ 화살표가 생길거에요. 이걸 클릭하면 해당 블록을 접을 수 있습니다. 복잡한 코드를 볼 때 관심 없는 부분을 접어두면 구조가 한 눈에 보입니다.
( '들여쓰기'는 lint, prettier라는 툴하고도 연결이 되는데, 지금은 '이쁘게 정렬이 된 상태'를 가정하고 작성했습니다 )
4. import/export: 파일 간의 연결
import와 export는 다른 파일의 코드를 가져오거나 내보내는 문법입니다.
import: 다른 파일에서 가져오기
// React 라이브러리에서 useState 가져오기
import { useState } from "react";
// 같은 프로젝트의 다른 파일에서 가져오기
import Button from "./components/Button";
import { formatDate, formatPrice } from "./utils/helpers";
// CSS 파일 가져오기
import "./App.css";
export: 다른 파일에서 쓸 수 있게 내보내기
// 기본 내보내기 (파일당 하나)
export default function LoginForm() { ... }
// 이름 있는 내보내기 (여러 개 가능)
export function formatDate(date) { ... }
export function formatPrice(price) { ... }
export const API_URL = "https://api.example.com";
import를 보면 알 수 있는 것:
파일 상단의 import 목록만 봐도 이 파일이 뭘 사용하는지 파악됩니다.
import { useState, useEffect } from "react"; // React 상태와 효과 사용
import { supabase } from "./lib/supabase"; // Supabase DB 사용
import { Button, Input } from "./components/ui"; // UI 컴포넌트 사용
import { validateEmail } from "./utils/validation"; // 이메일 검증 사용
이 파일은:
-
React의 상태 관리를 쓰고
-
Supabase 데이터베이스를 연결하고
-
공통 UI 컴포넌트를 가져다 쓰고
-
이메일 검증 기능이 있구나
경로 읽는 법:
import Button from "./components/Button";
// ↑
// 현재 파일 기준 상대 경로
// ./ = 현재 폴더
// ../ = 상위 폴더
// / = 프로젝트 루트 (설정에 따라 다름)
5. 파일 구조: 프로젝트의 지도
Cursor 왼쪽의 파일 탐색기는 프로젝트의 지도입니다. 폴더 이름만 봐도 뭐가 어디 있는지 알 수 있습니다.
일반적인 React 프로젝트 구조:
my-project/
├── src/
│ ├── components/ # 재사용 UI 컴포넌트
│ │ ├── Button.tsx
│ │ ├── Header.tsx
│ │ └── Card.tsx
│ │
│ ├── pages/ # 페이지 단위 컴포넌트 (라우팅)
│ │ ├── Home.tsx
│ │ ├── Login.tsx
│ │ └── Dashboard.tsx
│ │
│ ├── hooks/ # 커스텀 훅
│ │ └── useAuth.ts
│ │
│ ├── lib/ # 외부 서비스 연결 (Supabase, Firebase 등)
│ │ └── supabase.ts
│ │
│ ├── types/ # 타입 정의
│ │ └── index.ts
│ │
│ ├── utils/ # 유틸리티 함수
│ │ ├── helpers.ts
│ │ └── validation.ts
│ │
│ ├── api/ # API 호출 함수
│ │ └── auth.ts
│ │
│ ├── store/ # 상태관리 (Zustand 등)
│ │ └── useStore.ts
│ │
│ ├── styles/ # 전역 스타일
│ │ └── globals.css
│ │
│ ├── App.tsx # 메인 앱 (라우터 설정)
│ └── main.tsx # 진입점 (건드릴 일 거의 없음)
│
├── public/ # 정적 파일 (favicon, og 이미지 등)
│ └── logo.png
│
├── index.html # HTML 템플릿
├── vite.config.ts # Vite 설정
├── tsconfig.json # TypeScript 설정
├── .env # 환경변수 (VITE_ 접두사 필수!)
├── .env.local # 로컬 환경변수 (Git 제외)
├── package.json # 프로젝트 설정
└── README.md # 프로젝트 설명
폴더별 역할 요약:
| 폴더 | 역할 | 언제 보나? |
|---|---|---|
| components/ | 재사용 UI 조각 | 버튼, 카드 등 수정할 때 |
| pages/ | 각 화면 | 특정 페이지 수정할 때 |
| hooks/ | 재사용 로직 | 인증, 데이터 로직 볼 때 |
| lib/ | 외부 서비스 연결 | DB, API 설정 확인할 때 |
| utils/ | 도우미 함수 | 포맷팅, 검증 로직 볼 때 |
| styles/ | CSS | 스타일 수정할 때 |
Related Articles
Thank you for reading.