web-dev-qa-db-ja.com

古いC ++プロジェクトを書き直すか、ゆっくりとリファクタリングするには

私たちのチームは最近、比較的大きなプロジェクト(約25万ライン)を他の会社から引き継ぎました。 C++ Builderを使用して開発されており、Ui側をQtに移植する予定です。ほとんどのUiコードはビジネスロジックから分離されています(そうです!)が、ロジック側はかなり混乱しています。

ダイヤモンドの継承はたくさんありますが(ありがたいことに仮想継承)、コードの理解が非常に難しくなります。

私たちが進めるドキュメントはほとんどありません。何が古くなっているのですか(コメントが含まれています)。

私はDoxygenを使用してクラス図を生成しました、これは最も複雑なものです(クラス名のほとんどを削除する必要がありましたが、より重要なものをいくつか保持し、標準のC++データ型とstdクラスを保持しました、はい、それらはstdから継承します)

confusing inheritance

これまでのところ、基本プログラムをQtに変換することができ、プログラムの機能を少しずつ変換し始めることができるようになりました。問題は、それは長期的に価値があるのでしょうか?私たちはこのソフトウェアを私たち自身の長期的に維持したいと考えています。

この種の継承の混乱を解くために取るべき一般的なアプローチはありますか、それとも単にゼロから再設計して既存のコードの一部のみを保持するべきですか?

編集:いくつかの詳細

ザビオールは、ゼロから始めるべきではない理由についての記事へのリンクを投稿しましたが、プトレマイオスもいくつかの良い質問を持ち出しました。

私たちのプログラムは「バグフリー」ではありません。ユーザーがほとんどの回避策を持っている既知の問題があります。これらの問題の「一覧」はありません。現在、すべての既存のユーザーが物事を自分のものにしておく傾向があるため、1人1人と話し合うことによって編集されています。

私たちは皆、このプロジェクトの新しい開発者です。私たちの唯一のリソースは、プロジェクトの存続期間の半分ほどでプロジェクトに取り組み始めた開発者です。彼は主に電子メール/チャットで利用できます。また、コードの一部がどのように機能するかについてのドキュメントもまとめました。

このプログラムは、これまで内部ツールとしてのみ使用されてきました。それを商業的に実行可能にしたいと考えています。

編集2:

私たちがやりたい最も重要なことの1つは、プログラムをQtに置くことです。現在、C++ BuilderのVCLフレームワークを使用しており、チームの誰も精通しておらず、ライセンスは1つしかありません。 VCLからQtへの移植作業中に、厄介なコード構造を見つけ、「変換」対「やり直し」の決定に疑問を投げかけました。

17
Boumbles

最初から書き直して再設計すると、2つの大きな問題が発生します。

  1. スペックがありません。仕様があると思うかもしれませんが、REAL仕様は古いコードであることがわかります。そのため、実際に何が行われるのかを理解するためにそれを掘り下げる必要があります。それで、新しいシステムに何をさせるべきかを理解できます。
  2. あなたは、(そのクラスの階層を見ると、おそらく何年か)長い間、販売可能な製品を手に入れることができなくなります。つまり、古いものを並行して維持するか、長期間の出荷をあきらめる必要があります。

それは悪臭を放ちますが、おそらく古いものをより良くしようとする必要があるでしょう。触れたものすべてのテストを作成し、大きなセクションを抜粋して改善することをためらわないでください。ただし、一度にすべてを書き直そうとしないでください。プロジェクトはそのような試みに耐えられないかもしれません。

36
Michael Kohne

このサイズのプロジェクトの書き換えは、Michael Kohneの投稿の理由により失敗する運命にあります。

バグの原因がリファクタリングなのか元のコードなのかわからないため、バグの多いコードベースのリファクタリングは困難です。

私はかなりの期間、バグ修正のみを行うというアプローチを取ります。これらのバグ修正の一部として、明らかに間違っている小さなセクションを書き直すことができます。これの利点は次のとおりです。

  1. 開発者に、コード、アーキテクチャ、製品の動作について多くを学ぶ機会を与えます。重要なリファクタリングを行うには、この知識が必要です。
  2. 主要な再構築作業の前にコードベースを安定させます。
  3. 後で大きな変更が行われている間、安定した製品を販売できます。

また、バグを見つけて修正を確認するために、バグ追跡システムと何らかのQAが必要なようです。

6
17 of 26

プロジェクトに大規模なリファクタリングを実装したときは、通常、最初からアーキテクチャーを作り直し、最初にアーキテクチャーを証明する戦略を使用して、元のプロジェクトの開発を続けました。新しいアーキテクチャが証明されたら、既存のロジックを新しいアーキテクチャに大量に転送します。これは、バックグラウンドタスクとしてではなく、迅速に行うのが最善のようです。

やる価値はありますか?これは、プロジェクトに参加しないと判断が難しい問題ですが、次の問題について考えてください。

  1. 既存のコードベースは安定していてバグはありませんか?実際のコードを理解せずに既存のコードを見つけてパッチを当てるのにかなりの時間を費やさなければならない場合、理解されたコードを使用して再実装することによるサポートの削減によって節約される時間はかなり大きくなる可能性があります。

  2. 少なくとも元のコーダーと同じくらい製品についての知識がありますか?予期せぬ状況に対するバグ修正が原因でどれほど複雑で、設計が不十分だったのか。

  3. タスクを完了する時間はありますか?コードベースについて私が最も重視することの1つは一貫性です。一貫性のないコードは、チームの新しいメンバーをサポート、拡張、紹介するための悪夢です。

  4. 製品のビジネスルールを十分に理解していない場合は、現在のバージョンよりも悪い仕事をする可能性があります。

結論-質問の更新に基づいて、再実装を行うためのプロジェクトの十分な知識がないということです。現在の状況では、大幅なリファクタリングを行うことも危険です。少なくとも良いニュースは、現在の顧客が製品の使用を妨げるバグに遭遇しないことです。つまり、コードベースを理解する時間があります。これはあなたの最初の目標である必要があります。

4
Michael Shaw

私は自分自身がDelphi開発者であり(そしてVCLはObject Pascalで書かれています)、私は他の人に同意します。

VCL自体は主にWindows APIの概念と結びついており、非常に正確なOO変換を作成します。マルチプラットフォームの目的を持つQTとは異なります。

ビジネスロジックに関しては、それを(コードから)解読して、RULESの非常に正確な仕様(つまり、コードベースが表現および解決することを目的とした実際の問題の正確な概念)を記述できるようにします。これで、歩く方向がわかります。

1
Fabricio Araujo

それはあなたのビジネス状況に依存します。

と仮定する

  1. 特に最初からコードベースに慣れていないため、独自の最初のドラフトコードをリファクタリングしていた場合のように予測できないため、コードを完全にリファクタリングするには長い時間がかかります。

この仮定を前提として、このコードを移植するビジネスニーズを考慮する必要があります。コードを「維持したい」と言いました。それは正確に何を伴いますか?追加機能を追加しますか?またはマイナーな出力バグを修正するか、論理的には簡単ですが、見事にクラッシュします。

リファクタリングから他にどのようなメリットがありますか?コードはより移植性が高く、新しい環境やOSで使用できますか?一緒にビジネスニーズに適切に対応するプロジェクトに、より簡単に統合できますか?

ケースを決定または提示するときは、これらの質問を考慮に入れてください。

このタスクの短期、中期、および長期の目標を検討してください。短期的にはリファクタリングに多くの費用がかかる可能性がありますが、概念モデルを維持するつもりであれば、それはまったく新しい世代の製品の基礎として役立ちます。

逆に、ごちゃごちゃしたコードだけでなく、ビジネス環境に大きな変更がある場合はただし、概念モデル全体廃止されている場合、バグの多い10個のブロックまたは混乱しやすいコードを選択するほうがよい場合があります。 、元の言語で書き直しますが、明確にして次に進んでください。ただそれを生かし、お金を節約し、後で本当に欲しいものを作り、あなたが持っているものや好きなものからレッスンを受け、あなたを導きたくない/あなたを導く必要がない

0
Andyz Smith

一般的に、混乱しているため、リファクタリングするつもりだとあなたは言った。ええと、ユーザーは実行したいプログラムを望み、望んだことを実行します。古いプログラムのコード(彼らさえ見ていない)は混乱しているので、新しいプログラムを要求しません。

古いプログラムが何かをするのを妨げているなら、おそらく、あなたは時間、お金などを費やして、一からそれをすることができるでしょう。ただし、これには多くの点があることに留意してください。

1-悪いかどうか、ユーザーはいくつかのバグを回避する方法を知っています。アプリを書き直して完璧だとしても、ユーザーは最初はそれをどのように処理するかを知りません。誰よりも、変更が好きではありません。

2-ユーザーが回避策を知っている=文書化されていないことを意味するため、新しいソフトウェアを実行しようとすると、一部の機能が見落とされる可能性があります(古いコードに含まれていないか、誰かが見落とすためです)。

3-ユーザーがそれを書き直すことを正当化するための利益を得る必要があります:同じシステムで終わるためにそれをすべてやり直すことは、ユーザーに利益がないことを意味します

4-新しいソフトウェアには新しいバグがあり、それはあなたと対戦します

5-ユーザーは、すでに持っているものをやり直すのではなく、何か新しいシステムや別のシステムなどを望んでいませんか?

0
woliveirajr

大規模なプロジェクト(特に、まだ取り組んでいないプロジェクト)を見る場合、1つのことを実現することが非常に重要です。誰もがあなたがそれを完全に理解することを期待すべきではありません。あなたは分割と征服の信条に従って生きるべきです。それは私がいつも使ってきたテクニックで、まだ私を失望させていません。

自分の注意を必要とする複数の重傷を負った患者がいる外科医を自分で考えてください。足の傷に感染があるとしましょう。これは、コードから取り除く必要のある不良ライブラリ/コードに類似しています。あなたは最初に感染の範囲を確立しようとします。類推は、ライブラリ/コードを実際に使用しているファイルの数と使用の性質を確認するための簡単なgrepです。これはプロセス全体の重要なステップであり、通常は最も面倒です。しかし、これを行った後、あなたが達成することはあなたの境界の特定であり、これらは重要です。範囲がわかったら、麻酔を適切に適用できます(例により局所麻酔が適していると想定)。コードの点では、これは境界に近い適切な場所のインターフェース、ユニットテストなどです。境界でインターフェースを構築してユニットテストを作成すると、境界をマークできます。境界をマークした後は、ほぼ自由に感染/不正なコードを攻撃できるはずですが、インターフェースと境界ユニットテストでは、道に迷うことはありません。境界内のすべての変更(つまり、すべてのへこみとペイント)が完了すると、アプリケーションは、これまでに行われた操作について何も知らなくても、動作するはずです。

次に、すべてをターゲットにするまで、次のライブラリ/不良コードに対してこのプロセス全体を繰り返します。したがって、要約すると、そのような大自然の醜い獣に取り組むとき、戦いを選び、焦点を合わせることが最も重要です。幸運を。

0
siphr