배열 고차 함수(reduce)로 만드는 자산 관리 자바스크립트 가계부

안녕하세요! 오늘 10번째 프로젝트로는 누구나 한 번쯤 해봤을 법한 고민, “내 지출을 한눈에 관리할 수 없을까?”라는 질문에서 시작해 ‘나만의 자바스크립트 가계부’를 만들어보았습니다..

사실 단순히 얼마를 썼는지만 기록하는 것은 반쪽짜리 가계부나 다름없습니다. “이번 달 수입은 얼마였고, 그래서 지금 내 통장 잔액은 얼마인가?”라는 질문에 답할 수 있어야 진짜 가계부라고 할 수 있죠. 이번 포스팅에서는 날짜 기반의 정렬부터 수입/지출 통합 합산 로직까지, 자바스크립트의 데이터를 어떻게 가공하고 시각화하는지에 집중하여 글을 써 내려가 보겠습니다. 이와 더불어 브라우저를 껐다 켜도 데이터가 유지되는 저장(Storage) 기능과 대량의 데이터를 효율적으로 가공하는 고차 함수를 적극적으로 활용했습니다.

자바스크립트 가계부 메인 화면

1. 수입과 지출의 ‘순수 합계’를 구하는 법

데이터 구조가 복잡해질수록 로직은 간결해야 합니다. 수입 내역과 지출 내역이 하나의 배열에 섞여 있을 때, 우리는 어떻게 각각의 합계를 구하고 최종 잔액을 도출할 수 있을까요?

// 1. 수입만 걸러내어 합계 계산
const totalIncome = records
    .filter(r => r.type === 'income')
    .reduce((acc, curr) => acc + curr.amount, 0);

// 2. 지출만 걸러내어 합계 계산
const totalExpense = records
    .filter(r => r.type === 'expense')
    .reduce((acc, curr) => acc + curr.amount, 0);

// 3. 최종 잔액 계산
const netBalance = totalIncome - totalExpense;

그 정답은 바로 filterreduce에 있습니다. 두 개를 잘 조합해서 사용하면 어렵지 않게 기능을 구현할 수 있습니다. 반복문을 여러 번 돌릴 필요 없이, 필요한 데이터만 쏙쏙 골라내어 연산하는 이 방식은 코드의 가독성을 획기적으로 높여줍니다. 특히 마지막에 수입에서 지출을 뺀 netBalance를 통해 사용자가 현재 자산 상태를 즉시 확인할 수 있도록 설계했습니다.

2. UX

  • 날짜순으로 정렬된 일관된 데이터

가계부를 쓰다 보면 어제의 지출을 오늘 기록할 때도 있고, 깜빡하고 지난주 내역을 몰아서 적을 때도 있습니다. 입력한 순서대로만 리스트가 나온다면 가계부로서의 가치가 떨어지겠죠.

// 날짜 데이터를 기준으로 내림차순(최신순) 정렬
records.sort((a, b) => new Date(b.date) - new Date(a.date));

저는 sort() 함수를 활용해 사용자가 어떤 순서로 입력하든 상관없이, 화면에는 항상 최신 날짜가 위로 오도록 로직을 보완했습니다. Date 객체를 비교하여 배열의 순서를 실시간으로 바꾸는 이 기술은 데이터 중심의 앱을 만들 때 반드시 익혀야 할 테크닉입니다.

  • 1,000원과 1000원의 차이

자바스크립트 가계부에서 가장 중요한 것은 가독성입니다. 1000000원이라고 적혀 있으면 한눈에 얼마인지 파악하기 어렵죠. 그래서 저는 자바스크립트의 toLocaleString() 함수를 사용해 세 자리마다 콤마(,)가 찍히도록 배려했습니다. 이런 작은 디테일이 모여 사용자가 “이 가계부는 쓰기 편하다”라고 느끼게 만드는 차별점이 됩니다. 레이아웃 역시 CSS Grid를 활용해 입력창을 깔끔하게 정렬하여 모바일에서도 사용하기 좋게 구성했습니다.

3. 왜 LocalStorage를 고집하나요?

Q: 데이터베이스(DB)를 쓰지 않고 로컬스토리지를 쓰는 이유가 뭔가요?

A: 이번에 만든 자바스크립트 가계부의 목표는 ‘가볍고 빠른 개인용 도구’입니다. 서버나 로그인이 필요 없는 로컬스토리지 방식은 사용자의 데이터를 서버에 전송하지 않아 프라이버시 보호에 유리하며, 오프라인 환경에서도 즉시 작동한다는 강력한 장점이 있습니다. 물론 나중에는 Firebase 같은 서비스와 연동해 모바일-PC 동기화를 구현할 수도 있겠죠!

// 데이터를 저장할 때: JSON 객체를 문자열로 변환
localStorage.setItem('records', JSON.stringify(records));

// 데이터를 불러올 때: 문자열을 다시 JSON 객체로 변환
let records = JSON.parse(localStorage.getItem('records')) || [];

4. 시행착오: “총 합계”가 주는 심리적 안정감

처음에는 수입과 지출만 따로 보여줬습니다. 하지만 테스트를 해보니 정작 중요한 “그래서 지금 얼마 남았지?”를 확인하기 위해 사용자가 다시 계산기를 두드려야 하는 번거로움이 있더군요.

사용자 피드백을 통해 대시보드 하단에 큼직한 ‘현재 총 잔액’ 섹션을 추가했습니다. 수입은 초록색, 지출은 빨간색으로 대비를 주고 잔액은 신뢰감을 주는 네이비 톤으로 구성했습니다. 기능을 추가하는 것보다 더 중요한 것은 ‘사용자가 무엇을 궁금해하는가’를 파악하는 것임을 다시 한번 깨달았습니다.

5. 보완점 및 향후 발전 방향

  • 카테고리별 차트: Chart.js를 연동해 각 카테고리별 원형 그래프로 시각화하기.
  • 날짜 필터: 이번 주, 이번 달 등 특정 기간의 지출, 수입만 모아보기.
  • 핸드폰과 연동: 카드를 결제했을 때 전송되어 온 문자나 메시지를 파싱하여 자동으로 가계부에 입력할 수 있도록 하기.

6. 자바스크립트 가계부 플레이 화면

자바스크립트 가계부 플레이 화면

10개의 프로젝트를 진행하며 조건문, 반복문 같은 기초 문법부터 오늘 다룬 비동기 데이터 가공과 로컬 저장소 활용까지 다양한 기술을 활용해보려고 노력을 많이 했습니다.

데이터를 저장하고 관리하는 기초는 [자바스크립트 할 일 목록] 포스팅에서 다룬 LocalStorage 개념을 먼저 이해하시면 훨씬 수월합니다.

오늘 만든 ‘자바스크립트 가계부’는 단순히 코딩 연습용 예제가 아닙니다. 여러분의 실제 생활을 관리하는 진짜 서비스로 발전시킬 수 있는 훌륭한 베이스캠프죠. 이 코드를 바탕으로 카테고리별 아이콘을 추가하거나, 월별 리포트 기능을 더해보는 것은 어떨까요? 더 나아가 실제로 운영할 수 있는 웹앱으로 만들어도 좋을 것 같습니다.

단순히 지출 내역을 나열하는 것보다 전체 잔액을 실시간으로 계산하는 로직이 중요했습니다. 자바스크립트의 배열 고차 함수인 reduce를 활용해 복잡한 반복문 없이 깔끔하게 합계를 산출하는 코드를 작성하며 ‘클린 코드’의 중요성을 체감했습니다. 데이터의 흐름을 관리하는 법을 배우고 싶은 분들에게 좋은 예제가 될 것입니다.

또 다른 기술들을 활용할 수 있는 주제를 가지고 11번째 프로젝트로 찾아 오겠습니다! 새해 복 많이 받으세요!

댓글 남기기