巨大なStrutsアクションに対処するには?
-
03-07-2019 - |
質問
Struts 1.2.4を使用して、この巨大なレガシーJava Webアプリを継承しました。アクションに関して特定の質問があります。ほとんどのページにはActionが1つだけあり、processExecute()メソッドは恐ろしいモンスターです(要求パラメーターに基づいた非常に長く、大量のネストされたifステートメント)。
アクションがコマンドパターンの実装であることを考えると、これらのアクションをユーザージェスチャごとに1つのアクションに分割することを考えています。これは大きなリファクタリングになりますが、私は疑問に思っています:
- これは正しい方向ですか?
- モノリシックなアクションの内部の混乱を処理する中間的なステップ、つまりパターンはありますか?おそらくアクション内の別のコマンドパターンですか?
解決
これに対処する私の方法は次のとおりです。
- 「すべてを一度に」しないでください
- 何かを変更するときはいつでも、見つけたよりも良いままにしておきます
- 条件を別のAction実装に置き換えることは1つのステップです。
- さらに良い:フレームワークを変更するときに使用できるように、実装をActionクラスから分離します
- Strutsを参照せずに新しいコマンドの実装を絶対に維持し、これらの実装のラッパーとして新しいアクションを使用します。
- すべてのデータをコピーせずにStruts ActionFormを渡すために、Struts ActionFormにインターフェースを提供する必要がある場合があります。一方、通常は文字列の集まりであるActionForms以外のオブジェクトを渡すこともできます( Struts 1.2 ActionForms )
- パーツの新しい&への移行を開始より良い技術。 Struts 1.2がリリースされたときは素晴らしいものでしたが、永遠にサポートしたいものではありません。現在、いくつかの世代のより良いフレームワークがあります。
間違いなく他にもあります-申し訳ありませんが、ここで時間切れです...
他のヒント
Strutsアクションは、私の考えでは、あまり多くのコードを含むべきではありません。彼らは単にリクエストとレスポンスと直接やり取りする必要があります-フォームまたはリクエストパラメータからいくつかのデータを取得し、その情報をサービスレイヤーに渡してから、Responseオブジェクトに何かを入れるか、ユーザーのセッションにデータを保存します。
アクションクラスでの継承を避けることをお勧めします。最初は良いアイデアのように聞こえますが、遅かれ早かれ、実際にコードベースを堅牢にするよりも、あなたが靴磨きをしていることに気づくと思います。 Strutsには十分な基本アクションがあります。新しいアクションを作成する場合、Webレイヤーにあるはずのないコードを持っている可能性があります。
それは私の個人的な経験です。
この種のことは以前に扱ったことがあります。良い最初のステップは、Actionと元の巨大なアクションクラスの1つとの間の継承チェーンに別の基本クラスを挿入することです(ClassAと呼びます)。特に、すべてを一度に行う時間がない場合。その後、機能の一部を小さな並列Actionクラス(ClassB、ClassC)に引き出し始めることができます。元のClassAと新しいリファクタリングされたクラスに共通するものはすべて、新しい基本クラスにプルアップできます。したがって、階層は次のようになります。
Original Hierarchy: New Hierarchy:
Action Action
| |
| BaseA
(old)ClassA |
+--------+----------+
| | |
ClassB (new)ClassA ClassC
- 一度に1つのメソッドを実行する
- 後で再生できるテストケースを記録します。 ここの例(コードを通るパスをできるだけ多くヒットするようにしてください。つまり、このアクションを呼び出すページ上のすべてのユーザージェスチャー)
- メソッドをリファクタリングして、より小さなことを行うより小さなメソッドを作成することにより、複雑さを軽減します。
- これを行うときにテストを再実行します
この時点で、大きな巨大な迷惑なメソッドのリファクタリングバージョンができました。 今特定のアクションの作成を実際に開始できます。
新しくリファクタリングされたクラスを基本クラスとして使用し、リファクタリングされたこれらの小さなメソッドを使用して、特定の各アクションをサブクラスとして実装できます。
これを実行したら、クラス間で共有されるロジックの概要を把握し、必要に応じてこれらのメソッドをプルアップまたはプッシュダウンできます。
面白くありませんが、しばらくの間コードベースで作業する場合、時間と頭痛の種を節約できます。
難しい問題ですが、初期のWebアプリ開発の典型です。
まず最初に、どのロジックがビジネス行動を構成し、どのロジックが「フロー」を構成するかについて考え始める必要があります。 (つまり、ユーザーが見るもの)、および彼が見るもののコンテンツを取得するロジック。
工場やインターフェースなどすべてのルートをたどる必要はありません。遡及的な実装はあまり有用ではありません...しかし、ビジネスロジックとデータ取得ロジックをある種のデリゲートに統合し、そのロジックの成功/失敗に基づいてページフローを決定するためにstrutsアクションを残します。
そこから数週間かけて粉砕する必要があります
1つの長いメソッドは、ケースが非常に短い単一のswitchステートメント(トークン解析またはそのようなもの)である場合を除き、決して良いものではありません。
少なくとも、長いメソッドをわかりやすい名前の小さなメソッドにリファクタリングできます。
可能な場合は、フォームを調べることでメソッドが何をすべきかを認識してメソッドを開始し、さまざまなオプションに進むかどうかを選択できます。ただし、ネストされたifはありません。これらはコードを読みにくくする傾向があります。ただ
enum Operation {
ADD, DELETE;
}
...
Operation operation = determineOperation(form);
if (operation == Operation.DELETE) {
doDelete(form);
} else if (operation == Operation.ADD) {
doAdd(form);
}
そこまで行けば、あなたのロジックはすっきりときれいになり、リファクタリングは何でもできます。
難しいのは、ロジックを明確にすることであり、それを段階的に行うことができます。問題が何であるかを正確に理解するまで、パターンを選択しないでください。
コードのリファクタリングを計画している場合は、最初に既存のコードのテストを作成して、リファクタリングを開始した後にコードの機能を変更していないことを確認する必要があります。