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.
Jawaban:
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.
sumber
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
sumber
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
Server
yangRequest
masuk akal bagi saya. TheServer
mungkin memerlukan konfigurasi dan memiliki default masuk akal. Anda mungkin menyediakan sesuatu seperti singleton atau pabrik untuk memudahkan penggunaannya. Hal-hal menarik yang sebenarnya terjadi diRequest
. Klien Anda hanya perlu memastikan untuk membangunRequest
objek 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
Request
objek, 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 bahwaRequest
objek tidak pernah menjadi kelas dewa , atau API diubah jika fitur baru ditambahkan.sumber