Apakah ini praktik yang baik untuk memiliki nilai khusus "SEMUA" dalam enum

11

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 eranilai, 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 ALLdan Ancient- apa yang akan diambil dari aplikasi? Saya kira itu ALLharus 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 ALLjuga digunakan untuk output (menggunakan logika yang sama), maka tanggung jawab konsumen untuk mengartikannya ALLsebagai ["Ancient", "Post Classical", "Modern"].

Pertanyaan saya

Saya pikir memiliki yang baru ALLmenyebabkan lebih banyak kebingungan daripada tidak memilikinya sama sekali.

Bagaimana menurut anda? Apakah Anda menambahkan ALLnilai ini atau mempertahankan API Anda tanpanya?

Ron Klein
sumber
7
Apa yang terjadi jika Anda memutuskan ingin menambahkan era atom? Apakah buku-buku yang mencakup "semua" era ajaib mendapatkan konten baru? Apakah Anda mulai berbohong tentang isi buku? Apakah Anda melalui dan memperbarui semuanya? Itu bisa menjadi nontrivial jika beberapa buku sebenarnya sudah memiliki konten tentang era atom.
8bittree

Jawaban:

13

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.

LoztInSpace
sumber
6

Jika tidak ada era yang disediakan dalam input, maka buku ini dianggap mencakup semua era.

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.

GoatInTheMachine
sumber
1

Untuk variabel kategori, saya akan menghindari meletakkan wildcard "semua" pada level yang sama.

Sepertinya Anda memiliki kriteria pencarian dua tingkat untuk periode waktu:

  1. boolean, is_selective?
  2. set, disjunction kategori tertentu

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.

J_H
sumber
1

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:

// C++-inspired pseudo-code
enum Era { ancient, post_classical, modern };
using Eras = Collection<Era>;

Sebuah allpencacah 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 allenumerator, tetapi juga koleksi kosong yang berarti semua era . Ini persis kasus khusus yang sama, hanya dalam penyamaran yang berbeda.

Jika dua item dalam daftar disediakan, katakan SEMUA dan Kuno - apa yang akan diambil dari aplikasi? [...]

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.

besc
sumber
1

Saya pikir memiliki SEMUA yang baru menyebabkan lebih banyak kebingungan daripada tidak memilikinya sama sekali.

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 ALLmasalahnya, ketika tidak ada filter yang diterapkan, bukan "kondisi filternya ALL" .

Jika tidak ada era yang disediakan dalam input, maka buku ini dianggap mencakup semua era.

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".

Thomas Junk
sumber
0

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)

Markus
sumber
0

Saya suka gagasan secara eksplisit membawa SEMUA enum, tapi saya lebih suka mengaturnya sebagai bendera

const enum = {
    ALL: { value: 0 },
    ANCIENT: { name: 'Ancient', value: 1 },
    POST_CLASSICAL: { name: 'Post Classical', value: 2 },
    MODERN: { name: 'Modern', value: 4 }
}

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.

MVCDS
sumber