KENTEM TechBlog

建設業のDXを実現するKENTEMの技術ブログです。

「意味と操作」はコードの外にも広がる—オブザーバビリティとOTelの知識地図—

ようやく春めいてきたかと思えば、急に冬が逆襲してくる寒暖差。
袖不足人間のエンジニアTです。

業務でAzure Application Insightsを使っていて、.NET 10へのアップデートに伴い「OpenTelemetry SDKへの移行」が話題に上がるようになりました。

learn.microsoft.com

そこからOTelを調べ始めたのですが、調べていくうちにOTel単体の話ではなく、その考え方が普段のコード設計で大切にしている「意味と操作」という視点と深く繋がっていそうなことに興奮したため、勢いのまま書いた次第です。

opentelemetry.io

この記事では、OTelが概念上どこに位置するのかという「知識の地図」を示しつつ、オブザーバビリティを「意味と操作」という切り口で整理してみます。

注意点: 本稿の正しい読み方 本稿は学習のアウトプットとして作成した大変引用に向かない記事です。
曖昧な表現や本質的ではない部分にフォーカスして説明している部分があります。 また、シンプルに間違っている場合もあります。
これらをご了承の上でお楽しみください。

「意味と操作」とは何か

本記事を通じて軸になる考え方を、最初に紹介しておきます。

プログラミングにおいて、関数やメソッドには2つの側面があります。

  • 意味(シグネチャ): そのメソッドが「何をしたいのか」——名前、引数、戻り値が表現する目的
  • 操作(実装): そのメソッドが「どうやるのか」——内部のロジックや手続き

たとえば以下のようなシグネチャを見れば、中身を読まなくても「IDでユーザーを探す」という意味がわかります。

FindUserById(id: string): User

まず「何をしたいか」をシグネチャで定義し、その後に「どう実現するか」を実装する。この順序で考えることで、設計の意図が明確になります。

逆に、操作(手続き)から先に書いてしまうと、そのメソッドが本当は何を表現したかったのかが見えにくくなります。

この「意味を先に考え、操作は後から」という姿勢は、コーディングだけでなくタスク管理にも通じます。手順をいきなり書くのではなく、「このタスクで何ができればいいのか」という目的を先に定義する。そうすると、途中で目的を見失わず、より本質的なアプローチに辿り着けます。

この考え方について、以下の記事が非常にわかりやすく解説しています。

user-first.ikyu.co.jp

zenn.dev

ここから先は、この「意味と操作」の視点を、コードの外——アプリケーション全体の観測へと広げていきます。

知識の地図—OTelはどこにいるのか

OTelを理解するには、まず「OTelがどの問題領域に属しているのか」を知ることが近道です。いきなりOTelの仕様を読むのではなく、全体の地図を眺めてから位置を確認しましょう。

ざっくり整理すると、こうなります。

OTelの立ち位置

SREは「サイトの信頼性をどう保つか」という大きな目標を持っています。その中で「信頼性を確かめるためにシステムの状態を観測可能にしよう」というのがオブザーバビリティ・エンジニアリングの役割です。

そしてOTelは、観測に必要なデータ(テレメトリ)を「ベンダーに依存しない標準的な方法で集める」ための仕組みです。集めたデータを見るための画面やダッシュボードは、Azure Workbooks などのバックエンドが担当します。

learn.microsoft.com

つまり、OTelはオブザーバビリティという大きな枠組みの中の「データ収集」を担う1ピースです。OTelを導入するだけでオブザーバビリティが実現するわけではなく、「何を観測すべきか」という設計思想のほうがずっと重要です。

オブザーバビリティ・エンジニアリングとは何か

では、その「設計思想」部分、オブザーバビリティ・エンジニアリングとは何でしょうか。

一言で言えば、アプリケーションの中身の実装に依存せず、外部からその状態を知ることができる構造を作ることです。

従来の監視(モニタリング)は、「CPUが90%を超えたらアラート」「エラーログが出たら通知」のように、あらかじめ想定した異常を検知するものでした。これは既知の問題には有効ですが、想定していなかった問題には対応できません。

オブザーバビリティは、そこから一歩進みます。「何が起きるかわからないから、起きたことを後から理解できるようにしておこう」という発想です。そのために、システムが発するテレメトリデータを3種類に分類して収集します。

  • メトリクス: 数値で表される計測値(リクエスト数、応答時間、エラー率など)
  • ログ: イベント発生時の構造化されたテキストデータ
  • トレース: リクエストがシステム内をどのように通過したかの経路情報

ここで「意味と操作」の話に戻ります。

オブザーバビリティが見ているのは、アプリケーションの意味の部分です。「このアプリケーションはユーザーにどんな価値を届けようとしているのか」「それが正しく届いているのか」を、内部の操作(実装の詳細)に立ち入らずに確認する。

これは、メソッドのシグネチャを見て「何をしたいか」を理解するのと同じ構造です。中身のコードを1行ずつ追わなくても、シグネチャ(外から見える振る舞い)で十分に判断できる——オブザーバビリティが目指しているのは、アプリケーション全体に対してそれを実現することです。

実務で考える—ステータスコードは「意味」を明らかにするか

ここまでの話を踏まえて、実務的な視点で考えてみます。

バックエンドのWeb APIがあったとして、そのAPIが実現したいことは「ユーザーのリクエストに対して正確なレスポンスを返すこと」です。では、テレメトリとしてHTTPメソッド・エンドポイントのルート・ステータスコードの3つを取れば、それで十分でしょうか。

結論から言うと、これだけでは「意味」を表現できていません

ステータスコードは「操作の結果」であって「意味の実現」ではない

たとえば、商品検索APIを考えてみます。ユーザーが「Tシャツ」で検索したとき、APIがステータスコード200を返した。操作としては成功です。しかし、内部のロジックバグで検索結果が0件だったとしたら? あるいはレスポンスは返せたが、在庫情報のデータソースがタイムアウトして不完全なデータを返していたとしたら?

ステータスコード200は「サーバーが処理に成功したと判断した」ことを示しているだけで、「ユーザーに届けたい価値が実現できた」ことは保証していません。

「意味と操作」の視点で言えば、ステータスコードは操作が正常に完了したかどうかのシグナルです。意味が正しく実現されたかどうかは、また別の観点で確認する必要があります。

「意味」を観測するために必要な情報

では、このAPIが提供する「意味」(ユーザーに価値を届けること)を本当に検証するには、何が必要でしょうか。

  • 処理にどれぐらいかかっているのか(応答時間)——ユーザーがストレスなく使えているか
  • 処理がちゃんと完了しているのか——部分的な失敗や不完全なデータを返していないか
  • SLOに準じて提供できているか——「99.9%のリクエストを500ms以内に返す」といった目標を満たしているか

これらを判断するための情報を考えていくと、自然と「このAPIが提供したい意味とは何か」を理解し、表現できるようになるはずです。

具体的にイメージするために、先ほどの商品検索APIのスパン属性をJSON形式で見てみましょう。

操作だけを記録したスパン(自動計装のみ):

{
  "http.request.method": "GET",
  "http.route": "/api/products/search",
  "http.response.status_code": 200
}

実はこれらの属性は、OTelの自動計装(auto-instrumentation)を導入するだけで自動的に記録されます。タイムスタンプやスパンの処理時間(duration)もスパンのメタデータとして自動付与されるため、自分で書く必要はありません。OTelは「最低限これは絶対に必要だよね」という情報を、設定するだけで取得してくれる設計になっています。

しかし、自動計装だけでは「処理が成功した」ことしかわかりません。ユーザーに価値が届いたかどうかは不明です。

意味の実現を観測できるスパン(自動計装 + カスタム属性):

{
  "http.request.method": "GET",
  "http.route": "/api/products/search",
  "http.response.status_code": 200,
  "app.search.query": "Tシャツ",
  "app.search.result_count": 15,
  "app.search.inventory_source_healthy": true
}

上3つはOTelが自動で取得する属性、下3つが自分で追加するカスタム属性です。

スパンの処理時間は自動記録されているので、SLOを満たしているかはそこから判断できます。検索結果件数(app.search.result_count)で「ユーザーが求めた情報を返せているか」がわかり、データソースの健全性(app.search.inventory_source_healthy)で「不完全なデータを返していないか」が確認できます。

レスポンスの中身をまるごと残す必要はありません。OTelの自動計装+「意味を証明できるシグナル」があれば十分です。

「とりあえずログを出しておけば後からどうにかなる」という発想は、操作から考えているのと同じです。「このAPIは何を実現したいのか」という意味から考えれば、本当に必要な情報が見えてきます。

実装の不備に気づける

この「APIの意味を定義する」というプロセスには、テレメトリ設計以外にも面白い効果があります。

エンドポイントの意味を改めて言語化しようとすると、「このAPIが本来提供すべき意味を、シグネチャがちゃんと表現できていない」ケースに気づくことがあります。たとえば、名前と実際の振る舞いがずれている、戻り値の型が意味を正確に反映していない、といったことです。

さらに進むと、実装アーキテクチャ上の矛盾にも気づけるかもしれません。「このエンドポイントが担っている責務が広すぎて、一つの意味として定義できない」としたら、それはアーキテクチャの設計に問題がある可能性を示唆しています。

つまり、オブザーバビリティのために「意味」を考えること自体が、コードやアーキテクチャを見直すきっかけにもなり得るのです。

その先に見えるもの—DDDから経営まで

ここまでの話は、コード設計の「意味と操作」をアプリケーション全体の観測に広げたものでした。しかし、この視点をさらに広げると、思いがけない場所に繋がっていきます。

DDDでは、ドメインモデルを意味のある単位でモデリングし、それをコードに落とし込みます。オブザーバビリティは、そのモデリング要件がコード上で正確に実現されているかを外部から検証する手段と捉えることもできます。

そしてさらに「意味」を突き詰めていくと、最終的には「このアプリケーションはユーザーに何を届けたいのか」「会社としてどんな価値を提供したいのか」という経営の領域に到達します。

最初は非常にミクロな「メソッドのシグネチャ」から始まった話が、アプリケーションの価値定義を経て、経営方針にまで一気に視野が広がっていく。この思考の展開が、自分にとって最も面白い発見でした。

なお、「この機能の利用状況を詳しく知りたい」といったプロダクト分析的なニーズは、SRE的なオブザーバビリティとはまた別の概念かもしれません。この領域についてはまだ詳しくありませんが、少なくともオブザーバビリティの文脈では、「アプリケーションが正確に動いているか」を確認するという軸で整理できそうだと考えています。

まとめ

OTelを調べ始めたことをきっかけに、オブザーバビリティ・エンジニアリングという考え方にたどり着き、さらにそれが普段のコード設計で大切にしている「意味と操作」と深く繋がっていることに気づきました。

  • OTelは、オブザーバビリティという大きな枠組みの中の「データ収集」を担う1ピース
  • オブザーバビリティは、アプリケーションの「意味」を外部から観測可能にすること
  • 「意味と操作」はコード設計の原則であると同時に、観測やサービス運用の原則でもある かもしれない

この視点を持つことで、「何のためにログを出すのか」「何を観測すべきか」という問いに対する答え方が変わりました。まだ学びの途中ですが、同じように「OTelって何だろう」と思っている方の参考になれば嬉しいです。

おわりに

KENTEMでは、様々な拠点でエンジニアを大募集しています! 建設×ITにご興味頂いた方は、是非下記のリンクからご応募ください。 recruit.kentem.jp career.kentem.jp