web-dev-qa-db-ja.com

C ++のリファクタリング

C++リファクタリングについて otherquestions があることは知っていますが、私のニーズを満たすものはありません。

JavaおよびPythonプログラミング)の背景がありますが、今はC++に近づいています。アジャイルコーディングに関する本を読んだ(そして絶対に好きです)。 テスト駆動開発 (TDD)、リファクタリングなど。最初に頭に浮かぶのは「クリーンなコード」です。このことから、多くのことを学びました:関数を短くして、クラスを維持してください短く、変数/クラスの名前を一致させるなど。

私はこの作業方法が非常に好きです:最初に問題を解決し、次に小さな関数をリファクタリングし(1つの関数は1つのことだけを実行します)、サブクラスを追加します。

この作業方法は、ファイルの追加、関数の名前の変更、クラスの名前の変更など、最近のIDEによって簡単になると強く信じています。

CMtQt Creator の内部でC++でコーディングしています。これらすべてのことはより困難です。ファイルを追加することも「より困難」です(1つのヘッダーファイル、1つのソースファイルを生成し、それらをcmakelist.txtに追加して、もう一度cmakeなどを実行する必要があります)。ファイル名の変更(すべてのインクルードを手動で変更する必要があります)、またはJava with Eclipse でコストがかからない)の強力なリファクタリング方法について考えると、頭痛がします。

つまり、「難しい」という意味では「難しい」ではありませんが、人間の心は一種の怠惰です。

Java with Eclipse IDE with Eclipse ..のように..リファクタリングは楽しい部分です;いくつかのクリックとボイラー、それは行われます。合格するたびに行いますテストは簡単で、楽しく、小さな関数と素敵な名前の付いたクリーンなコードを読むのが好きです。

今では、主にコストなしでそれを行うことができるツールがないため、すべてがより困難です。新しいファイルを作成したくないので、1つの非常に長い.hファイルに複数のクラスを記述し、クラス/関数/変数をより適切な名前で変更し、すべてを手動で変更するため、何時間も費やしましたstd lib Qt Creatorに関係する関数の属性を自動的に変更するとテンプレートが削除されるため、それを回避するため、長い関数を含めます。

これは非常にイライラします..私に何をアドバイスできますか?クリーンなコードを書く「ルール」でもっとリラックスする必要がありますか?私はこのことについて考えずに、物事がうまくいくようにするためだけに考えなければならないのですか?または(おそらくこれがより重要な質問です)、他の作業方法について考えなければなりませんか?テストに合格したときのリファクタリングを最小限に抑えるために、増分/反復/アジャイルの方法ではなく、 waterfall を増やし、コーディングの前により多くの時間を費やして設計しますか?

とにかく、私は良いプログラマーとはほど遠いので、どんなコメントも歓迎します:)

5
nkint

TL; DR:C++には古いコンパイルモデルと処理が難しい構文(高度にコンテキストに依存しているため)があり、ツールの作成が難しくなりますが、それらは存在します。 C++ではリファクタリングは少し難しいですが、他の言語よりも少し遅いだけです。

C++自体と関連ツールに関する追加情報が必要なだけだと思います。どれどれ:

  1. ファイルの名前変更などに役立つC++用のリファクタリングツールがあります。1つの例は、Visual Studioプラグイン Visual Assist X です。 Eclipseや他のエディターには、リファクタリングツールもいくつかあると思います。それらは不完全ですが、何年もの間私にとって非常に役に立ちました。さて、あまり役に立たないのは、JavaまたはPythonのような他の言語では「強制」されている)通常の方法でコードを編成しない場合です。 =またはC#の理由...

  2. C++は、非常に古いコンパイルモデルを使用することで多くの問題を抱えています。ある種のコード(ヘッダーが重い)のコンパイルが遅くなったり、ライブラリヘッダーの特定が困難になったりします。使用または開発するライブラリの種類に応じて、コンパイルしない理由を完全に理解するには、コンパイルを理解する必要があります。同じ方法でソースディレクトリを作成します。とにかく、これはツールをその周りに構築するのを難しくします。特に、マクロはモジュールをインポートする方法です。つまり、すべてコピー貼り付けです。

  3. ほとんどのクラスシステムを定義する場合、ヘッダー+ソースの定義は古典的ですが、C++で物事を行うための通常の/唯一の方法ではありません。たとえば、多くの Boost C++ライブラリはヘッダーのみであり、関連するcppファイルがないため、cppファイルを追加してコンパイルしないとコードをテストできません(ヘッダーは実際には存在しません)コンパイラについては、コンパイルモデルを参照してください)。

  4. また、C++構文は非常にコンテキストに依存しているため、C++を正しくリファクタリングできるツールには、処理されたソースコードに関する情報とコンパイラーと同じ種類の情報が必要です。これが [〜#〜] llvm [〜#〜] の取り組みの1つの理由であり、解析して、C++コードの正しいモデルを持ち、ツールの実装で使用できるライブラリを提供します。ただし、これまでに使用できるツールはごくわずかですが、LLVMの取り組みから、今後数年で多くのリファクタリングツールが登場すると予想しています。

  5. Java、C#、PythonおよびRubyのような、近代的で構造化された明確なモジュールシステムがあることは、コンパイル速度が明らかに優れていますが、より重要なことにコンパイラはモジュールとは何か、モジュールがどのようにリンクされるかを知っています。C++ ISO標準委員会は、C++ 17バージョンに準備ができている場合に追加できるように、このような最新のモジュールシステムに取り組んでいます。問題は、これに関する作業はLLVM/ Clang コンパイラで行われています。

  6. CMakeはメタビルドシステムであることに注意してください。ここで私が言っているのは、使用するエディションツール(たとえば、Visual Studioで使用しています)とは独立しており、ファイルの追加/削除/名前変更のプロセスに、間接指定を追加するということです。 C++には標準のビルドシステムがないため、C++はそのようなツールの1つですが、プロジェクトのメタ記述です。たとえば、Visual StudioまたはQtCreatorのデフォルトのプロジェクト形式を直接使用する場合、エディターで直接行うことができるため、ファイル名を変更する方がはるかに簡単です。しかし、実際にはこれらのプロジェクトファイルは他のエディター/プラットフォームと互換性がありません。そのため、CMakeを使用して、さまざまな開発設定用のプロジェクトファイルを確実に生成できるようにします。基本的に、CMakeを使用しない場合、リファクタリングは高速になりますが、クロスエディター/クロスプラットフォームのビルドシステム機能が失われます。

そうは言っても、C++リファクタリングに関するこれまでの私の経験は、VAssistXのようなものがあれば、ほとんどのことを行うのに十分であるということです。実際にファイルの名前を変更することは、他の言語よりも正しく実行するのに時間がかかりますが、それほど長くはありません。そうは言っても、C++プロジェクトへの変更がより迅速に確認できると便利です。そのため、モジュールシステムが本当に必要です。コンパイルに1時間以上かかるコードをまだ使用していないことを願います。この場合、人々がコードをあまり変更したくないので、リファクタリングへの影響は計り知れません。これはC++コミュニティにとって大きな問題であり、これを修正するための作業が進行中です。しかし、それは数年かかります。

13
Klaim

今では、主にコストなしでそれを行うことができるツールがないため、すべてがより困難になっています。私は怠惰によって引き起こされる悪い態度に身を任せています:新しいファイルを作成したくないので、単一の非常に長い.hファイルにいくつかのクラスを記述します。

これについて考えさせてください。それはポップアップし続け、私は困惑したままです。なぜ人々は物事を別々のファイルにパッケージ化することに取りつかれているのですかここ2013年?ヘッダーに複数のクラスを配置すると、遅延または不良と見なされるのはなぜですか?

ヘッダーについては言い訳を見つけることができましたが、実装ファイルにも同じことが当てはまります。なぜかと思うと、私が恐れている一般的な答えは「自分のものが簡単に見つかるように」です。そしてデモは、彼がソリューションエクスプローラーを呼び出し、関係のないブランチを閉じるのに1分を費やし、それがどのプロジェクトになるかをもう1分考え、それから3つに配置し、内部で異なるサブブランチを試行し、最終的にクラス名に一致するファイルを(目を使用して)検索します。 50の類似した名前のリストから。最後に小さなフーレイでそれを開きます。背中を6回撃って川に飛び込みたいです。

VA-Xの「プロジェクトでファイルを開く」方法と、より適切な「シンボルを探す」方法、ワンクリックナビゲーション、または最後の手段として古いスタイルのファイル検索を使用すると、数秒でどこからでも何でも生成できます。そして、今説明したばかりのWTFメソッドを使用しても、50個のファイルすべてが1つに連結されている場合は、より早く見つけることができます。

C++でビルドをいじる人は、時間は.cppファイルの数に非常に比例し、ファイルの長さは無関係であることをよく知っています。 50個のファイルに50個のクラスを配置すると、1つのファイルにすべてを配置する場合よりも50倍遅くコンパイルされます。ええと、たぶん25回だけかもしれませんが、それはまだ大きな数字です。

非常に古いエディターでは、個別のファイルでない限り、複数の場所で作業することが問題になる可能性があります。ただし、同じファイルで無制限の数のウィンドウを要求でき、通常は任意のウィンドウを複数のペインに分割します。また、ブックマークを1つのストロークでドロップすると、削除されるまで保持されます。

そして、ドキュメント化/読み取りのために、doxygenがあります。インラインコードが削除されて、クラスが個別に表示されます。ソースでのクラスの表示方法に関係なく。

ソースを直接読み取ることを選択した場合でも、「クラス」が基本単位になるのはいつですか?常に「パッケージ」、「モジュール」、「ライブラリ」など、簡潔な哲学と、列挙型、マクロ、およびその他のギズモをサポートするクラス、関数の公平なコレクションがありました。場所。

質問で言及された一連の問題は、実際にはこの人為的な分裂から生じています。宣言はヘッダーで維持する必要がありますか?それらのうちいくつが実際に「エクスポート」用であり、何個がコンポーネント内で内部的に使用するためのものですか?後者の関数の大部分は、関数は初期に定義された静的な関数であるため、分割なしでは必要ありません。メンテナンスの面で非常に軽いものは何ですか。

結合の唯一の欠点は、静的/名前空間オブジェクトが衝突する可能性があることです。しかし、うまくいけば、かなり前にブラックリストに載っています。

問題の少ない状態にシステムをリファクタリングしてみませんか?そして、ノアが残したいくつかのアイデアに従って人工的に頭痛の種を導入していませんか?

7
Balog Pal