Next.js와 Flutter를 위한 통합 계산 엔진: 숫자 불일치 피하기
동일한 건설 계산기가 Flutter 모바일 앱과 Next.js 웹사이트로 모두 존재할 때, 공식의 사소한 차이조차 사용자 신뢰를 흔들 수 있습니다. 실제 사례에서 보듯: 앱과 사이트가 울타리 기둥에 대한 콘크리트 양을 다르게 출력하면, 이는 단순한 버그가 아니라—중복 로직의 체계적 문제입니다. 해결책은 선언적 JSON 사양과 패리티 테스트를 기반으로 한 단일 진실 원천입니다.
두 개의 독립 코드베이스 문제
처음에 계산 로직은 두 번 구현되었습니다: Flutter 앱용 Dart와 Next.js 사이트용 TypeScript로요. 두 프로젝트는 병렬로 진화했지만 독립적이었습니다. 계수, 기본값(예: 기둥 구멍 지름), 반올림 규칙, 자재 포장 방식이 각 런타임 코드에 별도로 존재했습니다. 결과: 동일 입력에 대한 출력 불일치.
이 아키텍처는 DRY(중복하지 말라) 원칙을 위반하며, 결국 사용자 불만으로 기술 부채가 드러납니다. 특히 계산 정확도가 제품 신뢰에 직결되는 틈새 도구에서 치명적입니다.
선언적 접근: JSON을 진실 원천으로
비즈니스 로직 중복 대신 모든 변수 매개변수를 구조화된 JSON 파일로 이동했습니다—계산기당 하나씩. 각 사양에는 다음이 포함됩니다:
- 입력 필드 기본값(예: 말뚝 지름—150 mm)
- 반올림 규칙(항상 올림)
- 정확도 모드에 따른 손실 계수
- 자재 포장 정보(25 kg 봉지, 봉지당 0.01 m³ 수율)
- 최소 층 두께와 체결부 간격
이 JSON 파일들이 단일 진실 원천이 되었습니다. 이제 매개변수 변경은 JSON에서 한 번만 하고, 두 런타임에 자동 적용됩니다.
동기화를 위한 코드 생성
두 프로젝트가 동일 데이터를 사용하도록 코드 생성 프로세스를 도입했습니다:
- JSON 사양 변경 시
npm run sync:specs스크립트 실행 - 스크립트가 모든 사양 읽고 상수 맵(
const Map)으로 Dart 파일 생성 - 생성된 파일을 Flutter 앱 저장소에 커밋
- 두 시스템의 CI/CD가 변경 확인 후 업데이트 버전 배포
생성 파일은 @generated로 표시되며, 린터가 수동 편집 차단합니다. 이는 인간 오류를 없애고 데이터 일관성을 보장합니다.
패리티 테스트: 로직 불일치 방지
동일 데이터라도 언어 차이로 동작 차이가 발생할 수 있습니다: TypeScript의 Math.ceil()과 Dart의 num.ceil()이 경계 케이스에서 다를 수 있죠. 이를 막기 위해 패리티 테스트 시스템을 구현했습니다:
- 고정 데이터 세트—61개 계산기 각각에 수십 개 입력 조합
- TypeScript 엔진이 모든 고정 데이터 실행 후 참조 파일에 결과 저장
- 동일 파일을 Flutter 저장소에서 Dart 엔진 결과와 비교
- 불일치—마지막 소수점 자리라도—CI 실패
6개월간 이 테스트가 자동 검사 없이는 놓쳤을 세 가지 실제 불일치를 잡아냈습니다.
"+10% 더하기" 대신 세 가지 정확도 모드
전통 계산기는 보통 보편적 안전 계수(예: +10%)를 씁니다. 이 지름길은 부정확성을 초래하죠: 타일은 절단 여유, 석고는 바닥 불균일 보상, 접착제는 표면 흡수 고려가 필요합니다.
대신 세 가지 계산 모드를 구현했습니다:
- Basic—여유 없는 표준 기반 계산, GOST/SP 준수
- Realistic(기본)—일반 아파트 리모델링 조건 반영
- Professional—복잡 프로젝트와 부족 보장에 최대 여유
각 모드 계수는 JSON 사양에 저장되어 앱 재빌드 없이 변경 가능합니다.
핵심 규칙: 동일 입력에서 결과가 Basic ≤ Realistic ≤ Professional을 만족해야 합니다. 전용 CI 테스트가 모든 계산기 확인합니다.
검증기를 두 번째 방어선으로
단위 테스트와 패리티 검사 외에 CI가 세 가지 전문 검증기를 실행합니다:
- 논리 검증기: 구매 수량 ≥ 순수량 확인, 유효 입력에서 결과 0 방지, 라벨에 적절한 미터법 단위 사용(“m²”, “sq m” 아님)
- 포장 검증기: 현실적 자재 포장 확인(접착제 5/10/15 L 버킷, 타일 팩 단위, 개별 아님)
- 단위 검증기: 미터법 혼동 포착(예: 변환 없이 mm를 m에 더함)
이 스크립트들은 시스템 관문의 "보안 체크포인트" 역할을 합니다—단위 테스트 대체가 아니라, 단위 테스트가 놓칠 수 있는 어리석지만 치명적인 생태계 오류를 막습니다.
주요 교훈
- JSON 사양을 통한 단일 진실 원천으로 런타임 간 매개변수 중복 제거.
- 코드 생성으로 수동 개입 없이 데이터 동기화.
- 패리티 테스트로 Dart와 TypeScript에서 동일 결과 보장.
- 세 가지 정확도 모드로 단순 "+10%" 대체하고 사용자 여유 제어.
- CI의 전문 검증기로 단위 테스트가 놓칠 체계 오류 방지.
— Editorial Team
아직 댓글이 없습니다.