「まだ行われていない場合に何かを行う」という用語(または「パターン」?)[クローズ]


54

かなり基本的に聞こえますが、最近、同僚に、呼び出されたメソッドstartHttpServerがまだ実行されていない場合にサーバーを起動するだけなので、理解するには複雑すぎると言われました。「真剣に?私はこれを何十年も続けてきました。これはプログラミングの一般的なパターンです」と答えたとき、私はトラブルに陥ります。私が認めようと思うよりも頻繁に、彼は、プログラミングコミュニティ全体が彼の視点の背後にあることを示す文書化された証拠とともに戻ってきて、私はひどい気持ちになります。

質問:必要なアクションが既に有効になっている場合、ノーオペレーションであるメソッドの概念の背後にある文書化された設計パターンはありますか?または、パターンでない場合、名前もありますか?そうでない場合、この方法でメソッドを記述することを検討するのが複雑すぎると考える理由はありますか?


6
キャッシングのように聞こえます-そして実際には複雑であると考えられることがよくあります($ {something}を$ {someone}に説明するにはどうすればよいですか?
gnat

8
あなたは3つの異なる答えを手に入れましたが、最良の答えはそれらをすべて適用することです:元の関数の名前を変更し、コードを2つの関数に分割し(2つのうちの1つが名前を取得するstartHttpServer)、はい、「idempotent」という用語がここに適用されますまあ。
Doc Brown

8
同僚はどのような反証を提供しますか?それへのリンクを提供できますか?
ロバートハーヴェイ

5
私はあなたの同僚が彼の引用をどこから入手したか見てみたいです。少なくともStack OverflowとSoftware Engineeringの周辺では、この関数はせいぜいおかしな名前になりますが、異常な動作はしません。ブログのどこかがプログラミングコミュニティの全体像を表しているということを誰かがブログに書いたからではありません。マーティン・ファウラーのような有名人でさえ、時々非常に奇妙なことを言っています。私たちはすべて人間です。
T.サール-モニカ元に戻し

4
「まだ行われていない場合に何かを行う」ことを考えるより良い方法は、「この状態にシステムを置く」ことだと思います。もちろん、システムがすでにその状態にある場合、メソッドは何もしません-これは予期される動作です。
T.サール-モニカ元に戻し

回答:


127

NickWilliams がすでに言ったように:OPが記述する概念は、べきIdempotency)と呼ばれます。特に高レベルのAPIでは、実際に一般的な方法です。

ただし、関数の名前を変更します。

またはをstartHttpServer呼び出す代わりに。makeSureHttpServerIsRunningensureHttpServerIsRunning

関数が呼び出されるとstartHttpServer、読者はHTTPサーバーを起動することを期待します。連続して10回呼び出されると、10台のサーバーが実行されます。ほとんどの場合、関数はそれを行いません。さらに、「start」の付いた名前は、1つのサーバーのみを実行する場合、関数が既に呼び出されているかどうかを追跡する必要があることを示しています。

関数が呼び出されるとき、makeSureHttpServerIsRunningHTTPサーバーが実行されていることを確認するために必要なことを行うと思います。ほとんどの場合、既に実行されているかどうかを確認し、そうでない場合は開始します。また、この関数は、サーバーが実際に実行されていることを確認すると想定しています(サーバーの起動には、まだ完全に実行されていない時間がかかる場合があります)。


83
この。個人的には、代わりに「保証」を使用します。ポイントは、これがあなたのチームで理解される命名スキームになるべきだということです。
陶酔

3
または、既に開始されている場合、startが例外をスローします。sqlconnection.openのような
Ewan

9
私は常に「まだしていない場合」機能に「保証」命名を使用します。
カズ

3
私がよく目にする別の名前はgetOrCreateSomethingです。これは最初の呼び出しでのみ作成され、その後何かを返すだけです
-Fabich

5
@aroth使用可能なポートを見つけてそれを返すことを期待しないと思いますか?それともただひどく書かれている?;)
jpmc26

33

名前をに変更しEnsureServerRunningます。

完全に明確であり、再起動を暗示することなく実行されていることを確認します(実行されていない場合)。

(代替:StartServerIfNotRunning?)


1
ほとんどの呼び出し元は、呼び出し後にサーバーが実行されていることだけを気にします。それがどのように達成されるか、彼らは気にしません。
gnasher729

29

実際には設計パターンではありませんが、私はあなたのメソッドをべきと呼びます。通常、この用語はリモートコールを指すために使用されますが、説明はあなたがしていることと一致するようです。

べき等メソッド。メソッドは、(エラーまたは有効期限の問題を除いて)N> 0の同一リクエストの副作用が単一リクエストの場合と同じであるという点で、「べき等性」のプロパティを持つこともできます。(W3.orgから

ここでのサーバー側の効果は、メソッドが呼び出されるとhttpサーバーが開始されることです。これを行うメソッドに問題はありません。

デザインパターンが必要な場合は、httpServerを初期化時に開始されるシングルトンとして公開できると思います。


5
関数を1回呼び出すとhttpサーバーが起動し、2回目の呼び出しでは起動しない 場合、この関数はdem等でありません。それは文字通りi等性の反対です。すべての呼び出しが新しいHTTPサーバーを開始した場合べき等になります。
ポリノーム

36
@Polygnome Wikipediaは、 dem 等性をf(f(x))= f(x)として定義します。これは、ニックの説明とほぼ一致します。ここでは、関数の入力と出力は暗黙的なサーバー状態になるため、「サーバーが実行中」状態はこの関数の固定小数点になります。ここのウィキペディアの記事を誤解しているのかもしれませんが、他の参考文献にリンクしていただけますか?
アモン

16
@Polygnome:この答えは正しいです。べき等性とは、関数が一度呼び出されても複数回呼び出されても問題ではない関数を指し、結果は常に同じです。この場合、結果は、関数が呼び出される回数とは無関係に、httpサービスを実行するものになります。
Doc Brown

14
混乱は、中核のi等性が関数に適用される数学的概念であるという事実から生じます。定義はそれらにとって素晴らしくシンプルであり、純粋な関数型言語でもうまく機能します。副作用を導入するとすぐに複雑になります。関数を実行する環境を(暗黙の)引数および関数の出力として考慮する必要があります。その状態が関数へのさらなる呼び出しによって修正されない場合、それはdem等であり、そうでない場合はそうではありません。この場合、関連する状態は「httpサーバーが実行中」です。したがって、関数はべき等です。
-Voo

10
@Polygnome申し訳ありませんが、あなたは間違っています。べき等とは、リクエストが1回実行されても複数回実行されても同じ効果があることを意味します。要求のN個の重複が受信された場合、N個のhttpサーバーを起動することは、definitely等ではありません。
カズ

7

この実装一つとしてツールをstartHttpServerあなたはそれが最も簡単な滑らかで作ろうとしなければならないシームレスに使用します...

関数のロジック

技術的には、分割することによりstartHttpServer、2つの'関数にsのロジックをし、それらを呼び出す別に、あなたがされないものをすべて移動 startHttpServer冪等を、あなたが何をするかである第三の機能(の両方のロジックをラップしない限り、さらに...代わりに、両方の機能を呼び出すコードにstartHttpServerそもそも)、これにより、DRYされていないコードを記述し、を呼び出す必要のあるすべての場所で指数関数的に複製しますstartHttpServer。要するに、関数自体startHttpServer 呼び出す必要がありisHttpServerRunningます。

だから私のポイントは:

  • isHttpServerRunningとにかくこれは独立して必要になる可能性があるため、関数を実装します...
  • それに応じて、次のアクションを定義するためstartHttpServerに使用isHttpServerRunningするように実装します...

それでも、startHttpServerこの関数のユーザーが必要とする可能性のある任意の値を返すことができます。例えば:

  • 0 =>サーバーの起動失敗
  • 1 =>サーバー起動成功
  • 2 =>サーバーはすでに開始されています

関数の命名

まず、ユーザーの主な目標は何ですか?するHTTPサーバを起動し、右?

基本的に、すでに開始されているもの、AKAを開始しようとすることで問題はありません1*1=1。それで、少なくとも私にとって、それを「ensureHttpServerIsRunning」と呼ぶことはそれほど必要ではないように思えます。関数の名前がどれだけ長く、自然で記憶に残るかをもっと気にしたいと思います。

フードの下の関数の詳細な作業方法を知りたい場合は、そのためのドキュメントまたはコードソースがあります。ライブラリ/フレームワーク/ API /などの他の関数のように...

あなたそれを複数回書いている間に一度あなたは関数を学びます...

とにかく、私startHttpServerはに比べて短く、シンプルで、より明示的であることに固執しensureHttpServerIsRunningます。


1
特に、このメソッドはルートディレクトリ、セキュリティ設定、場合によってはポート番号などの構成引数をとる必要があるため、ここで「開始」することに100%満足しています。
user949300

@ user949300: "ensureHttpServerIsRunning"の呼び出し元は、構成、ルートディレクトリなどを気にしません。それは、それを実装する人の仕事です。
gnasher729

2
@ gnasher729これは、httpサーバーがシングルトンであることを前提としています。シングルトンは悪です。ここではおそらく不適切です。複数のポートに複数のサーバーを簡単に配置できます。本当にhttpサーバーが1つしかない場合、このメソッド全体はIMOであり、設計が悪いプログラムの初期化時にサーバーを一度だけ起動する方が良いでしょう。
user949300

2

私はあなたの同僚がそれstartHttpServerをやりすぎていることを意味すると思います:

  • サーバーが既に実行されているかどうかを確認し、
  • 必要に応じてサーバーを起動します。

これらは、コードの2つの無関係な部分です。たとえば、デスクトップアプリケーションが起動時にまだ実行されていないことを確認する必要がある場合、同様の状況が存在します。アプリインスタンスを処理するコードの一部(たとえば、ミューテックスを使用)と、アプリケーションメッセージループを開始するコードがあります。

つまり、1つではなく、少なくとも1つの2つのメソッドが必要です。

  • isHttpServerRunning: boolean
  • startHttpServer

アプリケーションのエントリポイントは最初のメソッドを呼び出し、戻り値がの場合は2番目のメソッドを呼び出しますfalse。現在、すべてのメソッドは1つのことを実行しており、理解しやすいものです。


¹サーバーが既に実行されているかどうかを知るために必要なロジックが複雑すぎる場合、複数のメソッドにさらに分離する必要があります。


21
2つの関数を呼び出す別の何かが2つのことを行っています。さらに、関数を個別に公開すると競合状態が発生する可能性があります。無料のランチはありません。
-whatsisname

1
同僚にとってそれが多すぎる場合は、幸運を祈ります。
gnasher729

@ gnasher729:この答えはあなたのものと矛盾しません-まったく逆で、メソッドの名前の変更を2つに分割することを組み合わせるのは良い考えかもしれません。また、実際のコードが表示されない限り、コードがどれほど複雑かはわかりません。
Doc Brown

10
この答えは、抽象化とDRYに反対しているようです。startHttpServerコード内で複数の場所が呼び出された場合はどうなりますか?複数の同様の行をどこにでもコピーアンドペーストする必要がありますか?これはすべての機能で行う必要がありますか?すぐにプログラムのサイズは無限になります。
ジャックB

3
このアプローチの最初の副作用は、startHttpServerメソッドの開始がほぼのようになることだと思いますif (isHttpServerRunning()){ return; }。「httpサーバーが既に実行されている場合、httpサーバーを起動することは有効ではありません」というビジネスルールをアサートしますが、そのルールを強制する責任は他の人に与えます。アドホックで、電話をかける可能性のあるすべての場所で繰り返しstartHttpServer
アロス

2

言語を指定しないので、JavaScriptの多くのライブラリには「1回」関数(たとえば、アンダースコア)があります。そのため、それが馴染みのある場合は、「1回」パターンと呼び、メソッドの名前を変更する可能性があります。

私自身、Javaから来たもので、「キャッシング」または「遅延評価」という用語が思い浮かびます。「べき等」は技術的に正確であり、特に良い選択です。より機能的な背景がある場合。


サーバーを停止できる場合、「1回」ではない可能性があります。
gnasher729

@ gnasher729。めったに使用されないrestartHttpServer()方法を想像できました。しかし、ただ停止します -そこにユースケースは何ですか?散発的な接続障害が好きですか?:-)
user949300

HTTPサーバーがプログラム自体の外部の何かによって停止された可能性があるため、HTTPサーバーを停止するだけのユースケースは必要ありません。等
デイブ・セロフマン

Dave、クラッシュは「例外的」であり、そのように処理する必要があります。また、クラッシュはいつでも発生する可能性があるので、コードのすべての行がそうである必要はありませんensureRunning()か?:-)管理者がそれを停止することに関しては、管理者が何かを修正または修正しようとしている間にこの他のコードが絶えず再起動することは、非常に迷惑で間違っています。コードではなく、管理者に再起動させます。
user949300

-2

私は好むstartHttpServerIfNotIsRunning

このように、条件はメソッド名にすでに明記されています。EnsureあるいはmakeSure、それは技術的な表現ではないとして、私には少しあいまいなようです。何が起こるのか正確にはわからないようです。


私はあなたがネイティブスピーカーではないと仮定していますか?なぜなら、ensure目的を正確に定義しているからです。しかし、それでもドキュメントとAPIがネイティブの英語話者レベルを理解できることを要求するべきではないことは公正な点です。
VOO

1
どういうEnsure意味なのか、私はまったく知りません。技術的な表現としてこの言葉がまだ好きではありません。Ensure人間のものです。システムは何も保証することはできません。システムが行うべきことを行うだけです。
君ダーブ

2
@Voo-私はネイティブスピーカーです。どのような意味があるのか​​わかりません。
ジョナサンキャスト

ここに投稿するすべての人がインターネットにアクセスできるので、どういう意味かわからないのに「Ensure」の定義を調べてみませんか?ちょっとしたトリビア...多くの人々は、「Ensure」と「Assure」の使用を交換しますが、これらの単語の1つを使用すると誤って「合法的に」責任を負い、他の単語は責任を負わないことに気づきません。
ダンク

@jcast:真剣に?
gnasher729

-3

あなたの同僚があなたに言ったことは、あなたはその方法を書いているビジネスがないということです。それはすでに何度も書かれており、あなたが書こうとするよりもよく書かれています。例:http : //docs.ansible.com/ansible/latest/systemd_module.html https://docs.saltstack.com/en/latest/ref/states/all/salt.states.service.html

アーキテクチャの観点から見ると、Webサーバーを管理するコードの任意のビットが悪夢のようなものです。サービスの管理があなたのコードが独占的に行うことでない限り。しかし、私はあなたがmonit(またはkubernetesまたは...)を書いていなかったと推測しています。


2
言語はJavaであり、このメソッドはスタンドアロンのJerseyアプリケーションでグリズリー組み込みサーバーを起動するように設計されています。あなたのコメントの正確性に誤りはありません、私はあなたに多くの文脈を与えなかったので、あなたはあなたの声明を作ることに多くを仮定しました。サーバーを起動するためにjettyまたはgrizzlyを呼び出すメソッドがあるのはまったく問題ありません。
ジョンカルコート

1
APIを提供する自己ホスト型HTTPサーバーを含む数百万のビジネスアプリケーションがあります。そして、それらのすべてが持ついくつかの非常に単純な実際に彼らが使用しているライブラリを設定し、そのようにバインドするインターフェイスなどの情報を提供し、コード、使用するポート、セキュリティ設定などが必要になりますstartServer機能または類似する珍しい何でもあり。それは、あなたが核心な低レベルの詳細を書くことを意味しません。
VOO
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.