日本語版
最新ニュース
科学&テクノロジー

ブール値を使わない | LUU.IO

代わりに列挙型を使用してください。 このような包括的な説明には、常に例外があります。ただし、データを 1 つの物理ビットに詰め込む必要がある場合を除き、一般的には、ブール値よりも列挙型を使用する方がよい場合が多いと思います。 読みやすさ 最近、コードベースで関数呼び出しを見つけました。そこで、チームに現金と引き換えに引数の名前を付けるチャレンジをしましたが、残念ながら、お金は私のものになりました。次のような感じでした。 fetch(accountId, false, true, true); 明らかに、インライン注釈を付けることで読みやすさが大幅に向上します。 fetch( accountId, true, // include disabled, true, // fetch history, true, // fetch details ); しかし、ここでわかるように、厳格なコードレビュープロセスまたはリンター、あるいは開発者のデューデリジェンスに頼るしかありません。次のようなコードの方がはるかに読みやすくなります。 fetch( accountId, {ItemStatus::Active, ItemStatus::Disabled}, FetchOptions::History | FetchOptions::Details, ); の違いに注目してください ItemStatus そして…

1721987982
2024-07-22 08:25:59

代わりに列挙型を使用してください。

このような包括的な説明には、常に例外があります。ただし、データを 1 つの物理ビットに詰め込む必要がある場合を除き、一般的には、ブール値よりも列挙型を使用する方がよい場合が多いと思います。

読みやすさ

最近、コードベースで関数呼び出しを見つけました。そこで、チームに現金と引き換えに引数の名前を付けるチャレンジをしましたが、残念ながら、お金は私のものになりました。次のような感じでした。

fetch(accountId, false, true, true);

明らかに、インライン注釈を付けることで読みやすさが大幅に向上します。

fetch(
  accountId,
  true, // include disabled,
  true, // fetch history, 
  true, // fetch details
);

しかし、ここでわかるように、厳格なコードレビュープロセスまたはリンター、あるいは開発者のデューデリジェンスに頼るしかありません。次のようなコードの方がはるかに読みやすくなります。

fetch(
  accountId,
  {ItemStatus::Active, ItemStatus::Disabled},
  FetchOptions::History | FetchOptions::Details,
);

の違いに注目してください ItemStatus そして FetchOptions 列挙型。1 つは排他的な列挙型 (つまり、各項目はブール値の 1 つだけを持つことができます) であり、もう 1 つはビットマスク フラグです。

明示的な型付け

なぜ明示的な型付けが必要なのでしょうか?夜遅くまで起きてバグを修正し、これを呼び出しているところを想像してみてください fetch 関数。もしあなたが私と同じなら、目をそらして間違った場所にtrue/falseを渡してしまう可能性が高いです。 fetch(false, true, false) の代わりに fetch(true, false, false)この問題を検出するには、ブール値のすべての順列をテストでテストする必要があります。また、テストが失敗した場合でも、問題を見つけるのは難しいでしょう。

APIの列挙型バージョンでは、誤って fetch(FetchOptions::History, {ItemStatus::Active})この場合、コンパイラまたはインタープリタはかなり大きな警告を発するはずです。

プログラミング言語で可能な場合は、明示的なビットマスク型を使用してください。 intこれにより、呼び出しサイトが誤って間違ったフラグを渡すことがなくなります。

行動主導型と拡張性

ブール値を使用する際に、代わりに列挙型を使用することを検討するたびに、実際のユースケースやアプリケーションの動作や状態についてよく考えていました。その時点で、実際のユースケースやAPIの動作を考慮せずに、別のブール値を追加するのは簡単です。 fetch 再び API。ブール型シグネチャは次のとおりです。

fetch(
  int accountId,
  bool includeDisabled,
  bool includeHistory,
  bool includeDetails,
);

という新しいデータがあるとします。 flags、そして私たちはそれらを返したいのです flagsただし、既存の呼び出し元との下位互換性を保つ必要があり、明示的に示されている場合にのみフラグを返します。そこで、API 署名を更新しましょう。

fetch(
  int accountId,
  bool includeDisabled,
  bool includeHistory,
  bool includeDetails,
  bool includeFlags, // 

しかし、1つの問題があります。フラグは実際には詳細から来ています。言い換えれば、 includeFlagstrue、発信者はまた設定する必要があります includeDetails true に設定し、それをどこかに文書化する必要があります (呼び出し側がドキュメントを読むことを前提としています)。

if (includeFlags) {
  assert includeHistory;
}

相互に依存しない列挙型が 3 つ以上あるとしたら、突然大きな互換性マトリックスが必要になります。この API の列挙型バージョンを拡張する方法を見てみましょう。

enum FetchOptions {
  None = 0,
  History = 1,
  Details = 2,
}
fetch(int accountId, set statuses, FetchOptions options);

私たちがしなければならないのは、新しいオプションを追加することだけです FetchOptions 列挙型:

enum FetchOptions {
  None = 0,
  History = 1,
  Details = 2,
  DetailsWithFlags = 4, // 

電話をかけてきた人は できない 間違ったものを渡してください!

まとめ

どのコードベースでも、どの程度「オーバーエンジニアリング」すべきかという微妙なバランスが常に存在します。ただし、ブール値の列挙型を使用するオーバーヘッドは非常に低く、列挙型が提供する利点は努力する価値があると感じています。

#ブール値を使わない #LUU.IO

執筆者について: nipponese

Nipponese News編集部は、国内外のニュースを日本語で分かりやすくお届けします。