Saya mengembangkan layanan baru di lingkungan layanan mikro. Ini adalah layanan REST. Untuk kesederhanaan, katakanlah jalannya adalah: / buku sejarah
Dan metode POST untuk jalur ini menciptakan buku sejarah baru.
Mari kita asumsikan bahwa buku sejarah mencakup satu atau lebih era dalam sejarah.
Untuk singkatnya, mari kita asumsikan kita hanya memiliki era sejarah manusia berikut:
- Kuno
- Post Klasik
- Modern
Dalam kode saya, saya ingin mewakili mereka dalam enum
.
Badan metode (payload) dalam format JSON, dan harus menyertakan nama bidang eras
. Bidang ini adalah daftar era
nilai, yang dicakup buku ini.
Tubuh mungkin terlihat seperti:
{
"name": "From the cave to Einstein - a brief history review",
"author": "Foo Bar",
"eras": ["Ancient", "Post Classical", "Modern"]
}
Dalam layanan khusus ini, logika bisnisnya adalah:
Jika tidak ada era yang disediakan dalam input, maka buku ini dianggap mencakup semua era.
Dalam ulasan API, saran dibuat:
Sertakan nilai lain ALL
, untuk era enum, untuk secara eksplisit menunjukkan bahwa semua era dicakup.
Saya pikir ada beberapa pro dan kontra.
Pro:
Masukan eksplisit
Cons:
Jika dua item dalam daftar disediakan, katakan ALL
dan Ancient
- apa yang akan diambil dari aplikasi? Saya kira itu ALL
harus mengesampingkan nilai-nilai lain, tapi itu logika bisnis baru.
Jika saya menjalankan kueri, untuk buku yang mencakup era tertentu, bagaimana saya akan mewakili buku yang mencakup semua era? Jika ALL
juga digunakan untuk output (menggunakan logika yang sama), maka tanggung jawab konsumen untuk mengartikannya ALL
sebagai ["Ancient", "Post Classical", "Modern"]
.
Pertanyaan saya
Saya pikir memiliki yang baru ALL
menyebabkan lebih banyak kebingungan daripada tidak memilikinya sama sekali.
Bagaimana menurut anda? Apakah Anda menambahkan ALL
nilai ini atau mempertahankan API Anda tanpanya?
Jawaban:
Tergantung pada apakah era Anda yang tersedia tersedia untuk aplikasi panggilan. Agaknya begitu sehingga pengguna dapat memilih apa yang mereka minati. Jika itu masalahnya maka masalah front-end untuk menyediakan opsi "SEMUA". Jika itu saya, itu akan mengirim daftar semua era daripada opsi "semua". Jika tidak, maka Anda memerlukan opsi "SEMUA" dan menjalankan risiko maka ujung depan akan mendapatkan hal-hal kembali dari era yang tidak akan dimengerti.
Seperti yang Anda tunjukkan, SEMUA dengan opsi lain berarti Anda bisa mendapatkan permintaan yang saling bertentangan. Satu pertimbangan lebih lanjut adalah bahwa Anda dapat melewati "SEMUA" maka enum lain menjadi pengecualian daripada inklusi, misalnya "SEMUA", "Kuno" berarti "Semuanya kecuali Dahulu". Itu masuk akal tapi jelas UI kemudian harus mencerminkan apa yang mungkin terlalu rumit.
TL; DR; Sebagian besar "SEMUA" adalah keramahan UI & Anda dapat mencapai hal yang sama di tingkat layanan tanpa ambiguitas jadi jangan lakukan itu.
sumber
Ini, dan juga memiliki kasus 'SEMUA' khusus, adalah IMHO buruk - API Anda harus eksplisit jika memungkinkan. Memiliki kasus khusus seperti 'tidak ada yang berarti segalanya' berarti bahwa siapa pun yang menggunakan API Anda juga harus mengetahui semua kasus khusus Anda, atau, seperti halnya dengan kasus 'SEMUA', mengarah ke permintaan di mana maksud dan / atau hasilnya ambigu.
Kasus khusus juga sering mengarah pada kode yang lebih kompleks baik dalam hal memvalidasi apakah input pengguna valid atau tidak, dan juga menangani permintaan dengan benar.
sumber
Untuk variabel kategori, saya akan menghindari meletakkan wildcard "semua" pada level yang sama.
Sepertinya Anda memiliki kriteria pencarian dua tingkat untuk periode waktu:
Penelepon dapat menentukan (false, diabaikan) atau (benar, {'kuno', 'modern'}).
Atau Anda dapat memilih untuk mengartikan set kosong sebagai wildcard, ini menandakan Tidak Selektif.
Untuk kasus spesifik Anda, sepertinya Anda memiliki variabel kontinu, tahun, yang didiskritkan ke beberapa nilai terkenal, dan yang Anda inginkan adalah melakukan aritmatika interval. Jadi pertanyaan Anda akan menerima rentang (mulai, akhir) tahun, dan enum dapat dengan mudah menyediakan atribut tersebut.
sumber
tl; dr
Untuk pertanyaan aktual Anda - mengenai struktur data lokal dalam implementasi - Saya setuju dengan kesimpulan Anda: Hindari nilai khusus semua era karena sebagian besar menambah kompleksitas dan peluang untuk membuat kesalahan. Namun, terutama pengguna akhir UI dan mungkin data muatan serial mungkin cerita yang berbeda.
Struktur data lokal
Mari kita lihat ini dari perspektif sistem tipe. Pada dasarnya enum adalah tipe yang mendefinisikan sekumpulan kategori khusus (enumerator) yang terpisah, sebagaimana telah ditunjukkan dalam jawaban oleh @JH . Variabel tipe enum memiliki tepat salah satu kategori tersebut. Jika Anda ingin merepresentasikan kumpulan nilai enumerator, Anda memerlukan tipe kedua:
Sebuah
all
pencacah adalah tidak-pergi karena mashes dua jenis bersama-sama. Ini bukan kategori tunggal, tetapi koleksi semua kategori yang mungkin.Pada tingkat yang sangat praktis, berurusan dengan segala jenis nilai khusus mempersulit implementasi - dan karenanya meningkatkan kemungkinan kesalahan - karena Anda harus membuat case khusus di mana-mana atau membukanya agar sesuai dengan arti sebenarnya. Oh, dan bagaimana dengan koleksi eksplisit dari semua enumerator yang mungkin. Kapan dan di mana ini harus diciutkan ke nilai khusus
all
? Haruskah itu runtuh sama sekali?Arsitektur pilihan saya adalah tidak memiliki representasi semua era dalam kode. Itu termasuk
all
enumerator, tetapi juga koleksi kosong yang berarti semua era . Ini persis kasus khusus yang sama, hanya dalam penyamaran yang berbeda.Saya akan menentukan dalam spesifikasi API bahwa penanda semua era harus selalu muncul sendiri karena memiliki sesuatu di atasnya tidak masuk akal. Maka saya akan menolak ini sebagai pelanggaran kontrak. Tetapi ini adalah contoh yang bagus tentang bagaimana semua era mempersulit implementasi dan logika bisnis.
Masalah utama adalah Anda dipaksa menentukan aturan untuk mengkonversi antara nilai khusus dan makna yang mendasarinya. Dan kemudian Anda dan semua orang yang menggunakan API harus mengimplementasikan aturan-aturan itu dengan benar. Orang yang sinis dalam diri saya memberi tahu saya bahwa itu bukan pertanyaan apakah seseorang akan salah, tetapi hanya kapan .
Serialized Data (JSON)
Awalnya saya memiliki seluruh bagian di sini tentang memodifikasi kueri vs hanya baca dan peran yang berbeda untuk
"eras"
daftar. Tetapi pada akhirnya saya menghapusnya karena KISS. Aturan untuk enum / pengumpulan tidak masuk akal untuk data JSON, jadi menjaga semuanya tetap konsisten adalah solusi paling sederhana.UI untuk pengguna akhir
Saya berasumsi akan ada transformasi data antara UI dan struktur data yang mendasarinya, kemungkinan besar karena Anda memiliki semacam arsitektur MVC-ish. Jadi, gunakan apa pun yang paling nyaman dan intuitif bagi pengguna. Dalam jawabannya @Markus memberikan contoh yang bagus dengan berbagai pilihan pilihan untuk hari-hari dalam seminggu.
sumber
Iya.
Jika Anda berpikir dari perspektif koleksi: Anda memiliki seluruh koleksi sesuatu. Dan setiap kali Anda hanya menginginkan subset dari koleksi itu, Anda harus memberikan semacam kondisi filter , ketika sebuah elemen dianggap sebagai elemen dari subset ini. Dan
ALL
masalahnya, ketika tidak ada filter yang diterapkan, bukan "kondisi filternyaALL
" .Saya akan membalikkannya: Buku ini tidak membahas era tertentu .
Ini juga konsisten dari perspektif kueri:
Jika tidak ada era yang dipilih, semua buku dikembalikan (termasuk ini dengan bidang era kosong); dan ketika suatu era dipilih, hanya buku-buku dengan era yang dipilih yang dikembalikan - mengambil semua buku dari era khusus plus yang umum akan menjadi tak terduga.
Satu-satunya titik, di mana saya akan menambahkan
ALL
- kategori adalah untuk kenyamanan pengguna, karena mungkin lebih menjengkelkan memiliki "Tidak ada" yang dipilih daripada "Semuanya".sumber
Saya baru-baru ini menerapkan penjadwal dasar dan sebagai @LoztInSpace sudah disebutkan sebagian besar adalah gula UI.
Antarmuka pengguna harus benar-benar jelas dalam hal apa yang akan dicapai pengguna saat memilih salah satu opsi.
Dalam kasus saya, saya memiliki hari kerja untuk memilih. Selain "Semua", saya menambahkan "Hari kerja" dan "Akhir Pekan" sebagai opsi. Memilih setiap opsi akan memasukkannya dalam penggunaan nanti dan Anda harus membatalkan pilihan secara manual setiap hari yang tidak ingin Anda sertakan.
Secara teknis ini berarti jika pengguna memilih "Hari Kerja" UI akan memiliki lima kotak centang dicentang dan enum akan menggunakan nilai "Hari kerja". Jika salah satu kotak centang tidak dipilih, nilai "Hari kerja" diganti dengan peta bit or-ed dari sisa empat hari.
Jangan menggunakan salah satu bagian dari opsi untuk memasukkan semuanya dan pada saat yang sama untuk mengecualikan sesuatu untuk menghindari konflik dan memastikan UI masuk akal bagi pengguna.
Saya pikir orientasi yang baik adalah bahwa menggunakan dan "Semua" pilihan masuk akal jika pengguna dapat dengan mudah memahami konsep apa yang "Semua" termasuk (semua hari dalam seminggu) atau jika agak tidak penting (cari semua kategori di amazon)
sumber
Saya suka gagasan secara eksplisit membawa SEMUA enum, tapi saya lebih suka mengaturnya sebagai bendera
Menggunakan perpustakaan seperti guci anggur atau bermain secara manual dengan operasi bitwise ketika semua nilai dipilih, Anda menggunakan ALL sebagai gantinya.
Perlu diingat bahwa nilai-nilai enum harus selalu dua kali lipat dari pendahulunya. Dan untuk pemeriksaan kewarasan Anda tidak boleh menghapus enum, meskipun Anda dapat menonaktifkannya, menyesuaikan kode Anda untuk selalu menghitung yang dinonaktifkan sebagai bagian dari SEMUA.
Meskipun saya akan memiliki flag NONE sebagai gantinya dan membiarkan klien memutuskan apa yang harus dilakukan ketika NONE digunakan, kalau-kalau bisnis berubah nanti.
Jika implementasi ini dilakukan, alih-alih meneruskan enuns, Anda akan meneruskan jumlah nilai yang dipilih.
sumber