현장

날짜 옆에 근거가 따라온다 — 마감 보드가 저장하지 않는 것

2026-06에 세무 마감 보드 이야기를 실었다. 그 글에는 날짜가 어디서 왔는지가 없었다. 이번엔 직접 만들었다 — 이 보드는 마감일을 하나도 저장하지 않는다. 규칙만 갖고 매번 계산하고, 주말에 밀린 날은 밀렸다고 말한다.

작성: makemind · 2026년 8월 17일

먼저 밝혀 둔다. 2026년 6월에 이 매거진은 어느 회계사무소의 마감 보드 이야기를 실었다. 이 현장은 특정 업체가 아니다. 실제로 그렇게 돌아가는 형태를 그대로 구성했고, 어느 곳인지는 밝히지 않는다. 아래는 그 형태대로 직접 만든 것이고, 거래처와 마감 항목은 지어낸 것이다.

이 도메인의 어려움은 산수가 아니다. 규칙과 날짜가 다른 것인데, 사무실은 늘 규칙 쪽을 잃어버린다는 것이다.

스프레드시트 셀에 2026-04-27 이 적혀 있다고 하자. 그걸 읽는 사람은 그게 법정 기한인지, 주말이라 밀린 날인지, 작년 것을 복사하다 생긴 오타인지 알 방법이 없다.

그래서 이 보드는 마감일을 하나도 저장하지 않는다.

저장하는 것은 규칙이다

/// A filing obligation, as a rule rather than a date.
class Duty {
  const Duty(this.client, this.name, this.dayOfMonth, this.monthOf, this.note);

  /// Statutory day of the month.
  final int dayOfMonth;

  /// Which month it lands in, relative to the period being filed.
  final int monthOf;
}

날짜가 없다. 몇 월 며칠이라는 규칙만 있다. 화면에 뜨는 날짜는 매번 그 규칙에서 계산된다.

그리고 검증이 그걸 확인한다. 화면에 뜬 마감일이 소스에 문자열로 존재하면 실패시킨다.

for D in $(grep -o "20[0-9][0-9]-[0-9][0-9]-[0-9][0-9] D-\?[0-9]*" captures/run.log | awk '{print $1}' | sort -u); do
  if grep -RIn --exclude-dir=captures -F "$D" deadline_server/bin deadlines.mbd bundle_host/lib; then
    echo "   due date $D is a literal in the sources — it must be computed"
    exit 1
  fi
done

이 검사가 실제로 뭔가를 잡았다. 처음 돌렸을 때 실패했는데, 원인은 내가 문서 주석에 예시로 적어 둔 2026-04-27 이었다. 오탐이다 — 주석이지 저장된 날짜가 아니니까.

그런데 고치면서 진짜 하나가 같이 나왔다. 상태 응답에 'today': '2026-04-20' 이라고 문자열이 박혀 있었고, 그 값은 코드 위쪽의 _today같아야 하는 두 곳이었다.

// Derived, not typed twice. Two places that must agree eventually
// disagree.
'today': _fmt(_today),

검사가 잡은 건 주석이었지만, 그걸 보러 간 김에 진짜를 고쳤다. 검사가 오탐을 내는 것과 쓸모없는 것은 다르다.

주말에 밀렸으면 밀렸다고 말한다

이 도메인의 대표적인 함정이다. 모두가 아는 규칙인데 스프레드시트는 늘 잊는다.

/// Shift a statutory date off a weekend, and say that you did.
///
/// This is the rule everyone knows and every spreadsheet forgets. Returning
/// the shift as text rather than silently moving the date is the whole point:
/// "25th, moved to Monday" is checkable, "27th" is not.

실행 로그다.

2026-03-31 D-20  Dodam   Corporate tax        [day 31 of month 3]
2026-04-10 D-10  Hanbit  Withholding — March  [day 10 of month 4]
2026-04-10 D-10  Seum    Withholding — March  [day 10 of month 4]
2026-04-27 D7    Hanbit  VAT — Q1   [day 25 of month 4 · statutory 25th fell on Saturday]
2026-04-27 D7    Dodam   VAT — Q1   [day 25 of month 4 · statutory 25th fell on Saturday]
2026-04-30 D10   Seum    Local income tax     [day 30 of month 4]

04-25가 실제로 토요일이라 04-27로 밀렸고, 그 사유가 대괄호 안에 붙어 있다. 밀리지 않은 줄에도 규칙이 붙어 있다는 것도 봐 달라 — 밀린 것만 설명하고 나머지는 그냥 날짜로 두면, 규칙이 있는 줄과 없는 줄이 화면에서 구별되지 않는다.

검증이 둘 다 본다.

grep -q "statutory 25th fell on Saturday" captures/run.log || exit 1
grep -q "\[day 10 of month 4\]" captures/run.log || exit 1   # 안 밀린 줄에도 규칙이
마감 보드 · 2026-04-20 — 연체 3 · 임박 2. 줄마다 그 날짜를 만든 규칙이 붙고, 주말에 밀린 두 건은 그 사실까지 적혀 있다
마감 보드 · 2026-04-20 — 연체 3 · 임박 2. 줄마다 그 날짜를 만든 규칙이 붙고, 주말에 밀린 두 건은 그 사실까지 적혀 있다

거래처 하나로 좁혀도 규칙은 그대로 따라간다.

한 거래처만 — 규칙은 그대로, 줄만 줄었다
한 거래처만 — 규칙은 그대로, 줄만 줄었다

이 콘텐츠는 개발자 이상이 필요합니다

로그인 후 플랜을 업그레이드하면 계속 읽을 수 있습니다.

플랜 보기
Twitter