インスタンス変数よりもローカル変数を好む理由は?


109

私が取り組んでいるコードベースでは、インスタンス変数を頻繁に使用して、さまざまな簡単なメソッド間でデータを共有しています。元の開発者は、これがアンクルボブ/ロバートマーティンによる「クリーンコード」の本で述べられているベストプラクティス、つまり「機能の最初のルールは小さくなければならない」に準拠していると断言します。「関数の理想的な引数の数はゼロ(niladic)です。(...)引数は難しいです。概念的な力を多く必要とします。」

例:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  private byte[] encodedData;
  private EncryptionInfo encryptionInfo;
  private EncryptedObject payloadOfResponse;
  private URI destinationURI;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    getEncodedData(encryptedRequest);
    getEncryptionInfo();
    getDestinationURI();
    passRequestToServiceClient();

    return cryptoService.encryptResponse(payloadOfResponse);
  }

  private void getEncodedData(EncryptedRequest encryptedRequest) {
    encodedData = cryptoService.decryptRequest(encryptedRequest, byte[].class);
  }

  private void getEncryptionInfo() {
    encryptionInfo = cryptoService.getEncryptionInfoForDefaultClient();
  }

  private void getDestinationURI() {
    destinationURI = router.getDestination().getUri();
  }

  private void passRequestToServiceClient() {
    payloadOfResponse = serviceClient.handle(destinationURI, encodedData, encryptionInfo);
  }
}

ローカル変数を使用して、次のようにリファクタリングします。

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    byte[] encodedData = cryptoService.decryptRequest(encryptedRequest, byte[].class);
    EncryptionInfo encryptionInfo = cryptoService.getEncryptionInfoForDefaultClient();
    URI destinationURI = router.getDestination().getUri();
    EncryptedObject payloadOfResponse = serviceClient.handle(destinationURI, encodedData,
      encryptionInfo);

    return cryptoService.encryptResponse(payloadOfResponse);
  }
}

これは短く、さまざまな単純なメソッド間の暗黙的なデータカップリングを排除し、変数スコープを必要最小限に制限します。しかし、これらの利点にもかかわらず、前述のボブおじさんの慣行と矛盾するように見えるため、このリファクタリングが正当であると元の開発者を納得させることはできません。

したがって、私の質問:インスタンス変数よりもローカル変数を優先する客観的、科学的根拠は何ですか?指を置くようには思えません。私の直感では、隠された結合は悪いものであり、狭い範囲は広い範囲よりも優れていると教えてくれます。しかし、これを裏付ける科学は何ですか?

そして逆に、私が見落としていたかもしれないこのリファクタリングの欠点はありますか?


コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
maple_shaft

回答:


170

インスタンス変数よりもローカル変数を優先する客観的、科学的根拠は何ですか?

スコープはバイナリ状態ではなく、勾配です。これらを最大から最小にランク付けできます。

Global > Class > Local (method) > Local (code block, e.g. if, for, ...)

編集:私が「クラススコープ」と呼ぶものは、「インスタンス変数」が意味するものです。私の知る限り、これらは同義語ですが、私はJava開発者ではなくC#開発者です。簡潔にするために、静的は問題のトピックではないため、すべての静的をグローバルカテゴリにまとめました。

スコープが小さいほど優れています。理論的根拠は、変数は可能な限り最小のスコープ内に存在する必要があるということです。これには多くの利点があります。

  • 現在のクラスの責任について考えるように強制し、SRPに固執するのに役立ちます。
  • これは、2つの以上のクラスが持っている場合例えば、グローバル・ネーミングの競合を避けるために持っていないことができますNameプロパティを、あなたのような彼らの前に付けることを強制していないFooNameBarNameしたがって、できるだけ清潔で簡潔としてあなたの変数名を保ち、...。
  • 使用可能な変数(Intellisenseなど)をコンテキストに関連する変数に制限することにより、コードを整理します。
  • 何らかの形のアクセス制御が可能になるため、知らないアクター(同僚が開発した別のクラスなど)がデータを操作することはできません。
  • これらの変数の宣言が、これらの変数の実際の使用に可能な限り近くなるようにすることを保証するため、コードが読みやすくなります。
  • 過度に広いスコープで変数を宣言するだけでは、OOPを完全に把握していない開発者やその実装方法を示すことがよくあります。過度に広範囲にスコープされた変数を見ることは、おそらくOOPアプローチ(開発者全般または特定のコードベースのいずれか)で何か問題が発生していることを示すレッドフラグとして機能します。
  • (Kevinによるコメント)地元の人々を使用すると、正しい順序で物事を行うように強制します。元の(クラス変数)コードでpassRequestToServiceClient()は、メソッドの先頭に誤って移動する可能性がありますが、それでもコンパイルされます。ローカルでは、初期化されていない変数を渡した場合にのみ間違いを犯す可能性があります。

しかし、これらの利点にもかかわらず、前述のボブおじさんの慣行と矛盾するように見えるため、このリファクタリングが正当であると元の開発者を納得させることはできません。

そして逆に、私が見落としていたかもしれないこのリファクタリングの欠点はありますか?

ここでの問題は、ローカル変数の引数が有効であるが、正しくない追加の変更も加えているため、提案された修正が匂いテストに失敗することです。

私はあなたの「クラス変数なし」の提案を理解し、それにメリットがありますが、実際にはメソッド自体も削除しましたが、それはまったく異なる球技です。メソッドはそのままで、代わりに値をクラス変数に格納するのではなく、返すように変更する必要があります。

private byte[] getEncodedData() {
    return cryptoService.decryptRequest(encryptedRequest, byte[].class);
}

private EncryptionInfo getEncryptionInfo() {
    return cryptoService.getEncryptionInfoForDefaultClient();
}

// and so on...

processメソッドで行ったことに同意しますが、本体を直接実行するのではなく、プライベートサブメソッドを呼び出す必要があります。

public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    byte[] encodedData = getEncodedData();
    EncryptionInfo encryptionInfo = getEncryptionInfo();

    //and so on...

    return cryptoService.encryptResponse(payloadOfResponse);
}

特に、数回再利用する必要のあるメソッドに遭遇した場合、追加の抽象レイヤーが必要になります。現在メソッドを再利用していない場合でも、コードの読みやすさを支援するためであっても、関連するサブメソッドをすでに作成することは依然として良い習慣です。

ローカル変数の引数に関係なく、提案された修正が元の修正よりもかなり読みにくいことにすぐに気付きました。クラス変数の不必要な使用はコードの可読性を損なうことも認めますが、すべてのロジックを単一の(現在は長い)メソッドに積み上げた場合と比べると一見ではありません。


コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
maple_shaft

79

元のコードは、引数のようなメンバー変数を使用しています。彼が引数の数を最小限にすると言うとき、彼が本当に意味するのは、メソッドが機能するために必要なデータの量を最小限にすることです。そのデータをメンバー変数に入れても何も改善されません。


20
完全に同意する!これらのメンバー変数は、単に暗黙的な関数引数です。今、これらの変数の値と(外部のPOVから)機能の使用状況との間に明示的なリンクが存在しないので、実際にそれは悪いことだ
レミ

1
私はこれが本の意味ではないと言うでしょう。実行するために正確にゼロの入力データを必要とする関数はいくつありますか?私はこの本が間違っていたと思うビットの1つ。
Qwertie

1
@Qwertieオブジェクトがある場合、それが機能するデータはその中に完全にカプセル化される可能性があります。以下のような関数process.Start();かは、myString.ToLowerCase()あまりにも奇妙に見える(実際に理解するのが最も簡単です)べきではありません。
R.シュミッツ

5
どちらにも、暗黙の引数が1つありますthis。この議論はドットの前に明示的に与えられていると主張することさえできます。
ブラックジャック

47

他の答えはすでにローカル変数の利点を完全に説明しているので、残っているのはあなたの質問のこの部分だけです:

しかし、これらの利点にもかかわらず、前述のボブおじさんの慣行と矛盾するように見えるため、このリファクタリングが正当であると元の開発者を納得させることはできません。

それは簡単なはずです。ボブおじさんのクリーンコードの次の引用を単に彼に指してください:

副作用がない

副作用は嘘です。あなたの関数は一つのことをすることを約束しますが、他の隠されたこともします。時には、それ自身のクラスの変数に予期しない変更を加えることがあります。場合によっては、関数またはシステムグローバルに渡されるパラメーターになります。どちらの場合でも、それらは不正で有害な誤解であり、しばしば奇妙な時間的結合と順序依存性をもたらします。

(例は省略)

この副作用により、一時的な結合が作成されます。つまり、checkPasswordは特定の時間(つまり、セッションを初期化しても安全な場合)にのみ呼び出すことができます。順番どおりに呼び出されないと、セッションデータが誤って失われる可能性があります。特に副作用として隠されている場合、時間的カップリングは混乱を招きます。一時的な結合が必要な場合は、関数の名前でそれを明確にする必要があります。この場合、関数checkPasswordAndInitializeSessionの名前を変更することがありますが、これは確かに「Do one thing」に違反します。

つまり、ボブおじさんは、関数が引数をほとんどとらないと言っているだけでなく、関数は可能な限り非ローカル状態との対話を避けるべきだとも言っています。


3
「完全な世界」では、これが2番目にリストされた答えになります。同僚が理性に耳を傾けるという理想的な状況に対する最初の答え-しかし、同僚が熱狂者である場合、この答えはあまりファズのない状況に対処します。
R.シュミッツ

2
この考えのより実用的なバリエーションについては、インスタンスまたはグローバル状態よりもローカル状態について推論する方がはるかに簡単であるというだけです。明確に定義され、しっかりと含まれる可変性と副作用は、ほとんど問題につながりません。たとえば、多くのソート関数は副作用によってインプレースで動作しますが、これはローカルスコープで簡単に推論できます。
ビーフスター

1
ああ、古き良き「矛盾した公理では、何でも証明することができる」。確固たる真実や嘘のIRLはないので、ドグマは反対のことを述べている、つまり矛盾しているという記述を含める必要があります。
ivan_pozdeev

26

「誰かの叔父が考えていることと矛盾する」というのは決して良い議論ではありません。絶対に。おじさんから知恵を奪わないで、自分で考えてください。

ただし、インスタンス変数は、実際に永続的または半永続的に保存する必要がある情報を保存するために使用する必要があります。ここの情報はそうではありません。インスタンス変数なしで生きるのはとても簡単なので、インスタンス変数を使用できます。

テスト:各インスタンス変数のドキュメントコメントを記述します。完全に無意味ではないものを書くことができますか?そして、4つのアクセサにドキュメントコメントを書きます。それらも同様に無意味です。

最悪のことは、異なるcryptoServiceを使用するため、変更を復号化する方法を想定することです。4行のコードを変更する代わりに、4つのインスタンス変数を異なるものに、4つのゲッターを異なるものに置き換え、4行のコードを変更する必要があります。

しかしもちろん、コードの行で支払われるのであれば、最初のバージョンが望ましいです。11行ではなく31行。3倍以上の行を書き込み、永久に維持し、デバッグ中に読み取り、変更が必要な場合に適応し、2番目のcryptoServiceをサポートする場合に複製します。

(ローカル変数を使用すると、正しい順序で呼び出しを行う必要があるという重要な点を逃しました)。


16
自分で考えることはもちろん良いことです。しかし、冒頭の段落には、教師や先輩の意見を無視した学習者や後輩が効果的に含まれています。行き過ぎです。
7:29の

9
@Flater教師や先輩の入力について考え、彼らが間違っているのを見てから、入力を却下することが唯一の正しいことです。結局のところ、それは却下することではなく、質問し、間違いが間違いであることが明らかになった場合にのみ却下することです。
glglgl

10
@ChristianHackl:私は伝統主義に盲目的に従わずに完全に参加していますが、盲目的にそれを却下しません。答えは、あなた自身の見解を支持して獲得した知識を避けることを示唆しているように思われますが、それは取るに足りないアプローチです。盲目的に他人の意見に従う、いいえ。あなたが同意しないときに何かを質問する、明らかにはい。あなたが同意しないのでそれを完全に却下します、いいえ。私がそれを読んだとき、答えの最初の段落は少なくとも後者を示唆しているようです。それは、gnasherが「自分で考えて」という意味に非常に依存しており、これには詳細が必要です。
10:27の

9
共有の知恵のプラットフォームでは、これは少し
場違いに思え

4
決して決して良い議論でもありません...私はルールが規定するのではなく、ガイドするために存在することに完全に同意します。ただし、ルールに関するルールはルールのサブクラスにすぎないため、独自の判定を行いました...
cmaster

14

インスタンス変数よりもローカル変数を優先する客観的、科学的根拠は何ですか?指を置くようには思えません。私の直感では、隠された結合は悪いものであり、狭い範囲は広い範囲よりも優れていると教えてくれます。しかし、これを裏付ける科学は何ですか?

インスタンス変数は、ホストオブジェクトのプロパティを表すためのものであり、オブジェクト自体よりも狭いスコープの計算スレッドに固有のプロパティを表すためのものではありません。まだカバーされていないように見えるこのような区別を描く理由のいくつかは、並行性と再入可能性を中心に展開します。メソッドがインスタンス変数の値を設定してデータを交換する場合、2つの同時スレッドがそれらのインスタンス変数の互いの値を簡単に上書きして、見つけにくい断続的なバグを生成できます。

インスタンス変数に依存するデータ交換パターンがメソッドを再入不可能にするリスクが高いため、1つのスレッドだけでもこれらの行に沿って問題に遭遇する可能性があります。同様に、メソッドの異なるペア間でデータを伝達するために同じ変数が使用される場合、メソッド呼び出しの非再帰的チェーンでさえ実行する単一のスレッドが、関連するインスタンス変数の予期しない変更に関連するバグに遭遇するリスクがあります。

そのようなシナリオで確実に正しい結果を得るには、別々の変数を使用して、一方が他方を呼び出すメソッドの各ペア間で通信するか、すべてのメソッド実装に他のすべての実装の詳細を考慮させる必要があります直接または間接にかかわらず、それが呼び出すメソッド。これはもろく、スケーリングが不十分です。


7
これまでのところ、これはスレッドの安全性と並行性について言及している唯一の答えです。質問の特定のコード例を考えると、それは驚くべきことです。SomeBusinessProcessのインスタンスは、一度に複数の暗号化されたリクエストを安全に処理することはできません。メソッドpublic EncryptedResponse process(EncryptedRequest encryptedRequest)は同期されず、同時呼び出しはインスタンス変数の値を破壊する可能性が非常に高いです。これは育てるのに良いポイントです。
ジョシュアテイラー

9

ちょうど議論してprocess(...)、あなたの同僚の例はビジネスロジックの意味ではるかに読みやすいです。逆に、反例では、意味を抽出するために一見以上のものが必要です。

そうは言っても、クリーンなコードは読みやすく高品質です。ローカル状態をよりグローバルな空間に押し出すことは、単なる高レベルのアセンブリなので、品質はゼロです。

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest request) {
    checkNotNull(encryptedRequest);

    return encryptResponse
      (routeTo
         ( destination()
         , requestData(request)
         , destinationEncryption()
         )
      );
  }

  private byte[] requestData(EncryptedRequest encryptedRequest) {
    return cryptoService.decryptRequest(encryptedRequest, byte[].class);
  }

  private EncryptionInfo destinationEncryption() {
    return cryptoService.getEncryptionInfoForDefaultClient();
  }

  private URI destination() {
    return router.getDestination().getUri();
  }

  private EncryptedObject routeTo(URI destinationURI, byte[] encodedData, EncryptionInfo encryptionInfo) {
    return serviceClient.handle(destinationURI, encodedData, encryptionInfo);
  }

  private void encryptResponse(EncryptedObject payloadOfResponse) {
    return cryptoService.encryptResponse(payloadOfResponse);
  }
}

これは、任意のスコープで変数の必要性を取り除くレンディションです。はい、コンパイラはそれらを生成しますが、重要な部分は、それがコードを効率的にするように制御することです。比較的読みやすい一方で。

命名のポイント。意味のある最短の名前が必要であり、すでに利用可能な情報を拡張します。すなわち。destinationURI、「URI」はすでにタイプ署名によって認識されています。


4
すべての変数を削除しても、コードが読みやすくなるとは限りません。
ファラプ

ポイントフリースタイルですべての変数を完全に削除en.wikipedia.org/wiki/Tacit_programming
Marcin

@Pharap確かに、変数の欠如は読みやすさを保証しません。場合によっては、デバッグがさらに難しくなります。重要なのは、適切に選択された名前、表現の明確な用法は、効率的でありながらアイデアを非常に明確に伝えることができるということです。
Kain0_0

7

これらの変数とプライベートメソッドを完全に削除します。私のリファクターは次のとおりです。

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    return cryptoService.encryptResponse(
        serviceClient.handle(router.getDestination().getUri(),
        cryptoService.decryptRequest(encryptedRequest, byte[].class),
        cryptoService.getEncryptionInfoForDefaultClient()));
  }
}

プライベートメソッドの場合、たとえば router.getDestination().getUri()よりも明確で読みやすいですgetDestinationURI()。同じクラスで同じ行を2回使用する場合、それを繰り返します。別の見方をすると、が必要な場合、getDestinationURI()おそらくクラスではなく、他のクラスに属しSomeBusinessProcessます。

変数とプロパティの一般的な必要性は、後で使用される値を保持することです。クラスにプロパティのパブリックインターフェイスがない場合、おそらくプロパティにしないでください。最悪の種類のクラスプロパティの使用は、おそらく副作用としてプライベートメソッド間で値を渡すためです。

とにかく、クラスを実行するだけでprocess()オブジェクトは破棄され、メモリに状態を保持する必要はありません。さらなるリファクタリングの可能性は、そのクラスからCryptoServiceを取り除くことです。

コメントに基づいて、この答えは実世界の実践に基づいていると付け加えたい。実際、コードレビューで最初に選択することは、クラスをリファクタリングし、暗号化/復号化の作業を削除することです。それが完了したら、メソッドと変数が必要かどうか、それらに正しい名前が付けられているかなどを尋ねます。最終的なコードはおそらくこれに近いでしょう:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;

  public Response process(Request request) {
    return serviceClient.handle(router.getDestination().getUri());
  }
}

上記のコードでは、さらにリファクタリングする必要はないと思います。ルールと同様に、いつ適用するか、いつ適用しないかを知るには経験が必要だと思います。ルールは、すべての状況で機能することが証明されている理論ではありません。

一方、コードレビューは、コードが通過するまでの時間に実際の影響を与えます。私のコツは、コードを減らして理解しやすくすることです。変数名は議論のポイントになり得ます。もしそれを削除できれば、レビュアーはそれについて考える必要すらありません。


多くの人がここでheしますが、私の賛成票です。もちろん、いくつかの抽象化は理にかなっています。(ところで「プロセス」と呼ばれるメソッドはひどいです。)しかし、ここでのロジックは最小限です。ただし、OPの問題はコードスタイル全体にあり、ケースはより複雑になる可能性があります。
Joop Eggen

1
すべてを1つのメソッド呼び出しにチェーンする際の1つの明確な問題は、完全な読みやすさです。また、特定のオブジェクトに対して複数の操作が必要な場合にも機能しません。また、操作をステップ実行してオブジェクトを検査することはできないため、デバッグすることはほとんど不可能です。これは技術的なレベルでは機能しますが、ソフトウェア開発のランタイム以外の側面を大いに無視しているため、私はこれを支持しません。
フラット

@Flaterあなたのコメントに同意します。これをどこにでも適用したくありません。私の答えを編集して、実際的な立場を明確にしました。見せたいのは、実際には適切な場合にのみルールを適用するということです。この場合、メソッド呼び出しのチェーンは問題ありません。デバッグする必要がある場合は、チェーンされたメソッドのテストを呼び出します。
imel96

@JoopEggenはい、抽象化は理にかなっています。例では、民間の方法は、とにかくすべての抽象化を与えていない、クラスのユーザーも、それらについて知っていない
imel96

1
@ imel96 ServiceClientとCryptoServiceの結合により、CSをSBPではなくSCに注入し、上位のアーキテクチャレベルで根本的な問題を解決することに価値があることに気づいた数少ない人の1人であることは、おもしろいことです...これがIMVHOのこのストーリーの主なポイントです。詳細に集中しながら全体像を把握するのは簡単すぎます。
vaxquis

4

Flaterの答えは、スコーピングの問題を非常によくカバーしていますが、ここにも別の問題があると思います。

データ処理する関数と単純にdataにアクセスする関数には違いがあることに注意してください。

前者は実際のビジネスロジックを実行しますが、後者は入力を節約し、おそらくよりシンプルで再利用可能なインターフェイスを追加することで安全性を高めます。

この場合、データアクセス関数は入力を保存せず、どこでも再利用されないようです(または、それらを削除する際に他の問題が発生します)。したがって、これらの関数は単に存在するべきではありません。

名前付き関数のビジネスロジックのみを保持することにより、両方の世界の最高のものを取得します(Flaterの答えimel96の答え間のどこか)。

public EncryptedResponse process(EncryptedRequest encryptedRequest) {

    byte[] requestData = decryptRequest(encryptedRequest);
    EncryptedObject responseData = handleRequest(router.getDestination().getUri(), requestData, cryptoService.getEncryptionInfoForDefaultClient());
    EncryptedResponse response = encryptResponse(responseData);

    return response;
}

// define: decryptRequest(), handleRequest(), encryptResponse()

3

最初の最も重要なこと:ボブおじさんは時々説教者のように見えますが、彼の規則には例外があると述べています。

Clean Codeの全体的な考え方は、読みやすさを改善し、エラーを回避することです。互いに違反しているいくつかのルールがあります。

関数に関する彼の議論は、ニラディック関数が最適であるが、最大3つのパラメーターが許容されるというものです。個人的には4でもいいと思います。

インスタンス変数を使用する場合、一貫したクラスを作成する必要があります。つまり、すべての非静的メソッドではなくても、多くの変数で変数を使用する必要があります。

クラスの多くの場所で使用されていない変数は移動する必要があります。

元のバージョンもリファクタリングされたバージョンも最適だとは考えていません。@ Flaterは戻り値で何ができるかをすでに非常によく述べています。可読性が向上し、戻り値を使用する際のエラーが減少します。


1

ローカル変数はスコープを縮小するため、変数の使用方法が制限され、特定のクラスのエラーの防止に役立ち、可読性が向上します。

インスタンス変数は、関数の呼び出し方法を減らし、特定のクラスのエラーを減らし、読みやすさを向上させます。

特定のケースでは、一方が正しいと他方が間違っていると言うのは妥当な結論かもしれませんが、一般的なアドバイスとして...

TL; DR:熱心すぎる匂いがするのは、熱心すぎるからだと思います。


0

get ...で始まるメソッドはvoidを返すべきではないという事実にもかかわらず、メソッド内の抽象化レベルの分離は最初のソリューションで与えられています。2番目のソリューションはよりスコープが広くなっていますが、メソッドで何が起こっているのかを推論することは依然として困難です。ここでは、ローカル変数の割り当ては必要ありません。メソッド名を保持し、コードをそのようなものにリファクタリングします。

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    return getEncryptedResponse(
            passRequestToServiceClient(getDestinationURI(), getEncodedData(encryptedRequest) getEncryptionInfo())
        );
  }

  private EncryptedResponse getEncryptedResponse(EncryptedObject encryptedObject) {
    return cryptoService.encryptResponse(encryptedObject);
  }

  private byte[] getEncodedData(EncryptedRequest encryptedRequest) {
    return cryptoService.decryptRequest(encryptedRequest, byte[].class);
  }

  private EncryptionInfo getEncryptionInfo() {
    return cryptoService.getEncryptionInfoForDefaultClient();
  }

  private URI getDestinationURI() {
    return router.getDestination().getUri();
  }

  private EncryptedObject passRequestToServiceClient(URI destinationURI, byte[] encodedData, EncryptionInfo encryptionInfo) {
    return serviceClient.handle(destinationURI, encodedData, encryptionInfo);
  }
}

0

両方とも同じことを行い、パフォーマンスの違いは目立たないため、科学的な議論はないと思います。それは主観的な好みに帰着します。

そして、私もあなたのやり方があなたの同僚よりも好きになる傾向があります。どうして?何人かの本の著者が言っているにも関わらず、読みやすく理解しやすいと思うからです。

どちらの方法も同じことを達成しますが、彼の方法はより広範です。そのコードを読むには、いくつかの関数とメンバー変数の間を行き来する必要があります。すべてが1か所に凝縮されているわけではありません。それを理解するには、頭の中ですべてを覚えておく必要があります。それははるかに大きな認知的負荷です。

対照的に、あなたのアプローチはすべてをはるかに密にパックしますが、それを突き通すことができないようにします。行ごとに読むだけで、理解するためにそれほど覚える必要はありません。

しかし、もし彼がそのような方法でレイアウトされているコードに慣れていたら、彼にとっては逆かもしれないと想像できます。


流れを理解することは私にとって大きなハードルであることが実際に証明されています。この例は非常に小さいですが、別の例では、中間結果に35(!)インスタンス変数を使用し、依存関係を含む12個のインスタンス変数をカウントしていません。既に設定されているものを追跡する必要があるため、これを追跡するのは非常に困難でした。一部は後で再利用され、さらに難しくなりました。幸いなことに、ここで提示された議論により、私の同僚はついにリファクタリングに同意するようになりました。
アレクサンダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.