kmuto’s blog

はてな社でMackerel CREをやっています。料理と旅行といろんなIT技術

『Software Design』2023年6月号を読んだ

続けて6月号を読む。

gihyo.jp

  • 特集1は「正しく理解したいクリーンアーキテクチャ」。
    • よく見る円はフレームワーク設計図じゃなくてコンセプトを伝えるための方便だよ、と。ソフトウェアの構造には意識の異なる複数の領域がある、領域のレイヤー関係は常に詳細から主題へと一定の方向に依存する。
    • 変化しない本質を見極めてプログラミング可能なモデルに固めるコンセプトレベルの設計。部分部分のコード記述のデザイン性を持ったコードレベルの設計。後者は変更しやすく、リファクタリングを適用でき、技術的負債として戦略的に借り入れ可能。コンセプトとコードを支える構造が課せられるアーキテクチャ設計。無駄な負担を戦略的に減らすアーキテクチャ設計が、アジャイル成功の必要条件。
    • DDD。ドメインモデルを際立たせ、それがプロジェクトを牽引すべきとする考え方。コンセプトレベルの設計とコードレベルの設計に先に注目する。DDDはプロジェクトのポリシーで、クリーンアーキテクチャは結果として構築された形を静的に評価した様子。
    • 凝集性。関係の強い要素がまとまっていて関係の弱い要素は離れている。オブジェクトにメソッドを集めすぎる、無関係なものがモジュールに混在、あるいは強い関係なものが別のモジュールに、などのアンチパターン
    • 結合性。密結合と疎結合を適切に決めていく。
    • 依存性。依存の向きがある。依存性による変更影響ダメージをいかに減らすか。疎結合、実装詳細依存の回避。
    • 中心となるエンティティ。モデリング対象にのみ関心を払い、核となる普遍的な要素を列挙定義。
    • ユースケース。ユーザーが利用可能なアプリケーション機能を列挙する。項目はエンティティとの間で調整しながら洗練させる。コードは実装・技術詳細ではなくすべて意図的に抽象化し、純粋なロジックだけ。
    • インターフェイスアダプタ。ビジネス都合モデル-コンピュータ都合モデルの変換、関心事の変換。あくまでアダプタであり外の技術的な理由からの変更影響を受けない抽象度。
    • インフラストラクチャ(フレームワークとドライバ)。技術的変更理由をすべて受け持つが、データベースドライバそのものやWeb-UIフレームワークそのものではなく、「それらとの接続」を受け持つ。
    • 水平(ユースケースのグループ同士など)・垂直(ユースケースインターフェイスアダプタなど)の責務分離の両方が大事。結合性を考えるとき、垂直の依存は明確な指針があるので簡単、水平は無駄な結合を可能な限り避けるべき。
    • SOLID原則。
      • 単一責任原則。これ以上分割できないといえる最小の責務単位と1つのモジュールの粒度をきっちり一致させる。入庫処理・販売処理をDBから考えるとstock/sellを1つのクラスにしてしまうが、入庫処理(stock)・販売処理(sales)という関心に分ける、など。
      • 依存性反転原則。依存の向きのコントロールユースケースからデータゲートウェイに依存するのは循環の可能性もありよくない。ユースケースインターフェイスに向かせる。
    • 実践エピソード。修正箇所が詳細であれば外側にとどまり、抽象であれば正しく必要な箇所に修正が波及する。ユースケースが分けられていることで不用意な依存が起きづらい。
  • 「改善につながるオブザーバビリティ」。良き特集。Mackerelがここに登場しなくてNew Relic・Data Dogだけなのが悔しい。New Relicの小林良太郎さん、サイバーエージェントの永野一馬さん、TVerの加我貴志さんがそれぞれの記事を執筆。
    • オブザーバビリティはObserve + Abilityの造語、もともとは制御理論の文脈で外部出力情報から内部状態を推測すること。「システムの状態をリアルタイムで把握でき、また正常・異常な状態に関わらずシステムがどのような振る舞いをしても、その原因を調査、理解することができる能力」。
    • サステナブルなシステムとエンジニアの幸福、ビジネスニーズの充足と顧客の幸福をオブザーバビリティで目指す。
    • ITサービス障害と監視の分類。Known Knownsは原因を理解しており具体的な行動をとれる監視。Unknown Knownsは監視していなくて気付かなかったが監視可能なもので、次回からKnown Knowns化できる。Known Unknownsは監視はしているが理解できていないもので、アラートが出ても原因がわからない。Unknown Unknownsは認識・理解がなく監視していなくて影響が甚大。システムのあらゆるところからデータを収集し、集約したデータを解析し、気付けなかった問題に気付いたり問題の答えを導いたりするようになることを意識する。
    • 監視はシステムの健康状態を定期的にチェックする方法、Known Knowns, Known Unknowns。オブザーバビリティはシステムの内部状態を観測し、エンジニアがシステム最適化のための洞察を得られる能力、Unknown Unknowns, Known Unknowns。目的は同じでありアプローチが異なるだけなので、監視が「古い手法」になるわけではない。オブザーバビリティは監視を内包し、複雑化したシステムのUnknown Unknownsへの必要性が高まっている。
    • ログ、メトリクス、トレースが3本柱と呼ばれることがあるが、目的を達成できるなら1つの活用でも問題ない。逆に、アプリケーションプロファイルやクラッシュダンプのような別手段が必要なケースもある。
    • ログ・メトリクス・トレースを集約したとしても「イベント」(トランザクションの発生やアプリケーションクラッシュなどのある瞬間に発生する個別のアクション)の文脈が必要。イベントを軸に検索し、特定の環境だけか、ユーザーの特定行動起因かなどを調査できる。カーディナリティ、データの一意性が高い情報が付与されていることも重要。
    • オブザーバビリティが高ければSLIの精度も上がる。
    • アプリケーション開発者にとってのオブザーバビリティのメリット。アプリケーションの本番環境での振る舞い(応答時間、エラーの有無など)をトレース情報などをもとにコードレベルで確認できる。デプロイ後のバグやデグレーションのチェック。技術的負債がたまってしまったアプリケーションもオブザーバビリティが高ければシステムの挙動や状態を把握できて運用保守コストを低減できる。
    • オブザーバビリティ成熟度モデル(『オブザーバビリティ・エンジニアリング』)のチェックリストを使ってみる。システム障害にレジリエンスで対応できているか、高品質なコードをデリバリーできているか、複雑さと技術的負債に立ち向かえているか、予測可能なリズムでリリースしているか、ユーザーの振る舞いを理解できているか。
    • New Relicのオブザーバビリティ成熟度モデル
      • レベル0 計測を始める: まったくか部分的にしか計測できていない。レスポンスタイム等よく使われる指標の計測から始める。目的に応じて必要な計測ツールを入れる。サービスがどのように動いているか現状を理解できるようになる。
      • レベル1 受動的対応: データを収集してサービスが正常に動いていることを認識できている。サービスの停止や性能劣化を検知通知し、チームが対応できる。障害に対してチームが対応できるようになる。稼働率MTTRなど客観的指標を持てる。
      • レベル2 積極的対応: 受動的対応ができている。パフォーマンスの悪いところを探して改善、SLO設定、アラート通知を必要なもののみに、デプロイ後のサービス品質計測。急なトラフィックやデータの増加に耐えられるようになる、客観的指標を目標化できる、MTTRの短縮などができる。
      • レベル3 データ駆動: 受動的・積極的対応ができている。需要予測に対してキャパシティプランニングを行いシステムリソースを調整する、サービスを顧客がどのように利用しているか可視化、顧客のサービス利用状況とシステムパフォーマンスの関係調査。コスト最適化、顧客満足度の可視化と向上。
      • 詳細は『New Relic実践入門』を参照とのこと。
    • オブザーバビリティツール導入のアンチパターン。既存ツールの運用フローに固執する。すべてを監視・通知しようとする。小規模で安定した環境で小さく始めようとする(Unknown Unknownsが発生する環境でこそ効果が発揮されるので)。
    • ツールの導入や運用のしやすさ、ツールのコストや課金体系、導入前後のサポート体制、アカウント管理や請求単位が組織にフィットするか を観点に組織導入を考えるとよい。
    • 組織全体がポジティブな気持ちでオブザーバビリティの継続的改善に取り組む。成熟度モデルを使って定期的に確認し、見直した結果を共有する。導入効果を経営陣や他部門にアピールする。改善施策を中長期計画に組み込む。
    • モバイルアプリでのSRE・モバイルエンジニアのオブザーバビリティ実現。モバイルアプリケーションの信頼性の担保が難しい(デバイスが多様すぎ、アップデートはユーザー任せなので不具合解決に時間がかかる、ログのィメンションが多くて見やすいダッシュボードを作りにくい、ロールバックできないし変更リードタイムも長い)。レポーティング、モニタリング、トレースの要素。
    • 多次元のディメンション相手のダッシュボード作成。多くの人が一目で理解できるようデザインされているのが望ましい。リリースアプリ単位に合わせる。用途別に分割する。
    • UXに近い形でSLI/SLOを再設計。フリックやメッセージ画面の利用などを重要な機能として可用性を定義した。
    • モバイルアプリケーションのトレーサビリティ向上。APIレスポンスのパースエラー、不具合が発生したタイミングとどのようなエラーが発生したか、外部SNS認証サービスの障害検知が効果的だった。
    • TVerのサービスリニューアルとシステムの内製化。フロントエンド・バックエンド・インフラまでシステム全体を通して観測できるフルスタックなオブザーバビリティ導入が必要だった。
    • New Relicの導入。Webフロントエンド(React)にはNew Relic Browser AgentのJSファイル、iOSアプリ(Swift)にはCocoaPodsを使ってNew Relic Mobile Agent、Androidアプリ(Kotlin)にはGradleを使ってNew Relic Mobile Agentを登録。動画プレイヤーの振る舞い観測にNew Relic Video Agent。バックエンド(Go)のAPIサーバーにNew Relic APMを導入して諸々の重要な指標をトレースとして得られる。
    • TVerは主要ワークロードにAWS、データ分析基盤にGoogle Cloud。New Relicとの連携ではAWSはCloudWatch経由、Google CloudはCloud Monitoring API経由。CloudWatchはAPI Pollingだと5分間隔、Kinesis Data FirehoseのMetrics Streamだと2分未満。API Pollingでないと取れないメトリクスもある。New Relic Inrastructure AgentでVMやコンテナのメトリクス取得、ログ転送。TVerではFargateクラスタ運用なのでサイドカー実行でホスト情報を取得、一部はAutomatic Logs in Contextでログ転送。
    • ダッシュボードをサマリー、Webフロントエンド、モバイルアプリケーション、バックエンド、インフラで分けている。
    • 定期的な品質報告やレクチャー会を継続し、エンジニアだけでなくテクニカルディレクターも巻き込んで、データドリブンな開発計画(安定しているので新規開発タスクを多めに積もう、など)や障害予兆の発見に役立てている。
  • 「SBOM今後求められる運用と立ちふさがる課題」。OSSのライセンスコンプライアンス情報を適切に取り扱うためのSPDX。セキュリティに冠する情報を適切に取り扱うためのCycloneDX。汎用的にSPDXを生成するツールはまだ存在しない。
  • 「メールセキュリティ対策の現場」。今回はDMARC。SPFDKIMときたらまぁDMARCですよね。自分の個人サーバーもDMARCを設定はしていたものの、様子見でnoneのままだったのを思い出したので、このたびquarantineに変更。しかしSMTPを2023年になっても捨てられないの本当に辛い。
  • Google Cloudを軸に実践するSREプラクティス」は前月号に引き続きTerraform。勉強してちょっと使っていたけど、しばらく使わないとすぐ忘れる。tfstateの暗号化、確かに必要だな。
  • 「なるほど納得Go言語」。ゼロ値の続き。
    • varで宣言しただけの状態ですぐに使えるデータ型になっていると良い。標準パッケージではsync.WaitGroup、sync.Mutex、bytes.Bufferなど。
    • http.RequestはMethodに意味のある値、URL/Hostに整合性がとれている、Headerはマップ型で追加できる状態でないといけないという制約があるので、ゼロ値ができない。NewRequestを使う。
    • ゼロ値以外の値をデフォルト値としたい、各種フィールドにセットする値のバリデーションをしたいというときには、ファクトリー関数のNewXxx関数を用意すると良い。
  • 「リソースから考えるBCPの手続き」。最終回だった。前職だとこういうことを内々に考えたりもしていたので、毎回興味深く読んでいた。最後はBCP訓練の話。
  • AWS活用ジャーニー」。AWS CloudTrailとConfigをテーマに。SAA取得で勉強はしたけれども、自身の業務や個人管理範囲だと使うシーンはまずないので、実例を見るのは参考になる。