私は窮地に立たされています。関数内でデータベースに多くの変更を加えるリポジトリで作業しています。

処理している関数は応答IDを返します(ただし、データベースアクションからではなく、変換から)。ただし、副作用として、これらのresponseIdを含むオブジェクトがデータベースに追加されます。

名前を付ける必要があります:

  • getResponseIds:これは戻り値を強調表示します。これは非常に機能的な考え方ですが、関数postToDBがある場合は、getStatusOfPost
  • addResponseIdToDB:これは副作用を浮き彫りにしますが、私の関数の多くはデータベース上で動作するだけだと思います(そして何も返さない傾向があります)

  • getAndAddResponseIdsToDB:非常に有益ですが、非常に長いです。

上記の提案の長所と短所は何ですか?または、自分でより良い提案をすることはできますか?

コメント

  • persistResponseIdsはどうですか?
  • getStatusOfPost 🙂
  • getAndSaveResponseIds
  • は明確で簡潔なようです。 get()以前は’存在しなかったものがあるため、createが適切な動詞です。新しく作成されたものは、’ create()関数が返すことを期待するものです。または、’明らかな何かが欠けているのではないでしょうか?

  • @fattieコードは自己コメントする必要があることに同意します。コメントは、コードの機能を教えてはなりません。コメントは、コードが存在する理由を教えてくれるはずです。コードのリファクタリングが’のコメントのリファクタリングを意味する場合、悪いコメントがあります。名前は長い全文になる可能性があることに同意します。良い名前は、あなたを驚かせないように関数の内部を見続ける必要があります。 ‘それを実装する方法を教えてはいけません。クライアントが何を期待しているのかを教えてくれるはずです。そうすれば、価値のある抽象化ができます。

回答

and誤った抽象化レベルです。

addResponseIdToDB()に傾倒します。そうしないと、「副作用」が完全に驚きます。ただし:

responseIds = addResponseIdToDB(); 

誰もが驚かされることはありません。

コマンドクエリ責任分離の原則は、これがresponseIdオブジェクトを取得する唯一の方法ではないと主張しています。このオブジェクトを取得できるDBを変更しないクエリも必要です。

Bertrand Meyer とは異なり、これは追加でvoidを返す必要があることを意味するとは思われません。同等の純粋なクエリが存在する必要があることを意味します。また、状態変更クエリを使用してDBが不必要に悪用されないように、簡単に見つけることができます。

getResponseIds()が存在し、データベースと通信しないようにする必要がある場合、両方を行うメソッドの最適な名前は実際には。しかし、それは、それに関するすべての機能構成を取得したい場合に限ります。

コメント

  • 言われたことに加えて、ただし、’が使用されていない単語を追加すると、”および”は、関数がアトミックである何かを実行する場合に適切です。アトミック/一緒に/一度に発生する2つのことから得られる利点がある場合は、それらの2つのことが関数内にあることを明示します。名前は良いです。ですから、私はあなたの最初の声明に一般的に同意しますが、資格なしでは同意しません。
  • …誰も残しません驚いた。 “。同意しません。’ブール変数がそして、それがすべてを1つに追加して取得することを理解するために、メンタルシフトを行う必要があります。しかし、getAndAddResponseIdsToDBという@tintintongには同意しません。長すぎます; ‘は、私の関数名の非常に多くの半分の長さです。関数が2つのことを行う場合は、その名前でそのように言います。
  • @Luaan OK、それではgetAndIncrementの名前を何に変更しますか? otherIncrement
  • @Luaanでは、Incrementは、インクリメント前またはインクリメント後のどちらの値を返しますか? ‘は、ドキュメントに飛び込むことなしにどちらになるかは明確ではありません。incrementAndGetgetAndIncrementの方がはるかに優れているメソッド名だと思います。これは、

    AND “メソッド名、少なくとも戻り値に影響を与える可能性のある副作用があるメソッドの特定の場合。

  • @Luaan “インクリメントはインクリメントされた値を返します”と言うと、インクリメント前の値を意味しますか?了解しました。最初は誤解していました。これは、getAndIncrementincrementAndGetが単なるincrement、個別に検討した場合でも

回答

他の人が言及しているように、関数名にandを使用すると、関数が少なくとも2つのことを実行していることを自動的に意味します。これは通常、関数が実行しすぎているか、何かを実行していることを示します。

関数名でand句を使用することは、私の経験では、特定のフローに次のようなステップがある場合に意味があります。順番に実行するか、計算全体が意味のあるものになったときに実行する必要があります。

数値計算では、これは非常に理にかなっています。

normalizeAndInvert(Matrix m)

つまり、誰が知っているのでしょうか?計算する必要がある場合は、たとえば、コンピューターグラフィックスや証明書での照明の軌跡などです。ステージでは、特定の行列を正規化して反転する必要があり、常に次のように記述していることに気付きます。

m = normalize(m)、続いてinvert(m)は、単純な例として、正規化と反転の抽象化を導入することで、読みやすさの観点から優れている場合があります。

意味論的に言えば、divideAndConquer()など、明示的に書き出すことはおそらくお勧めできませんが、基本的にはAndが必要です。

コメント

  • 関数は通常、複数のことを実行しますが、それらは小さなことであり、1つの大きなことになるはずです’はより高いレベルで意味があります。 normalizeAndInvertcomputeLightingdivideAndConquerapplyMachiavelli
  • 明らかに:)名前に”と”を含む関数を最初に作成することを述べるだけです特定のコンテキストに基づいた自然な抽象化として提供される場合があります。 “名前変更方法”によるリファクタリングは、;)
  • @BrunoOliveiraの直後に行う必要があります。それ自体が多くのもののコンポーネントであるため、名前の変更は’適切なアプローチではありません。まれなはずですが、絶対に使用しないということは、’繰り返していることを意味します。

回答

一般的には問題ないと思いますが、すべての場合に受け入れられるわけではありません。

たとえば、and 単一責任の原則に基づく関数名のdiv>別名SOLIDのS- andが意味する可能性があるため複数の責任。 andが実際に関数が2つのことを実行していることを意味する場合は、何が起こっているのかを慎重に検討する必要があります。

ライブラリの例関数名にandを使用するのは、Javaの同時実行性とここandは実際に起こっていることの非常に重要な部分であり、状態が変更されて状態が返される投稿で説明した内容と厳密に一致します。 状態が返されるので、明らかに一部の人がいます(および一部のユースケース)許容できると見なされる場合。

コメント

  • andは複数の責任を意味する可能性があります “。そしてこの場合、それは確かにそれを示しています。この関数は、どこかからいくつかの応答IDを取得し、それらをデータベースに書き込み、返します。その”と”の必要性は、少なくとも2つの機能が必要であるというOPのアイデアを提起する必要があります。1つはIDを取得するためです。
  • andはコードの臭いであることに同意しますが、基本的な動作は正当なようです。一般的には悪くありません。その主な機能を実行することの必要な(中間の)結果であるメソッドからいくつかの追加の値を返すという考え。このメソッドの主な機能が応答IDをデータベースに追加することである場合、呼び出し元に追加したIDを追加で返すことは、メソッドの使いやすさを向上させる機能です。
  • これが必ずしもSRPに違反しているとは思わない’。複数のことを行う関数が常に必要になります。重要なのは、これらの関数に、必要なコードを直接含めるのではなく、実行したいすべてのことに対して別の関数を呼び出させることです。
  • 関数が2つのことを実行する場合、名前はそれを反映する必要があります。

回答

確かに、「多くのコメントが証明できるため、答えるのが難しい質問です。人々は矛盾した意見やアドバイスを持っているようです。良い名前は何ですか。

すでに提案されているものにさらに色を追加できると思うので、この2か月前のスレッドに2セントを追加したいと思います。

ネーミングはプロセスです

これはすべて、優れた6つのステップガイドを思い出させます:プロセスとしてのネーミング

貧弱な関数名は、驚くべきものであり、信頼できないことに気づきます。最初のショットで適切な名前を付けるのは困難です。経験を積むと簡単になります。

適切な名前を作成するための6つの反復ステップ

  1. 意外な名前を明白なナンセンスに置き換えます appleSauce()のように。ばかげているように聞こえますが、それは一時的なものであり、名前が信頼できないことは明らかです。
  2. 正直な名前を取得してください、関数の機能から理解した内容に基づいています。 DB部分への挿入をまだ理解していない場合は、getResponseIdsAndProbablyUseDbを選択できます。
  3. 取得完全に正直に言うとなので、関数名は関数が行うすべてのことを示します(getAndAddResponseIdsToDBまたはgetResponsesButAlsoAddCacheOfTheResponsesToTheDb @Fattieからの良い例です)
  4. 基本的に「正しいことをする」にアクセスします関数を「AND」に沿って分割する部分。したがって、実際にはgetResponseIdsaddResponseIdsToDbがあります。
  5. 「意図を明らかにする」名前を取得する 「常に応答IDを取得したいI実装の詳細について考えるのをやめ、2つの最小関数を使用して他の何かを構築する抽象化を構築します。これは、@ candied_orangeによって言及されたより高い抽象化レベルです。 xample createResponseIdsはそれを行うことができ、getResponseIdsaddResponseIdsToDbの構成になります。
  6. ドメインの抽象化を取得します。これは難しいです、それはあなたのビジネスに依存します。正しく理解するには、ビジネス言語を聞くのに時間がかかります。最終的には、Responseの概念になってしまう可能性があります。Response.createIds()は理にかなっています。あるいは、ResponseIdは価値のあるものであり、多くを作成するためのファクトリがあります。 DBへの挿入は、リポジトリなどの実装の詳細になります。はい、設計はより抽象的です。それはより豊かになり、あなたにもっと表現させてくれるでしょう。チームの外部の誰も、あなたの状況で正しいドメイン抽象化がどうあるべきかをあなたに言うことができません。 状況によって異なります

あなたの場合、すでに1と2を理解しているので、少なくとも3に進む必要があります(「AND」を使用)またはそれ以上。しかし、さらに先に進むことは名前の問題だけではなく、実際に責任を分割します。

したがって、ここでのさまざまな提案は有効です

本質的に:

  • はい、意外な関数名はひどいので、誰もそれに対処したくありません
  • はい、「AND」は誤解を招く名前よりも優れているため、関数名で使用できます
  • はい、抽象化のレベルは関連する概念であり、重要です

すぐにステージ6に進む必要はありません。そのままで構いません。よくわかるまでステージ2、3、4!


矛盾したアドバイスのように見えるものについて異なる視点を与えるのに役立つことを願っています。誰もが同じ目標を目指していると信じています(驚くことではない名前)が、彼ら自身の経験に基づいて、さまざまな段階で停止します。

質問がある場合は、喜んでお答えします。 🙂

回答

関数は2つのことを行います:

  1. IDのセットを取得しますトランスフォームを介して呼び出し元に返します。
  2. そのIDのセットをデータベースに書き込みます。

ここで単一責任の原則を覚えておいてください。関数を目指す必要があります。 2つではなく1つの責任を持つこと。 2つの責任があるため、2つの関数があります。

getResponseIds-トランスフォームを介してIDのセットを取得し、呼び出し元に返します
addResponseIdToDB -IDのセットを取得し、データベースに書き込みます。

そして、複数の責任を持つ単一の関数を何と呼ぶかという問題全体がなくなり、関数名にandを入れたいという誘惑もなくなります。

追加のボーナスとして、同じ関数が2つの無関係なアクションを担当しなくなったため、getResponseIdsをリポジトリコードから移動できます(所属していない場合)。 「DB関連のアクティビティを実行していないため)、別のビジネスレベルのクラス/モジュールなどに。

コメント

  • その’は確かに真実ですが、これら2つのSRPメソッドを使用してスニペットを何度も繰り返すことに気付いた場合は、これを行う簡単なメソッドを作成して、乾燥させる必要があります。’ t you?
  • @maaartinus、これら2つのメソッドを多くの場所で呼び出していることに気付いた場合は、コードのまとまりがないという問題が発生している可能性があります。 ” DRY “関数を作成すると、このまとまりの欠如がマスクされます。

回答

複合関数名を使用することは許容されるため、使用する命名スキームはコンテキストによって異なります。それを分割するようにあなたに言う純粋主義者がいますが、私はそうではないと主張します。

そのようなことを避けようとする2つの理由があります:

  • 純度-機能2つのことを行う2つの関数は、それぞれ1つのことを行う2つの関数に変換する必要があります。
  • 字句サイズ-bigUglyCompositeFunctionNameは読みにくくなります。

純度の議論は、通常、焦点を当てている議論です。漠然とした一般的なヒューリスティックとして、関数を分割することは良いことです。何が起こっているのかを区分化するのに役立ち、理解しやすくなります。 2つの動作間の結合につながる変数の共有で「巧妙な」トリックを行う可能性は低くなります。

したがって、自問することは「とにかくやるべきか」ということです。物事を分割することは漠然としたヒューリスティックであると私は言います、それであなたはそれに反対するために本当にまともな議論を必要とするだけです。

1つの主な理由は2つの操作を1つとして考えることが有益であるということです。これの最終的な例は、アトミック操作にあります:compare_and_setcompare_and_setは、アトミック(ロックなしでマルチスレッドを実行する方法)の基本的な基盤であり、多くの人がそれを と考えるほど成功しています。礎石。その名前には「and」があります。これには非常に正当な理由があります。この操作の要点は、1つの分割できない操作として比較と設定を行うことです。 compare()set()に分割すると、最初に関数が存在した理由全体が無効になります。 div id = “464bc5fa4e”>

は、set()の前に連続して発生する可能性があります。

これはパフォーマンスでも見られます。私のお気に入りの例は、 fastInvSqrt 。これは、1 / sqrt(x)を計算するQuakeの有名なアルゴリズムです。これにより、「逆」演算と「平方根」演算を組み合わせます。パフォーマンスが大幅に向上します。ニュートンの近似を実行し、両方の操作を1つのステップで実行します(そして、時代に重要だった浮動小数点ではなく、整数演算で実行します)。 inverse(sqrt(x))を実行すると、はるかに遅くなります!

結果がより明確になる場合があります。デッドロックなどに細心の注意を払う必要があるスレッドを含むいくつかのAPIを作成しました。ユーザーに内部実装の詳細を認識させたくなかったので(特に変更する可能性があるため)、次のようにAPIを作成しました。ユーザーが複数の関数呼び出しのためにロックを保持する必要がないようにするいくつかの「and」関数。つまり、内部でマルチスレッド同期をどのように処理しているかを知る必要はありませんでした。実際、私のユーザーのほとんどは、マルチスレッド環境にいることにさえ気づいていませんでした。

したがって、一般的なルールは物事を分割することですが、それらを結合する理由は常にあります。たとえば、 、ユーザーは、間に「gets」を入れずにデータベースに複数回追加することでアーキテクチャを壊すことができますか?DBに記録された各応答に一意の識別子が必要な場合、ユーザーがそれらを進んで実行すると問題が発生する可能性があります。同様に、結果をDBに記録せずにユーザーに「取得」させたいと思いませんか?答えが「はい」の場合は、ユーザーが「取得」機能にアクセスできるように分割します。ユーザーが結果をDBに記録せずに「取得」できる場合、アプリケーションのセキュリティは破られます。実際には関数をまとめておく必要があります。

字句の問題については、関数名で何を説明する必要があります。ユーザーはそれについて知る必要があります。「get」の部分から始めましょう。すべての例で割り当てが表示されるため、関数名から「get」を削除するのは非常に簡単です:int id = addResponseIdToDB() “。関数が使用されるすべての場所で、終了します。関数が値を返したという事実を文書化します。

同様に、「追加」はオプションです。「副作用」という用語をすべての包括的な用語として使用しますが、さまざまな色合いがあります。 DBエントリが単なるログである場合、それを強調表示する理由がない可能性があります。 playMusicAndSendPersonalInformationToOurCorporateServersのような関数は表示されません。これはplayMusicであり、運が良ければ、ドキュメントにインターネット経由のソケット接続に関する情報が記載されている場合があります。一方、ユーザーがDBに追加する目的でこの関数を呼び出すことが予想される場合は、「追加」が不可欠です。 「取り出さないでください。

今、私はあなたが求めていることのすべての可能な組み合わせを行う多くの理由を書きました。選択の余地があるため、意図的に質問に答えていません。従うのはルールではありません。あなたはAPIを作成しています。

そうは言っても、私の本能は、addResponseIdToDBが最良の答えである可能性が高いということです。ほとんどの場合、「取得」部分は明らかな十分な副作用であるため、どこにでも入力することによって発生する余分なノイズは発生しません。ただし、重要と思われる場所がいくつかあります。

  • 「get」が高額な場合-インターネット経由で何かをフェッチしてローカルキャッシュDBに追加する「get」を実行する必要がある場合は、必ず「get」が重要です。これは、ユーザーがやろうとしていることです。
  • ユーザーが値に注意を払う必要があることを 明確にする必要がある場合。ユーザーが変数を使用したい場合は、APIが変数を返すことに気付き、ユーザーはそれを使用します。ただし、必要なことを知らないユーザーに注意する必要があります。たとえば、後でメモリを解放するためにこの操作をIDで「閉じる」必要がある場合は、次のことに注意を向けることができます。 「何かをしている。このような場合、「get」以外の動詞を確認することをお勧めします。 「get」は冪等関数を意味することがよくあります(再度呼び出しても何も起こりません)。リソースを返す場合は、「create」や「acquire」などの他の動詞が適しています。この特定の失敗メカニズムは、例外処理を行う場合のCの主要な問題です。 .CにはC ++のキャッチ/スローメカニズムがないため、リターンコードに依存しています。開発者は、これらのリターンコードのチェックに失敗し、それが原因でバッファオーバーフローなどの非常に悪い状況に陥ることで、有名です。
  • 対称性-語彙対称性を持つようにAPIを設計する場合があります。ペアまたは他のパターンになるように単語を設定し、視覚的に識別しやすいようにコマンドを作成します。パターンが守られているかどうか。これはまれだと思いますが、前代未聞ではありません。 XMLタグを閉じる理由は、タグ名を繰り返します(< foo >や< / foo >)。

コメント

  • そうでない人向け’数学がわからない:1 / xとsqrt(x)はどちらもかなり遅い関数です。いくつかの巧妙な数学を使用すると、1 / sqrt(x)より速く除算または平方根よりも。実際には非常に高速なので、sqrt(x)を計算する最も速い方法は、巧妙な実装で1 / sqrt(x)を計算し、結果にxを掛けることです。
  • 物理学のように、基本単位はもはやメートルと秒ではなく、光の速度です。これは、メーターの長さよりも正確に光の速度を測定できるためです。

回答

究極とは この方法の意図 od?なぜこれらの変換されたIDをDBに追加するのですか、それはキャッシュの目的ですか?私は「その仮定の下で作業します。

このメソッドの目的は、実際には変換された応答IDを取得すること(変換を実行するか、キャッシュから取得すること)であるように思われるので、メソッド名:

getTransformedResponseIds 以下の詳細 getResponseIds()

この名前のメソッドはキャッシュできますまたはそうではないかもしれませんが、それは文書化できますが、メソッド名は特定の実装に結び付けるべきではありません。DBの使用をやめ、代わりに一時的にメモリにキャッシュするなど、他の場所にキャッシュする場合はどうなりますか?

副作用は、副作用である必要があります。おそらく文書化する必要がありますが、コアの意図(または成功)や機能の名前に実際に影響を与えるべきではありません。キャッシュからの値の取得に失敗した場合(またはキャッシュをスキップするように構成した場合)、重大な問題ではないはずですが、メソッドは透過的に再計算し、キャッシュ(またはキャッシュしない)して、新しい値を返す必要があります。

「AND」を使用すると、JavaメソッドgetAndIncrementincrementAndGetなどで意図を伝えるのに役立つ場合があります。それは確かにテーブルから外れているわけではありません。

回答

関数は、変換からではなく、変換から何かを返すと言います。任意のdbアクション」。

これは、関数がゲッターというよりコンストラクターのように動作することを示しています。ただし、コンストラクターも副作用を引き起こしてはなりません(リンクに感謝します、 @ MechMK1 )。

一方、ファクトリメソッドは、すでにある程度の混乱を前提としています。 。たとえば、ファクトリメソッドを使用する動機の1つは、ファクトリメソッドです。

複数のコンストラクタが存在する場合に、それぞれが別の理由。 -ウィキペディア

同様に、

副作用を処理する必要がある場合は、ファクトリメソッドに名前を付けて、それらの副作用がより明確になるようにすることができます。 -ruakh

「logged」という用語を使用してプログラマーにデータベースストレージを警告することにより、関数をファクトリメソッドにすることを検討してください。

  • 宣言:createLoggedResponseid(...) {...} // log object to db
  • 電話:responseid = createLoggedResponseid(...);

コメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です