피날레 — DailyLedger 월말 마감
요구사항
개인 가계부의 월말 마감을 처리하세요. 열 개의 항목이 저장소에 있고(아래 코드에 고정 데이터로 있습니다), id로 각 항목을 불러오되 — 최대 세 개까지만 동시에 로드합니다, 이는 최대 동시 실행 수 카운터로 증명됩니다 — 그런 다음 2026년 7월 마감을 계산합니다: 7월 항목만 남기고(하나는 6월에 낀 예외입니다), 수입과 지출을 나누어 각각 합산한 뒤, 순액과 항목 수를 포함한 상위 세 지출 카테고리를 출력합니다.
여기 쓰인 형태들은 실제 앱에서 그대로 가져온 것입니다:
Entry 모델, 수입/지출 분리(filter →
partition → 각 절반에 sumBy), 카테고리
분석(groupBy → 그룹별 sumBy →
내림차순 sortBy → take(3))은 DailyLedger의
monthSummary와 categoryBreakdown
파이프라인을 그대로 옮긴 것이며, 앞단의 비동기 로드 단계
(toAsync → map → concurrent(3))도
마찬가지입니다.
예상 출력
July 2026 close — 10 entries loaded, 3 at a time (max in flight: 3) income $3600.00 expense $1478.15 net $2121.85 top spending categories: housing: $1150.00 (1 entry) food: $206.35 (3 entries) utilities: $106.30 (2 entries)
나란히 보기
네이티브 Dart
FxDart
차이가 나는 이유
쉰 개의 예제를 지나오며 결국 모두가 하나로 수렴하는 패턴이
이것입니다: 순수 Dart는 기능 하나에 세 가지 방언이 필요합니다 —
그룹화를 위한 package:collection 헬퍼, 합계를 위한
명시적 초기값이 있는 fold, 그리고 로드 단계에
동시성 제한이 필요해지는 순간 직접 짜야 하는 워커 풀. 각 조각은
그 자체로는 문제없지만, 합쳐지면 비즈니스 로직이 화면에서 가장
찾기 어려운 것이 되어 버립니다. FxDart 버전은 로드 단계부터
리포트까지 같은 어휘로 이어지며, 모든 단계가 순수한 파이프라인이기
때문에 각각을 떼어내어 항목이 들어가고 뷰 데이터가 나온다는
형태로 단위 테스트할 수 있습니다.
이 파이프라인들은 데모용으로 꾸며낸 것이 아닙니다: 실제로 DailyLedger 데모 앱이 대시보드를 계산하는 방식 그대로입니다 — 같은 모델, 같은 연산자가 여러분의 브라우저에서 실시간으로 동작합니다. 쉰 개의 비교가 단어들을 보여줬다면, DailyLedger는 그 단어들이 만들어 가던 문장입니다.
벤치마크
비동기 예제입니다. 대표 스케일이 1,000,000이 아니라 N = 20,000인 이유 — 원소 하나마다 양쪽 모두 이벤트 루프를 한 바퀴 돌아야 하므로, 실제 await 백만 번은 파이프라인이 아니라 Dart 이벤트 루프를 몇 분씩 재게 됩니다. 지연은 0으로 두고 예제의 동시성 제한은 그대로 유지합니다. 막대가 비교하는 것은 파이프라인 기계 장치 자체입니다.
N = 100
시간 무승부
최대 메모리 무승부
N = 10,000
시간 무승부
최대 메모리 무승부
N = 20,000
시간 무승부
최대 메모리 무승부
막대는 사이드별로 새 프로세스에서 반복 측정한 중앙값입니다(작은 N은 타이머 해상도를 위해 배치 처리). 두 사이드가 서로 5% 이내이거나 — 사람이 지각할 수 없는 차이인 0.6ms 이내이면 — 무승부로 칩니다. 상대 차이가 근소한 경우는 최대 5회까지 다시 측정합니다. 앱에서는 어느 막대가 짧든 몇 밀리초 이하의 차이는 사용자에게 보이지 않습니다. 메모리는 프로세스 최대 RSS입니다. Dart VM과 데이터셋은 양쪽이 동일하므로, 두 막대의 차이가 곧 파이프라인 자체가 붙들고 있는 양입니다.