Refactoring API klien untuk menghindari duplikasi kode dan bagian parameter yang tidak jelas

8

Saya perlu mengembangkan API, fungsi API adalah permintaan yang memanggil layanan yang diekspos oleh server.

Awalnya API bekerja seperti ini:

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')

Ada banyak kode duplikat dan saya tidak suka cara itu melewati argumen untuk permintaan. Karena ada banyak argumen, jadi saya ingin mengekstraknya dari permintaan dan membuat sesuatu yang lebih parametrik.

Jadi saya refactored dengan cara ini:

# 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)

Pola strategi berhasil, duplikasi dihapus. Terlepas dari ini saya takut memiliki hal-hal rumit, terutama dalam hal argumen, saya tidak suka cara saya menangani mereka, karena ketika saya melihat kode tidak tampak mudah dan jelas.

Jadi saya ingin tahu apakah ada pola atau cara yang lebih baik dan lebih jelas untuk menangani kode API sisi klien semacam ini.

k4ppa
sumber
1
Sudahkah Anda mempertimbangkan untuk menanyakan hal ini di Pertukaran Peninjauan Kode? Para pengguna di sana berspesialisasi dalam hal-hal seperti ini.
Nzall
@NateKerkhofs Ya saya telah mempertimbangkannya, tetapi kemudian saya memilih Programmer karena ini adalah papan tempat untuk bertanya tentang desain dan arsitektur ketika saya membaca di bagian bantuan . Dalam Peninjauan Kode bahkan tidak ada tag untuk refactoring.
k4ppa
2
Itu karena seluruh tujuan CR adalah kode refactoring. Pada dasarnya tersirat bahwa semua pertanyaan di sana adalah tentang kode refactoring. Kode Anda seharusnya sudah berfungsi, tetapi selain itu, jawaban berasumsi bahwa Anda ingin kode Anda diperiksa untuk bug dan refactoring.
Nzall
2
@NateKerkhofs - CR cenderung mengambil fokus yang sangat sempit terkait dengan tinjauan desain. Karena OP meminta panduan tentang arsitektur solusi, saya pikir ini sesuai topik untuk situs ini.

Jawaban:

1

Saya akan mempertimbangkan kembali menggunakan kamus (hash, peta, apa pun bahasa Anda memanggil seperangkat pasangan kunci / nilai) untuk argumen. Melakukannya dengan cara itu membuat kompiler tidak dapat memeriksa apakah pemanggil telah memasukkan semua nilai yang diperlukan. Itu membuat pengembang kesulitan menggunakannya untuk mencari tahu apakah mereka memiliki semua argumen yang diperlukan. Ini membuatnya mudah untuk secara tidak sengaja memasukkan sesuatu yang tidak Anda butuhkan dan melupakan sesuatu yang memang Anda butuhkan. Dan Anda akhirnya harus memasukkan semua nilai ke dalam kamus saat memanggil, dan harus memeriksa kamus di setiap fungsi untuk mengekstraksi semua argumen, menambah overhead. Menggunakan semacam struktur khusus dapat mengurangi jumlah argumen tanpa mengurangi kemampuan kompiler untuk memeriksanya dan kemampuan pengembang untuk melihat dengan jelas apa yang dibutuhkan.

pengguna1118321
sumber
Sama seperti add-on, jika Anda khawatir tentang memastikan semua parameter dilewatkan untuk permintaan yang diberikan, maka Anda dapat melihat menggunakan kelas atau antarmuka abstrak (tidak ingat apakah itu ada di python dengan cara yang sama seperti C # atau Java) , tapi itu bisa menjadi berlebihan tergantung pada ruang lingkup saat ini. Manfaat utama akan memiliki definisi yang jelas per permintaan.
eparham7861
0

Saya pikir API server Anda harus memiliki entri sebanyak permintaan yang diminta. Dengan demikian, setiap pengembang akan dapat membaca API dengan mudah ( lihat lask routing sebagai contoh ).

Untuk menghindari duplikasi dalam kode, Anda dapat menggunakan metode internal

juanmiguelRua
sumber
0

API, arsitektur, dan pola semuanya tentang komunikasi dan maksud. Versi kedua Anda terlihat cukup sederhana bagi saya dan tampaknya agak bisa diperluas juga, tetapi pendapat saya (atau bahkan milik Anda) bukanlah yang penting di sini.

Dapatkan umpan balik

Lihatlah perangkat lunak Anda dari luar ke dalam (bukan dari dalam ke luar). Jika sudah memiliki situs web, mulailah dari sana. Berharap untuk menemukan dengan mudah satu dan hanya satu cara yang jelas untuk melakukan apa yang diharapkan perangkat lunak Anda. Temukan seseorang di lorong dan minta umpan balik tentang kegunaannya.

Identifikasi objek bisnis utama

Karena pemrograman perangkat lunak selalu tentang membuat sesuatu yang baru dari dua hal yang berbeda, memiliki sesuatu Serveryang Requestmasuk akal bagi saya. The Servermungkin memerlukan konfigurasi dan memiliki default masuk akal. Anda mungkin menyediakan sesuatu seperti singleton atau pabrik untuk memudahkan penggunaannya. Hal-hal menarik yang sebenarnya terjadi di Request. Klien Anda hanya perlu memastikan untuk membangun Requestobjek yang tepat . Buat niat Anda jelas dan bisnis Anda jelas.

Terbuka untuk ekstensi, tetapi tertutup untuk modifikasi

Anda bisa membuatnya lebih sederhana dengan menyandikan perilaku yang berbeda menggunakan pewarisan alih-alih beberapa metode publik di Requestobjek, cukup banyak seperti dalam pola perintah . Dengan cara ini, klien juga dapat menulis permintaan mereka sendiri, dan permintaan baru dapat disediakan oleh plugin (menggunakan titik masuk setuptools misalnya) jika diperlukan. Ini juga akan memastikan bahwa Requestobjek tidak pernah menjadi kelas dewa , atau API diubah jika fitur baru ditambahkan.

abstrus
sumber