이번 4주차부터 6주차까지는 클린 코드에 대해 과제를 진행하는 주간입니다! 그 중에 4주차의 기본 과제는 바닐라 자바스크립트로 구현된 매우매우 더티한 코드를 가지고 클린 코드로 개선하는 것이고 심화과제는 클린 코드로 변경한 내용들을 리액트와 타입스크립트로 마이그레이션하...
👋 안녕하세요, 프론트엔드 개발자 여찬규입니다! 요즘 회사일에 치여서 인생이 재미없던 차에 항해 플러스 모집광고를 보게 되었고, 그 자리에서 바로 지원하게 되었어요 무언가에 이끌려 시작하게 되었는데, 시작한지 1주일밖에 안되었지만 엄청 재미있고 좋은 사람들도 많이 알...
드디어 항해 마지막 주차인 10주차가 되었습니다. 시간이 너무 빠른 것 같아요. 이제 수료만 남겨두고 있는 상황인데, 마지막인 만큼 10주차 과제에 대한 회고 내용을 열심히 정리해보겠습니다.
1주차에서는 프레임워크 없이 SPA를 맨땅에서부터 만들어봤습니다. 그럼 이번 주차 과제는 뭘까요? 간단하게 요약하자면 Virtual DOM과 이벤트 위임 시스템을 직접 구현하고, diff 알고리즘을 통한 렌더링 최적화를 하는 건데요. 평소 단어만 알았던 Virtual...
이전 블로그 링크: https://velog.io/@chan9yu/hanghae-plus-wil4
이번 과제부터는 테오 코치님이 발제를 해주시는데 발제 때 AI를 적극적으로 사용해보라고 권장하셨고, 이번 기회로 직접 AI를 활용해서 엄청나게 더러운 더티코드를 클린코드로 바꿔보면서 AI 사용에 익숙해지는 것을 목표로 했습니다.
(🚀 대 AI의 시대에서 개발 스타트업..)

드디어 클린 코드 주차인 4주차가 시작되었습니다~ 이번 주차부터 페어팀이 만들어진다고 했는데


(이거 맞나요...?)
사람들이 많아져서 뭔가 더 재미있어지고 얘기도 많이 할 기회가 생겨서 좋은 것 같습니다.
페어 1팀 잘 부탁드려요 😌

이번 4주차부터 6주차까지는 클린 코드에 대해 과제를 진행하는 주간입니다!
그 중에 4주차의 기본 과제는 바닐라 자바스크립트로 구현된 매우매우 더티한 코드를 가지고 클린 코드로 개선하는 것이고 심화 과제는 클린 코드로 변경한 내용들을 리액트와 타입스크립트로 마이그레이션하는 것이었습니다.

...오 와우
var 도배에 일관성 없는 네이밍까지... 마치 테오 코치님이 "얼마나 더러운 코드를 만들 수 있을까?" 하고 고민하며 만든 것 같은 느낌이었어요 ㅠㅠ
그리고 700줄 넘는 한 파일에 모든 로직이 들어있고, 중첩된 for문 지옥, 매직 넘버 천국, 전역변수 남발... 정말 모든 안티패턴의 집합체였습니다.
이번 과제에서는 Claude의 도움을 많이 받았는데 시간이 지나면서 AI 활용 방식이 변화가 있었습니다.
1단계: Claude 웹 - 전략 수립"리팩토링을 어떻게 시작해야 할까요?"
"이 더티코드의 문제점을 분석해주세요"
처음에는 개괄적인 방향성을 잡는 데 사용했어요.
2단계: Claude Desktop - 부분적 도움그러다가 Claude Desktop을 발견하고 그냥 웹에서 사용하는 것보다 많은 도움을 받을 수 있었습니다.
하지만 Claude Code를 발견하고 완전 삶의 질이 달라졌는데요. 정말 Claude Code 정말 기똥차네요!
프로젝트 전체를 연결해서 실시간으로 파일을 읽고 수정할 수 있게 되니까, 마치 똑똑한 페어 프로그래머와 함께 작업하는 느낌이었습니다.
과제를 진행하면서 가장 무서웠던 게 혹시 내가 놓친 케이스가 있어서 기능이 깨질까..? 였습니다. 그래서 정말 소심하게 리팩토링을 진행했는데
pnpm test:basic, pnpm test:advanced 실행한 상태에서 리팩토링실제로 findProductById 함수의 파라미터 순서를 잘못 바꾸는 실수로 테스트가 실패한 적이 있었는데, 변경을 단계적으로 진행한 덕분에 금방 파악하고 수정할 수 있었습니다.
가장 만족스러웠던 부분은 스파게티 코드를 feature별로 분리한 것이에요.
각 feature는 자신만의 책임을 가지고, 다른 feature와는 느슨하게 결합되도록 만들었습니다.
Before: 지옥의 한 함수 After: 역할별로 분리이번 과제를 통해 깨달은 AI 활용 노하우
요청은 최대한 구체적으로AI가 만든 코드도 완벽하지 않습니다. 특히 미묘한 로직 변경이나 엣지케이스 처리에서 실수가 있을 수 있어서 항상 검증이 필요합니다!!
모르면 꼭 물어보기"왜 이렇게 작성했나요?"라고 물어보면 AI가 의도를 설명해줘서 코드 이해에 도움이 많이 됩니다.
심화 과제에서는 정제된 바닐라 JS 코드를 React로 마이그레이션했는데, basic에서 구조를 잘 잡아둔 덕분에 생각보다 수월했습니다.

기본 과제와 심화 과제 모두 통과할 수 있었습니다!
배포 링크
Claude Code는 정말 현시점 최고의 개발 AI 도구인 것 같습니다. 단순 질의응답 → 부분적 도움 → 실시간 협업으로 발전하는 과정이 재미있었어요.
무조건 신뢰하지 않고 항상 검증하며 사용한 습관도 정말 중요했습니다.
기존 기능을 절대 깨뜨리지 않는다는 원칙을 지킨 덕분에 안전하게 개선할 수 있었어요. 작은 변경 → 테스트 → 다음 변경의 사이클이 정말 효과적이었습니다.
관심사 분리를 통해 코드 가독성이 크게 향상됐습니다. 각 기능을 독립적으로 테스트하고 수정할 수 있게 되었어요.
처음 리팩토링을 시작할 때는 매직 넘버 제거부터 시작했는데, 작업 중간에 "이걸 feature 단위로 나누려면 이 부분도 바꿔야 하네..." 같은 재수정 작업이 생기면서 비효율이 발생했습니다.
90% AI에 맡기다 보니 리팩토링 과정과 결과물 이해가 부족했던 순간들이 있었어요. 잘못된 코드를 주면 판별이 어려웠던 경우도 있었습니다.
여전히 회사 업무와 병행하다 보니 더 깊이 있게 공부하지 못한 아쉬움이 있어요... (이번 주 진짜 역대급 바쁨 진짜로오오오오오 😭😭)
앞으로는 작업 전에 전체 구조를 파악 후 목표 구조를 먼저 설계해두고 시작하는 게 더 효율적일 거라고 느꼈습니다.
현재는 성능에 대한 집착보다, 읽기 쉽고 관리하기 쉬운 코드 작성에 집중하자는 마음가짐을 가지게 되었어요.
엄청난 더티코드를 리팩토링하는 과정에서 많은 걸 얻어갈 수 있었던 것 같아요. 기존 기능을 절대 깨뜨리지 않으면서 점진적으로 개선하기 위해 나름 규칙도 세웠던 것 같고, 구조적으로 생각할 수 있는 힘을 기른 것 같습니다.
물론 이번 과제는 AI 의존도가 조금 높았습니다. 아마 Claude가 아니었다면 과제를 완성할 수 없었을 것 같아요. 하지만 AI는 도구일 뿐, 방향과 기준은 내가 먼저 세워야 한다는 걸 깨달았습니다.
이번 주차도 과제에 시간을 많이 투자하지 못해 아쉬웠지만, 분명 얻어간 게 있다고 생각하고 있습니다.

회사 업무 때문에 과제 못해서 결국 목요일에 밤을 새고 출근해버린 나... 진짜 죽을뻔

(도대체 무슨 싸움을...)
src/features/
├── cart/ # 장바구니 관련 로직
├── help/ # 도움말 모달
├── loyalty/ # 보너스 포인트
├── product/ # 상품 선택
└── sales/ # 할인 이벤트
var prodList;
var bonusPts = 0;
var stockInfo;
var itemCnt;
var lastSel;
var sel;
var addBtn;
var totalAmt = 0;
var PRODUCT_ONE = "p1";
var p2 = "p2";
var product_3 = "p3";
var p4 = "p4";
var PRODUCT_5 = `p5`;
function handleCalculateCartStuff() {
let cartItems;
let subTot;
// ... 20개 넘는 변수 선언
for (idx = 0; idx < prodList.length; idx++) {
for (let i = 0; i < cartItems.length; i++) {
// 150줄 넘는 중첩 로직...
}
}
}
// features/cart/index.js
export function handleCalculateCartStuff() {
const cartItems = getCartItems();
const totals = calculateCartTotals(cartItems);
const bonusPoints = calculateBonusPoints(totals.total);
updateCartDisplay(cartItems, totals, bonusPoints);
}
// 타입 안전성 확보
interface Product {
id: string;
name: string;
val: number;
originalVal: number;
q: number;
onSale: boolean;
suggestSale: boolean;
}
interface CartItem extends Product {
quantity: number;
}