とあるAPIのスキーマの叩き台をクライアントサイドとして検討している際に、コンテンツの公開期間やイベントの開催期間のような期間について議論が少し盛り上がった。
要件としては、期間の開始と終了の日時をそれぞれ取得できたい。
期間を考える時、開始と終了がそれぞれinclusiveなのかexclusiveなのかをまず考慮すべきであるが、開始日時の重複や終了日時に隙間を発生させないためには、開始はinclusive、終了はexclusive、つまり半開区間(左閉右開)にするのが望ましいだろう。
終了をexclusiveにすると、例えば8月の1ヶ月間、つまり8月1日0時0分〜9月1日0時0分という期間の場合、ユーザー向けの表示としては終了日時は「8月31日23時59分まで」と表示したくはなるが、これはプレゼンテーションロジックとしてクライアントサイドの責務としてやる。基本的には-1秒してからフォーマットすればよい。
次にその名前を簡単に考えてみるとsince
/ until
のような名前が思い付く。ここであるメンバーから「untilにはinclusiveな意味合いを感じてしまうがどうだろうか」という意見が出た。
untilはinclusiveかexclusiveなのかを少し調べてみると、どちらの意味にも取り得て、文脈依存であるようだ。
- Is "Until" Inclusive or Exclusive? - One Minute English
- ambiguity - Is "until" inclusive or exclusive? - English Language Learners Stack Exchange
ここではuntil
はexclusiveとして扱いますよ、ということでもいいのだが、『リーダブルコード』にもそういう話がありましたね、ということをまた別のメンバーが提示してくれた。該当箇所は「3.5 包含/排他的範囲にはbeginとendを使う」で、
ここに使う仮引数の名前は何がいいだろうか? プログラミングの命名規約では、包含/排他的範囲に begin と end を使うことが多い。
でも、end は少しあいまいだ。例えば、「本の終盤(the end of the book)を読んでいる」の「end」は包含的だ。残念ながら英語には「ちょうど最後の値を超えたところ」を意味する簡潔な言葉がない。
begin と end の対はイディオムになっている(少なくとも C++ の標準ライブラリではこれが使われている。また、配列がこのように「スライス」されることも多い)ので、これが最善の選択と言える。
begin
/ end
というイディオムが示されていた。我々の扱うAPIでは開始日時としてstartAt
という命名例もあったので、これを考慮すると startAt
/ endAt
ということになるだろうか(DBの日時系のカラムで created_at
や updated_at
とするように、日時系のデータに At
サフィックスを付けている)。
また別の例として、半開区間の話にも絡むが、java.time
の Period
や Duration
のAPIはこのようになっていた。
between(LocalDate startDateInclusive, LocalDate endDateExclusive)
between(Temporal startInclusive, Temporal endExclusive)
APIの仕様として左閉右開の半開区間であることを明にして、引数名にもInclusiveとExclusiveを入れていて冗長だが分かりやすい。今回のケースではそこまで冗長にはせず startAt
/ endAt
に落ち着きそうになったのであった。
学びある議論で楽しかった。