時間的パターン
過去の情報状態に関する質問に答えるために使用できる様々なパターンをまとめたものです。「1999年7月1日のマーチンの住所は?」「1999年8月12日に請求書を送った時に、1999年7月1日のマーチンの住所は何だと考えていたか?」といった質問が含まれます。
2005年2月16日
これは、私が2000年代半ばに行っていた「エンタープライズアプリケーションアーキテクチャのさらなる開発」の執筆の一部です。残念ながら、他の多くのことが私の注意を奪ってしまい、それ以降、さらに取り組む時間がありません。また、近い将来も時間を見つけることが難しい状況です。そのため、この資料はまだ草稿の段階であり、再び取り組む時間が見つかるまで、修正や更新を行う予定はありません。
物事は変化します。世界に関する情報を保存している場合、これは問題ではないかもしれません。結局のところ、何かが変化した場合、コンピュータ化された記録システムの大きな価値の1つは、修正液や情報を再入力することなく、記録を簡単に更新できることです。
しかし、変更の履歴を記録する必要がある場合、物事は興味深くなります。世界の状況を知りたいだけでなく、6ヶ月前の世界の状況も知りたいのです。さらに悪いことに、2ヶ月前に私たちが6ヶ月前の世界の状況は何だと考えていたかを知りたい場合もあります。これらの質問は、時間的パターンの魅力的な領域へと私たちを導きます。これはすべて、ドメインモデルを完全に混乱させることなく、これらの質問への答えを簡単に見つけられるようにオブジェクトを整理することに関するものです。オブジェクトモデリングのすべての課題の中で、これは最も一般的であり、最も複雑なものの1つです。
この問題を解決する最も簡単な方法は、監査ログを使用することです。ここでは、変更の記録を保持することが重要ですが、それを使って過去にさかのぼることはあまり期待していません。したがって、作成が簡単で、作業への干渉が最小限であることが望ましいでしょう。誰かがそれを見る必要がある場合、情報を掘り出すために多くの作業を行う必要があると予想されます。それほど頻繁に行う必要がなく、結果として得られる情報がすぐに必要なわけではない場合は、これで問題ありません。実際、データベースを使用している場合は、無料です。
情報へのアクセスがより容易になる必要がある場合は、もう少し作業が必要です。この状況で人々が使用する最も一般的なパターンは、有効性です。これは単にオブジェクトに、それが有効とみなされる期間を示すマークを付けるだけです(図1)。そして、オブジェクトを操作するときは、この期間を使用して、適切なオブジェクトを適切なタイミングで取得します。

図1:有効性を示すために明示的な日付範囲を使用する。
有効性の問題は、それが明白で明示的であることです。すべてのコンテキストでオブジェクトを使用するすべての人が、時間的側面を認識する必要があります。これにより、モデルがかなり複雑になる可能性があります。したがって、時間的な問題が蔓延している場合は、必要のないときにそれらを隠し、必要なときに操作しやすくすることが理にかなっている場合がよくあります。
アクセスしやすい時間的情報が必要なオブジェクトのプロパティがわずかしかない場合は、それらのオブジェクトで時間的プロパティを使用できます。時間的プロパティの重要な点は、明らかな有効性の日付を削除し、代わりに、日付を引数として取るアクセサを持つ通常のプロパティのように見えるものを使用することです。これにより、「2000年4月1日のこのプロパティの値は何ですか」と尋ねることができます。

図2:アドレスに時間的プロパティを使用する。
時間的プロパティの本質は、有効性を持つオブジェクトの束をナビゲートする必要がないように、日付によってパラメータ化されたアクセサを持つという概念です。したがって、時間的プロパティと有効性は、相互に排他的なパターンではありません。時間的プロパティインターフェースを実装するために、アドレス使用オブジェクト(有効性を使用)を使用する場合があります。アドレス使用オブジェクトに他の責任がある場合は、他の責任を必要とするクライアント向けにアドレス使用をアクセスするメソッドと、より便利だと感じる人向けに時間的プロパティインターフェースを提供できます。
時間的プロパティは、時間ベースのインデックスで何かを参照するという概念を導入しますが、単一のプロパティとしてしか使用しません。オブジェクトに多数の時間的プロパティがある場合、扱いにくくなる可能性があります。これに対処する方法は2つあります。1つ目は、スナップショットを使用することです。これは、ある時点での実際のオブジェクトの状態を参照するオブジェクトを提供します。したがって、2000年4月1日時点の顧客について多くの質問をしたい場合は、2000年4月1日のその顧客のスナップショットを要求し、日付を繰り返し入力することなくプロパティの値を要求します。

図3:スナップショットは、特定の日付時点のオブジェクトのビューを示す。
スナップショットを使用すると、ある日付時点のオブジェクトのビューを表示できますが、変更が時間を通じて行われるにつれて、オブジェクトが明示的なバージョンを通過することを本当に考えたい場合があります。この要望は、時間的オブジェクトにつながります。時間的オブジェクトには多くの形式がありますが、最も簡単な形式は、図4のように2つのクラスを持つ形式です。コントラクトクラスは、時間の経過とともにコントラクトを表すため、他のオブジェクトによって通常参照されるクラスです。これには、各変更時の契約の状態を記録するバージョンのコレクションが含まれています。これにより、人々は契約の不変の概念、または特定の時点での特定のバージョンを参照できます。

図4:時間的オブジェクトには、バージョンの明示的な履歴があり、各変更によって新しいバージョンが生成される。
実際には、有効性が広く使用されているのを目にしますが、それは人々が時間的プロパティや他のより洗練されたパターンにあまり精通していないことが原因であることがよくあります。時間的プロパティや時間的オブジェクトのようなパターンは、時間的動作のメカニズムの多くを隠すためによく機能します。ただし、有効性は依然として重要です。特定の期間のみ有効な明示的なオブジェクトが必要な場合は、これが適切な選択肢です。
時間の次元
上記で説明したように、時間はモデリングにおいて非常に困難な概念です。しかし、時間的モデルの最も厄介な側面については省略してきました。私たちは皆、ひどいSF小説からだけでも、時間が4次元であることを学びました。問題は、これが間違っているということです。
この問題を説明する最良の方法は、例を挙げることだと思います。従業員が1月1日から1日あたり100ドルのレートを持っていることを知っている給与計算システムがあると想像してください。2月25日に、このレートで給与計算を実行します。3月15日に、2月15日付けで従業員のレートが1日あたり211ドルに変更されたことを知ります。2月25日のレートは何だったかと尋ねられた場合、何と答えるべきでしょうか?
ある意味では、それがレートだったと今では知っているので、211ドルと答えるべきです。しかし多くの場合、2月25日にレートが100ドルだったと考えていたことを無視することはできません。結局のところ、その時に給与計算を実行しました。私たちは小切手を印刷し、彼に送り、彼はそれを現金化しました。これらはすべて、彼のレートがいくらであったかに基づいて発生しました。税務当局が2月25日の彼のレートを尋ねた場合、これは重要になります。
実際には、私たちにとって重要なディンスデールの給与レートの2つの履歴が実際にあると考えることができます。私たちが今知っている履歴と、2月25日に知っていた履歴です。実際、一般的に、過去の毎日に対するディンスデールの給与レートの履歴だけでなく、ディンスデールの給与レートの履歴の履歴があると言えます。時間は4次元ではなく、4次元と5次元なのです!
私は最初の次元を実際の時間、つまり何かが起こった時間と見なしています。2番目の次元は記録時間、つまり私たちがそれを知った時間です。何かが起こると、常にこれら2つの時間が付随します。ディンスデールの昇給の実際の日は2月15日で、記録日は3月15日でした。同様に、ディンスデールの給与レートは何だったかと尋ねるときは、実際に2つの日付(記録日と実際の日付)を指定する必要があります。
記録日 | 実際の日付 | ディンスデールのレート |
---|---|---|
1月1日 | 1月1日 | 1日あたり100ドル |
2月25日 | 2月25日 | 1日あたり100ドル |
3月14日 | 2月25日 | 1日あたり100ドル |
3月15日 | 1月1日 | 1日あたり100ドル |
3月15日 | 2月25日 | 1日あたり211ドル |
私たちは、2つの次元をこのように考えることができます。実際の履歴は、実際の時間を遡るものです。現在の実際の履歴を見ると、ディンスデールの給料は2月15日まで100ドルで、その時点で211ドルに上がったことがわかります。ただし、これは記録時間における今日の実際の履歴です。2月25日の実際の履歴を見ると、ディンスデールは1月1日から100ドルで支払われ、211ドルはまったく関係していませんでした。記録時間の毎日(厳密には時間点)には、実際の履歴があります。私たちが真実だと思っていたことがもはや真実ではないことを知るにつれて、これらの履歴は異なります。
別の角度から見ると、実際の履歴の毎日には、記録履歴があると言うことができます。記録履歴は、その日についての知識が時間の経過とともにどのように変化したかを教えてくれます。したがって、実際の時間の2月25日には、3月15日までディンスデールの給料は100ドルで、その時点で211ドルに達したという記録履歴があります。
さらに例を掘り下げてみましょう。3月26日の給与計算で対応する調整を行ったと仮定します。4月4日になって、従業員の以前の情報が間違っており、2月15日に実際にはレートが255ドルに変更されていたと伝えられます。ここで、「2月25日の従業員のレートは何だったか?」という質問にどう答えるでしょうか?
私は、経験豊富な開発者がこの種の事態に直面したときに、頭を抱えてしまうのを見てきました。しかし、すべてが2つの次元の概念に帰着すると気づけば、物事ははるかに単純になります。これを視覚化する1つの方法は、以前のテーブルを拡張することです。
記録日 | 実際の日付 | 従業員のレート |
---|---|---|
1月1日 | 1月1日 | 1日あたり100ドル |
2月25日 | 2月25日 | 1日あたり100ドル |
3月14日 | 2月25日 | 1日あたり100ドル |
3月15日 | 1月1日 | 1日あたり100ドル |
3月15日 | 2月25日 | 1日あたり211ドル |
3月26日 | 2月25日 | 1日あたり211ドル |
4月4日 | 1月1日 | 1日あたり100ドル |
4月4日 | 2月25日 | 255ドル/日 |
現在の実際の履歴(つまり、レコード日が今日である実際の履歴)を見ると、Dinsdaleの給与は1月1日から100ドルで、2月15日に255ドルに上がったと言うでしょう。現在の実際の履歴では、211ドルのレートは一度も発生しません。それは決して真実ではなかったからです。3月26日の実際の履歴を見ると、Dinsdaleの給与は2月15日まで100ドルで、そこから211ドルに上がったことがわかります。3月26日の実際の履歴では、255ドルのレートはまだ知らなかったため、発生しませんでした。
2月25日の記録履歴についても考えてみましょう。この記録履歴では、レートは3月15日に211ドルに変更されるまで(その日は)100ドルだったと示しています。その後、4月4日に再び255ドルに変更されました。
2つの次元について理解すると、問題を考えるのがはるかに簡単になりますが、この種のものを実装する必要があると思うと恐ろしくなります。幸いなことに、実装に関しては問題を簡略化できるいくつかの方法があります。
最初の簡略化は、監査ログを使用してこれらの変更に対処するのが難しくないということです。必要なのは、各エントリでログにレコード日と実際の日付の両方を記録することだけです。この単純な作業だけで、両方の次元でログを有効に保つのに十分であり、片方の次元しか気にしない場合でも、実行する価値があると私は信じています。
2番目の簡略化は、多くの場合、モデルに両方の次元を処理させたくないということです。ここで重要なのは、モデルにどちらがあり、監査ログにどちらを残しているかを知ることです。
時間の経過とともに物事がどのように変化したかを知りたいものの、変更を知った時期を気にしない履歴を保持したい場合、それは実時間的であると言うでしょう。したがって、従業員の住所の記録を保持する場合、それを実時間的なプロパティとして保持することを選択するかもしれません。オンラインクエリを支援するための情報システムの場合、データベースにアクセスするときは通常、実際の履歴について知りたいので、これはうまく機能します。
記録時間的な事実は、オブジェクトの状態に基づいて請求書を作成するようなシステムがある場合に現れます。これらのことは、請求書がどのように計算されたかについての質問につながり、請求書が計算されたときにオブジェクトの状態が何だったかを知る必要が出てきます。記録時間的な事実は、多くの場合、ソフトウェアのバージョン管理システムと比較でき、「4月1日のこのファイルはどのようなものだったか?」を遡って確認できます。
もちろん、両方の次元を一度に必要とするときもあります。これらは二時間的事実と呼ばれます。基本的に、二時間的な情報には常に両方の日付が必要です。
二時間性は完全な解決策ですが、それを回避する方法を常に考える価値があります。例として、請求書の計算があります。請求書がなぜそのようになったのかを知りたい場合、1つの可能性は完全に二時間的なデータベースを持つことです。ただし、請求書を計算するときに計算の詳細なトレースを保存する方が多くの場合優れています。それは、二時間的なオブジェクトモデルよりもはるかに単純な方法で要件を満たします。
時間的レコードの更新
これまで、情報の更新ではなく、情報へのアクセスという観点から時間的な情報についてのみ説明してきました。更新をどのように許可するかによって、さらに多くの決定が導かれますが、その多くには役立つ簡略化が含まれます。
一般的に、時間記録を変更するのは非常に面倒です。従業員のレートが2月15日から4月15日まで211ドルだった場合、完全に一般的な更新では、開始日、終了日、および値の任意の組み合わせを変更できます。クライアントが時間的な情報がどのように機能するかについて多くを知る必要があるため、このインターフェースを提供するのは面倒です。
最初の簡略化は、加算的な変更のみがある場合です。加算的な変更は常に記録の最後に追加されます。加算的な変更の例は、「2月15日から従業員のレートを211ドルにする」です。最初は、データの一部をミックスから削除しているだけのように見えますが、結果として更新が大幅に簡略化されます。実際に行われる更新のほとんどは加算的であるため、クライアントを大幅に簡略化できます。さらに、加算的な更新の組み合わせで変更を加えることができます。これにより、複雑な履歴を持つオブジェクトではひどく混乱する可能性がありますが、このプロパティを使用すると、加算的なインターフェイスのみをサポートすることで、単純な履歴を持つオブジェクトを簡略化できます。
2番目の簡略化は、現在の更新のみを許可することです。現在の更新では、今日有効な日付でのみ記録を変更できます。一般に、加算的な変更でさえ、過去または未来の任意の日付で発生する可能性があります。現在の変更では、日付情報がまったく必要ないため、完全に非時間的な更新のインターフェースを持つことができます。
現在の更新は信じられないほど優れているように見えます。現在の更新でのみ更新する場合、なぜ時間的な情報が必要なのでしょうか?ここでの朗報は、記録時間的な情報は現在の更新でのみ更新できるということです。記録時間的な情報への遡及的な変更は記録の整合性を損なうだけでなく、実際時間的な次元で処理できない遡及的な変更が必要な状況はありません(詐欺が要件の1つでない限り)。これは、1つの次元全体に非表示の更新があることを意味するため、大きな一歩です。更新時ではなく、クエリ時に記録時間を気にするだけで済みます。
その他の資料
これは複雑な分野であるため、人々がこれらの問題を検討するにつれて、他の著作も生まれています。この分野の最も包括的な扱いは、Snodgrassです。彼の作品はリレーショナルデータベースに基づいており、本のほとんどはSQLでこれらの問題を処理する方法に基づいています。ただし、問題は同じです。さらに、彼が行うコメントや使用する用語の多くは、時間的データベースに関する今後のSQL標準の資料と同じです。この本は現在絶版ですが、Richard Snodgrassの出版ページからPDFを入手できます。
用語の問題は、私がまだ完全には満足していない問題の1つです。彼は私と同じ2つの次元を使用していますが、彼の用語は異なります。私が実時間と呼んでいるものを彼は有効時間と呼び、私が記録時間と呼んでいるものを彼はトランザクション時間と呼んでいます。これらのパターンの初期バージョンでは、私は彼の用語に従っていましたが、多くの人がこれらの用語は非常に理解しにくいと言っていました。その結果、私は別の用語を使用することにしました。もう1つの違いは、時間の経過とともに変化するテーブルを彼がシーケンス化と呼んでいることです。もちろん、オブジェクトは時間的な目的だけでなく、常にシーケンスを使用するため、私は時間の経過とともに変化するものを時間的と呼んでいます。
[Anderson]は、時間的なパターンの最高のコレクションの1つです。繰り返しますが、私はアイデアを略奪しましたが、一部の用語を変更しました。私はエディションではなく、バージョンという用語を使用して、ある期間中のプロパティまたはオブジェクトの値を示しました。彼の変更ログおよび関連付け履歴パターンは、時間的プロパティと同じです。私は、2つのアンダーソンパターンの違いを実装の問題と見なしています。彼の自己履歴パターンは、時間的オブジェクトと同じです。
また、同じPLoPD 4の本には、アンディ・カールソンが私とシャロン・エステップと共同で書いた論文[Carlson et al]があります。これは、時間的プロパティとスナップショットの以前の説明を示しています。また、現在有効性の使用と見なしている時間的関連付けパターンについても言及しています。
PLoPにも提出されましたが、現時点では公開されていないのは、[Arnoldi et al]です。これは、私がここのパターンで(少なくともまだ)十分に調査していない、いくつかの興味深いアイデアを紹介しています。
[Anderson]と[Arnoldi et al]の両方が、時間的記録へのインデックスとして機能するために、タイムポイント以外のオブジェクトを使用することを検討しています。[Anderson]は(単一時間的な)イベントを使用し、[Arnoldi et al]はパースペクティブを使用します。これは基本的に2つのタイムポイントを1つのオブジェクトに結合したものです。これらのアプローチの両方に言えることはありますが、タイムポイントを使用することで必要なもののほとんどが実現でき、説明が簡単だと感じているため、ここでは使用していません。
大幅な改訂
2005年2月16日:これらのパターンをEAA開発セクションに移動しました。
2001年1月15日:二次元用語を有効/トランザクションから実際/記録に変更しました。
2000年8月28日:最初の草案