約100行にわたる関数を記述したところです。それを聞いて、あなたはおそらく私に単一の責任について話して、リファクタリングするように促したくなるでしょう。これも私の直感ですが、ここに問題があります:関数は1つのことを実行します。これは複雑な文字列操作を実行し、関数本体は主に1つの詳細な正規表現で構成され、文書化されている多くの行に分割されます。正規表現を複数の関数に分割した場合、実際に言語を切り替えているので、実際には読みにくく読みやすいように感じ、正規表現が提供するいくつかの機能を利用する。これが私の質問です:
正規表現による文字列操作に関して、大きな関数本体は依然としてアンチパターンですか?名前付きキャプチャグループは関数と非常によく似た目的を果たしているようです。ちなみに、私は正規表現を通るすべてのフローのテストをしています。
あなたが遭遇しているのは、合理的な意思決定よりも「ベストプラクティス」を装ってガイドラインへの奴隷の順守を支持する人々の意見を聞くことから生じる認知的不協和です。
宿題を明確に終えました。
これらの点のいずれかが真でなかった場合、私は最初にあなたの関数が機能する必要があると言います。したがって、コードを現状のままにしておくことに1票の投票があります。
2番目の投票は、オプションと、それぞれから得られる(および失う)オプションを確認することから行われます。
この決定は、読みやすさや長さなど、どちらを重視するかにかかっています。長さがいいと信じているが、読みやすさは重要である後者は前者よりもいつでも使用されます。
結論:壊れていない場合は修正しないでください。
正直なところ、あなたの機能は「一つのこと」をするかもしれませんが、あなたが自分で述べたように
正規表現を複数の関数に分解し始めることができました。
つまり、正規表現コードは多くのことを行います。そして、それはより小さく、個別にテスト可能なユニットに分解できると思います。ただし、これが良いアイデアである場合は、答えるのは簡単ではありません(特に実際のコードを見ない場合)。そして、正しい答えは「はい」でも「いいえ」でもないかもしれませんが、「まだではありませんが、次回はその正規表現で何かを変更する必要があります」。
言語を効果的に切り替えているので、実際にはそのように読みやすさが失われるような気がします
そしてこれがコアポイントです-あなたはreg ex languageで書かれたコードの一部を持っています。この言語自体は、抽象化の優れた手段を提供していません(「名前付きキャプチャグループ」を関数の代わりとして使用することは考えていません)。したがって、「正規表現言語で」リファクタリングすることは実際には不可能であり、小さい正規表現をホスト言語と織り交ぜても、実際には読みやすさは改善されない場合があります(少なくとも、あなた感なので、疑問がある、そうでなければあなたは質問を投稿しなかったでしょう。これが私のアドバイスです
他の上級開発者にコードを見せ(多分 https://codereview.stackexchange.com/ )、他の人があなたのやり方で読みやすさについて考えていることを確認します。他の人があなたと同じくらい読みやすい100行の正規表現を見つけられない可能性があるという考えを受け入れてください。時々、「それをより小さな断片に簡単に分解できない」という概念は、2番目の目だけで克服できる場合があります。
実際の進化可能性を観察してください-新しい要件が到着し、それらを実装してテストする必要がある場合でも、光沢のある正規表現はまだとてもよく見えますか?あなたの正規表現が機能する限り、私はそれに触れませんが、何かを変更する必要があるときはいつでも、この1つの大きなブロックにすべてを取り入れることが本当に良いアイデアであるかどうかを再考し、(真剣に!)小さいピースは良いオプションではありません。
保守性を観察してください-現在の形式で正規表現を効果的にデバッグできますか?特に、何かを変更する必要があり、テストで何かが間違っていることがわかった後、根本的な原因を見つけるのに役立つ正規表現デバッガーがありますか?デバッグが困難になった場合は、設計を再検討する機会にもなります。
1つの処理を実行する長い関数が、作業単位を処理する最も適切な方法である場合があります。 (お好みのクエリ言語を使用して)データベースのクエリを開始すると、非常に長い関数に簡単にアクセスできます。関数(またはメソッド)を記述された目的に限定しながら、より読みやすくすることは、関数の最も望ましい結果と考えるものです。
コードサイズに関しては、長さは任意の「標準」です。 C#の100行の関数が長すぎると考えられる場合、Assemblyの一部のバージョンではごくわずかです。レポートに非常に複雑なデータのセットを返す200行のコード範囲に収まるSQLクエリをいくつか見ました。
完全に機能するコード、それはあなたができる限り簡単です合理的にそれを目標にします。
長いからといって変更しないでください。
正規表現を常にサブ正規表現に分割し、徐々に最終的な式を作成することができます。これは、特に同じサブパターンが何度も繰り返される場合に、非常に大きなパターンの理解に役立ちます。たとえば、Perlで。
my $start_re = qr/(?:\w+\.\w+)/;
my $middle_re = qr/(?:DOG)|(?:CAT)/;
my $end_re = qr/ => \d+/;
my $final_re = $start_re . $middle_re . $end_re;
# or:
# my $final_re = qr/${start_re}${middle_re}${end_re}/
それが壊れやすいなら、私はそれを壊すと言います。保守性の観点から、そしておそらく再利用性の観点から、それを壊すことは理にかなっていますが、もちろん、関数の自然な性質と、入力の取得方法とそれが返すものを考慮する必要があります。
ストリーミングチャンクデータをオブジェクトに解析する作業をしていたのを覚えているので、基本的には2つの部分に分割しました。1つはエンコードされたテキストから文字列の完全なユニットを構築し、2つ目はそれらのユニットをデータディクショナリに解析して整理しました。それら(異なるオブジェクトのランダムプロパティである可能性があります)およびオブジェクトの更新または作成よりも。
また、各主要部分をいくつかのより小さくより具体的な関数に分割することができたので、結局、5つの異なる関数ですべてを行い、いくつかの関数を別の場所で再利用することができました。
あなたが考慮したかもしれないし、考慮していないかもしれないことの一つは、その言語で正規表現を使用する代わりに、使用している言語で小さなパーサーを書くことです。これは、読みやすく、テストし、保守しやすいかもしれません。
ほとんどの場合、巨大な正規表現は不適切な選択です。私の経験では、開発者が解析に慣れていないため、これらがよく使用されます( Thomas Edingの回答 を参照)。
とにかく、正規表現ベースのソリューションに固執したいとします。
実際のコードがわからないので、考えられる2つのシナリオを調べます。
正規表現は単純です(多くのリテラルマッチングといくつかの代替)
この場合、単一の正規表現によって提供される高度な機能は必須ではありません。つまり、分割することでメリットが得られる可能性が高くなります。
正規表現は複雑です(多くの選択肢)
この場合、おそらく数百万のフローが存在する可能性があるため、実際には完全なテストカバレッジを確保することはできません。したがって、テストするには、分割する必要があります。
想像力に欠けるかもしれませんが、100行の正規表現が適切な解決策である現実の状況は考えられません。