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


8

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コードを処理するためのパターンまたはより明確で明確な方法があるかどうかを知りたいと思いました。


1
コードレビューエクスチェンジでこれについて質問することを検討しましたか?そこのユーザーはこのようなことに特化しています。
Nzall

@NateKerkhofsはい私はそれを検討しましたが、私がプログラマーを選択したのは、これがヘルプセクションで読んだ設計とアーキテクチャについて質問するボードだからです。コードレビューでは、リファクタリングのタグすらありません。
k4ppa

2
これは、CRの目的全体がコードのリファクタリングであるためです。基本的に、そこにあるすべての質問はコードのリファクタリングに関するものであることを意味します。コードはすでに機能しているはずですが、それとは別に、バグとリファクタリングのためにコードをチェックアウトすることを前提としています。
Nzall

2
@NateKerkhofs-CRは、デザインレビューに関して非常に狭い焦点を当てる傾向があります。OPがソリューションのアーキテクチャについてのガイダンスを求めているので、このサイトのトピックであると思います。

回答:


1

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


アドオンと同様に、特定のリクエストに対してすべてのパラメーターが渡されることを確認する必要がある場合は、抽象クラスまたはインターフェースを使用して調べることができます(PythonにC#またはJavaと同じ方法で存在するかどうか覚えていないでください)が、現在のスコープによってはやり過ぎになる可能性があります。主な利点は、リクエストごとに明確な定義を持つことです。
eparham7861


0

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

フィードバックを得る

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

主なビジネスオブジェクトを特定する

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.