私は窮地に陥っています。私は、その機能内で多くのデータベース変更を行うリポジトリーで作業しています。
私が扱っている関数は、responseidを返します(ただし、データベースアクションからではなく、変換から)。ただし、副作用として、それらのresponseIdを含むオブジェクトがデータベースに追加されます。
だから私はそれに名前を付ける必要があります:
getResponseIds
:戻り値を強調表示します。これは非常に機能的な考え方ですが、関数postToDB
がある場合、getStatusOfPost
を使用しても意味がありません。addResponseIdToDB
:これは副作用を浮き彫りにしますが、私の関数の多くはデータベース上でのみ動作する(そして何も返さない傾向がある)と本当に思います。getAndAddResponseIdsToDB
:非常に有益ですが、非常に長いです。上記の提案の長所と短所は何ですか?それとも、自分でより良い提案をすることができますか?
and
を含む関数名は 間違った抽象化レベル です。
私はaddResponseIdToDB()
に傾いています。それ以外の場合、「副作用」は完全な驚きだからです。しかしながら:
_responseIds = addResponseIdToDB();
_
誰も驚かないままにしません。
コマンドクエリの責任分離の原則 は、これがresponseIdオブジェクトを取得する唯一の方法ではないことを主張しています。このオブジェクトを取得できるDBを変更しないクエリもあります。
Bertrand Meyer とは対照的に、これはaddがvoidを返す必要があることを意味するとは思わない。同等の純粋なクエリが存在し、簡単に検索できるようにして、状態変更クエリの使用によってDBが不必要に悪用されないようにするだけです。
getResponseIds()
が存在し、データベースと通信しないようにする必要があるため、両方を実行するメソッドの最適な名前は実際にはaddToDB(getResponseId())
です。しかし、それはあなたがそれについてすべての機能的な構成を取得したい場合にだけです。
他の人が述べたように、関数名でand
を使用すると、関数が少なくとも2つのことを実行していることを自動的に意味します。これは通常、関数が過度に実行している、または間違った場所で何かを実行していることを示します。
関数名でand
句を使用することは、私の経験では、特定のフローで順番に実行する必要があるステップがある場合や、計算全体が意味を持つようになった場合に意味があります。
数値計算では、これは非常に理にかなっています。
normalizeAndInvert(Matrix m)
つまり、誰が知っているのでしょう?いくつか計算する必要がある場合は、たとえば、コンピュータグラフィックスのライティング軌道と特定の段階で、特定の行列を正規化および反転する必要があります。
単純な例として、正規化と反転の抽象化を導入するm = normalize(m)
の後にinvert(m)
を続けると、読みやすさの観点からは良いかもしれません。
意味論的に言えば、divideAndConquer()
などのようなものは、明示的に書き出すことはおそらくお勧めできませんが、まあ、基本的にはAnd
が必要です。
一般的には問題ないと思いますが、すべての場合に許容できるわけではありません。
たとえば、関数名のand
に対して、 単一責任の原則 別名S SOLID--and
は複数の責任を意味する可能性があります。and
が実際に関数が2つのことを実行していることを意味する場合は、おそらく何が起こっているのかを慎重に検討する必要があります。
関数名にand
を使用するライブラリの例は、Javaの concurrency にあります。ここでand
は、実際に起こっていることの非常に重要な部分であり、状態が変更され、状態が返される投稿での説明と一致します。したがって、受け入れられると思われる人々(およびいくつかのユースケース)がいるのは明らかです。
確かに、多くのコメントが証明できるように、それは答えるのが難しい質問です。人々は、良い名前とは何かについて、矛盾した意見やアドバイスを持っているようです。
この2か月前のスレッドに2セントを追加したいと思います。これは、すでに提案されているものにさらに色を追加できると思います。
これらすべては、優れた6ステップガイド プロセスとしての命名 を思い出させます。
貧弱な関数名は驚くべきものであり、信頼できないことに気づきます。最初のショットで適切な名前を付けるのは難しい。経験すれば簡単になります。
appleSauce()
のように明らかなナンセンスに置き換えます。ばかげているように聞こえますが、それは一時的なものであり、その名前が信頼できないことは明らかです。getResponseIdsAndProbablyUseDb
がオプションになります。getAndAddResponseIdsToDB
またはgetResponsesButAlsoAddCacheOfTheResponsesToTheDb
@Fattieは素晴らしい例)getResponseIds
とaddResponseIdsToDb
があります。createResponseIds
はそれを行うことができ、getResponseIds
とaddResponseIdsToDb
の合成になります。Response
の概念に到達する可能性があり、Response.createIds()
は理にかなっています。あるいは、ResponseId
は貴重なものであり、多くを作成するためのファクトリーがあるでしょう。 DBへの挿入は、リポジトリなどの実装の詳細になります。はい、設計はより抽象的です。それはより豊かで、より多くのことを表現させるでしょう。あなたのチームの外の誰も、あなたの状況で正しいドメイン抽象化がどうあるべきかをあなたに教えることができません。 状況によります。あなたのケースでは、すでに1と2を理解しているので、少なくとも3に進む必要があります(「AND」を使用します)。しかし、さらに先に進むことは、名前を付けるだけの問題ではなく、実際には責任を分割することになります。
基本的に:
すぐにステージ6に行く必要はありません。よくわかるまで、ステージ2、3、または4にとどまっても問題ありません。
それが矛盾するアドバイスのように見えるものに別の視点を与えるのに役立つことを願っています。私は誰もが同じ目標(驚くべき名前ではない)を目指していますが、自分の経験に基づいて、さまざまな段階で立ち止まると思います。
質問があればお答えします:)
関数は2つのことを行います。
ここでは単一の責任の原則を思い出してください。関数は2つの責任ではなく1つの責任を持つことを目指す必要があります。あなたには2つの責任があるので、2つの機能があります。
getResponseIds
-変換を介してIDのセットを取得し、呼び出し元に返しますaddResponseIdToDB
-IDのセットを取得して、データベースに書き込みます。
そして、複数の責任を持つ単一の関数を何と呼ぶかという問題全体がなくなり、関数名にand
を入れる誘惑もなくなります。
追加のボーナスとして、同じ関数が2つの無関係なアクションの原因ではなくなったため、getResponseIds
をリポジトリコードから移動できます(DB関連のアクティビティを実行していないため、属していない)。別のビジネスレベルのクラス/モジュールなどに.
複合関数名を使用することは許容されるため、使用する命名方式はコンテキストによって異なります。それを分解するように言う純粋主義者がいますが、私はそうでないと主張します。
そのようなことを回避しようとする2つの理由があります。
bigUglyCompositeFunctionName
は読みにくくなります。純粋性の議論は、通常、焦点を当てているものです。漠然とした一般的なヒューリスティックとして、関数を分割することは良いことです。何が起こっているのかを区分して、理解しやすくします。変数を共有して「賢い」トリックを行う可能性は低く、2つの動作の結合につながります。
だから自問するのは「とにかくやるべきか」ということです。物事を分割することはあいまいなヒューリスティックなので、本当にそれに反対するために必要なのは、適切な議論だけです。
主な理由の1つは、2つの操作を1つとして考えることが有益であることです。これのすべての究極の例は、アトミック操作:_compare_and_set
_にあります。 _compare_and_set
_はアトミック(ロックなしでマルチスレッドを実行する方法)の基本的な基礎であり、多くの人がそれをthe基礎。その名前には「and」があります。これには非常に正当な理由があります。この操作の要点は、比較と設定を1つの分割できない操作として行うことです。 compare()
とset()
に分割すると、2つのcompares()
が次のように発生する可能性があるため、最初に関数が存在した理由全体を無効にしますset()
sの前に戻ります。
これはパフォーマンスでも見られます。私のお気に入りの例は fastInvSqrt です。これは、1/sqrt(x)を計算するQuakeの有名なアルゴリズムです。 「逆」操作と「平方根」操作を組み合わせると、パフォーマンスが大幅に向上します。それらは、単一のステップで両方の演算を実行するニュートンの近似を実行します(当時は、浮動小数点ではなく整数演算で実行されていました)。 inverse(sqrt(x))
を実行すると、かなり遅くなります。
結果がより明確になる場合があります。デッドロックのようなものについてひどく注意しなければならないスレッド化を含むいくつかのAPIを書きました。ユーザーに内部実装の詳細を知らせたくなかったので(特に変更する可能性があるため)、いくつかの「and」関数を使用してAPIを作成しました。 1つの関数呼び出し。これは、彼らが私が内部でマルチスレッド同期をどのように処理していたかを知る必要がなかったことを意味します。実際、ほとんどのユーザーは、マルチスレッド環境にいることにさえ気づいていませんでした。
したがって、一般的なルールは物事を分割することですが、それらを結合する理由は常にあります。たとえば、ユーザーは「gets」を間に挟まずにデータベースに複数回追加することで、アーキテクチャを壊すことができますか? DBに記録された各応答に一意の識別子が必要な場合、ユーザーが無理にそれらを実行しなければならない場合、問題が発生する可能性があります。同様に、ユーザーが結果をDBに記録せずに「取得」できるようにしたいですか?答えが「はい」の場合は、それらを分割して、ユーザーが「取得」機能にアクセスできるようにします。ただし、ユーザーが結果をDBに記録せずに「取得」できる場合に、アプリケーションのセキュリティが壊れている場合は、機能をまとめておく必要があります。
語彙の問題については、関数名はユーザーがそれについて知る必要があることを説明する必要があります。 「取得」の部分から始めましょう。すべての例で割り当てが表示されるため、関数名から「get」を削除するのは非常に簡単です:int id = addResponseIdToDB()
"。関数が使用されるすべての場所で、最終的に関数が値を返しました。
同様に、「追加」はオプションにすることができます。 「副作用」という用語はすべてを包括する用語として使用しますが、色合いはさまざまです。 DBエントリが単なるログである場合、それを強調表示する理由はありません。 playMusicAndSendPersonalInformationToOurCorporateServers
のような関数はありません。それは単にplayMusic
であり、運が良ければ、ドキュメントにはインターネット経由のソケット接続についての記述があるかもしれません。一方、ユーザーがDBに追加する目的でこの関数を呼び出すことが予想される場合は、「追加」が不可欠です。取り出さないでください。
今、私はあなたが求めていることのあらゆる可能な組み合わせをする多くの理由を書きました。選択の余地があるため、質問には意図的に回答しませんでした。従うべき規則ではありません。 APIを作成しています。
そうは言っても、私の本能はaddResponseIdToDBがおそらく最良の答えであるということです。ほとんどの場合、「取得」部分は明らかな十分な副作用であり、どこにでも入力することによって引き起こされる余分なノイズを獲得しません。ただし、私が重要だと考える場所はいくつかあります。
究極とはintentこのメソッドの?なぜこれらの変換されたIDをDBに追加するのですか、それはキャッシュの目的ですか?その仮定の下で働きます。
メソッドの目的は、実際には変換された応答IDを取得すること(変換を実行するか、キャッシュから取得すること)であると思われるため、メソッド名があります。
getTransformedResponseIds
以下の詳細getResponseIds()
この名前のメソッドはキャッシュすることもしないこともあり、ドキュメント化することもできますが、メソッド名で特定の実装に結び付けることはできません。 DBの使用をやめ、代わりに一時的にメモリなどの他の場所にキャッシュする場合はどうなりますか?
副作用はそれだけでなければなりません。副作用はおそらく文書化されるべきですが、関数のコアインテント(または成功)や名前に実際に影響を与えるべきではありません。キャッシュからの値の取得が失敗した場合(またはキャッシュをスキップするように構成した場合)、それが重大な問題ではない場合、メソッドは透過的に再計算し、キャッシュ(またはそうでない)にして、新しい値を返します。
JavaメソッドgetAndIncrement
およびincrementAndGet
など)を使用して意図を伝えるのに「AND」を使用すると役立つことがあるので、これは間違いなくテーブルから外れていません。