MyGeneration を nHibernate と共に使用して、基本的な POCO オブジェクトと XML マッピング ファイルを作成します。コード ジェネレーターは良い考えではないと考える人がいると聞いたことがあります。現在の最良の考え方は何ですか?何千行もの理解できないコードが生成されると、コード生成が悪いだけですか?
26 に答える
コードジェネレーターによって生成されたコードは、(一般化として) 人間の介入によって後で編集される状況では使用されるべきではありません。Visual C++ で生成されたコードのさまざまな化身のウィザードなどの一部のシステムでは、プログラマーが手動で編集する必要がありました。これは、開発者が生成されたコードを分解して理解し、修正する必要があったため、一般的ではありませんでした。それはまた、生成プロセスが一発であることを意味しました。
生成されたコードは、システム内の他のコードとは別のファイルに存在し、ジェネレーターからのみ生成される必要があります。生成されたコード コードは、人がそれを変更してはならないことを示すために、そのように明確にマークする必要があります。私はかなりの数のコード生成システムを実行する機会がありましたが、そのように生成されたすべてのコードには、前文に次のようなものがあります。
-- =============================================================
-- === Foobar Module ===========================================
-- =============================================================
--
-- === THIS IS GENERATED CODE. DO NOT EDIT. ===
--
-- =============================================================
Code Generation in Actionは、このテーマに関する非常に優れた本です。
コード ジェネレーターは優れていますが、悪いコードは悪いものです。
このページの他の回答のほとんどは、「いいえ、生成されたコードがあまり良くないことが多いためです」という行に沿っています。
次の理由により、これは悪い答えです。
1) ジェネレーターは他のツールと同じです。誤って使用した場合は、ツールのせいにしないでください。
2) 開発者は、優れたコードを 1 回で作成できると自負する傾向がありますが、1 回限りのプロジェクトでコード ジェネレーターを使用することはありません。
すべての Java プロジェクトで永続化のためにコード生成システムを使用しており、生成された数千のクラスが本番環境にあります。
マネージャーとして、私が彼らを気に入っている理由は次のとおりです。
1) 信頼性: そのコードには重大なバグが残っていません。何年にもわたって徹底的にテストされ、洗練されてきたので、デバッグ時に永続層について心配することはありません。
2) 標準化: すべての開発者コードはこの点で同一であるため、同僚から新しいプロジェクトを取り上げるときに学ぶことはほとんどありません。
3) 進化: 物事を行うためのより良い方法を見つけた場合、テンプレートを更新し、何千ものクラスを迅速かつ一貫して更新できます。
4) 革新: 将来別の永続化システムに切り替える場合、すべての永続化クラスがまったく同じ API を持っているという事実により、私の仕事ははるかに簡単になります。
5) 生産性: 数回クリックするだけで、メタデータから永続オブジェクト システムを構築できます。これにより、退屈な開発時間を何千時間も節約できます。
コード生成は、コンパイラを使用するようなものです。個々のケースでは、より最適化されたアセンブリ言語を記述できる場合がありますが、多数のプロジェクトでは、コンパイラにそれを実行してもらいたいと思いますよね?
カスタマイズを失わずにクラスを常に再生成できるようにするために、単純なトリックを採用しています。生成されたすべてのクラスは抽象クラスです。次に、開発者は具象クラスでそれを拡張し、カスタム ビジネス ロジックを追加し、標準とは異なる基本クラス メソッドをオーバーライドします。メタデータに変更があった場合、彼はいつでも抽象クラスを再生成できます。新しいモデルが具象クラスを壊した場合、コンパイラは彼に知らせます。
コード ジェネレーターに関して私が経験した最大の問題は、メンテナンス中です。生成されたコードを変更し、スキーマまたはテンプレートを変更して再生成しようとすると、問題が発生する可能性があります。
問題の 1 つは、変更したコードに加えた変更をツールで保護できない場合、変更が上書きされることです。
私が見たもう 1 つの問題は、特に Web サービス用の RSA のコード ジェネレーターで、生成されたコードを変更しすぎると、ジェネレーターが不一致があると不平を言い、コードの再生成を拒否することです。これは、変数の型を変更するような単純なことで発生する可能性があります。次に、コードを別のプロジェクトに生成し、結果を元のコードにマージすることに行き詰まります。
コードジェネレーターは生産性に恩恵をもたらす可能性がありますが、探すべきことがいくつかあります。
やりたいように働きましょう。
生成されたコードに合わせて生成されていないコードを曲げる必要がある場合は、おそらく別のアプローチを選択する必要があります。
通常のビルドの一部として実行します。
出力は中間ディレクトリに生成されるべきであり、ソース管理にチェックインされるべきではありません。ただし、入力はソース管理にチェックインする必要があります。
インストールなし
理想的には、ツールをソース管理にもチェックインします。新しいビルドマシンを準備するときに人々に物をインストールさせるのは悪いニュースです。たとえば、分岐する場合は、コードを使用してツールをバージョン管理できるようにする必要があります。
必要に応じて、ソースツリーのコピーを使用してクリーンなマシンを取得する単一のスクリプトを作成し、必要に応じてマシンを構成します。完全に自動化してください。
編集出力なし
出力を編集する必要はありません。出力がそのままでは十分に役に立たない場合は、ツールが機能していません。
また、出力には、生成されたファイルであり、編集してはならないことが明確に示されている必要があります。
読み取り可能な出力
出力は適切に記述およびフォーマットする必要があります。出力を開いて、問題なく読み取ることができるようにする必要があります。
#line
多くの言語は、#line
ディレクティブのようなものをサポートしています。これにより、たとえばコンパイラエラーメッセージを生成するときやデバッガにステップインするときに、出力の内容を入力にマップして戻すことができます。これは便利な場合もありますが、実際にうまく行わないと煩わしい場合もあるため、必須ではありません。
私のスタンスは、コード ジェネレーターは悪くないということですが、コード ジェネレーターの多くの用途は悪いものです。
時間を節約するために優れたコードを作成するコード ジェネレーターを使用している場合、それは素晴らしいことですが、多くの場合、最適化されていないか、多くのオーバーヘッドが追加されます。
振る舞いをクラスに混ぜたい場合、コード生成はあなたにいくらかの悲しみを引き起こすかもしれません。同様に生産的な代替手段は、属性/注釈と実行時の反映である可能性があります。
コンパイラはコード ジェネレーターであるため、生のマシン コードでのみプログラミングする場合を除き、コンパイラは本質的に悪いものではありません。
ただし、コード ジェネレーターは生成されたコードを常に完全にカプセル化する必要があると思います。つまり、生成されたコードを手動で変更する必要はありません。変更は、ジェネレータへの入力を変更してコードを再生成することによって行う必要があります。
Fran Tarkenton があなたに売り込もうとしているのがメインフレーム COBOL コード ジェネレーターであるなら、絶対にイエスです!
コード生成を使用するときに多くの人が犯す間違いは、生成されたコードを編集することです。コードを編集する必要があると感じた場合、実際にはコード生成ツールを編集する必要があることに注意してください。これは生産性の向上に役立ちます。生成されるコードと常に格闘していると、生産性が犠牲になります。
私が見つけた最高のコード ジェネレーターは、コードを生成するテンプレートを編集できるものです。テンプレートベースで、テンプレートは簡単に編集できるため、この理由で Codesmith が本当に気に入っています。生成されたコードに欠陥があることがわかった場合は、テンプレートを編集してコードを再生成するだけで、その後は永遠に問題ありません。
私が発見したもう 1 つのことは、多くのコード ジェネレーターは、ソース管理システムで簡単に使用できないということです。これを回避する方法は、コードではなくテンプレートをチェックインすることであり、生成されたソース管理にチェックインするのは、生成されたコード (主に DLL ファイル) のコンパイル済みバージョンだけです。何百もの生成されたファイルではなく、いくつかの DLL をチェックインするだけでよいため、これにより多くの手間が省けます。
私は以前にいくつかのコード ジェネレーターを書いたことがあります。
オブジェクト - コレクション - ユーザー コントロールの設計を明確に定義したら、コード ジェネレーターを使用して基本を構築することができます。これにより、開発者としての時間をより効果的に複雑なものの構築に使用できます。 300 以上のパブリック プロパティの宣言と変数の宣言を作成するには? 無意味な反復作業よりも、ビジネス ロジックに没頭したいのです。
現在のプロジェクトでは、コード ジェネレーターを多用しています。つまり、初めてコードを生成することの「明らかな」利点 (コーダー エラーやタイプミスがないこと、標準のコーディング スタイルへの準拠が向上したこと) と、メンテナンス モードで数か月経過した後の予想外の欠点の両方を見てきたことを意味します。実際、私たちのコード ジェネレーターは、最初はコードベースの品質を向上させました。完全に自動化され、自動化されたビルドと統合されていることを確認しました。ただし、次のように言います。
(1) コードジェネレーターは松葉杖になることができます。現在、私たちのシステムには、保守が困難なコードの巨大で醜い塊がいくつかあります。これは、過去のある時点で、適切な分析とクラスを実行するよりも、コード生成 XML ファイルに 20 の新しいクラスを追加する方が簡単だったためです。リファクタリング。
(2) ルールの例外はあなたを殺します。コード ジェネレーターを使用して、数百の画面およびビジネス オブジェクト クラスを作成します。当初、クラスにどのメソッドを表示できるかについて標準を適用しましたが、すべての標準と同様に、例外を作り始めました。さて、私たちのコード生成 XML ファイルは巨大なモンスターであり、選択したクラスに挿入される Java コードの特別なケースのスニペットでいっぱいです。解析または理解することはほとんど不可能です。
(3) 非常に多くのコードがデータベースの値を使用して生成されるため、開発者が個々のワークステーションで一貫したコード ベースを維持することは困難であることが証明されています (データベースには複数のバージョンが存在する可能性があるため)。ソフトウェアを介したデバッグとトレースははるかに難しく、クラス間の余分な抽象化と暗黙の関係により、チームの初心者はコードの「フロー」を理解するのにはるかに時間がかかります。IDE は、コード生成クラスを介して通信する 2 つのクラス間の関係を取得できません。
それはおそらく今のところ十分です。コード ジェネレーターは、開発者の個々のツールキットの一部として優れていると思います。ボイラープレート コードを書き出す一連のスクリプトを使用すると、プロジェクトの開始がはるかに簡単になります。しかし、コード ジェネレーターによってメンテナンスの問題がなくなるわけではありません。
これはワークフローの質問です。ASP.NETはコードジェネレーターです。XAML解析エンジンは、MSILに変換される前に実際にC#を生成します。コードジェネレーターが開発ワークフローから分離されたCodeSmithのような外部製品になる場合、プロジェクトの同期を維持するために特別な注意を払う必要があります。たとえば、生成されたコードがORM出力であり、データベーススキーマに変更を加える場合は、コードジェネレーターを完全に放棄するか、C#の機能を利用して部分クラス(メンバーを追加できる)を操作する必要があります。および既存のクラスへの機能を継承せずに)。
私は個人的に、ジェネレーターワークフローの孤立した/Alt-Tabの性質が嫌いです。コードジェネレーターが私のIDEの一部ではない場合、それはごちゃごちゃしているように感じます。Entity Spaces 2009(まだリリースされていません)などの一部のコードジェネレーターは、前世代のジェネレーターよりも統合されています。
コードジェネレーターの目的に対する万能薬は、コンパイル前のルーチンで楽しむことができると思います。C#やその他の.NET言語にはこれがありませんが、ASP.NETはこれを楽しんでいます。そのため、たとえば、SubSonicはASP.NETで非常にうまく機能しますが、それ以外はあまり機能しません。SubSonicは、通常のASP.NETコンパイルが開始される直前のビルド時にC#コードを生成します。
ツールベンダー(つまりMicrosoft)に、ビルド前のルーチンをより完全にサポートするよう依頼してください。これにより、コードジェネレーターを、分離して維持する必要のある外部出力コードファイルとして手動で管理するのではなく、メタデータを使用してソリューションのワークフローに統合できます。
ジョン
最初のC++コンパイラは、Cコード(CFront)を吐き出すコードジェネレータでした。
これがコードジェネレーターの賛成か反対かはわかりません。
特定の (多くはありませんが) 場合には、それらが役立ちます。データベース テーブル内のルックアップ タイプのデータに基づいてクラスを生成する場合などです。
コード生成は、プログラミングをより困難にする場合 (IE、不十分に生成されたコード、またはメンテナンスの悪夢) には良くありませんが、プログラミングをより効率的にする場合には優れています。
常に最適なコードが生成されるとは限りませんが、必要に応じて、節約された開発者の工数がいくつかの小さな問題を補うと判断する場合があります。
そうは言っても、ORM コード ジェネレーターに対する私の最大の不満は、スキーマが変更された場合、生成されたコードのメンテナンスが PITA になる可能性があることです。
コード ジェネレーターは悪くありませんが、別の解決策が存在する状況で使用されることがあります (つまり、オブジェクトの配列がより適切で、数行のコードで実行できる場合に、100 万個のオブジェクトをインスタンス化する場合など)。
もう 1 つの状況は、それらが正しく使用されていないか、不適切にコーディングされている場合です。バグが原因で悪い経験をしたり、正しく構成する方法を誤解したりしたため、コードジェネレーターを断念する人が多すぎます。
しかし、コード ジェネレーター自体は悪くありません。
-アダム
コード ジェネレーターの最適なアプリケーションは、プロジェクト全体がモデルであり、プロジェクトのすべてのソース コードがそのモデルから生成される場合です。私はUMLとそれに関連するがらくたについて話しているのではありません。この場合、プロジェクト モデルにはカスタム コードも含まれます。
その場合、開発者が気にする必要があるのはモデルだけです。単純なアーキテクチャの変更により、何千ものソース コード行が即座に変更される可能性があります。しかし、すべてが同期されたままです。
これは私見の最良のアプローチです。ユートピアに聞こえますか?少なくとも私はそうではないことを知っています ;) 近い将来わかります。
それらは他のツールと同じです。他のものよりも良い結果をもたらすものもありますが、それらをいつ使用するかを知るのはユーザー次第です. ネジをねじ込む場合、ハンマーはひどいツールです。
これは、非常に論争の的となっている問題の 1 つです。個人的には、コード ジェネレーターは、ほとんどが最適化されていないくだらないコードを出すため、本当に悪いと思います。
しかし、その質問は、あなただけが答えられる質問です。多くの組織では、開発時間はプロジェクトの実行速度や保守性よりも重要です。
コード ジェネレーターを使用して、データ エンティティ クラス、データベース オブジェクト (トリガー、ストアド プロシージャなど)、サービス プロキシなどを生成します。パターンに従って反復的なコードが多く、多くの手作業が必要な場合は、コード ジェネレーターが役立ちます。ただし、保守性が苦痛になるほど使いすぎるべきではありません。それらを再生成したい場合にも、いくつかの問題が発生します。
Visual Studio や Codesmith などのツールには、ほとんどの一般的なタスク用の独自のテンプレートがあり、このプロセスを簡単にします。ただし、自分で展開するのは簡単です。
戻ってきてコードで何が起こっているのか理解できない場合、保守性の問題になる可能性があります。したがって、容易な保守性と比較して、プロジェクトを迅速に完了することの重要性を何度も比較検討する必要があります。
保守性 <> 簡単または迅速なコーディング プロセス
My Generation を Entity Spaces で使用していますが、問題はありません。スキーマを変更した場合は、クラスを再生成するだけで、すべてうまくいきます。
それらは、プログラムを長期的に維持する能力を無効にする松葉杖として機能します。
コード ジェネレーターは、優れたコード ジェネレーターであると仮定すると優れています。特に、非常に冗長な c++/java の動作。
ミッチェルが頭を打ったと思います。コード生成にはその役割があります。コンピューターに作業を任せた方が効果的な場合もあります。コードの変更にかかる時間コストが小さい場合は、特定のコンポーネントの実装について自由に考えを変えることができます。もちろん、コード ジェネレーターの出力を理解することはおそらく重要ですが、常にそうとは限りません。いくつかの C++ アプリが名前付きパイプを介して C# アプリと通信する必要がある、完成したばかりのプロジェクトの例がありました。メッセージを定義し、トランザクションの両側で生成されたすべてのクラスとコードを含む、小さくて単純なファイルを使用する方が適切でした。プログラマーが問題 X に取り組んでいたとき、
最近のプロジェクトでは、独自のコード ジェネレーターを作成しました。すべてのデータベースと、ビューおよびビュー コントローラー クラスのすべての基本コードを生成しました。ジェネレーターの構築には数か月かかりましたが (主にこれを行ったのはこれが初めてであり、2 回の失敗があったためです)、最初に実行したときに採算が取れ、アプリ全体の基本的なフレームワークを約10分。これはすべて Java で行われましたが、Ruby は、特に小規模で 1 回限りのタイプのプロジェクト向けの優れたコード記述言語になります。一番良かったのは、コードとプロジェクト組織の一貫性です。さらに、基本的なフレームワークを前もって考えておく必要がありますが、これは常に良いことです。