見出し画像

NASAのコーディング要件がヤバい

12,343 文字

さて、今回はNASAが安全性を重視してどのようにコードを書いているのか、その10の方法についてお話ししていきます。NASAってやっぱり安全性の確保が得意ですよね。ボイジャーのプロジェクトとか本当にすごいです。ほとんどの真面目なソフトウェアプロジェクトでは、コーディングガイドラインが使われています。これらのガイドラインは、ソフトウェアを書くための基本ルールを定めたり、どのように構成すべきか、どの言語機能を活用すべきか、あるいは使わないほうがいいかを示すものです。面白いことに、良いコーディングスタンダードが何なのかについては、あまり一致した意見がないんです。たくさん書かれたガイドラインの中でも、明確なパターンを見つけられるものは驚くほど少ないんですよ。

ただ一つ言えるのは、新しいドキュメントほど前のものより長くなりがちだということです。これはなかなか面白い傾向ですよね。ダークモードにできますか?PDFをダークモードにする方法はわからないですけど…。すみませんでした、これはNASAのライトモードです。で、結局のところ、既存のガイドラインの多くは100以上のルールを含んでいます。それも、時にはその理由がちょっと疑問に思えるようなものまであります。特に、プログラム内の空白の使い方を細かく指定しようとするルールとか、Pythonで話題に上がったものとかは、個人の好みで入れられたんじゃないかと思っちゃいますね。

他にも、過去の同じ組織内でのコーディング作業で起きた、かなり特殊で起こりにくいエラー防止を目的にしたルールもあります。驚くことじゃないですけど、既存のコードガイドラインって、開発者が実際にコードを書くときにほとんど影響を与えないんです。ちなみに、この記事の冒頭部分が大好きです。NASAが作ったこの始まりの部分、めっちゃいいですよね。本当にその通りで、コードガイドラインには個人の好みがたくさん盛り込まれているんですよ。

多くのガイドラインの最も致命的な点は、ツールを使った包括的な適合性チェックがほとんどできないことなんです。ツールベースのチェックって大事ですよね。大規模なプロジェクトでは、何十万行ものコードを手動でレビューするのは現実的じゃないですから。この点について、今語られていることは全部大好きです。自動化やツールに頼るべきだし、個人の好みなんてゼロでいいはずです。なかなかいい感じになってきましたね。

既存のコーディングガイドラインの利点って、安全性が重要なアプリケーションでも実はあまり大きくないんです。でも、厳選された検証可能なコーディングルールのセットがあれば、ルールそのものの遵守を超えた特性について、重要なソフトウェアコンポーネントをより徹底的に分析できるんです。そのためには、ルールの数が少なく、理解しやすく覚えやすいくらい明確である必要があります。そして、機械的にチェックできるくらい具体的じゃないといけないんです。

効果的なガイドラインのルール数を簡単に上限を設定するなら、10個以下に制限することで大きなメリットが得られると私は主張したいですね。そんな小さなルールセットじゃ全てを網羅できないのはもちろんですが、ソフトウェアの信頼性や検証可能性に測定可能な効果をもたらす足がかりにはなるんです。この話、めっちゃいい感じですよ。今のところ全部気に入ってます。

強力なチェックをサポートするために、ルールはちょっと厳しいです。まるでドラコニアン(超厳格)って言ってもいいくらいですね。でも、そのトレードオフは明確であるべきです。特に、安全性が本当に重要なコードの開発では。私は今、Twitch用のボットを作ってるんですけど、ストリーム推薦ボットにこの10のルールを考えるべきかなって思ってます。やっぱりここでは安全性が大事ですからね。検証可能性を最大限にしたいし、プログラミングの十戒みたいなものが見たいです。

ちょっと頑張って、厳しい制限の中で暮らす価値はあるかもしれません。その見返りとして、重要なソフトウェアが意図した通りに動くことをより説得力を持って証明できるはずです。では、安全性重視のコーディングのための10のルールを見ていきましょう。安全性を重視するコードの言語選び自体が重要なポイントなんですが、ここではあまり議論しないでおきます。JPL(ジェット推進研究所)を含めた多くの組織では、重要なコードはC言語で書かれています。C言語には長い歴史があって、強力なソースコードアナライザーや論理モデル抽出ツール、メトリックツール、デバッガー、テスト支援ツール、そして成熟した安定したコンパイラーが選べるくらいサポートが充実してるんです。

だから、C言語はこれまで展開されてきた、あるいは開発されてきたコーディングガイドラインのほとんどのターゲットになってるんです。それじゃあ、わりと現実的な理由で、私たちのコードルールは主にC言語を対象にしてて、C言語で書かれた重要なアプリケーションの信頼性をより徹底的にチェックする能力を最適化しようとしてるんです。みなさん、ここで聞いてくださいね。今、世の中には「C言語」って聞いただけでビビっちゃうような開発者がたくさんいるのは知ってます。でもね、ボイジャーを宇宙に飛ばしてるようなすごい人たちじゃないんだから、そんなに驚かなくてもいいですよ。みなさん、スクリプトキッズみたいにふわっとしたシステムエンジニアじゃないんだから、黙って聞いててください。

さて、次のルールがどんなメリットをもたらすか見てみましょう。特にルール数が少ないと、開発者が実際に守ってくれる可能性が上がるんです。各ルールには、なぜそれが含まれているかの簡単な理由もつけています。ルール1:すべてのコードをとてもシンプルな制御フロー構造に制限してください。goto文やsetjump、longjump構造、そして直接的または間接的な再帰は使わないでください。間接的な再帰って何だろう?間接的な再帰って、2つの関数が互いに呼び出し合うことですかね?

このルールを理解するのを手伝ってください。どうやるんだろう?だって、これってよくあるケースですよね。関数が別の関数を呼び出して、何かチェックをして、制御できない方法で戻ってくるみたいなこと。async/awaitがない言語だと、スレッドをブロックするしかないんですかね?つまり、async/awaitがなければスレッドをブロックして、whileループでやってくれってことですか?私が再接続するソケットで間接的な再帰を使ってる時を思い出してみます。たとえば、ソケットを開いて、再接続する処理があって、それがプライベートの再接続関数を呼び出して状態をリセットして、また再接続を呼び出して…みたいな。

接続が切れたらまた接続を呼び出すっていう、これって技術的には一種の再帰ですよね。whileループにして待機させればいいのかな?それのほうがシンプルかなって、今すごく考えちゃってます。ちょっともっと考えてみますね。プライムはもうルール1を破っちゃいましたね。間接的な再帰って、無限の問題解決のための強力な仕組みなんですけど、試してみるのは全然問題ないですよね。

理由:シンプルな制御フローは、検証能力を強くして、コードの明確さを向上させることが多いんです。私もそれは同意します。たとえば、接続が閉じた時に再接続を呼び出して、開始してるかチェックして、接続中ならreturnするみたいな。これって順番に並んだステートメントがたくさんあって、問題を引き起こす原因になるんですよね。だから、これが起こる理由がわかるし、納得できるんです。

再帰が禁止されてるのはここでは一番の驚きかもしれません。でも、再帰がなければ、関数呼び出しグラフが非循環的になることが保証されて、コードアナライザーがそれを活用できて、制限されるべきすべての実行が実際に制限されてることを証明する助けになります。このルールでは、すべての関数が単一の戻り値を持つ必要はないですよ。それでも、早期リターンや早期エラーリターンがシンプルな解決策になるケースは十分あります。

実はこれ、めっちゃ現実的な議論なんです。完全に公平に言えば、私の大学2年生の時に先生がAVLツリーをやらされたんです。AVLツリーって知らない人のために言うと、回転を使って自己平衡するバイナリサーチツリーの一種で、4種類の回転があるんです。たとえば、ロングライトとかRR、LL、RL、LRとかがあって、結構楽しいんですよ。ここで簡単に書いてみますね。たとえば、a、b、cってツリーがあったら、これをb、a、cに整理して、別のツリーがa、b、cならa、c、bに回転する感じです。簡単ですよね。

先生は再帰を使わずにAVLツリーをプログラムしろって言ってきて、それは私にとってすごい学びの経験でした。すべてのループには固定の上限が必要です。チェックツールが静的に証明できる、ループの反復回数の上限が超えられないことが簡単にわかるようにしてください。もしループの上限が静的に証明できないなら、このルールは違反とみなされます。ってことは、arrayのdoやforeachみたいなものは使えないってことですか?だって、上限が配列によって動的じゃないですか。それとも、while(true)はダメってこと?

理由:再帰がないことと、ループの上限があることで、コードが暴走するのを防ぎます。このルールはもちろん、プロセススケジューラーのように終わりがないと意図された反復には適用されません。そういう特別なケースでは、逆にその反復が終われないことが静的に証明できるべきです。このルールをサポートする方法の一つは、反復回数が可変のすべてのループに明確な上限を追加することですね。リンクリストを走査するコードで、上限を超えたらアサーション失敗がトリガーされて、失敗した反復を含む関数がエラーを返すんです。ルール5でアサーションの使い方が出てきますよ。面白いですね。

ルール3:初期化後は動的メモリ割り当てを使わないでください。ってことは、JavaScriptとGoがアウトですね。でも、実は公平に言えば、JavaScriptとGoでもこれできるんですよ。たとえば、Gファンクみたいなものを使ったら、裏で知らないうちにメモリが割り当てられちゃうでしょうけど。すべてのインタプリテッド言語がそうってわけじゃないです。クロージャーが使えないってことですよね?アリーナ割り当てをしなきゃいけないってことですか。リストや文字列も使えないの?

いや、リストや文字列は使えます。ただ、最初に割り当てるメモリで全部まかなうってことです。ヒープじゃなくてスタックのことじゃないかって思いますけど、さらにたとえば、サーバーから特定の応答セットを受け取る何かがあったとして、必要になりうる応答の量に専用のメモリ領域を用意して、それをリングバッファみたいに循環させるんです。そうすれば割り当てが起こらないし、すべてのデータが事前に割り当てられてるってことになりますね。最初に必要なメモリを全部確保しておくってことですよね。

文字列も使えるけど、どれだけの量を使うかの領域を予め定義しておく必要があるってこと。めっちゃ考えることが多いですね。サーキュラーバッファーか。うん、このルールは安全性重視のソフトウェアでは一般的で、ほとんどのコーディングガイドラインに出てきます。理由は簡単で、マロックみたいなメモリ割り当てやガベージコレクターは予測できない動きをして、パフォーマンスに大きく影響することがあるからです。

メモリ割り当てや解放のミスからくるエラーの一群もありますね。メモリを解放し忘れたり、解放後に使い続けたり、物理的に利用可能な以上のメモリを割り当てようとしたり、割り当てられたメモリの境界を超えたりとか。すべてのアプリケーションを固定の事前割り当てられたメモリ領域内で動作させることで、これらの問題の多くをなくして、メモリ使用の検証がしやすくなるんです。ヒープからのメモリ割り当てがない場合に動的にメモリを確保する唯一の方法はスタックメモリを使うことです。

ルール1で再帰がないから、スタックメモリの上限を静的に導き出せるので、アプリケーションが常に事前割り当てられたメモリ内で動作することが証明できるんです。めっちゃクールですね。ちょっと頭おかしいくらいに感じますけど、実はそんなにおかしくないです。これって完全に理解できるんです。ゲームプログラミングでやってること聞いたことありますよ。ダンビルがまだここにいるなら間違ってるか教えてくださいね。

たとえば、サブチームごとに予算を決めて、メモリやCPU時間の割り当てを決めておいて、その範囲内でプログラムの一部を動かすんです。それを超えたら、「おい、物理チーム、時間使いすぎだよ」とか報告があって、何か別の方法を考えようかってなるんです。それって素敵ですよね。私が理解できる例で、素人ゲームプログラマーがわかるように説明してみました。FPSがちょっと下がってもボーナスなしって感じですね。

大まかに言えばそうです。Twitchチャットで語るにはちょっと細かい話ですけど、私なりに素人目線で頑張って説明してみました。私は素人ゲームプログラマーです。小さいゲームは作ったことありますけど、本物のゲームプログラマーじゃないのはわかってます。ルール4:関数は、標準的な参照形式で1枚の紙に印刷できる長さを超えてはいけません。1ステートメント1行、1宣言1行で、通常は1関数あたり約60行までってことです。

それって結構公平ですよね。60行あれば十分にいろいろできますし。Uncle Bobだと1関数3~5行しか許さないですけど、60行って結構多いですよ。でも、1枚の紙に印刷できるって書いてますよね。厳密に硬いルールじゃないけど、紙に印刷できる範囲って感じで、60行でかなり表現できると思います。このルール破る方法もあるだろうけど、60行以内の関数なら簡単に書ける気がします。そんなに難しくないですよ。

Goの標準ライブラリは数千行ありますけどね。でも、Goの標準ライブラリって、そこまでクリーンで素敵なコードってわけじゃないですよね。私的には、読むとちょっとゴミっぽい感じがします。理由:各関数は論理的なコードの単位で、理解しやすく検証しやすいものであるべきです。コンピュータ画面で複数スクリーンにまたがったり、印刷で複数ページになるような論理単位は理解しにくいです。長すぎる関数は、コードがうまく作られてないサインですね。

その意見には基本的に同意します。60行以上のコードって実は珍しいし、見つけたとしても、動作の局所性のせいで全部一緒にしないといけない難しいものか、クソみたいな関数かのどっちかだと思います。React書いてるなら別ですけど、私が言ったことは当てはまると思います。ルール5:コードのアサーション密度は、1関数あたり最低2つのアサーションが平均になるようにしてください。アサーションは、現実の実行では絶対に起こらないはずの異常状態をチェックするために使います。

アサーションは常に副作用がなく、ブーリアンテストとして定義されるべきです。アサーションが失敗したら、明確なリカバリーアクションを取る必要があります。たとえば、失敗したアサーションを実行する関数にエラー状態を返すとかですね。静的チェックツールが絶対に失敗しない、あるいは成り立たないと証明できるアサーションは、このルールに違反します。つまり、無意味な「true」アサーションを追加してルールを満たすことはできないってことです。

このルール、めっちゃ好きですね。すごくいいルールだと思います。私もこれをもっと実践しないとなって思います。まだまだ続けていかなきゃいけないですけど、私のコードベースでも結構アサーション使ってますよ。でも、今のアサーションって、プログラムをハードクラッシュさせちゃうんです。内部で作ったメッセージが期待に合わない時、私がめっちゃやらかしたと思って、爆発させちゃうんです。

結果パターンならどこでもそうなるって感じですね。理由:産業コーディングの統計によると、ユニットテストは10~100行のコードにつき少なくとも1つの欠陥を見つけることが多いです。アサーション密度が高いほど欠陥を見つける確率が上がります。アサーションの使用は、強力な防御的コーディング戦略の一部としてもよく推奨されます。いいところは、ファジング戦略を考え出せば、プログラムを完全にテストできるってことです。

ランダムなものを山ほど投げつけて、プログラムのどこかで防御的なステートメントがあって、それ以降のアサーションが起こらないようにできるんです。それで、特定のユニットテストを減らしてファジングテストに置き換えられるのもすごいですよね。アサーションは、関数の事前条件や事後条件、パラメータ値、戻り値、ループの不変条件を検証するのに使えます。アサーションは副作用がないので、パフォーマンスが重要なコードではテスト後に選択的に無効化できます。

典型的なアサーションの使い方としては、たとえば、Cアサートで「pがtrue以上ならエラーを返す」とかですね。アサーションは「Cアサートデバッグ失敗アサーション ファイル 行」みたいに定義されてて、ファイルと行はマクロプリプロセッサで定義済みで、失敗したアサーションのファイル名と行番号を出してくれます。構文「#e」はアサーション条件を文字列に変えて、エラーメッセージの一部として出力するんです。

組み込みプロセッサ向けのコードだと、エラーメッセージを出力する場所がないので、その場合はテストデバッグへの呼び出しがnoopになって、アサーションが純粋なブーリアンテストになるんです。それで異常な動作からのエラー回復ができるんですよ。私のこの「パワー・オブ・10」への旅は、タイガービートルからヨンさんが参加してくれたことから始まったんです。彼はこのことをすごく具体的に話してくれて、タイガービートルにはどんなデータでも投げつけても常に適切に動作するんです。

毎日、毎ビルドごとに200年分のクエリテストみたいなことをやってて、ずっとハンマーで叩かれてる感じで、アサーションが至るところにあるんです。超クールなプロジェクトですよ。データオブジェクトは可能な限り最小のスコープで宣言してください。これはC言語に適切なエラーハンドリングや構文機能がないだけじゃないかって、私はその意見に強く反対します。アサーションって実はめっちゃ役に立つんですよ。

タイガービートルはZigで書かれてて、適切なエラーハンドリングユーティリティがあって、結果オブジェクトもあるんですけど、それ自体が標準エラーよりずっと良いスタックトレースを提供してくれるんです。めっちゃクールですよ。インタビュー時に8,000個のアサーションがあったって言ってましたね。アサーションはエラーハンドリングじゃないです。不変条件のハードストップって感じですかね。

Zigでエラーを返すのと何か違うんですか?Zigではエラーか値を返すんですけど、ここではハードストップじゃなくて、リカバリーが必要なんです。それでもハードストップかソフトストップか、エラー回復メカニズムを全部に作るかはいいと思います。このルールはデータ隠蔽の基本原則をサポートしてます。オブジェクトがスコープになければ、その値は参照も破損もできないですよね。

同様に、オブジェクトの値にエラーがあれば、値が割り当てられるステートメントが少ないほど問題の診断が簡単になります。このルールは、互換性のない複数の目的で変数を再利用することを避けて、障害診断を複雑にしないようにするんです。ルール6って、使われるところで定義するのが常に最小スコープってことですかね?カプセル化してるって感じですかね。

ルール7:voidでない関数の戻り値は、呼び出し元の各関数でチェックされる必要があり、パラメータの有効性は各関数内でチェックされる必要があります。どういう意味かわからないです。ちょっと待ってください。これはおそらく最もよく違反されるルールで、一般ルールとしてはちょっと怪しいですね。この形式だと、printf文やファイルクローズ文の戻り値もチェックしないといけないってことです。

でも、エラーへの対応が成功への対応と正当に変わらないなら、戻り値を明示的にチェックする意味はあまりないって主張もできます。printfやcloseの呼び出しではよくそうなるんですよ。それが私がZigを好きな理由の一つなんです。ここにZigのコードがあるんですけど、DNAが何か起こった時にオブジェクトを返してくれて、私はその戻り値を気にしないって明示的に言ってるんです。

たとえば、fooを呼ぶと、エラーか何かあるかもしれないけど、私はそれが起こっても気にしないって言ってるんです。それって素晴らしいと思います。Rustも同じようなことがあって、戻り値やasyncを無視すると警告が出るんです。このルール、いいと思いますね。特にエラー戻り値を関数呼び出しチェーンで伝播させる必要があるなら、関数の戻り値を無視しないほうがいいです。

標準ライブラリはこれを有名に違反してて、かなり重大な結果になることがあります。たとえば、Cの標準文字列ライブラリでstrlen(0)やstrcatを誤って実行するとどうなるか見てみてください。きれいじゃないですよ。一般ルールを守ることで、例外は正当化される必要があって、機械的なチェッカーが違反を見つけてくれるんです。たいていは、ルールに従うほうが、非準拠を説明するより簡単ですよ。

プリプロセッサの使用は、ヘッダーファイルのインクルードとシンプルなマクロ定義に制限してください。トークンペースト、可変引数リストの省略記号、再帰的マクロ呼び出しはダメです。すべてのマクロは完全な静的ユニットに展開される必要があります。条件付きコンパイルディレクティブの使用もよく怪しいですけど、常に避けられるわけじゃないです。大きなソフトウェア開発でも、同一ヘッダーファイルの複数インクルードを防ぐ標準的なボイラープレート以外では、1つか2つ以上の条件付きコンパイルディレクティブに正当性があることは稀です。

そういう使用はツールベースのチェッカーでフラグを立てて、コード内で正当化されるべきです。プリプロセッサマクロに注意するのは間違いなく正しいですね。コードを理解するのにプリプロセッサマクロほど問題が多いものはないです。このルール、ゲームをめっちゃ複雑にしちゃいますね。プリプロセッサ全般が好きじゃないです。マクロはすごく便利ですけど、めっちゃ理解しにくいんです。

Cにマクロがないのはありがたいですね。すごいハンマーみたいなツールですけど、すごいツールはみんな超危険です。プリプロセッサはコードの明確さを壊して、テキストベースのチェッカーを混乱させる強力で曖昧なツールです。制限のないプリプロセッサコードの効果は、正式な言語定義があっても解読するのがめっちゃ難しいんです。新しいCプリプロセッサの実装では、開発者はよく以前の実装を参照にして、C標準の複雑な定義言語を解釈しないといけないんです。

条件付きコンパイルに慎重になる理由も同じくらい大事です。条件付きコンパイルディレクティブが10個あるだけで、2の10乗、つまり1024通りのコードバージョンができちゃって、それぞれをテストしないといけないから、テスト負担がめっちゃ増えるんです。これは素晴らしい指摘ですよね。条件付きコンパイルって基本的に悪夢ですよ。でも、どうしても必要な時もあるんです。

私がこれ好きなのは、それが現実的なルールだってことです。条件付きコンパイルを完全に避けられないけど、すごく難しくてひどいものだって認識してるんです。Rustのcargo機能は、Rustのコンパイルが遅いから存在してるんだと思います。私が知ってるほとんどの人はRustバイナリにそんなに入れ込んでなくて、ただコンパイル時間が遅いのが心配なだけなんですよ。

ポインタの使用は制限されるべきです。具体的には、1レベルのデリファレンス以上はダメです。ポインタのデリファレンス操作は、マクロ定義やtypedef宣言の中に隠してはいけません。関数ポインタも許可されません。ポインタは経験豊富なプログラマーでも簡単に誤用しちゃいます。プログラムのデータフローを追ったり分析したりするのを難しくするんです。特にツールベースの静的アナライザーにとってはそうです。

関数ポインタも同じで、静的アナライザーができるチェックの種類を大きく制限しちゃいます。それを使う強い正当性がある場合にだけ使って、できればツールベースのチェッカーが制御フローや関数呼び出し階層を決定するのを助ける代替手段を提供するべきです。たとえば、関数ポインタを使うと、再帰がないことをツールで証明するのが不可能になるので、その損失を補うための別の保証が必要になるんです。

asyncとか割り込みはどうするんですかね?asyncはやってないと思いますよ。いや、きっとやってますよ。でも、どうやるかわからないですよね。ミューテックスかセマフォロックを使って、メモリへの何らかの参照をするんじゃないですか。asyncって決定的じゃないからダメですよね。決定的じゃないってわけじゃないけど、ある程度は必要ですよね。たとえば、プローブがあって、カメラがついてて、写真を撮るって考えてみてください。

写真を撮ったら処理して、メモリにダンプして、終わったら「終わったよ」って言って、何かが起きるんです。割り込みでコードの特定の部分を起こすのだって、ある意味関数ポインタじゃないですか。ミューテックスロックだと仮定しますね。たとえば、写真が来たら処理するコードがあって、セマフォが1の状態で待機してて、写真が来たらここを通ってコードを処理して、また戻って待機するんです。それでいいですよね。

すべてのコードは、開発初日からコンパイラの最も厳格な設定で全警告を有効にしてコンパイルされる必要があります。その設定で警告なしでコンパイルできなきゃダメです。毎日、少なくとも1つ、できれば複数の最先端の静的ソースコードアナライザーでチェックして、警告ゼロでパスするべきです。これは正直、かなり合理的だと思います。特に新しく始めるなら、これできるはずですよ。

今市場にはすごく効果的な静的ソースコードアナライザーがいくつかあって、無料ツールも結構あります。こんな便利な技術を使わないソフトウェア開発なんて言い訳できません。非重要なコード開発でも日常的な慣行と考えるべきです。警告ゼロのルールは、コンパイラや静的アナライザーが間違った警告を出した場合にも適用されます。コンパイラやアナライザーが混乱するなら、その混乱を引き起こすコードを簡単に有効になるように書き直すべきです。

多くの開発者が、警告は絶対間違ってるって思い込んで、後で実はそれがあまり明らかじゃない理由で正しかったって気づくことがあります。静的アナライザーって、昔のlintみたいにほとんど無効なメッセージばっかり出す先行者たちのせいでちょっと評判悪いですけど、もうそんなことないですよ。今の最高の静的アナライザーは速くて、選択的で正確なメッセージを出してくれます。真剣なソフトウェアプロジェクトではその使用は交渉の余地がないはずです。私、真剣なソフトウェア開発者じゃないから、納得ですね。

このルール10って、完全に実践的な意味があると思います。ただ、たくさんのプロジェクトに適用するのは難しいかもですね。JavaScriptだとどうします?ESLintってみんなクソだって同意しますよね。ESLintのほとんどの部分は完全にゴミで、ただの人々の良い悪いについての意見でしかないです。たとえば、Promiseの引数にresolveとrejectを直接使うのはダメだって言うんですけどね。

最初の2つのルールは、明確で透明な制御フロー構造を作ることを保証して、構築、テスト、分析が簡単になります。3番目のルールで動的メモリ割り当てがないことで、メモリの割り当てや解放に関する問題がなくなります。次の4~7のルールは、良いコーディングスタイルの標準としてかなり広く受け入れられてます。安全性重視のシステムのために、他のコーディングスタイルの利点も提案されてて、たとえばデザイン・バイ・コントラクトの規律はルール5~7に一部見られます。

この10のルールは、JPLでミッションクリティカルなソフトウェアを書くのに実験的に使われてて、励みになる結果が出てるんです。最初はこんな厳しい制約の中で暮らすことに健全な抵抗感があったけど、開発者はルールに従うことでコードの明確さ、分析可能性、コードの安全性にメリットがあることが多いって気づくんです。ルールは、開発者やテスターがコードの主要な特性(終了性や境界性、メモリやスタックの安全な使用など)を別の方法で確立する負担を軽くしてくれます。

このルールが最初はドラコニアンに感じるなら、それがコードをチェックできるようにするためのもので、あなたの命がかかってるかもしれない正しさが必要なコードだってことを思い出してください。飛行機の制御や、近くの原子力発電所、宇宙飛行士を軌道に乗せる宇宙船に使われるコードですよ。ルールは車のシートベルトみたいなものです。最初はちょっと不快かもしれないけど、慣れると使うのが当たり前になって、使わないなんて考えられなくなります。

このドキュメント大好きです。すべてのルールに同意するわけじゃないけど、このドキュメント自体は大好きです。政府が作ったものがこんなに一貫してるなんて衝撃ですよ。めっちゃ一貫してて、実践的であろうとしてる誰かによって書かれたみたいです。それが大好きですね。名前はプリマジェンです。

いいなと思ったら応援しよう!