インターネットには非常に多くのWebベースのタスク管理サービスがあります。 おそらく、自分のニーズに合った何か特別なものを望んでいる2番目のプログラマーは、インターネットで適切なものを検索し、理想を見つけられずに自分のバージョンを書いています。 マスマーケットに適用されるタスク管理システムの「死亡率」も非常に高くなっています。 私には、多くの競争と大きなセグメンテーションという2つの要因があるように思えます。誰かがグループ作業に重点を置く必要があり、誰かがメモをとる必要があります。 その結果、誰もが喜ぶことを望んでいる人は、自分ができることすべてに気づき、結果のモンスターは勤勉であることがわかります。
この投稿は、遅かれ早かれ反復タスクの実装、起こりうる困難(少なくとも私たちが遭遇したもの)、およびオプションを取り上げる人々を示す目的で書かれました。 投稿の簡潔な(そして非常に明白で、しばしば忘れられがちな)結論:開発中に「額」の問題を解決することは必ずしも価値がありません。
今後、反復タスクの実装には多くの時間と労力がかかりましたが、最終的には完全に使用可能なオプションに到達し、同時に他の多くの困難な問題を解決することができました。
反復タスクをサポートするシステムを見たこれらのシステムには、重要ではないものの、重要ないくつかの欠点がありました。
- 将来のタスクを見ることが不可能だったか
- 構成と使用のメカニズムが面倒すぎる
MyLifeOrganizedは、タスクの繰り返しに関して最も先進的なシステムであることが判明しましたが、Webアプリケーションではありません。 C LeaderTaskも一緒に成長しませんでしたが、インターフェイスに対する多くのアプローチは悪くありません。
そのため、タスクはタスクを繰り返し行うことでした。 それは複雑に見えるでしょうか? データベース設計の観点から、オプションのいずれかを選択する問題がありました。
- 繰り返しタスクの各インスタンスは、個別のタスクであり、タスクテーブルの個別のエントリです。
- 繰り返しタスクのテンプレートは個別に保存され、さらにフィールドが変更されたタスクは個別に保存されます。 同様のストレージメカニズムがGoogleカレンダーに実装されています-たとえば、イベントのフィールドを変更すると質問が発生します-チェーン全体、後続のイベントのみ、または1つのみを変更します。
2番目のオプションは最も論理的で最適なものと考えましたが、タスク用のフィールド(ウェルまたはパラメーター)が少ない場合にのみ最適ですが、ロジックを正しく維持する必要がある場合は、データベーストリガーなどのコード量が非常に大きくなります。 彼らは書いて書いたが、やがて止まった。 最初のオプションは残った。
その欠点は次のとおりです。
- タスクテーブル内の大量のエントリ。 たとえば、タスクがあり、毎週繰り返す必要があるため、毎週日曜日に別のタスクがあります。 繰り返しの終了日までにユーザーにデフォルトの制限はありませんでした。 つまり 「タスクスケジュール」を作成するとき、そのコピーは1年先に作成されました。 しかし、これは曲線の変形でもあります。これまで誰かが計画する必要はありませんが、誰かが十分ではありません。 OK、ユーザーが事前にタスクを作成する期間を設定できる機能を追加しました。
- 必要な日付ごとにタスクの個別のインスタンスが作成されるという事実にあるアプローチ自体は、時には実用的ではありませんでした。 たとえば、ユーザーに異なる日付の同じトレーニングタスクの束を考慮に入れて保存するように強制するのはなぜですか?
さらに、ユーザーとプログラマーの両方に反復タスクの「チェーン」を提供する複雑さは適切ではありませんでした。 ここに、例えば、小さいが、時間がかかる質問があります:
- タスクを削除するとき、チェーンを再構築するとき(たとえば、ユーザーが繰り返し設定を変更した場合)、リモートタスクを再作成しないことが必要でした。 考えられるすべてのオプションを検討した結果、リモートタスクに関する情報を別のテーブルに保存することが最も適切であることがわかりました。 しかし、経験から、この情報用に別のテーブルを選択することは間違ったアプローチの兆候であり、これが実現することが示唆されています。 その結果、ユーザーがスケジュールの変更を保存するためのパラメーターを作成しました-リモートタスクを再作成するかどうか。
- タスクチェーンにはテンプレート、つまり 繰り返しがユーザーによって構成され、本質的には作成されたすべての新しいインスタンスにコピーされるタスク。 タスクの日付がオプションのパラメーターであることを考えると、日付のないタスクを繰り返すことができるのは論理的です。 テンプレートタスク(日付なし)とその繰り返し(既に日付があります)があります。 しかし、これを実際に使用するのはかなり不便です。 仕事中のこのすべては、テンプレート、タスクインスタンス-なんとなく面倒に見えます。 助けなしでは理解できません。
- タスクリストのツリーのような性質を考慮して、ユーザーを制限し、繰り返しタスクの異なるインスタンスを異なる親フォルダー/タスクに配布できるようにしたくありませんでした。 しかし、別の問題が発生しました-ユーザーがチェーン全体を見る方法、またはむしろ問題はそれだけではなく、タスクのこれらの将来のインスタンスがユーザーの期待する場所ではなく、私の意見に現れたという事実でした。
ユーザビリティの問題は別の問題になっています-日付を除いて、タスクの異なるインスタンスを識別する方法は? つまり タスクリストには、日付のみが異なる多数の同一タスクがありました。 これは、投稿のタイトル画像で明確に見ることができます。
ユーザーがタスクの各インスタンスの名前を編集できるようにする必要があることが明らかになりました。 以前は、禁止されていました。 あなたがそれを名付けたように-それから悪魔は繰り返しがどこにあるのかを理解するでしょう。 私たちは、問題の主な分野のほとんどにこのような機会(個別の変更)を追加しました。 しかし、それでも実際にユーザビリティは改善されませんでした。
タスクをより視覚的にする最適なソリューションは、自動置換のオプションになると判断しました。 つまり、タスク名で「%% this.date.month %%」などを示すと、この式は画面に表示されるときに月の名前に置き換えられます。 「%% this.date.quarter.prev %% qv %% this.date.month.prev.year %% gの税に対するATP LLCの報告」というタスクを呼び出すと、次の図が表示されます。
これはすでに完全な決定でした。 考えられる表現の選択肢をたくさん積み重ねて、これはほんの始まりに過ぎないことに気付きました。 自動置換は、画面上に表示されたときに、送信された通知でどこでも機能するはずです。したがって、この「ハック」の実装で1か月以上殺されました。 私たちはそれをほぼどこでも考慮に入れました。 それでも、タスクの繰り返し機能の設定数が多すぎました。 毎週「トレーニング」タスクを繰り返すには、非常に多くの操作が必要でした。
要するに、それはある種の巨大なメカニズムであることが判明しました。これは維持するのが難しく、助けがなければユーザーにはわかりにくいものでした。
そのため、このメカニズムを終了し、トリガーを介してタスクの繰り返しを実装することにしました。 もっと面白かった。 これには革命的なものは何もありませんでした。なぜなら、リレーショナルデータベースとデータベースのトリガーは長い間存在していたからです。
特定のユーザー操作ごとに特定のアクションがタスクで自動的に実行される場合でも、このような実装を行うことにしました。 つまり、それぞれで:
- タスク作成
- タスクを完了する
- タスクを削除する
カスタマイズできます
- タスクの作成(この機能は一時的に無効にされました)
- タスクを完了としてマークする
- タスクを未処理としてマークする
- タスクを削除
繰り返しを正確に実装するには、アクションの実行にカスタマイズ可能な遅延を作成する必要がありました。たとえば、10日後にタスクを完了した後、再び実行されないようにします。
今では、前回の実行の瞬間から数えて、特定の期間を通してタスクの繰り返しを実現することが判明しました。 トリガーを使用したオプションの方がはるかに柔軟であることが明らかになったため、次の「機能」が追加されました。
- 特定のスケジュールでトリガーします。 つまり 定期的にトリガーされます。 直接の目的は、特定の周期でタスクを「復元」することです。 たとえば、毎週土曜日にタスク「ピクニックの購入」を未完了にする
- タスクの日付または期日(タスクの完了日)に起動するトリガー。 その主な目的は通知のために見つかりました(その時点までに通知の実装を取り上げていなかったため、非常に便利でした)、カスタム遅延と相まって、これにより、たとえば、電子メールが出てきたときなど、各タスクが複数の通知を持つことができました周期性の程度
- 各トリガーに対して、「タスクの日付を移動する」アクションが可能になりました。 これにより、日付が重要なタスクは、繰り返しのたびにシフトすることができました。 「タスク期間」フィールドでも同じことを行いました。
その結果、かなり柔軟でカスタマイズ可能なシステムになりましたが、再び同じ問題に戻りました-ユーザーはそれをあまりにも長く設定しなければなりません。 簡単な毎週の繰り返しをインストールするために、あまりにも多くの操作を行う必要がありました。
この問題を解決するために、トリガーをすぐにインストールする機能を追加しました:
- すべてのユーザータスク
- 特定のリストのすべてのタスク
- 特定のラベルを持つすべてのタスク
そして、特定のラベルを持つタスクにトリガーをインストールする可能性がまさに私たちにとって人生を楽にしてくれました。 現在、特定のタスクの繰り返しは次のように削減されました。
- 特定のラベルにトリガーを設定します。 つまり 「毎週土曜日」というラベルが作成され、トリガーが設定されました。これにより、土曜日に完了しなかったすべてのタスクにこのラベルが付けられました。 これは一度も登らない設定で一度以上行うことができます。
- 目的のタスクにこのラベルを設定します。
それだけです 自分自身のために、そしてすべての必要な繰り返しの原則(「20日に毎月」、「3月8日に毎年」、「月曜日」)を設定したら、これらのラベルで必要なタスクをマークするだけで、すべての繰り返しルールが適用されます。
もちろん、いくつかの未解決の問題が残っており、何かが完全に実装されていませんでした(たとえば、繰り返し期間の柔軟な調整)が、ほとんどの実際のタスクではこれですでに十分でしたが、同時に、タスクの表示そのものがはるかに視覚的になりました。 はい。初期設定では、少し理解する必要があります。ラベルのトリガーの編集は、[設定]メニュー-[グローバルトリガー]、またはこのラベルを持つタスクの[トリガー]コンテキストメニュー項目から利用できます。 将来的には、定期的なタスク用に事前に構成されたラベルを使用して、新しいユーザーの生活を楽にします。
トリガーの実装と定期的な再発の設定に関する実用的な情報が必要な1-2人のユーザー(およびその必要性は、タスク管理だけでなく、たとえばスケジューリングでも可能)について、技術的な側面を概略的に説明します。
簡単に実装について
驚くべきことに、システムでのトリガーの実装は、PostgreSQLデータベーストリガーに基づいています。 PostgreSQLのトリガーとプロシージャのソースを投稿することはおそらく意味がありません(さらにそれらが多すぎます)。 主な価値は、少なくとも私にとって、このビジネスを書くためにゼロから座っているデータベース構造です。これは最も重要であり、多くの時間を節約します。
テーブルtriggers_types 。 トリガーの種類に関する情報(「タスクが完了したとき」、「タスクの期限が切れたとき」、「タスクの期限が切れたとき」、...)を保存するだけです。
テーブルアクション 。 トリガーがトリガーされたときに可能なアクションのタイプに関する情報を保存します(「タスクの削除」、「完了としてマーク」、「タスクの完了日を移動」、...)。
テーブルトリガー 。 設定されたトリガーの説明が含まれています。
-trigger_id uuid-識別子
-trigger_obj uuid-オブジェクトへのリンク(タスク、リスト、ユーザーなど)
-trigger_action varchar-アクションのタイプ
-trigger_param1、trigger_param2-追加パラメーターのフィールド(通知時の件名とメッセージテキストなど)
-trigger_type varchar-トリガータイプ、つまり うまくいく
-trigger_dparam1、trigger_dparam2-追加パラメーターの整数フィールド
-trigger_name-カスタム名
-trigger_chk integer-パラメーターのチェックサム
-trigger_descr-ユーザーの説明
-trigger_offset_count整数、trigger_offset_item-実行遅延パラメーター
-trigger_user uuid-ユーザーID
-trigger_recreatedタイムスタンプ(3)-最後のチェックの日付
-trigger_sch_date1、trigger_sch_date2-繰り返しの開始日と終了日(「スケジュール済み」トリガーの場合)
-trigger_sch_period、trigger_sch_interval、trigger_sch_count-繰り返し頻度の設定(「スケジュールされた」トリガーの場合)
単純なトリガー(実行遅延なし)を実装するには、トリガーテーブルだけで十分です。 つまり、特定のイベント(タスクの作成、時間の開始、タスクの完了)をインターセプトし、このテーブル内の適切なトリガーを検索してアクションを実行するだけです。
遅延トリガーを使用するには、つまり 遅延を伴うアクションの実行には、時間、オブジェクトへのリンク(タスク、リスト、...)、および実行する必要のあるアクションを含む個別のテーブルactions_queueが必要です。 5分ごとに、cronは実行されたアクションを処理します。
しかし、「タスクの期日」および「タスクの期日」というトリガーでは、特に設定された遅延の場合、タスクはより複雑になります。 それを解決するには、別のテーブル( triggers_tableがあります )も必要です。このテーブルには、そのようなすべての日付に関するレコードが格納されます。 タスクごとに、タスク日付の個別のエントリとタスク期間の個別のエントリがあります。 これが必要だったのは トリガーは一度に多くのタスクにインストールできるため、トリガーが機能するタスクを計算してシステムを定期的にロードしないように(および遅延トリガー、つまり追加の時間シフトを考慮し、さらにユーザーがいつでも変更できるタイムゾーンを考慮に入れる)これはリソースを大量に消費するタスクです)、この情報を別のタスクに入れる方が簡単です。 トリガー自体の設定、タスクの日付、タイムゾーンなどのパラメーターを変更する場合は、自動更新に設定することを忘れないでください。
タイムゾーンについて。 各ユーザーには独自のタイムゾーンがあり(画面に表示されるときにすべてのタスクがカウントされます)、タスクの各リストに独自のタイムゾーンを設定することもできます。 メインタスクテーブル(この場合はイベント)では、タイムゾーンを指定せずに時間を保存することをお勧めします。これにより、タスクツリーの出力が大幅に節約されます。 ただし、他のすべてのテーブル、特にトリガーに関連するテーブルでは、UTCで時間を保存することをお勧めします。
テーブルtriggers_types 。 トリガーの種類に関する情報(「タスクが完了したとき」、「タスクの期限が切れたとき」、「タスクの期限が切れたとき」、...)を保存するだけです。
テーブルアクション 。 トリガーがトリガーされたときに可能なアクションのタイプに関する情報を保存します(「タスクの削除」、「完了としてマーク」、「タスクの完了日を移動」、...)。
テーブルトリガー 。 設定されたトリガーの説明が含まれています。
-trigger_id uuid-識別子
-trigger_obj uuid-オブジェクトへのリンク(タスク、リスト、ユーザーなど)
-trigger_action varchar-アクションのタイプ
-trigger_param1、trigger_param2-追加パラメーターのフィールド(通知時の件名とメッセージテキストなど)
-trigger_type varchar-トリガータイプ、つまり うまくいく
-trigger_dparam1、trigger_dparam2-追加パラメーターの整数フィールド
-trigger_name-カスタム名
-trigger_chk integer-パラメーターのチェックサム
-trigger_descr-ユーザーの説明
-trigger_offset_count整数、trigger_offset_item-実行遅延パラメーター
-trigger_user uuid-ユーザーID
-trigger_recreatedタイムスタンプ(3)-最後のチェックの日付
-trigger_sch_date1、trigger_sch_date2-繰り返しの開始日と終了日(「スケジュール済み」トリガーの場合)
-trigger_sch_period、trigger_sch_interval、trigger_sch_count-繰り返し頻度の設定(「スケジュールされた」トリガーの場合)
単純なトリガー(実行遅延なし)を実装するには、トリガーテーブルだけで十分です。 つまり、特定のイベント(タスクの作成、時間の開始、タスクの完了)をインターセプトし、このテーブル内の適切なトリガーを検索してアクションを実行するだけです。
遅延トリガーを使用するには、つまり 遅延を伴うアクションの実行には、時間、オブジェクトへのリンク(タスク、リスト、...)、および実行する必要のあるアクションを含む個別のテーブルactions_queueが必要です。 5分ごとに、cronは実行されたアクションを処理します。
しかし、「タスクの期日」および「タスクの期日」というトリガーでは、特に設定された遅延の場合、タスクはより複雑になります。 それを解決するには、別のテーブル( triggers_tableがあります )も必要です。このテーブルには、そのようなすべての日付に関するレコードが格納されます。 タスクごとに、タスク日付の個別のエントリとタスク期間の個別のエントリがあります。 これが必要だったのは トリガーは一度に多くのタスクにインストールできるため、トリガーが機能するタスクを計算してシステムを定期的にロードしないように(および遅延トリガー、つまり追加の時間シフトを考慮し、さらにユーザーがいつでも変更できるタイムゾーンを考慮に入れる)これはリソースを大量に消費するタスクです)、この情報を別のタスクに入れる方が簡単です。 トリガー自体の設定、タスクの日付、タイムゾーンなどのパラメーターを変更する場合は、自動更新に設定することを忘れないでください。
タイムゾーンについて。 各ユーザーには独自のタイムゾーンがあり(画面に表示されるときにすべてのタスクがカウントされます)、タスクの各リストに独自のタイムゾーンを設定することもできます。 メインタスクテーブル(この場合はイベント)では、タイムゾーンを指定せずに時間を保存することをお勧めします。これにより、タスクツリーの出力が大幅に節約されます。 ただし、他のすべてのテーブル、特にトリガーに関連するテーブルでは、UTCで時間を保存することをお勧めします。