Apakah ini praktik pengkodean yang buruk untuk menciptakan sesuatu jika tidak ada?

18

Jadi saya memiliki layanan web yang memiliki sesuatu seperti di getAccountmana ia akan mengembalikan pengenal ke akun jika mendapatkannya, selain melemparkan pengecualian. Klien akan selalu ingin membuat akun jika pengecualian dilemparkan dengan info yang sama dengan yang dilakukan.

Saya membuat perpustakaan praktis untuk klien yang akan menangani semua panggilan layanan web di dalamnya sehingga mereka tidak perlu tahu bagaimana melakukan panggilan itu sendiri.

Apa yang saya pikirkan adalah di perpustakaan ini jika saya membuat akun getAccount(accountName)yang akan mendapatkan akun jika ada, dan jika tidak maka buatlah dan kembalikan info, apakah itu hal yang buruk untuk dilakukan? Haruskah saya serahkan pada klien untuk menangani pengecualian atau cukup beri nama seperti getOrCreateAccount? Apakah itu penting?

Apakah praktik yang buruk untuk membuat sesuatu dalam operasi dapatkan?

Mike
sumber
9
Paling tidak, saya akan menyebutnya getOrCreateAccountatau serupa.
Telastyn
4
Tampaknya valid dalam konteks inisialisasi malas. Namun, itu tergantung jika Anda perlu menggunakan pola itu di perpustakaan Anda.
Chris C
1
Saya suka kata kerjanya acquire, like acquireAccount. Itu tidak memiliki makna yang ada dalam protokol utama yang saya temui, dan memiliki cincin imperatif yang cocok untuknya. "Lakukan apa yang harus kamu lakukan untuk mendapatkan salah satu dari ini untukku. Minta, buat, buat palsu, curi, aku tidak peduli, ambilkan aku satu atau mati coba."
Dan Ross
2
"Klien akan selalu ingin membuat akun" - yang tampaknya sangat tidak biasa. Jika saya tidak bisa mendapatkan akun karena pengguna salah ketik nama pengguna mereka, saya tentu tidak ingin membuat akun dengan nama yang salah ketik.
gnasher729
Menurut spec javabean oracle.com/technetwork/articles/javaee/spec-136004.html getSomething() adalah untuk getter, dan setSomething()untuk setter. Imo apa pun yang melakukan sesuatu yang lebih intelektual harus dipanggil sesuatu yang lain, yaitu fetchSomething, obtainSomething, computeSomething, atau doSomethingElsedll
ccpizza

Jawaban:

31

Ya itu penting. Menurut pendapat saya, pada umumnya merupakan praktik yang buruk untuk menciptakan sesuatu dalam prosedur yang tidak didokumentasikan memiliki kekuatan penciptaan. Baik nama prosedur getOrCreate...atau memiliki create...prosedur terpisah dan kemudian jika Anda benar - benar ingin, cobalah getOrCreate...yang pertama get..., dan jika itu gagal, panggilan create...dan panggilan get....

Pengguna perpustakaan mungkin tidak akan mengharapkan get...prosedur untuk membuat jika operasi gagal. Jika mereka tiba-tiba mengetahui bahwa panggilan tes mereka untuk get...menciptakan seluruh data, mereka mungkin akan agak terkejut. Dan bagaimana mereka membersihkannya? Bagaimana jika mereka menulis kode berpikir bahwa mereka akan mendapatkan kesalahan jika get...gagal dan mereka ingin mengatasinya dengan cara mereka ?

FrustratedWithFormsDesigner
sumber
Terima kasih, buat sebenarnya mengembalikan id yang mendapatkan akan kembali juga jadi saya tidak perlu melakukan get... create... get...hanya dua yang pertama. Saya akan berbicara dengan klien tentang apakah mereka akan memerlukan kemampuan untuk sekadar memanggil gettanpa ingin membuat
Mike
6
@ Mike: Saya masih berpikir itu seharusnya ada createdalam nama, hanya untuk menjadi 100% jelas tentang apa yang terjadi.
FrustratedWithFormsDesigner
Ya saya setuju, saya berencana membuat sesuatu sesuai aturan getOrCreate karena pemikiran awal saya hanya untuk mendapatkan tetapi saya menyadari bahwa tidak segera jelas bahwa itu juga menciptakan sesuatu di latar belakang
Mike
1
Ini sangat terlambat tetapi getOrCreatememiliki prioritas dalam kerangka kerja web yang populer: docs.djangoproject.com/en/1.10/ref/models/querysets/…
tex
18

Tidak, ini bukan 'praktik buruk'. Selama Anda dan pengembang lain sepakat bahwa itulah yang Anda inginkan, itu baik-baik saja. Bagaimanapun, itu akan mengembalikan akun, yang Anda inginkan. Bahwa akun dibuat 'di bawah tenda' tidak relevan bagi penelepon.

GrandmasterB
sumber
10
Satu-satunya pengecualian adalah jika itu adalah API yang tersedia untuk umum. Komunitas yang lebih besar telah sepakat bahwa GET bersifat indempoten dan nullipoten; dengan kata lain, tindakan yang sama dilakukan setiap kali, dan ini adalah metode yang aman yang tidak mengubah keadaan server. Ini ada di REST Wiki . Selain itu, jika API hanya ada di dunia kecil Anda sendiri, lakukan apa pun yang diterima oleh grup Anda.
jmort253
9
Saya tidak setuju, bahkan untuk API publik tidak masalah - selama itu masuk akal dalam konteks apa pun yang seharusnya dilakukan oleh API. Ada sedikit gunanya membuat banyak entri di API ketika satu orang akan melakukan trik.
GrandmasterB
Sebagai catatan, ini adalah sepenuhnya perpustakaan internal dan saya memiliki kemampuan untuk hanya memberitahu tim menggunakan cara kerjanya
Mike
1
@ jmort253: Layanan nullipotent jika tidak memiliki efek samping yang terlihat oleh klien . Server dapat melakukan apa saja yang diinginkan.
kevin cline
1
@ kevincline, saya kira saya memikirkannya dalam hal, katakanlah, menagih kartu kredit saya. Jika server mengisi daya kartu saya berdasarkan permintaan GET tetapi masih memberi saya hasil seperti "ditolak" setiap kali saya menjalankannya, rasanya seperti bertentangan dengan semangat GET. Dengan itu, saya melihat maksud Anda. Server dapat menghitung jumlah permintaan GET dan mengunci saya setelah 3 pertanyaan, sehingga tingkat membatasi saya, tetapi tanpa mengubah rincian akun saya. Saya pikir itu perbedaan penting ketika seseorang mengatakan keadaan server tidak dimodifikasi. Mungkin saya harus mengatakan "client state on server"
jmort253
10

Jika getAccount()selalu dapat mengembalikan akun, maka dari sudut pandang penelepon, akun itu memang ada, dan selalu ada. Tidak perlu untuk getAccount()'membuat' apa pun. Akun tidak harus disimpan di mana pun sampai berbeda dari akun default.

kevin cline
sumber
+1 Secara umum, GetOrCreateadalah semantik yang salah tetapi mendapatkan objek yang mungkin "secara logis" ada apakah secara fisik ada atau tidak ada. Sebagai contoh, sejumlah kecil item yang bisa berubah mungkin tidak memiliki penyimpanan yang dialokasikan untuk elemen 1.841.533, tetapi masih memungkinkan elemen itu untuk "diambil" dengan membuat objek baru, menyimpannya, dan mengembalikan referensi.
supercat
4

Masuk akal untuk membuat 3 metode:

getAccount -> Yang baru saja mendapatkan akun.

createAccount -> Membuat akun.

getAccountAndCreateIfNeeded -> Pilih nama Anda sendiri;)

Mengapa pemisahan: Anda memiliki metode sederhana untuk mendapatkan dan membuat. Itu adalah metode yang dapat diuji jelas untuk keduanya. Untuk getAccount bukan pengecualian untuk tidak menemukan akun. Jadi kembalikan saja yang salah atau yang seperti itu, itu yang diharapkan.

Kemudian Anda dapat menggunakan nilai kembali itu dalam fungsi yang dikelompokkan: getAccountAndCreateIfNeeded yang sekarang juga dapat diuji, itu harus selalu mengembalikan akun. Apapun yang kamu minta.

Ketiga metode ini jelas, jelas apa yang mereka lakukan dan apa yang mereka kembalikan. Anda dapat membuat perjanjian sekarang dengan tim Anda, tetapi pengecualian semacam ini mengerikan dalam jangka panjang. Cukup jelaskan dan Anda tidak akan mengalami masalah.

Luc Franken
sumber
Juga, dari Clean Code: "Jika metode Anda tidak dapat melakukan sesuai dengan namanya, maka buang Exception." Saya akan memiliki blok Coba / Tangkap di dalam 'GetOrCreateIfneeded' yang menampilkan GET yang gagal dan kemudian memiliki 'createAccount' di dalam Throw untuk jenis pengecualian apa pun yang kembali untuk mendapatkan yang gagal.
Graham
Saya mungkin menyarankan metode keempat:, getAccountIfExistsyang akan mendapatkan akun atau menunjukkan bahwa itu tidak ada tanpa membuat yang baru. The getAccountmetode itu sendiri harus mengandaikan bahwa akun itu ada, dan melemparkan pengecualian jika tidak.
supercat
2

Itu tergantung keadaan.

Sebagai contoh, Anda dapat menggunakannya untuk melakukan lazy loading / instantiation, menunda pemuatan data atau pembuatan instance hingga benar-benar dibutuhkan. Ini biasanya masuk akal karena menghemat sumber daya yang mungkin tidak Anda butuhkan (jika kelas / data tidak pernah dibutuhkan maka tidak pernah dimuat).

Namun, dalam kasus khusus ini, saya akan mengatakan bahwa memiliki metode yang disebut getAccount yang akan membuat akun baru jika tidak ada tidak akan menjadi praktik yang baik. Jika pengguna telah memberikan beberapa kredensial untuk mengidentifikasi akun tertentu dan akun itu tidak dapat ditemukan, apakah itu berarti bahwa pengguna belum menjadi pelanggan dan harus memiliki akun yang dibuat untuk mereka, atau apakah itu berarti bahwa kredensial salah ketik dan pengguna perlu diminta untuk memverifikasi bahwa mereka telah memasukkan apa yang mereka maksudkan untuk masuk?

Jika Anda memiliki metode getAccount yang memang membuat akun baru jika tidak dapat mengidentifikasi satu, maka Anda tidak punya pilihan dalam masalah ini. Jika Anda membagi pembuatan akun dan menggunakan metode terpisah, maka Anda memiliki lebih banyak fleksibilitas dalam memutuskan apa yang harus dilakukan jika upaya untuk mendapatkan akun gagal.

GordonM
sumber