Merancang metode terkait basis data, mana yang lebih baik untuk dikembalikan: true / false atau baris yang terpengaruh?

10

Saya memiliki beberapa metode yang melakukan beberapa perubahan data dalam database (menyisipkan, memperbarui, dan menghapus). The ORM Saya menggunakan kembali baris-dipengaruhi nilai-nilai int bagi mereka jenis metode. Apa yang harus saya kembalikan untuk "metode saya", untuk menunjukkan keberhasilan / kegagalan operasi?

Pertimbangkan kode yang mengembalikan int:

A.1

public int myLowerLevelMethod(int id) {
    ...
    int affectedRows = myOrm.deleteById(id)
    ...

    return affectedRows;
}

Kemudian penggunaan:

A.2

public void myOtherMethod() {
    ...
    int affectedRows = myLowerLevelMethod(id)

    if(affectedRows > 0) {
        // Success
    } else {
        // Fail
    }
}

Bandingkan dengan menggunakan boolean:

B.1

public boolean myLowerLevelMethod(int id) {
    ...
    int affectedRows = myOrm.deleteById(id)
    ...

    return affectedRows > 0;
}

Kemudian penggunaan:

B.2

public void myOtherMethod() {
    ...
    boolean isSuccess = myLowerLevelMethod(id)

    if(isSuccess) {
        // Success
    } else {
        // Fail
    }
}

Yang mana (A atau B) yang lebih baik? Atau pro / kontra masing-masing?

Hoang Tran
sumber
Di "A.2" Anda. Jika nol baris terpengaruh, mengapa itu gagal jika nol baris perlu dipengaruhi? Dengan kata lain jika tidak ada kesalahan basis data, mengapa gagal?
Jaydee
5
Apakah ada perbedaan semantik antara "tidak berhasil" dan "baris nol yang terpengaruh"? Misalnya, ketika menghapus semua pesanan pelanggan, ada perbedaan antara "pelanggan tidak ada" dan "pelanggan tidak memiliki pesanan".
Cephalopod
Apakah Anda menganggap penghapusan dengan nol baris tidak terduga? Dalam hal ini lemparan.
usr
@Arian saya pikir itu adalah pertanyaan sebenarnya bagi saya. Saya pikir saya akan memilih B, karena dengan A, kode saya sekarang berisi memeriksa 0 di beberapa tempat dan -1 di tempat lain
Hoang Tran

Jawaban:

18

Pilihan lain adalah mengembalikan objek hasil daripada tipe dasar. Sebagai contoh:

OperationResult deleteResult = myOrm.deleteById(id);

if (deleteResult.isSuccess()) {
    // ....
}

Dengan ini, jika karena alasan tertentu Anda perlu mengembalikan jumlah baris yang terpengaruh, Anda bisa menambahkan metode di OperationResult:

if (deleteResult.isSuccess()) {
    System.out.println("rows deleted: " + deleteResult.rowsAffected() );
}

Desain ini memungkinkan sistem Anda tumbuh dan mencakup fungsionalitas baru (mengetahui tentang baris yang terpengaruh) tanpa mengubah kode yang ada.

AlfredoCasado
sumber
2
+1 "Desain ini memungkinkan sistem Anda tumbuh dan menyertakan fungsionalitas baru (mengetahui tentang baris yang terpengaruh) tanpa mengubah kode yang ada" Ini adalah cara berpikir yang benar tentang kategori pertanyaan ini.
InformedA
Saya melakukan hal serupa di proyek lama saya. Saya memiliki objek Permintaan dan Hasil pembungkus. Keduanya menggunakan Komposisi untuk memasukkan lebih banyak detail. dan keduanya memiliki data dasar di dalamnya juga. Dalam hal ini, objek Hasil memiliki kode status dan bidang pesan.
InformedA
Khusus untuk sistem yang menggunakan ORM, saya akan menyebut praktik terbaik ini. ORM yang dimaksud mungkin sudah menyertakan jenis objek hasil seperti itu juga!
Brian S
Hanya dengan melihat contoh OPs, yang bisa saya pikirkan adalah deleteById akan mengembalikan 2 di beberapa titik :) jadi pasti tipe kustom, ya.
deadsven
Saya suka pendekatan ini. Saya pikir itu adalah non-blocking, mencakup kedua pendekatan saya, dan dapat dimodifikasi / diperluas (di masa depan, jika perlu). Satu-satunya downside yang bisa saya pikirkan adalah sedikit lebih banyak kode, terutama ketika itu datang di tengah-tengah proyek saya. Saya akan menandai ini sebagai jawabannya. Terima kasih.
Hoang Tran
12

Mengembalikan jumlah baris yang terpengaruh lebih baik karena memberikan informasi tambahan tentang bagaimana operasi berjalan.

Tidak ada programmer yang akan menyalahkan Anda karena ia harus menulis ini untuk memeriksa apakah ada perubahan selama operasi:

if(affectedRows > 0) {
    // success
} else {
    // fail
}

tetapi mereka akan menyalahkan Anda ketika mereka harus tahu jumlah baris yang terpengaruh dan mereka menyadari tidak ada metode untuk mendapatkan nomor itu.

BTW: jika dengan "kegagalan" yang Anda maksud adalah kesalahan kueri sintaksis (dalam hal ini jumlah baris yang terpengaruh jelas 0) maka melempar pengecualian akan lebih tepat.

Polisi
sumber
4
-1 karena alasan yang Anda berikan. Memberikan informasi tambahan tidak selalu merupakan ide yang baik. Seringkali, desain yang lebih baik akan mengarah pada komunikasi dengan penelepon hanya apa yang dibutuhkan, dan tidak lebih.
Arseni Mourzenko
1
@ MainMa tidak ada yang menghalangi pembuatan metode kelebihan beban. Selain itu, dalam bahasa asli (keluarga C misalnya), jumlah baris dapat digunakan secara langsung dalam logika (0 salah, yang lainnya benar).
PTwr
@ PTw: jadi untuk mengatasi kenyataan bahwa metode ini mengembalikan terlalu banyak informasi, Anda sarankan membuat kelebihan? Ini sepertinya tidak benar. Adapun "nol adalah salah, bukan nol adalah benar", ini bukan poin dari komentar saya, dan merupakan praktik buruk dalam beberapa bahasa.
Arseni Mourzenko
1
Mungkin saya salah satu programmer manja karena saya tidak berpikir menggunakan trik apa pun bisa dianggap praktik yang baik. Bahkan, setiap kali saya harus berurusan dengan kode orang lain, saya berterima kasih kepada siapa pun yang menulisnya dan tidak menggunakan trik apa pun.
proskor
4
Anda harus selalu mengembalikan jumlah baris yang terpengaruh di sini !!! Karena Anda tidak mungkin tahu apakah jumlah baris = 0 gagal, atau apakah jumlah baris = 3 berhasil? Jika seseorang ingin memasukkan 3 baris dan hanya 2 yang dimasukkan, Anda akan mengembalikan true, tetapi itu tidak benar! Dan jika seseorang ingin update t set category = 'default' where category IS NULLmeratakan 0 baris yang terpengaruh akan menjadi sukses, karena sekarang tidak ada item tanpa kategori, bahkan jika tidak ada baris yang terpengaruh!
Falco
10

Saya tidak akan merekomendasikan mereka. Alih-alih, jangan kembalikan apa pun (batal) pada kesuksesan dan berikan pengecualian pada kegagalan.

Ini untuk alasan yang persis sama saya memilih untuk mendeklarasikan memebers tertentu dari kelas privat. Ini juga membuat fungsi lebih mudah digunakan. Konteks yang lebih operasional tidak selalu berarti lebih baik, tetapi tentu saja berarti lebih kompleks. Semakin sedikit yang Anda janjikan, semakin abstrak Anda, semakin mudah bagi klien untuk memahami dan semakin banyak kebebasan yang Anda miliki dalam memilih bagaimana menerapkannya.

Pertanyaannya adalah bagaimana menunjukkan keberhasilan / kesalahan. Dalam hal ini cukup untuk menandai kegagalan dengan melemparkan pengecualian dan tidak mengembalikan apa pun pada kesuksesan. Mengapa saya harus menyediakan lebih dari kebutuhan pengguna?

Kegagalan / situasi luar biasa dapat terjadi dan Anda harus menghadapinya. Apakah Anda menggunakan mencoba / menangkap untuk melakukannya atau memeriksa kode kembali, adalah masalah gaya / preferensi pribadi. Gagasan di balik try / catch adalah: pisahkan aliran normal dari aliran luar biasa dan biarkan pengecualian muncul hingga ke lapisan di mana mereka dapat ditangani dengan paling tepat. Jadi, seperti yang sudah ditunjukkan banyak orang, itu tergantung pada apakah kegagalan itu benar-benar luar biasa atau tidak.

proskor
sumber
4
-1 Mengapa Anda tidak mengembalikan apa pun di mana Anda dapat mengembalikan sesuatu, tanpa efek samping negatif, yang memberikan konteks operasional tambahan?
FreeAsInBeer
7
Untuk alasan yang persis sama saya memilih untuk mendeklarasikan memebers tertentu dari kelas privat. Ini juga membuat fungsi lebih mudah digunakan. Konteks yang lebih operasional tidak selalu berarti lebih baik, tetapi tentu saja berarti lebih kompleks. Semakin sedikit yang Anda janjikan, semakin abstrak Anda, semakin mudah bagi klien untuk memahami dan semakin banyak kebebasan yang Anda miliki dalam memilih bagaimana menerapkannya.
proskor
1
Nah, data apa yang sebenarnya perlu didapatkan pengguna? Pertanyaannya adalah bagaimana menunjukkan keberhasilan / kesalahan. Dalam hal ini cukup untuk menandai kegagalan dengan melemparkan pengecualian dan tidak mengembalikan apa pun pada kesuksesan. Mengapa saya harus menyediakan lebih dari kebutuhan pengguna?
proskor
4
@proskor: Pengecualian untuk kasus luar biasa. "Kegagalan" dalam skenario ini mungkin merupakan hasil yang diharapkan. Dengan segala cara, cantumkan ini sebagai alternatif potensial, tetapi tidak ada informasi yang cukup di sini untuk membuat rekomendasi.
Nick Barnes
1
-1 Pengecualian tidak boleh menjadi bagian dari aliran program normal. Tidak jelas apa arti "kegagalan" dalam konteks kesalahan Anda, tetapi pengecualian dalam konteks panggilan basis data harus karena pengecualian yang terjadi dalam database. Mempengaruhi nol baris seharusnya tidak menjadi pengecualian. Query rusak yang tidak dapat diuraikan, referensi tabel tidak ada, dll. Akan menjadi pengecualian karena mesin database akan tersedak dan melempar.
2

"Apakah ini lebih baik dari itu?" bukan pertanyaan yang berguna ketika dua alternatif tidak melakukan hal yang sama.

Jika Anda perlu mengetahui jumlah baris yang terpengaruh, maka Anda harus menggunakan versi A. Jika Anda tidak harus, maka Anda dapat menggunakan versi B - tetapi setiap keuntungan yang Anda peroleh dalam hal upaya penulisan kode yang lebih sedikit sudah hilang sejak Anda kesulitan memposting kedua versi ke forum online!

Maksud saya adalah: solusi mana yang lebih baik sepenuhnya tergantung pada apa kebutuhan Anda secara spesifik untuk aplikasi ini, dan Anda tahu keadaan itu jauh lebih baik daripada kita. Tidak ada pilihan industri yang luas, aman digunakan, praktik terbaik, tidak akan dipecat yang lebih baik secara umum ; Anda harus memikirkannya sendiri. Dan untuk keputusan yang mudah direvisi seperti ini, Anda tidak perlu menghabiskan banyak waktu untuk berpikir.

Kilian Foth
sumber
Saya setuju bahwa ini sangat tergantung pada persyaratan aplikasi. Namun sepertinya situasi seperti ini tidak terlalu unik, dan saya tidak mencari peluru perak tapi pengalaman orang lain yang berurusan dengan hal yang sama / mirip (mungkin pertanyaannya agak menyesatkan, saya suka saran selain A / B)
Hoang Tran
1

Dua prinsip terpenting dalam desain perangkat lunak yang dapat dipelihara adalah KISS dan YAGNI .

  • KISS : Tetap Sederhana, Bodoh
  • YAGNI : Kamu Tidak Akan Membutuhkannya

Hampir tidak pernah merupakan ide yang baik untuk memasukkan logika yang tidak Anda butuhkan segera saat ini . Di antara banyak orang lain, Jeff Atwood (salah satu pendiri StackExchange) menulis tentang ini , dan dalam pengalaman saya dia dan pendukung lain dari konsep-konsep ini sepenuhnya benar.

Kerumitan apa pun yang Anda tambahkan ke program dikenakan biaya, dibayar dalam jangka waktu lama. Program menjadi lebih sulit dibaca, lebih kompleks untuk diubah, dan lebih mudah bagi bug untuk masuk. Jangan terpancing untuk menambahkan hal-hal "berjaga-jaga". Itu rasa aman yang salah.

Anda jarang mendapatkan kode yang benar saat pertama kali. Perubahan tidak bisa dihindari; menambahkan logika spekulatif untuk mempersiapkan diri menghadapi kemungkinan tak terduga di masa depan tidak akan benar-benar melindungi Anda dari keharusan memperbaiki kode Anda ketika masa depan ternyata berbeda dari yang Anda harapkan. Pemeliharaan pada logika yang tidak perlu / bergantung lebih merupakan masalah rawatan daripada refactoring kemudian untuk menambahkan fungsionalitas yang hilang.

Jadi, karena tampaknya semua kebutuhan program Anda untuk saat ini adalah untuk mengetahui apakah operasi berhasil atau gagal, solusi B yang Anda usulkan (kembalikan boolean tunggal) adalah pendekatan yang benar. Anda selalu dapat refactor nanti jika persyaratan berubah. Solusi ini adalah yang paling sederhana dan memiliki kompleksitas terendah (KISS) dan melakukan apa yang Anda butuhkan dan tidak lebih dari itu (YAGNI).

Ben Lee
sumber
-1

Seluruh baris atau status kesalahan

Pertimbangkan untuk mengembalikan seluruh baris, setidaknya sebagai opsi run-time. Dalam sisipan DB Anda mungkin perlu memeriksa data yang dimasukkan - karena sering berbeda dari apa yang Anda kirim ke DB; contoh umum termasuk ID baris yang dibuat secara otomatis (bahwa aplikasi kemungkinan akan segera membutuhkannya), nilai default yang ditentukan oleh DB, dan hasil pemicu jika Anda menggunakannya.

Di sisi lain, jika Anda tidak perlu data yang dikembalikan, maka Anda juga tidak perlu jumlah baris yang terkena dampak, karena itu tidak membantu untuk hasil 0. Jika ada kesalahan, maka Anda perlu kembali jenis dari kesalahan terjadi, dengan cara yang konsisten dengan prinsip-prinsip penanganan kesalahan proyek Anda (pengecualian, kode kesalahan numerik, apa pun); tetapi ada kueri yang valid yang akan memengaruhi 0 baris dengan benar (mis. "hapus semua pesanan kedaluwarsa" jika sebenarnya tidak ada).

Peter adalah
sumber