リファクタリングとは、コードの外部から見た振る舞いを変えずに、その内部構造を改善する形でソフトウェアシステムを変更するプロセスとして定義されます。
管理者がコードリファクタリングに対して取る一般的なアプローチは、次の3つに分類できます:
- 反復的リファクタリング:最高のアーキテクト、デザイナー、開発者が揃っていても、アプリケーションを最初の反復で完璧に開発することはできません。多額の資金を投じたり時間を無駄にしたりせずにリファクタリングを行う実践的な方法は、リファクタリングを開発プロセスに組み込み、各反復の後に実施することです。
- 必要に応じたリファクタリング:アプリケーションのデプロイ後にバグが報告されることがあります。それらの解決に多くの時間がかかる場合、またはクライアント要件の中に既存システムへの開発・統合が非常に難しいものがある場合、リファクタリングはコードベースの品質を改善する有効な解決策になり得ます。ただし、この場合には非常に大きなリスクが伴うため、既存コードでリグレッションが発生しないよう注意が必要です。
- リファクタリングしない:既存アプリケーションに多くの問題があっても、経営陣がそのプロセスに投資したがらないためにリファクタリングがまったく行われないことがあります。その結果、サポートチームはすべてのバグとフィードバックによって生じるストレスに対処しなければなりません。
チームがC++プロジェクトを定期的にリファクタリングしており、新しいC++11/C++14機能の一部を採用することにした場合、他の有名なC++プロジェクトが新しい標準を採用するためにコードをどのようにリファクタリングしたかを見ることは有益です。
Chromeブラウザは調査対象として適したプロジェクトです。コードベースが定期的にリファクタリングされており、新しい標準が承認されてコンパイラでサポートされるとすぐに、Chrome開発チームはそれらの新しい標準へ前進することを選択しました。
Chromeブラウザは成熟したC++プロジェクトであり、そのコードがどのように実装・設計されているかを探ることは非常に興味深いことです。実際、Chromeは何百万人ものユーザーに使用されており、開発チームには効率的なコードを生み出すことが求められています。
新しい標準の機能を使うためにC++コードベースをリファクタリングすることにした場合は、この興味深い Googleドキュメントに目を通す価値があります。許可されているC++11/C++14機能と禁止されている機能が一覧化されています。
このドキュメントで最も重要なのは、禁止されている機能とその理由の一覧です。この一覧を確認し、自分のプロジェクトにも当てはまるかどうかを検討する価値は十分にあります。
以下は、このドキュメントに記載されている禁止対象のC++11/C++14機能です:
禁止されているC++11機能
| 機能またはライブラリ | スニペット | 説明 | ドキュメントリンク | 注意事項とディスカッションスレッド |
|---|---|---|---|---|
| インライン名前空間 | inline namespace foo { ... } |
名前空間のバージョン管理を改善できる | インライン名前空間 | 次で禁止されている: Google Style Guide。コンポーネントでどのように機能するかは不明確。 |
long long Type |
long long var = value; |
少なくとも64ビットの整数 | 基本型 | 64ビット数値が必要な場合は、stdint.hの型を使用してください。 ディスカッションスレッド |
| 参照修飾メンバー関数 | class T {
void f() & {}
void f() && {}
};
t.f(); // first
T().f(); // second
std::move(t).f(); // second |
クラスメンバー関数を、rvalueまたはlvalueとしての|this|にのみバインドできるようにする。 | const、volatile、参照修飾メンバー関数 | 次で禁止されている: Google Style Guide。Chromiumで使用するには、次の明示的な承認が必要です: styleguide/c++/OWNERS。 ディスカッションスレッド |
| ユーザー定義リテラル | type var = literal_value_type |
ユーザー定義リテラル式を使用できるようにする | ユーザー定義リテラル | 次で禁止されている: Google Style Guide。 |
| thread_localストレージクラス | thread_local int foo = 1; |
変数をスレッドローカルストレージに配置する。 | ストレージ期間 | Macでは意外な影響がある(ディスカッション、 フォーク)。シーケンスサポートには SequenceLocalStorageSlot を使用し、それ以外の場合は ThreadLocal/ThreadLocalStorageを使用してください。 |
禁止されているC++14機能
| 機能 | スニペット | 説明 | ドキュメントリンク | 注意事項とディスカッションスレッド |
|---|---|---|---|---|
| 関数戻り値型の推論 | auto f() { return 42; }
decltype(auto) g() { return 42; } |
関数の戻り値型を、そのreturn文からテンプレートまたは decltype のルールに従って自動的に推論できるようにする。 |
戻り値型推論 | 次の理由により一時的に禁止されている: clangで無限ループが発生する可能性がある。このバグが修正され次第、許可する予定です。使用はまれであるべきで、主に抽象的なテンプレートコードに限定されます。 ディスカッションスレッド |
| ジェネリックラムダ | [](const auto& x) { ... } |
ラムダ引数の型を推論するために auto を使用できるようにする(テンプレートに適用されるルールに従う)。 |
ラムダ式 | 次の理由により一時的に禁止されている: clangで無限ループが発生する可能性がある。このバグが修正され次第、許可する予定です。 ディスカッションスレッド |
禁止されているC++11ライブラリ機能
| 機能 | スニペット | 説明 | ドキュメントリンク | 注意事項とディスカッションスレッド |
|---|---|---|---|---|
| アライン済みストレージ | std::aligned_storage<10, 128> |
特定のアライメントを必要とするオブジェクトのための未初期化ストレージ。 | std::aligned_storage | MSVC 2017の実装では、sizeof(double) = 8バイトを超える境界でアライメントされません。次を使用してください: alignas(128) char foo[10]; 。 これが発見されたパッチ。 |
| バインド操作 | std::bind(function, args, ...) |
特定の引数にバインドされた関数オブジェクトを宣言する | std::bind | 次を使用してください: base::Bind 。比較対象の std::bind、 base::Bind は、キャプチャするラムダのバインドを防ぎ、呼び出し元に生ポインタを次として宣言させることで、有効期限の問題を防ぐのに役立ちます: Unretained。 ディスカッションスレッド |
| C浮動小数点環境 | <cfenv>、 <fenv.h> |
C互換コードに浮動小数点ステータスフラグと制御モードを提供する | 標準ライブラリヘッダー <cfenv> | 次により禁止されている: Google Style Guide 。コンパイラサポートに関する懸念が理由です。 |
| 日付・時刻ユーティリティ | <chrono> |
標準の日付・時刻ライブラリ | 日付・時刻ユーティリティ | 次と重複している: Time API(場所: base/。当面は base/ クラスを使い続けてください。 |
| 例外 | <exception> |
例外の送出と処理に関する機能強化 | 標準ライブラリヘッダー <exception> | 例外は Google Style Guide により禁止され、Chromiumのコンパイルでは無効化されています。なお、 noexcept 指定子は上で明示的に許可されています。 ディスカッションスレッド |
| 関数オブジェクト | std::function |
標準のポリモーフィック関数をラップする | std::function | 次を使用してください: base::Callback 。比較対象の std::function、 base::Callback は、Chromiumの参照カウントクラスと弱いポインタを直接サポートし、追加のスレッドセーフティ上の懸念にも対処します。 ディスカッションスレッド |
| Ratioテンプレートクラス | std::ratio<numerator, denominator> |
コンパイル時の有理数を提供する | std::ratio | 次により禁止されている: Google Style Guide 。テンプレートを多用するインターフェーススタイルに結び付いていることが懸念されているためです。 |
| 正規表現 | <regex> |
標準の正規表現ライブラリ | 正規表現ライブラリ | Chromium内の多くの正規表現ライブラリと重複しています。迷った場合はre2を使用してください。 |
| 共有ポインタ | std::shared_ptr |
参照カウントを通じてポインタの共有所有権を可能にする | std::shared_ptr | Chromium向けにはさらに多くの評価が必要であり、この機能を推進するだけの十分な動きもありません。 Google Style Guide。 ディスカッションスレッド |
| スレッドライブラリ | <thread> および関連ヘッダー。含まれるもの:
<future>、 <mutex>、 <condition_variable> |
標準のマルチスレッドライブラリを提供し、使用するのは std::thread および関連クラス |
スレッドサポートライブラリ | 次に含まれる多くのクラスと重複している: base/。当面は base/ クラスを使い続けてください。 base::Thread は MessageLoop と強く結合しており、置き換えが困難です。ロック/同期クラスを置き換えるために、標準ミューテックスやunique_lockなどの使用を検討すべきです。 |
禁止されているC++14ライブラリ機能
このセクションでは、Chromiumコードベースで許可されていないC++14ライブラリ機能を一覧にします。
| 機能 | スニペット | 説明 | ドキュメントリンク | 注意事項とディスカッションスレッド |
|---|---|---|---|---|
std::chrono リテラル |
using namespace std::chrono_literals;
auto timeout = 30s; |
これにより、 std::chrono 型をより簡単に構築できるようになる。 |
std::literals::chrono_literals::operator""s | 次が禁止されているため、禁止されている: <chrono> 。 |
結論
有名なオープンソースプロジェクトのソースコードを調べ、その設計と実装の選択を理解することは、効率的なコードの書き方を学ぶための最良の方法の1つかもしれません。有名なC++プロジェクトは、一般的に、ベストプラクティスの適用に努めるC++エキスパートによって開発されています。
要約すると、Chromiumのソースコードに目を通してみてください。その時間をかける価値は十分にあります。
