あなたのアーキテクチャ図は、すでに嘘になっている
アーキテクチャ資料は、保存した瞬間から陳腐化する。コード生成ダイアグラム、ADR、自動化されたアーキテクチャテストを使って、資料を正直な状態に保つ方法を解説する。
私がWikiで見たアーキテクチャ図は、すべて間違っていた。劇的に間違っているわけではない。静かに、徐々に間違っているのだ。「Auth」と書かれたサービスは半年前に3つのマイクロサービスに分割された。「sync…
19 posts
アーキテクチャ資料は、保存した瞬間から陳腐化する。コード生成ダイアグラム、ADR、自動化されたアーキテクチャテストを使って、資料を正直な状態に保つ方法を解説する。
私がWikiで見たアーキテクチャ図は、すべて間違っていた。劇的に間違っているわけではない。静かに、徐々に間違っているのだ。「Auth」と書かれたサービスは半年前に3つのマイクロサービスに分割された。「sync…
タイムアウトやクラッシュは、APIリクエストが消失したことを意味しない。idempotency keyがどうやってリトライを安全にするか、そして実際に重複を防ぐストレージパターンについて解説する。
あなたのサービスが リクエストの途中でクラッシュした。クライアントはタイムアウトを検知してリトライする。結果として2件の課金が発生する。顧客は怒っている。データベースは整合性を保っている。だがビジネスロジックは保っていない。…
インメモリのミューテックスはサーバー再起動時に消滅する。フェンシングトークンとTTLを持つ分散リースが、クラッシュを跨いだ重複作業をどう防ぐか、そしてどこで破綻するかを解説する。
はを生き延びない。OOM、デプロイのロールアウト、ノードのリブートも同様だ。プロセスが終了した瞬間、ロックは消える。そのロックがスケジュールされたジョブ、データ移行、リーダー選出を守っていたなら、今や2つのプロセスが自分だけが動いていると確信している状況になっている。…
ほとんどのサーキットブレーカーライブラリは、復旧を検知するためにバックグラウンドスレッドを起動する。それは不要だ。ここでは、正確性を損なうことなくすべてのバックグラウンドオーバーヘッドを排除する、リクエスト駆動型の設計を紹介する。
私がレビューしたすべての本番環境のサーキットブレーカーは、最終的にバックグラウンドスレッドを起動する。それはGoのゴルーチンかもしれないし、Javaのかもしれないし、Rustのtokioタスクかもしれない。仕事はいつも同じだ:数秒ごとに目を覚まし、ダウンストリームサービスが復旧したかどうかを確認し、OPENからCLOS…
クラッシュオンリーソフトウェアは、あらゆる障害をクラッシュとして扱い、あらゆる起動をリカバリーとして扱う。Webサービスにとってこれは、シャットダウンロジックを削除し、kill -9でも生き残る状態を設計することを意味する。
あなたのWebサービスにはシャットダウンハンドラがある。バッファをフラッシュし、コネクションを閉じ、チェックポイントを書き出す。一度くらいはテストしたかもしれない。本番では、計画的なデプロイのときに年に一度動く程度だ。残りの時間、サービスはOOMキル、ノードの追放、停電、あるいはタイムアウトしてSIGKILLを受けるデ…
ミューテーションテストで生存者が見つかったが、そのミューテーションが何をしているのかまったくわからない。ミュータントを理解せずに正しいテストを書くためのステップバイステップの方法を紹介する。
あなたのミューテーションテストレポートは生存者でいっぱいで、そのうち少なくとも1つはあなたにとって意味不明だ。…
コードベース全体に単一のmutation scoreを課すのが間違いである理由と、実際のリスクに応じたモジュールごとのthresholdの設定方法。
コードベース全体に単一のmutation scoreを課すのは、チームにテストを嫌わせる最も効率的な方法だ。…
コードカバレッジは安全だと言う。ミューテーションテストは、テストのほとんどが飾りだと言う。生存ミュータントがその差をどう晒し、どう埋めるか。
テストは通る。カバレッジレポートは87%だ。しかしミューテーションスコアは40%で、半数のミュータントがまだ生きている。…
cargo-mutantsは、コードを検証したふりをしているテストを見つけ出す。Rustでのmutation testingの仕組み、何が捉えられるのか、そしてコンパイル時間のコストに見合う価値があるかを解説する。
100%のline coverageがある。すべての分岐が実行されている。すべての関数が呼ばれている。それなのに、誰かが価格ロジックのをに変えてテストを実行しても、すべて通ってしまう。…
ほとんどのチームはすべてのコミットでフルのミューテーションテストスイートを実行していない。ここでは、ビルドパイプラインを破壊することなく、エンジニアリングチームが実際にミューテーションテストをCIに統合する方法を紹介する。
ミューテーションテストスイートの実行に4時間かかるなら、おめでとう。誰もが疑っていたことを証明したことになる:テストスイートに穴が空いている。…
モック化されたデータベースのテストはSQLの構文を検証するだけで、クラッシュや並列書き込み、スキーマの不整合を経ても行が存続するかどうかは検証しない。永続性を本気でテストする方法を紹介する。
テストでデータベースをモック化していると、リポジトリ層が正しいメソッドを呼び出しているかどうかをテストしているに過ぎない。クラッシュからデータが復元されるか、ユニーク制約が実際に重複をブロックするか、何かが失敗したときにトランザクションがロールバックされるかどうかはテストできていない。…
すべてのReduxアクションをモックすると、テストは変更履歴の検証ツールになってしまう。実際の状態遷移を使ってストアをテストする方法を紹介する。
が正確なペイロードの形で呼ばれたかどうかを検証するテストを書いたことがあるなら、それは誰かが定数の名前を変更するたびに壊れるテストを書いたということです。 それは状態のロジックをテストしているのではありません。あなたの指が正しい文字列を打ったかどうかをテストしているだけです。…
Property-based testingのデフォルト100例は統計的戦略ではなく社会的妥協だ。自分の信頼性の要件とCI予算にマッチする実行回数の選び方を解説する。
Property-based testをデフォルトの100例で実行しているなら、最悪の両方を手に入れている。CIは必要以上に遅く、それでも大事なバグは見逃している。…
例ベースのテストは思いついた入力だけをカバーする。プロパティベースのテストはランダムデータを生成し、不変条件を検証し、失敗を最小の反例まで縮小する。
関数を書いた。 と でテストして、パスした。リリースした。 ユーザーが1要素のスライスを渡すと、関数はそれを黙って落とす。Issueが立つ。テストファイルを見つめながら、こんな当たり前のことにどうして気づかなかったのかと思う。…
コードカバレッジのメトリックは偽の安心感を生む。ここでは、ユニットテストがなぜ実際に寝不足を引き起こすバグを見逃し、代わりに何をテストすべきかを解説する。
コードカバレッジ90%なのに、午前2時にページャーが鳴った。 ユニットテストはパスした。CIはグリーンだった。それでもバグは本番に潜り込んだ。カバレッジは嘘をつかなかったが、真実も語らなかった。実行された行を測定しただけで、実際に検証された振る舞いを測定したわけではないからだ。…
Rustはdebug assertionsを自動で除去するが、本物のdesign-by-contractにはdebug_assert!以上のものが必要だ。リリースバイナリーから完全に消えるゼロコストのランタイムcontractsを作る方法を紹介する。
Rustは開発中にランタイムcontractsを強制し、リリースビルドから完全に消し去ることができる。ただし、この言語はcontractsを第一級の概念として扱っていない。ビルディングブロックは手に入るが、自分で配線を引く必要がある。…
開発者はアサーションを紙吹雪のように撒き散らすか、あるいは完全に避けるかのどちらかだ。有用な不変条件と本番クラッシュのトリガーを分ける判断フレームワークを紹介する。
ほとんどの本番 codebase は、二つの派閥のいずれかに属する。派閥Aは…
手作りのバリデーションは codebase を膨張させ、それでもエッジケースを見逃す。宣言的なスキーマで runtime contracts を enforce し、実装に干渉しない方法を解説する。
API がリクエストを受け取るたびにバリデーションを行う。外部システムから引数を受け取る関数も同様にチェックする。これを手作業で行うと、1つのエンドポイントにビジネスロジックを超える量のバリデーションコードが蓄積する。 これは runtime contracts に伴う隠れたコストだ。type system…
strict modeはあなたが書いたnullを捉えるが、APIやDOMクエリ、JSON.parseから実行時に到達するnullは捉えない。型システムが終わり、あなたの防御が始まる境界はここだ。
でを有効にした。赤い波線をすべて修正した。やはもう解決した問題だと確信して、プロダクションにリリースした。 するとバックエンドのレスポンスの構造が変わり、DOMクエリが何も返さず、がTypeScriptが安全だと教えてくれたまさにそのコードでを投げた。何が起きたのか? TypeScriptのstrict null…