초보자의 투두앱 코드를 한 단계 개선해보기: 코드 리뷰 Before & After

1. 주제 소개
투두앱은 초보자가 JavaScript를 익힐 때 가장 많이 만드는 프로젝트입니다. 입력값 추가, 목록 렌더링, 완료 체크, 삭제, 저장까지 기본 기능이 골고루 들어 있어 연습에 좋기 때문입니다. 하지만 실제 코드를 보면 기능은 동작하는데 구조가 빠르게 복잡해지는 경우가 많습니다. 예를 들어 전역 변수에 상태를 몰아두고, 이벤트 핸들러 안에서 직접 DOM을 계속 수정하며, localStorage 접근도 여기저기 섞여 있으면 작은 기능 추가도 어렵습니다. 결국 "고치면 다른 기능이 깨지는" 경험을 자주 하게 됩니다.
이번 글은 초보자의 투두앱 코드를 한 단계 개선하는 기준을 Before & After 관점으로 소개합니다. 목표는 거대한 아키텍처가 아니라, 읽기 쉽고 수정하기 쉬운 구조로 정리하는 것입니다. 작은 개선만 적용해도 코드 안정성과 개발 자신감이 함께 올라갑니다.
2. 핵심 내용
첫 번째 개선 포인트는 상태와 화면 로직 분리입니다. Before 코드에서는 배열 변경과 DOM 렌더링이 한 함수에 섞여 있는 경우가 많습니다. After에서는 `addTodo`, `toggleTodo`, `removeTodo`처럼 상태를 바꾸는 함수와 `renderTodos`처럼 화면을 그리는 함수를 분리합니다. 이렇게 하면 버그 원인을 "상태 문제인지 화면 문제인지" 빠르게 구분할 수 있습니다.
두 번째는 이벤트 처리 단순화입니다. 버튼마다 리스너를 개별로 붙이는 대신 목록 컨테이너에 이벤트 위임을 적용하면 코드가 줄고 동적 요소 대응이 쉬워집니다. 세 번째는 데이터 모델 명확화입니다. 단순 문자열 대신 `{ id, text, completed, createdAt }` 같은 객체 구조를 쓰면 확장성이 좋아집니다. 나중에 필터, 정렬, 수정 기능을 붙일 때도 부담이 적습니다.
네 번째는 저장소 접근 캡슐화입니다. localStorage를 직접 호출하는 코드를 분리해 `loadTodos`, `saveTodos` 같은 함수로 통일하면 에러 처리와 기본값 관리가 쉬워집니다. 다섯 번째는 조건문과 함수 길이 관리입니다. 긴 함수는 검증, 상태 변경, 렌더링 단위로 나누고, 이름을 통해 의도를 드러내야 리뷰와 유지보수가 쉬워집니다.
3. 적용 방법
실전에서는 한 번에 재작성하지 말고 단계적으로 바꾸는 것이 안전합니다. 먼저 현재 동작을 유지한 채 상태 조작 함수를 분리합니다. 다음으로 렌더링 함수를 단일 진입점으로 만들고, 상태 변경 후에는 항상 `renderTodos()`를 호출하는 규칙을 세웁니다. 이후 이벤트 위임으로 클릭 처리 구조를 단순화하고, 마지막에 localStorage 유틸을 붙여 저장/복원을 안정화합니다. 각 단계마다 추가/완료/삭제/새로고침 동작을 확인하면 회귀 버그를 줄일 수 있습니다.
| 개선 항목 | Before | After |
|---|---|---|
| 상태와 렌더링 | 한 함수에서 배열 변경과 DOM 갱신 혼합 | 상태 함수와 렌더 함수 분리 |
| 이벤트 처리 | 요소마다 개별 리스너 등록 | 목록 컨테이너 이벤트 위임 |
| 데이터 구조 | 문자열/인덱스 중심 처리 | id 기반 객체 모델로 관리 |
| 저장 로직 | 여러 위치에서 localStorage 직접 호출 | load/save 유틸 함수로 중앙화 |
Before 코드에서는 기능 하나를 추가할 때 관련 코드를 여러 군데 수정해야 해서 실수 가능성이 큽니다. After 구조에서는 변경 지점이 예측 가능해져 작업 속도와 안정성이 함께 좋아집니다. 예를 들어 "완료된 할 일만 보기" 필터를 추가할 때도 상태 계산과 렌더링 로직을 분리해 두었다면 최소한의 변경으로 확장할 수 있습니다. 이 차이가 바로 초보 코드를 다음 단계로 올리는 핵심입니다.
4. 정리
투두앱 개선의 핵심은 거창한 기술 도입이 아닙니다. 상태 분리, 이벤트 정리, 데이터 모델 명확화, 저장 로직 공통화라는 기본 원칙을 지키는 것입니다. 이 네 가지를 적용하면 코드 길이가 조금 늘어도 훨씬 읽기 쉽고, 수정 시 자신감이 생깁니다. 초보 단계에서는 "동작한다"에서 끝내기 쉽지만, 한 단계 더 나아가 "유지보수 가능하다"를 목표로 삼아보세요. 좋은 프로젝트 경험은 복잡한 기능보다, 작은 구조 개선을 끝까지 해본 경험에서 만들어집니다.
5. 자주 묻는 질문
Q1. 리팩터링부터 할까요, 기능 추가부터 할까요?
현재 코드가 자주 깨진다면 먼저 작은 리팩터링으로 기반을 정리하는 것이 좋습니다. 구조가 안정되면 기능 추가 속도도 자연스럽게 빨라집니다.
Q2. 상태 관리 라이브러리를 바로 써야 하나요?
작은 투두앱이라면 순수 JavaScript 구조만으로도 충분합니다. 먼저 기본 원칙을 익히고, 규모가 커졌을 때 라이브러리를 도입해도 늦지 않습니다.
Q3. 가장 먼저 고치면 효과 큰 부분은 어디인가요?
상태 변경과 렌더링 분리부터 추천합니다. 이 한 가지 개선만으로도 버그 추적과 기능 확장 난이도가 크게 낮아집니다.