通知ツールが実際に受け取ったのは NetworkManager のどの状態か
同じ整数が、ある列挙では「無効」、別の列挙では「設定の途中」を意味する。条件をコピーする前に、状態の型とオブジェクトを突き合わせよう。
四番目の状態は一方の API では通知を発火し、もう一方では別の意味になるのに、コードにはまったく違いが現れない。NetworkManager の状態値はすべて名前付きの列挙に属しており、列挙どうしは同じ数値の意味で一致していない。だから動作する断片から整数を別のコールバックへコピーすることは、振る舞いの移植ではなく、壊れるのを待つ偶然でしかない。まず型を見つければ、数値は読めるようになる。
型のない数は噂にすぎない
ここで重要な列挙は二つある。一つは一般的なアクティブ接続を表し、不明、アクティブ化中、アクティブ、非アクティブ化中、非アクティブという値を持つ。もう一つは VPN 接続専用で、途中の段階が多く、準備、接続の設定、IP 設定、そして何かがアクティブになる前の認証要求が含まれる。両者の番号はどちらもゼロから始まってから分岐するので、一般列挙で「非アクティブ」を意味する値は、VPN の並びのどこか中ほどに落ちる。どちらのヘッダーも間違っておらず、答えている問いが違うのだ。
リテラルの代わりに、インストール済みのヘッダーやバインディングのシンボリック定数を使う。名前は再番号付けに耐えるが、整数は耐えない。
マシンではなく一つの接続を見る
関心のあるプロファイルの UUID と、そのアクティブ化が作ったアクティブ接続オブジェクトから始める。デバイスの状態や別のトンネルの状態は、両者が同じ瞬間に変わるとしても代わりにならない。観測と一緒にオブジェクトの同一性を保ち、後から「どのプロファイルがそれを生んだか」と言えるようにする。マシンには多くの状態があるが、通知はそのうちの一つについてのものだ。
次に、その通知が何を意味すべきかを決める。アクティブ化に一度も到達しなかった接続は設定の失敗であり、アクティブだったセッションが消えたのは喪失だ。この二つは別の言葉に値する。
どの遷移を報告しているのかを言う
新しい値だけを単独で調べるのではなく、前の状態を保存して新しい状態と比べる。失敗状態への遷移と、アクティブ状態からの遷移は、どちらも何も接続されていない状態で終わっても別の出来事だ。理由の文字列も並べて記録するのは、ユーザーが行動できる唯一の部分であることが多いからだ。
意図的な切断は障害ではない。通知がその違いを見分けられなければ、人々に通知を無視するよう教え込むことになる。
監視役を生かしておく
変化していない状態に対して、繰り返しのポーリングが別の警告を出してはならない。この一つの規則が、こうした通知ツールが生む雑音の大半を取り除く。
マネージャーが再起動した場合や、観測対象のオブジェクトが差し替わった場合も扱う。古い同一性に結び付いた監視役は、何か興味深いことが起きるまさにその瞬間に沈黙し、沈黙は健全に見える。マネージャーの存在が変わった後に現在のオブジェクトを再発見し、再発見がいつ起きたかを記録する。そうしなければ、ログには報告をやめただけのトンネルが残る。
通知はユーザーのいる場所へ届ける
特権的なシステムコールバックは、デスクトップセッションの通知サービスを継承しない。root レベルのハンドラーから送られたメッセージはエラーもなく消えることがあり、手で試すと動き、実際には決して動かない通知ツールが生まれる。デスクトップを所有するセッションへ届けるか、デスクトップ自身のクライアントに通知を上げさせる。
クライアントの既存の通知がすでにそのケースを覆っているなら、一つの出来事に二つの通知ツールは冗長ではなくサポート上の問題だから、そちらを優先する。サポート記録には出来事の時刻、プロファイル、理由を残し、パスワードや完全なプロファイルは残さない。通知とは何かを忘れないこと、つまり観測された状態の報告であって強制の仕組みではなく、トンネルがない間に通信を遮断するのは独自の実装を持つ別のポリシーだ。