web-dev-qa-db-ja.com

コードの重複や不明確なパラメーターの通過を回避するためのクライアントAPIのリファクタリング

APIを開発する必要があります。APIの機能は、サーバーによって公開されたサービスを呼び出すリクエストです。

最初、APIは次のように機能しました。

class Server:
    def firstRequest(self, arg1, arg2):
        # block of code A
        async = Async()
        async.callFirstRequest(arg1, arg2)
        # block of code B

    def secondRequest(self, argA, argB, argC):
        # block of code A (identical to that of firstRequest)
        async = Async()
        async.callSecondRequest(argA, argB, argC)
        # block of code B (identical to that of firstRequest)

class Async:
    def callFirstRequest(self, arg1, arg2):
        doFirstRequest(arg1, arg2)

    # run the real request and wait for the answer
    def doFirstRequest(self, arg1, arg2):
        response = client.firstRequest(arg1, arg2)

    def callSecondRequest(self, argA, argB, argC):
        doSecondRequest(argA, argB, argC)

    # run the real request and wait for the answer
    def doSecondRequest(self, argA, argB, argC):
        response = client.secondRequest(argA, argB, argC)

server = Server()
server.firstRequest(arg1=1, arg2=2)
server.secondRequest(argA='A', argB='B', argC='C')

重複したコードがたくさんあり、リクエストの引数を渡す方法が好きではありません。引数はたくさんあるので、リクエストからそれらを抽出して、よりパラメトリックなものにしたかったのです。

だから私はこのようにリファクタリングしました:

# using a strategy pattern I was able to remove the duplication of code A and code B
# now send() receive and invoke the request I wanna send
class Server:
    def send(self, sendRequest):
        # block of code A
        asynch = Async()
        sendRequest(asynch)
        # block of code B

# Request contains all the requests and a list of the arguments used (requestInfo)
class Request:
    # number and name of the arguments are not the same for all the requests
    # this function take care of this and store the arguments in RequestInfo for later use
    def setRequestInfo(self, **kwargs):
        if kwargs is not None:
            for key, value in kwargs.iteritems():
                self.requestInfo[key] = value

    def firstRequest(async)
        async.doFirstRequest(self.requestInfo)

    def secondRequest(async)
        async.doSecondRequest(self.requestInfo)

# Async run the real request and wait for the answer
class Async:
    def doFirstRequest(requestInfo):
        response = client.firstRequest(requestInfo['arg1'], requestInfo['arg2'])

    def doSecondRequest(requestInfo)
        response = client.secondRequest(requestInfo['argA'], requestInfo['argB'], requestInfo['argC'])  


server = Server()
request = Request()

request.setRequestInfo(arg1=1, arg2=2) # set of the arguments needed for the request
server.send(request.firstRequest)

request.setRequestInfo(argA='A', argB='B', argC='C')
server.send(request.secondRequest)

戦略パターンが機能し、重複が削除されました。これに関係なく、特に引数に関しては、複雑なことをするのが怖いです。コードを見ると、簡単で明確に見えないので、それらの扱い方が好きではありません。

そのため、この種のクライアント側APIコードを処理するためのパターンまたはより明確で明確な方法があるかどうかを知りたいと思いました。

8
k4ppa

引数に辞書(ハッシュ、マップ、言語がキーと値のペアのセットを呼び出すものは何でも)を使用することを再考します。そのようにすると、呼び出し元が必要な値をすべて含んでいるかどうかをコンパイラがチェックできなくなります。開発者がそれを使用して、必要なすべての引数があるかどうかを判断するのは困難です。必要のないものを誤って入れてしまい、必要のないものを忘れてしまいがちです。また、呼び出し時にすべての値を辞書に入れなければならず、すべての関数で辞書をチェックしてすべての引数を抽出しなければならず、オーバーヘッドが増加します。ある種の特殊な構造を使用すると、コンパイラーが引数をチェックする能力や開発者が必要なものを明確に確認する能力を低下させることなく、引数の数を減らすことができます。

1
user1118321

サーバーAPIには必要なリクエストと同じ数のエントリが必要です。したがって、開発者は誰でも簡単にAPIを読み取ることができます( 例としてlaskルーティングを参照 )。

コードの重複を避けるために、内部メソッドを使用できます

0
juanmiguelRua

API、アーキテクチャ、パターンはすべて、コミュニケーションと意図に関するものです。あなたの2番目のバージョンは私には十分にシンプルに見え、多少拡張可能に見えますが、私の意見(またはあなたの意見)はここでは重要ではありません。

フィードバックを取得

ソフトウェアを外側から内側から見てください。ウェブサイトがある場合は、そこから始めます。ソフトウェアが実行することが期待されていることを実行するための1つだけの明白な方法を簡単に見つけることを期待してください。 hallway で誰かを見つけて、ユーザビリティに関するフィードバックを求めます。

主要なビジネスオブジェクトを特定します

ソフトウェアプログラミングは常に2つの異なるものから何かを新しくすることを目的としているため、Serverを取るRequestを用意することは私には理にかなっているようです。 Serverはおそらく設定が必要であり、適切なデフォルトがあります。使用を容易にするために、おそらくシングルトンまたはファクトリーのようなものを提供します。実際の興味深いものはRequestで発生します。クライアントは、適切なRequestオブジェクトを構築する必要があります。意図を明確にし、 ビジネス を明確にします。

拡張のために開いているが、変更のために閉じている

コマンドパターン のように、Requestオブジェクトで複数のパブリックメソッドの代わりに継承を使用してさまざまな動作をエンコードすることで、さらに簡単にすることができます。このようにして、クライアントは独自のリクエストを書き込むこともでき、必要に応じてプラグイン(たとえば、setuptoolsのエントリポイントを使用)によって新しいリクエストを提供できます。これにより、Requestオブジェクトが god class にならないようにするか、新しい機能が追加された場合にAPIが変更されるようにします。

0
abstrus