스택오버플로우 복붙러 & ChatGPT 의존러 — 검색의 달인들
스택오버플로우 복붙러 & ChatGPT 의존러 — 검색의 달인들
"개발자의 진짜 실력은 구글링 실력이다 — 라고 자위하던 시절이 있었음"
복붙의 황금기: 스택오버플로우 시대
2008년 스택오버플로우가 탄생하면서 개발자 생태계에 혁명이 일어남. 그 전에는 뭐 하나 모르면 600쪽짜리 O'Reilly 책을 뒤져야 했는데, 이제 구글에 에러 메시지만 복붙하면 답이 나오는 세상이 된 거임.
개발자 진화의 역사:
1990년대: man page 읽기 → 동료한테 물어보기 → 포기
2000년대: 구글링 → 포럼 뒤지기 → 아직도 모름
2010년대: 구글링 → 스택오버플로우 → 복붙 → 작동함 → 왜 되는지 모름
2020년대: ChatGPT한테 물어봄 → 복붙 → 작동함 → 왜 되는지 모름
2025년대: AI가 코드 다 짬 → 복붙 → 안 됨 → AI한테 왜 안 되냐고 물어봄
스택오버플로우 재미있는 통계
- 가장 많이 조회된 질문: "How do I undo the most recent local commits in Git?" (1400만+ 조회)
- 즉, 전 세계 개발자 1400만 명이 git commit을 잘못 했다는 뜻
- 개발자는 실수하는 존재. 우리 모두 평등하게 무능함.
스택오버플로우 복붙러의 하루
// 09:00 - 출근. 어제 머지된 코드에서 버그 발견
// Google: "TypeError: Cannot read property 'map' of undefined"
// 스택오버플로우 검색 결과 37개 중 2012년 답변 복붙
// 09:30 - 복붙한 코드가 jQuery 기반이라 React 프로젝트에 안 맞음
// Google: "react equivalent of jquery each"
// 또 복붙
// 10:00 - 이제 다른 에러 발생
// Google: "Uncaught TypeError: this.setState is not a function"
// 2016년 답변 발견: bind(this) 하라고 함
// 우리 프로젝트는 함수형 컴포넌트인데... 복붙함
// 10:30 - 클래스 컴포넌트 문법이 섞여서 더 안 됨
// Google: "convert class component to functional component react"
// 변환 가이드 복붙
// 11:00 - 원래 버그는 아직 안 고침. 새로운 버그 3개 추가됨
복붙의 수준 분류
// Level 1: 순수 복붙 (이해 0%)
// 스택오버플로우에서 가장 좋아요 많은 답변을 그대로 복붙
// "되긴 되는데 왜 되는지 모름"
// Level 2: 변수명만 바꾸는 복붙 (이해 10%)
// 원본: const foo = bar.filter(x => x.active)
// 변형: const users = data.filter(x => x.active)
// "이해했음" 이라고 착각하는 단계
// Level 3: 여러 답변을 프랑켄슈타인 복붙 (이해 30%)
// 답변 A에서 함수 구조 가져오고
// 답변 B에서 에러 처리 가져오고
// 답변 C에서 타입 정의 가져옴
// 세 개가 서로 호환이 안 됨
// Level 4: 복붙 후 커스터마이징 (이해 60%)
// 원리를 어느 정도 이해하고 프로젝트에 맞게 수정
// 사실 이 정도면 "참고"라고 부르는 게 맞음
// Level 5: 답변을 읽고 영감을 받아 직접 작성 (이해 90%)
// 이건 복붙이 아니라 "학습"임
// 여기까지 오면 졸업한 거임
ChatGPT 의존러의 탄생
2022년 11월, ChatGPT가 등장하면서 개발자 생태계가 다시 한번 뒤집어짐. 스택오버플로우 트래픽이 폭락하고, 새로운 종족이 탄생했음.
ChatGPT 의존러 — 일명 "프롬프트 엔지니어"
ChatGPT 의존러의 위험 신호
- 간단한 for 루프도 ChatGPT한테 물어봄
- "ChatGPT가 이렇게 하라고 했어요"를 코드 리뷰 코멘트에 씀
- AI가 생성한 코드를 검증 없이 프로덕션에 배포함
- 에러가 나면 에러 메시지를 AI한테 던지고 나온 답을 또 복붙함
- AI가 만든 코드의 로직을 설명하지 못함
ChatGPT 의존러의 코딩 패턴
// ChatGPT 의존러의 전형적인 대화:
// 프롬프트 1: "React에서 사용자 목록을 보여주는 컴포넌트 만들어줘"
// → AI가 완벽한 코드를 줌
// → 복붙. 작동함. 좋아.
// 프롬프트 2: "여기서 페이지네이션 추가해줘"
// → AI가 기존 코드 무시하고 새로운 코드를 줌
// → 복붙. 기존 코드와 충돌. 안 됨.
// 프롬프트 3: "이 에러 고쳐줘: TypeError: Cannot read property..."
// → AI가 또 다른 코드를 줌
// → 복붙. 다른 에러 발생.
// 프롬프트 4: "이 에러도 고쳐줘"
// → 무한 루프 진입
// 결과물: AI가 3번 리라이트한 프랑켄슈타인 코드
// 아무도 이해 못 함. AI도 이제 컨텍스트 잃어버림.
스택오버플로우 복붙 vs ChatGPT 복붙 비교
// 같은 문제: "배열에서 중복 제거"
// 스택오버플로우 복붙 (2015년 답변)
// → 검증됨 (좋아요 3,847개)
// → 댓글에 엣지 케이스 경고 있음
// → 성능 벤치마크까지 있음
const unique = [...new Set(array)];
// ChatGPT 복붙
// → 장황한 설명과 함께 옴
// → 보통은 맞지만 가끔 환각함
// → 존재하지 않는 라이브러리를 추천하기도 함
// ChatGPT가 실제로 추천한 적 있는 존재하지 않는 것들:
// - npm 패키지 "array-unique-deep" (없음)
// - Array.prototype.unique() (이런 메서드 없음)
// - lodash.deduplicate (이런 함수 없음)
// 자신감 있게 추천하니까 더 무서움
복붙의 함정들
1. 라이선스 지뢰밭
// 스택오버플로우의 코드는 CC BY-SA 4.0 라이선스임.
// 이게 뭔 뜻이냐면:
// 1. 출처를 밝혀야 함 (Attribution)
// → "이 코드는 스택오버플로우에서 가져왔습니다"
// → 솔직히 아무도 안 함
// 2. 같은 라이선스로 공유해야 함 (ShareAlike)
// → 니 프로젝트가 MIT 라이선스인데 CC BY-SA 코드를 넣으면
// → 라이선스 충돌 발생
// → 법적으로는 문제가 될 수 있음
// → "에이 설마 누가 고소하겠어" → 실제로 고소당한 사례 있음
// 회사 법무팀이 이걸 알면 경악할 내용:
// 프로덕션 코드의 약 30%가 스택오버플로우 출처라는 연구 결과가 있음
실제 사례: 라이선스 문제
2022년, 한 기업이 오픈소스 라이선스 감사를 받다가 스택오버플로우에서 가져온 코드 조각이 GPL 오염을 일으킨 걸 발견했음. 해당 모듈 전체를 다시 작성해야 했고, 3개월이 걸렸음. "그냥 복붙한 건데..." 가 3개월의 재작업으로 돌아온 사례.
2. 보안 취약점 복붙
// 스택오버플로우에서 가장 많이 복붙되는 보안 취약점 코드들
// 취약점 1: SQL 인젝션
// 2011년 답변이 아직도 복붙되고 있음
const query = `SELECT * FROM users WHERE name = '${userName}'`;
// userName에 "'; DROP TABLE users; --" 넣으면 테이블 날아감
// 올바른 방법: parameterized query 사용
// 취약점 2: XSS (Cross-Site Scripting)
// 사용자 입력을 검증 없이 DOM에 직접 렌더링하면
// 악성 스크립트가 삽입될 수 있음
// 올바른 방법: 입력 값 sanitize + 안전한 렌더링 API 사용
// 취약점 3: 인증서 검증 비활성화
// "SSL 에러 나요" 질문의 최다 좋아요 답변이
// TLS 검증을 비활성화하라고 함
// "야 이거 하니까 됨!!" ← 보안 구멍을 뚫어서 된 거임
// 취약점 4: CORS 전부 허용
// "CORS 에러 나요" 질문의 답변
// app.use(cors({ origin: '*' }));
// "오 됐다!" ← 전 세계 누구나 니 API 호출 가능하게 만든 거임
3. 버전 호환성 시한폭탄
// 2019년 답변을 2026년 프로젝트에 복붙하면 생기는 일
// 답변 (2019년, React 16 기준):
class UserList extends React.Component {
componentWillMount() { // React 17에서 deprecated, 18에서 제거됨
this.fetchUsers();
}
componentWillReceiveProps(nextProps) { // 이것도 제거됨
if (nextProps.filter !== this.props.filter) {
this.fetchUsers(nextProps.filter);
}
}
render() {
return (
<div>
{this.state.users.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
}
// 2026년 프로젝트에 이걸 넣으면:
// - componentWillMount → 존재하지 않음
// - componentWillReceiveProps → 존재하지 않음
// - 클래스 컴포넌트 → 팀원들의 따가운 눈초리
// 복붙러: "스택오버플로우에서 되는 코드인데 왜 안 되죠?"
// 팀원: "그 답변 7년 전 거잖아요..."
검색도 실력이다: 올바른 검색 방법
복붙 자체가 나쁜 건 아님. 문제는 생각 없이 복붙하는 것. 검색을 잘 하는 것도 진짜 실력임.
좋은 검색의 기술
// 나쁜 검색 (0.1x 검색법)
// Google: "react not working"
// → 결과 3억 개. 도움 안 됨.
// Google: "error in my code"
// → ???
// Google: "javascript why"
// → 이건 철학적 질문임
// 좋은 검색 (효과적인 검색법)
// Google: "React useEffect cleanup function not called unmount"
// → 구체적인 기술 + 구체적인 증상 + 구체적인 상황
// Google: "TypeScript generic constraint extends keyof"
// → 정확한 키워드 조합
// Google: "Next.js 16 app router fetch cache revalidate"
// → 버전 명시 (이게 중요!)
스택오버플로우 답변 평가법
// 좋은 답변의 신호:
// - 좋아요 수가 높음 (100+)
// - 최근에 수정됨 (3년 이내)
// - 댓글에서 엣지 케이스 토론이 있음
// - 왜 이렇게 하는지 설명이 있음
// - 대안 접근법도 언급됨
// - 답변자의 reputation이 높음 (10k+)
// 나쁜 답변의 신호:
// - 답변이 2015년 이전이고 수정 이력 없음
// - "이거 해보세요" 한 줄짜리
// - 댓글에 "이거 더 이상 안 됨" 이 달려있음
// - any 를 남발함
// - 보안 관련 설정을 비활성화함
// - "내 프로젝트에서는 됨" ← 니 프로젝트가 특이한 거임
효과적인 검색 프레임워크
검색할 때 이 순서로 접근하면 됨:
- 에러 메시지를 정확히 읽기 — 놀랍게도 대부분 답이 에러 메시지에 있음
- 공식 문서를 먼저 확인 — 구글 검색에 "site:nextjs.org" 추가
- 버전을 명시 — "React 19" 를 검색어에 포함
- GitHub Issues 확인 — 라이브러리 버그일 수도 있음
- 스택오버플로우/AI는 마지막 — 위 4단계로 해결 안 될 때
이 순서를 지키면 복붙해도 양질의 코드를 복붙하게 됨.
AI를 제대로 활용하는 방법
AI 도구를 아예 안 쓰는 건 비효율적임. 잘 쓰는 게 중요함.
// 나쁜 AI 활용
// "사용자 관리 시스템 만들어줘" → 500줄 코드 받음 → 전부 복붙
// 좋은 AI 활용
// 1. 구체적인 질문
// "TypeScript에서 discriminated union 타입으로
// API 응답을 모델링하려는데, 에러 케이스 처리 패턴 보여줘"
// 2. AI 답변을 검증
type ApiResponse<T> =
| { status: 'success'; data: T }
| { status: 'error'; error: { code: string; message: string } };
// → 이 패턴이 우리 프로젝트에 맞는지 확인
// → 타입 추론이 제대로 되는지 직접 테스트
// → 기존 코드와 일관성 있는지 확인
// 3. 학습 도구로 활용
// "이 코드에서 exhaustive check가 왜 필요한지 설명해줘"
// → 이해한 후에 적용. 이해 없이 복붙하지 않음.
function handleResponse<T>(response: ApiResponse<T>) {
switch (response.status) {
case 'success':
return response.data;
case 'error':
throw new Error(response.error.message);
default:
// exhaustive check
const _exhaustive: never = response;
throw new Error(`Unhandled status: ${_exhaustive}`);
}
}
복붙러에서 개발자로: 졸업 가이드
복붙에서 벗어나는 5단계
1단계: 인정 — "나 복붙 좀 많이 하는 것 같음" 인정하기
2단계: 이해 — 복붙하기 전에 코드가 뭘 하는지 한 줄씩 읽기. 모르는 메서드가 있으면 MDN이나 공식 문서에서 확인.
3단계: 변형 — 복붙한 코드를 프로젝트 스타일에 맞게 수정하기. 변수명, 에러 처리, 타입 등을 직접 고치기.
4단계: 재작성 — 복붙한 코드를 참고만 하고, 직접 처음부터 작성하기. 이 과정에서 진짜 이해가 됨.
5단계: 기여 — 내가 겪은 문제와 해결법을 블로그/스택오버플로우에 공유하기. 복붙 당하는 입장이 되어보기.
마지막으로: 모든 개발자는 검색한다
시니어 개발자도 검색함. 차이는:
// 주니어: 검색 → 첫 번째 결과 복붙 → 안 되면 두 번째 결과 복붙
// 시니어: 검색 → 여러 결과 비교 → 원리 이해 → 프로젝트에 맞게 적용
// 진짜 시니어가 검색하는 것들:
// - 라이브러리의 소스 코드 (GitHub)
// - RFC 문서 (표준 스펙)
// - 벤치마크 결과 (성능 비교)
// - 릴리즈 노트 (변경사항 확인)
// - 보안 어드바이저리 (취약점 확인)
// 주니어가 검색하는 것들:
// - "how to center a div"
// - "왜 안됨"
// - 에러 메시지 전체 (따옴표 없이)
검색은 부끄러운 게 아님. 기억력에는 한계가 있고, 기술은 계속 변하니까 전부 외울 수도 없음.
중요한 건 검색 결과를 어떻게 소화하느냐임. 복붙은 시작점이지, 도착점이 아님.
"나는 스택오버플로우에서 복사했고, ChatGPT에서 붙여넣기 했으며, 그것을 내 코드라 불렀다." — 현대 개발자의 고백