NASAのソフトウェア開発10のルール
(cs.otago.ac.nz)- NASAのソフトウェア開発10ルールに対する批判的分析
- これらのルールは、極めて重要な組み込みシステム(例: 宇宙船ソフトウェア)のためのもの
- しかし、こうしたルールが他の開発環境でも適切なのか、あるいは他の言語(C以外の言語)にも適用可能なのかについては議論が必要
1. 単純な制御フローを維持する(goto、setjmp/longjmp、再帰を禁止)
- このルールは、例外処理(setjmp()/longjmp())と再帰を禁止する。
- 再帰が必ずしも非効率とは限らない。適切な方法を使えば、再帰でも終了を保証できる。
- 強制的に再帰をループへ変換すると、保守しにくいコードになる危険がある。
批判:
- 終了保証は重要だが、極端な制限は可読性と保守性を損なう可能性がある。
- 無条件の再帰禁止は、不必要な複雑さを招く可能性が高い。
2. すべてのループは明確な上限を持つべき
- コンパイラがループの繰り返し回数を静的に解析できる必要がある。
- しかし、単に上限を設定するだけでは実際の実行時間を保証しにくい。
- 再帰の深さ制限を設けることは、ループの上限を設けるのと同じくらい安全でありうる。
批判:
- 単に上限を設けるだけでは、現実的な実行可能時間を保証できない。
- 上限を設定しても値が大きすぎれば、実質的には無限ループと大差ない。
3. 初期化後の動的メモリ割り当てを禁止
- 組み込みシステムではメモリが限られているため、メモリ不足によるクラッシュを防ぐことが目的。
- しかし、手動メモリ管理よりも予測可能な動的割り当てのほうが安全な場合もある。
- たとえば、リアルタイムガベージコレクタ(RTGC)を使えば、動的割り当ても予測可能にできる。
批判:
- 動的割り当てそのものを禁止するより、メモリ使用パターンを分析して安全性を確保するほうが、よりよいアプローチかもしれない。
- 現代的な静的解析ツール(SPlint など)を活用すれば、動的メモリ関連のエラーを事前に検出できる。
4. 関数のサイズはA4用紙1枚以内に制限する(約60行)
- 関数が長すぎると可読性が下がる、という理屈。
- しかし、現代の開発環境にはコード折りたたみ機能があり、関数の長さより論理的単位の大きさのほうが重要。
批判:
- 物理的な大きさ(行数)よりも、論理的複雑さを基準にすべき。
- 関数を小さく分割すること自体が目的になってはいけない → かえって保守を難しくすることもある。
5. 関数ごとに少なくとも2つのassert文を使う
- assertはデバッグと文書化に非常に有用。
- しかし、無条件の個数制限は非効率になりうる。
批判:
- assertの数よりも、どこでデータ妥当性検査が必要かを明確にすることが重要。
- すべての引数と外部入力を検証するほうが、より実用的。
6. データオブジェクトのスコープを最小化する
- ローカル変数の使用を推奨する良い原則。
- しかし、関数だけでなく型や関数のスコープも最小化すべき。
批判:
- Ada、Pascal、JavaScript、関数型言語では型や関数もローカルに宣言可能 → NASAのルールより優れたアプローチ。
7. 関数の戻り値および引数の妥当性検証を必須にする
- 戻り値は必ずチェックすべき。
- しかし、あらゆる場合をチェックするのは現実的に難しい。
批判:
- 実行時エラーを防ぐには、可能な限り多くの検査が必要だが、実用上の限界も考慮しなければならない。
- 特にCでは戻り値チェックが重要だが、現代言語(Java、Rust など)では型システムを活用してより安全に扱える。
8. プリプロセッサの使用を制限する(ヘッダのインクルードと単純なマクロのみ許可)
- 複雑なマクロ、トークン結合、可変引数マクロ(...)を禁止。
- しかし、可変引数マクロはデバッグツールとして有用なことがある。
批判:
- プリプロセッサの使用を制限するより、可読性の高いマクロスタイルを推奨するほうが望ましい。
#ifdefのような条件付きコンパイルを禁じると、プラットフォーム非依存のコードを書くのが難しくなる可能性がある。
9. ポインタの使用を制限する(二重ポインタ禁止、関数ポインタ禁止)
- 関数ポインタの使用禁止 → 高い安全性を目指す。
- しかし、関数ポインタはコールバック、ストラテジーパターン、デバイスドライバなどに不可欠。
批判:
- 関数ポインタなしで switch-case による関数選択を強制すると、コードの可読性が下がり、保守が難しくなる。
- OS、ネットワークスタック、ドライバ開発では関数ポインタが不可欠。
- ポインタ制限よりも、安全なポインタ使用を保証する方法(C++のスマートポインタ、Rust など)のほうが、よりよい解決策。
10. すべてのコードでコンパイラ警告を最大に設定し、静的解析ツールを使う
- このルールは非常に良い推奨事項。
- コンパイラ警告の解消 + 静的解析ツールの使用 = 安定性向上。
批判:
- NASAの他のルール(例: ポインタ禁止、関数サイズ制限)は、単に静的解析ツールの限界を補うことを目的としている。
- しかし、現代の静的解析ツールは非常に進歩しているため、過度な制限よりも、より精緻な解析手法を活用するほうが有用。
6件のコメント
リアルタイム、組み込みの観点から見ると、どれも理解できるし必要なルールですね。静的解析器はこれらのルールを代わりに満たしてくれるのでしょうか?
例えば、動的割り当てを許可した場合、すべての使用シナリオでメモリ割り当てが成功することを保証できるのでしょうか?
ソフトウェアテストを学ぶと、いつも初日の最初の時間に言及される命題があります。その一つが「完璧なテストは不可能だ」です。
反対のほうがより目についてしまうあたり、
自分には合わないルールみたいですね(笑)
NASAだけでなく、航空・自動車など人命に直結する産業でも、似たようなコーディング規則を適用していることが多いようですね(笑)
https://github.com/kubernetes/kubernetes/…
Kubernetesのソースコードの中で、NASAスペースシャトルのアプリケーションソースコード作成方法で書かれたという「space shuttle style」のコードブロックを思い出しました。
関連HNスレッド: https://news.ycombinator.com/item?id=18772873
Hacker Newsの意見
setjmp/longjmpを擁護する文章を最初から真剣に受け止めるのは難しかったsetjmp/longjmpが例外処理だと主張しているsetjmp()とlongjmp()は例外を処理する悪い方法だ> タイトルは規則に対する_批判_であることを示さなければならない
222