Apakah "hindari masalah yo-yo" alasan yang sah untuk memungkinkan "obsesi primitif"?

42

Menurut Kapan obsesi primitif bukan bau kode? , Saya harus membuat objek ZipCode untuk mewakili kode pos, bukan objek String.

Namun, dalam pengalaman saya, saya lebih suka melihat

public class Address{
    public String zipCode;
}

dari pada

public class Address{
    public ZipCode zipCode;
}

karena saya pikir yang terakhir mengharuskan saya untuk pindah ke kelas ZipCode untuk memahami program.

Dan saya percaya saya perlu bergerak di antara banyak kelas untuk melihat definisi jika setiap bidang data primitif digantikan oleh kelas, yang terasa seperti menderita masalah yo-yo (pola-anti).

Jadi saya ingin memindahkan metode ZipCode ke kelas baru, misalnya:

Tua:

public class ZipCode{
    public boolean validate(String zipCode){
    }
}

Baru:

public class ZipCodeHelper{
    public static boolean validate(String zipCode){
    }
}

sehingga hanya orang yang perlu memvalidasi kode pos yang akan bergantung pada kelas ZipCodeHelper. Dan saya menemukan "manfaat" lain dari menjaga obsesi primitif: itu membuat kelas tampak seperti bentuk serial, jika ada, misalnya: tabel alamat dengan kode kolom string zipCode.

Pertanyaan saya adalah, apakah "menghindari masalah yo-yo" (berpindah di antara definisi kelas) merupakan alasan yang sah untuk memungkinkan "obsesi primitif"?

ocomfd
sumber
9
@ jpmc26 Maka Anda akan terkejut melihat betapa kompleksnya objek kode pos kami - tidak mengatakan itu benar, tetapi memang ada
Jared Goguen
9
@ jpmc26, saya gagal melihat bagaimana Anda beralih dari "kompleks" ke "dirancang dengan buruk." Kode kompleks seringkali merupakan hasil dari kode sederhana yang bersentuhan dengan kompleksitas dunia nyata daripada dunia ideal yang mungkin kita harapkan ada. "Kembali ke fungsi dua halaman itu. Ya, saya tahu, itu hanya fungsi sederhana untuk menampilkan jendela, tetapi telah menumbuhkan sedikit rambut dan hal-hal di atasnya dan tidak ada yang tahu mengapa. Nah, saya akan memberitahu Anda mengapa: itu adalah bug perbaikan. "
Kyralessa
19
@ jpmc26 - titik pembungkus objek seperti ZipCode adalah tipe safety. Kode pos bukan string, ini kode pos. Jika suatu fungsi mengharapkan kode pos, Anda seharusnya hanya dapat meneruskan kode pos, bukan string.
Davor Ždralo
4
Ini terasa sangat spesifik bahasa, berbagai bahasa melakukan hal yang berbeda di sini. @ DavorŽdralo Dalam rentang yang sama kita juga harus menambahkan banyak tipe numerik. "hanya bilangan bulat positif", "hanya bilangan genap" semua bisa juga tipe.
paul23
6
@ paul23 Ya memang, dan alasan utama kami tidak memiliki itu adalah bahwa banyak bahasa tidak mendukung cara yang elegan untuk mendefinisikannya. Sangat masuk akal untuk mendefinisikan "usia" sebagai jenis yang berbeda dari "suhu dalam derajat celsius", jika saja "userAge == currentTemperature" terdeteksi sebagai omong kosong.
IMSoP

Jawaban:

116

Asumsinya adalah bahwa Anda tidak perlu yo-yo ke kelas ZipCode untuk memahami kelas Alamat. Jika ZipCode dirancang dengan baik, seharusnya sudah jelas apa fungsinya hanya dengan membaca kelas Address.

Program tidak dibaca ujung ke ujung - biasanya program terlalu rumit untuk memungkinkan hal ini. Anda tidak dapat menyimpan semua kode dalam suatu program di pikiran Anda secara bersamaan. Jadi kami menggunakan abstraksi dan enkapsulasi untuk "memotong" program menjadi unit yang bermakna, sehingga Anda dapat melihat satu bagian dari program (misalkan kelas Alamat) tanpa harus membaca semua kode yang tergantung padanya.

Sebagai contoh, saya yakin Anda tidak perlu membaca kode sumber untuk String setiap kali Anda menemukan kode String.

Mengganti nama kelas dari ZipCode ke ZipCodeHelper menyarankan sekarang ada dua konsep terpisah: kode pos dan penolong kode pos. Jadi dua kali lebih kompleks. Dan sekarang sistem tipe tidak dapat membantu Anda membedakan antara string arbitrer dan kode pos yang valid karena mereka memiliki tipe yang sama. Di sinilah "obsesi" tepat: Anda menyarankan alternatif yang lebih kompleks dan kurang aman hanya karena Anda ingin menghindari jenis pembungkus sederhana di sekitar primitif.

Menggunakan primitif adalah IMHO dibenarkan dalam kasus-kasus di mana tidak ada validasi atau logika lain tergantung pada tipe khusus ini. Tetapi segera setelah Anda menambahkan logika apa pun, akan jauh lebih mudah jika logika ini dienkapsulasi dengan tipenya.

Adapun serialisasi saya pikir itu terdengar seperti batasan dalam kerangka yang Anda gunakan. Tentunya Anda harus dapat membuat serial kode pos ke string atau memetakannya ke kolom dalam database.

JacquesB
sumber
2
Saya setuju dengan bagian "unit yang berarti" (utama-), tetapi tidak begitu banyak sehingga kode pos dan validasi kode pos adalah konsep yang sama. ZipCodeHelper(yang saya lebih suka menelepon ZipCodeValidator) mungkin sangat baik membuat koneksi ke layanan web untuk melakukan pekerjaan itu. Itu tidak akan menjadi bagian dari tanggung jawab tunggal "memegang data kode pos". Membuat jenis sistem tidak mengizinkan kode pos yang masih dapat dicapai dengan membuat ZipCodekonstruktor yang setara dengan paket-private Java dan memanggilnya dengan ZipCodeFactoryyang selalu memanggil validator.
R. Schmitz
16
@ R.Schmitz: Bukan itu yang dimaksud "tanggung jawab" dalam arti prinsip tanggung jawab tunggal. Tetapi bagaimanapun juga, Anda tentu saja harus menggunakan kelas sebanyak yang Anda butuhkan selama Anda merangkum kode pos dan validasinya. OP menyarankan penolong alih-alih merangkum kode pos, yang merupakan ide yang buruk.
JacquesB
1
Saya ingin dengan hormat tidak setuju. SRP berarti kelas harus memiliki "satu, dan hanya satu, alasan untuk diubah" (ubah "apa yang terdiri dari kode pos" vs "bagaimana itu divalidasi"). Kasus khusus ini di sini dijabarkan lebih lanjut dalam buku Kode Bersih : " Objek menyembunyikan data mereka di belakang abstraksi dan mengekspos fungsi yang beroperasi pada data itu. Struktur data mengekspos data mereka dan tidak memiliki fungsi yang berarti. " - ZipCodeakan menjadi "struktur data" dan ZipCodeHelpersebuah "objek '. Bagaimanapun, saya pikir kami sepakat bahwa kami tidak perlu melewati koneksi web ke konstruktor ZipCode
R. Schmitz
9
Menggunakan primitif adalah IMHO dibenarkan dalam kasus-kasus di mana tidak ada validasi atau logika lain tergantung pada tipe khusus ini. => Saya tidak setuju. Bahkan jika semua nilai valid, saya tetap lebih suka menyampaikan semantik ke bahasa daripada menggunakan primitif. Jika suatu fungsi dapat dipanggil pada tipe primitif yang tidak masuk akal untuk penggunaan semantiknya saat ini, maka ia seharusnya bukan tipe primitif, ia haruslah tipe yang tepat dengan hanya fungsi-fungsi yang masuk akal yang didefinisikan. (Sebagai contoh, menggunakan intsebagai ID memungkinkan mengalikan ID dengan ID ...)
Matthieu M.
@ R.Schmitz Saya pikir kode ZIP adalah contoh yang buruk untuk perbedaan yang Anda buat. Sesuatu yang sering berubah mungkin menjadi kandidat untuk kelas Foodan terpisah FooValidator. Kami dapat memiliki ZipCodekelas yang memvalidasi format dan ZipCodeValidatoryang mengenai beberapa layanan Web untuk memeriksa apakah format ZipCodeyang benar benar-benar aktual. Kita tahu bahwa kode ZIP berubah. Namun secara praktis, kita akan memiliki daftar kode ZIP yang valid yang dienkapsulasi ZipCode, atau dalam beberapa basis data lokal.
No U
55

Jika bisa:

new ZipCode("totally invalid zip code");

Dan konstruktor untuk Kode Pos tidak:

ZipCodeHelper.validate("totally invalid zip code");

Kemudian Anda telah merusak enkapsulasi, dan menambahkan ketergantungan yang cukup konyol ke kelas ZipCode. Jika konstruktor tidak memanggil ZipCodeHelper.validate(...)maka Anda telah mengisolasi logika di pulau sendiri tanpa benar-benar menegakkannya. Anda dapat membuat kode pos yang tidak valid.

The validateMetode harus menjadi metode statis pada kelas kode pos. Sekarang pengetahuan tentang kode pos "valid" dibundel bersama dengan kelas ZipCode. Karena contoh kode Anda terlihat seperti Java, konstruktor dari ZipCode harus memberikan pengecualian jika format yang salah diberikan:

public class ZipCode {
    private String zipCode;

    public ZipCode(string zipCode) {
        if (!validate(zipCode))
            throw new IllegalFormatException("Invalid zip code");

        this.zipCode = zipCode;
    }

    public static bool validate(String zipCode) {
        // logic to check format
    }

    @Override
    public String toString() {
        return zipCode;
    }
}

Konstruktor memeriksa format dan melempar pengecualian, sehingga mencegah kode pos tidak valid dibuat, dan validatemetode statis tersedia untuk kode lain sehingga logika memeriksa format dienkapsulasi dalam kelas ZipCode.

Tidak ada "yo-yo" di varian kelas ZipCode ini. Itu hanya disebut Pemrograman Berorientasi Objek yang tepat.


Kami juga akan mengabaikan internasionalisasi di sini, yang mungkin mengharuskan kelas lain yang disebut ZipCodeFormat atau PostalService (mis. PostalService.isValidPostalCode (...), PostalService.parsePostalCode (...), dll.).

Greg Burghardt
sumber
28
Catatan: Keuntungan utama dengan pendekatan @Greg Burkhardt di sini adalah bahwa jika seseorang memberi Anda objek ZipCode, Anda dapat percaya bahwa itu berisi string yang valid tanpa harus memeriksanya lagi, karena jenisnya dan fakta bahwa itu berhasil dibangun memberi Anda jaminan itu. Jika alih-alih melewati string, Anda mungkin merasa perlu "menegaskan validasi (kode pos)" di berbagai tempat dalam kode Anda hanya untuk memastikan bahwa Anda memiliki kode pos yang valid, tetapi dengan objek ZipCode yang berhasil dibuat, Anda dapat percaya bahwa isinya valid tanpa harus memeriksanya lagi.
Some Guy
3
@ R.Schmitz: ZipCode.validateMetode ini adalah pemeriksaan awal yang dapat dilakukan sebelum memanggil konstruktor yang melempar pengecualian.
Greg Burghardt
10
@ R.Schmitz: Jika Anda khawatir tentang pengecualian yang menjengkelkan, pendekatan alternatif untuk konstruksi adalah menjadikan konstruktor ZipCode pribadi, dan menyediakan fungsi pabrik statis publik (Zipcode.create?) Yang melakukan validasi parameter yang dilewati, mengembalikan null jika tidak berhasil, dan sebaliknya membangun objek ZipCode dan mengembalikannya. Penelepon harus selalu memeriksa nilai pengembalian nol, tentu saja. Di sisi lain, jika Anda terbiasa, misalnya, untuk selalu memvalidasi (regex? Memvalidasi? Dll.) Sebelum membangun Kode Pos, pengecualian mungkin tidak begitu menjengkelkan dalam praktik.
Some Guy
11
Fungsi pabrik yang mengembalikan <ZipCode> Opsional juga kemungkinan. Kemudian penelepon tidak punya pilihan selain secara eksplisit menangani kemungkinan kegagalan fungsi pabrik. Apapun, dalam kedua kasus, kesalahan akan ditemukan di suatu tempat di dekat tempat itu dibuat daripada mungkin nanti, dengan kode klien jauh dari masalah aslinya.
Some Guy
6
Anda tidak dapat memvalidasi Kode Pos secara mandiri, jadi jangan lakukan. Anda benar-benar membutuhkan objek Negara untuk mencari aturan validasi Kode Pos / Kode Pos.
Joshua
11

Jika Anda banyak bergulat dengan pertanyaan ini, mungkin bahasa yang Anda gunakan bukan alat yang tepat untuk pekerjaan itu? "Primitif tipe-domain" semacam ini mudah untuk diungkapkan, misalnya, F #.

Di sana Anda dapat, misalnya, menulis:

type ZipCode = ZipCode of string
type Town = Town of string

type Adress = {
  zipCode: ZipCode
  town: Town
  //etc
}

let adress1 = {
  zipCode = ZipCode "90210"
  town = Town "Beverly Hills"
}

let faultyAdress = {
  zipCode = "12345"  // <-Compiler error
  town = adress1.zipCode // <- Compiler error
}

Ini sangat berguna untuk menghindari kesalahan umum, seperti membandingkan id entitas yang berbeda. Dan karena primitif yang diketik ini jauh lebih ringan daripada kelas C # atau Java, Anda akan benar-benar menggunakannya.

Guran
sumber
Menarik - bagaimana rasanya jika Anda ingin menegakkan validasi ZipCode?
Hulk
4
@ Hulk Anda dapat menulis gaya OO di F # dan membuat tipe menjadi kelas. Namun, saya lebih suka gaya fungsional, mendeklarasikan tipe dengan tipe ZipCode = private ZipCode dari string dan menambahkan modul ZipCode dengan fungsi create. Ada beberapa contoh di sini: gist.github.com/swlaschin/54cfff886669ccab895a
Guran
@ Bent-Tranberg Terima kasih atas hasil editnya. Anda benar, singkatan tipe sederhana tidak memberikan keamanan tipe waktu kompilasi.
Guran
Jika Anda mengirim komentar pertama saya, yang saya hapus, alasannya adalah bahwa saya pertama kali salah memahami sumber Anda. Saya tidak cukup membacanya. Ketika saya mencoba untuk mengkompilasinya, saya akhirnya menyadari bahwa Anda benar-benar mencoba untuk menunjukkan hal ini, jadi saya memutuskan untuk mengeditnya untuk memperbaikinya.
Bent Tranberg
Ya. Sumber asli saya valid baik-baik saja, sayangnya termasuk contoh yang SEHARUSNYA tidak valid. Doh! Haruskah hanya ditautkan ke Wlaschin daripada mengetik kode sendiri :) fsharpforfunandprofit.com/posts/…
Guran
6

Jawabannya sepenuhnya tergantung pada apa yang sebenarnya ingin Anda lakukan dengan kode ZIP. Berikut adalah dua kemungkinan ekstrem:

(1) Semua alamat dijamin berada di satu negara. Tidak ada pengecualian sama sekali. (Misalnya tidak ada pelanggan asing, atau tidak ada karyawan yang alamat privatnya berada di luar negeri saat mereka bekerja untuk pelanggan asing). Negara ini memiliki kode ZIP dan mereka diharapkan tidak akan pernah menjadi masalah serius (yaitu mereka tidak memerlukan input bentuk bebas) seperti "saat ini D4B 6N2, tetapi ini berubah setiap 2 minggu"). Kode ZIP digunakan tidak hanya untuk pengalamatan, tetapi untuk validasi informasi pembayaran atau tujuan serupa. - Dalam keadaan ini, kelas kode ZIP sangat masuk akal.

(2) Alamat dapat di hampir setiap negara, sehingga puluhan atau ratusan skema pengalamatan dengan atau tanpa kode ZIP (dan dengan ribuan pengecualian aneh dan kasus khusus) adalah relevan. Kode "ZIP" benar-benar hanya diminta untuk mengingatkan orang-orang dari negara-negara di mana kode ZIP digunakan untuk tidak lupa memberikan kode mereka. Alamat hanya digunakan sehingga jika seseorang kehilangan akses ke akun mereka dan mereka dapat membuktikan nama dan alamat mereka, akses akan dipulihkan. - Dalam keadaan ini, kelas kode ZIP untuk semua negara yang relevan akan menjadi upaya yang sangat besar. Untungnya mereka tidak dibutuhkan sama sekali.


sumber
3

Jawaban lain telah berbicara tentang pemodelan domain OO dan menggunakan tipe yang lebih kaya untuk mewakili nilai Anda.

Saya tidak setuju, terutama mengingat kode contoh yang Anda posting.

Tetapi saya juga bertanya-tanya apakah itu benar-benar menjawab judul pertanyaan Anda.

Pertimbangkan skenario berikut (diambil dari proyek aktual yang sedang saya kerjakan):

Anda memiliki aplikasi jarak jauh pada perangkat lapangan yang berbicara ke server pusat Anda. Salah satu bidang DB untuk entri perangkat adalah kode pos untuk alamat di mana perangkat bidang berada. Anda tidak peduli dengan kode pos (atau alamat lainnya dalam hal ini). Semua orang yang peduli tentang hal itu berada di sisi lain dari batas HTTP: Anda hanya menjadi satu-satunya sumber kebenaran untuk data tersebut. Tidak ada tempat dalam pemodelan domain Anda. Anda cukup merekamnya, memvalidasinya, menyimpannya, dan atas permintaan mengocoknya dalam gumpalan JSON ke poin di tempat lain.

Dalam skenario ini, melakukan banyak hal di luar memvalidasi memasukkan dengan kendala regex SQL (atau ORM yang setara) mungkin berlebihan dari varietas YAGNI.

Jared Smith
sumber
6
Batasan regex SQL Anda dapat dilihat sebagai jenis yang memenuhi syarat - dalam basis data Anda, kode Zip tidak disimpan sebagai "VarChar" tetapi "VarChar dibatasi oleh aturan ini". Di beberapa DBMSes, Anda dapat dengan mudah memberikan tipe itu + membatasi nama sebagai "tipe domain" yang dapat digunakan kembali, dan kami kembali ke tempat yang disarankan untuk memberikan data tipe yang bermakna. Saya setuju dengan jawaban Anda pada prinsipnya, tetapi jangan menganggap contoh itu cocok; contoh yang lebih baik adalah jika data Anda adalah "data sensor mentah", dan tipe yang paling bermakna adalah "byte array" karena Anda tidak tahu apa artinya data tersebut.
IMSoP
@IMSoP poin menarik. Tidak yakin saya setuju: Anda bisa memvalidasi kode pos string di Jawa (atau bahasa lain) dengan regex tetapi masih berurusan dengan itu sebagai string, bukan tipe yang lebih kaya. Bergantung pada logika domain, manipulasi lebih lanjut mungkin diperlukan (misalnya memastikan bahwa kode pos cocok dengan negara, sesuatu yang akan sulit / tidak mungkin divalidasi dengan regex).
Jared Smith
Anda bisa , tetapi begitu Anda melakukannya, Anda menganggapnya sebagai perilaku khusus domain, dan itulah yang dikatakan oleh artikel yang dikutip harus mengarah pada penciptaan jenis kustom. Pertanyaannya bukan apakah Anda bisa melakukannya dalam satu gaya atau yang lain, tetapi apakah Anda harus , dengan asumsi bahasa pemrograman Anda memberi Anda pilihan.
IMSoP
Anda bisa memodelkan hal seperti itu RegexValidatedString, berisi string itu sendiri dan regex yang digunakan untuk memvalidasinya. Tetapi kecuali setiap instance memiliki regex unik (yang mungkin tetapi tidak mungkin) ini tampaknya agak konyol dan boros memori (dan mungkin regex waktu kompilasi). Jadi Anda bisa meletakkan regex ke dalam tabel terpisah dan meninggalkan kunci pencarian di setiap contoh untuk menemukannya (yang bisa dibilang lebih buruk karena tipuan) atau Anda menemukan cara untuk menyimpannya sekali untuk setiap jenis umum pembagian nilai yang mengatur - - mis. bidang statis pada tipe domain, atau metode yang setara, seperti yang dikatakan IMSoP.
Miral
2

The ZipCodeabstraksi hanya bisa masuk akal jika Anda Addresskelas tidak juga memiliki TownNameproperti. Jika tidak, Anda memiliki setengah abstraksi: kode pos menunjuk kota, tetapi dua bit informasi terkait ini ditemukan di kelas yang berbeda. Itu tidak masuk akal.

Namun, meskipun demikian, itu masih bukan aplikasi yang benar (atau lebih tepatnya solusi untuk) obsesi primitif; yang, seperti yang saya pahami, terutama berfokus pada dua hal:

  1. Menggunakan primitif sebagai input (atau bahkan output) nilai-nilai metode, terutama ketika koleksi primitif diperlukan.
  2. Kelas yang menumbuhkan properti tambahan dari waktu ke waktu tanpa pernah mempertimbangkan kembali apakah beberapa di antaranya harus dikelompokkan ke dalam subkelas mereka sendiri.

Kasus Anda juga tidak. Alamat adalah konsep yang terdefinisi dengan baik dengan properti yang jelas diperlukan (jalan, nomor, zip, kota, negara bagian, negara, ...). Ada sedikit atau tidak ada alasan untuk memecah data ini karena memiliki tanggung jawab tunggal : menunjuk lokasi di Bumi. Alamat membutuhkan semua bidang ini agar bermakna. Setengah alamat tidak ada gunanya.

Ini adalah bagaimana Anda tahu bahwa Anda tidak perlu membagi lagi: memecahnya lebih jauh akan mengurangi niat fungsional Addresskelas. Demikian pula, Anda tidak perlu Namesubclass untuk digunakan di Personkelas, kecuali Name(tanpa orang yang dilampirkan) adalah konsep yang bermakna dalam domain Anda. Yang mana (biasanya) tidak. Nama digunakan untuk mengidentifikasi orang, mereka biasanya tidak memiliki nilai sendiri.

Flater
sumber
1
@RikD: Dari jawaban: "Anda tidak perlu Namesubclass untuk digunakan di Personkelas, kecuali Nama (tanpa orang yang dilampirkan) adalah konsep yang bermakna dalam domain Anda ." Ketika Anda memiliki validasi khusus untuk nama-nama, nama tersebut kemudian menjadi konsep yang bermakna di domain Anda; yang secara eksplisit saya sebutkan sebagai use case yang valid untuk menggunakan subtipe. Kedua, untuk validasi kode pos, Anda memperkenalkan asumsi tambahan, seperti kode pos yang harus mengikuti format negara tertentu. Anda memulai topik yang jauh lebih luas dari maksud pertanyaan OP.
Flater
5
" Alamat adalah konsep yang terdefinisi dengan baik dengan properti yang jelas diperlukan (jalan, nomor, zip, kota, negara bagian, negara). " - Yah itu salah sekali. Untuk cara yang baik untuk mengatasi ini, lihat formulir alamat Amazon.
R. Schmitz
4
@Flater Yah saya tidak akan menyalahkan Anda karena tidak membaca daftar lengkap kepalsuan, karena itu cukup panjang, tetapi secara harfiah berisi "Alamat akan memiliki jalan", "Alamat memerlukan kota dan negara", "Alamat akan memiliki kode pos "dll., yang bertentangan dengan apa yang dikatakan kalimat yang dikutip.
R. Schmitz
8
@GregBurghardt "Kode pos mengasumsikan Layanan Pos Amerika Serikat, dan Anda dapat memperoleh nama kota dari kode pos. Kota-kota dapat memiliki beberapa kode pos, tetapi setiap kode pos hanya terikat pada 1 kota." Ini tidak benar secara umum. Saya memiliki kode pos yang digunakan terutama untuk kota tetangga tetapi tempat tinggal saya tidak ada di sana. Kode pos tidak selalu selaras dengan batas pemerintah. Misalnya 42.223 berisi kabupaten dari TN dan KY .
JimmyJames
2
Di Austria ada lembah yang hanya bisa diakses dari Jerman ( en.wikipedia.org/wiki/Kleinwalsertal ). Ada perjanjian khusus untuk wilayah ini yang, antara lain, juga mencakup bahwa alamat di wilayah ini memiliki kode pos Austria dan Jerman. Jadi secara umum, Anda bahkan tidak dapat berasumsi bahwa alamat hanya memiliki satu kode pos yang valid;)
Hulk
1

Dari artikel:

Secara lebih umum, masalah yo-yo juga dapat merujuk pada situasi apa pun di mana seseorang harus terus membalik di antara berbagai sumber informasi untuk memahami suatu konsep.

Kode sumber dibaca jauh lebih sering daripada yang tertulis. Jadi, masalah yo-yo, karena harus beralih di antara banyak file adalah masalah.

Namun, tidak , masalah yo-yo terasa jauh lebih relevan ketika berhadapan dengan modul atau kelas yang sangat saling tergantung (yang saling bolak-balik). Itu adalah jenis mimpi buruk khusus untuk dibaca, dan kemungkinan apa yang ada dalam pikiran Anda tentang masalah yo-yo.

Namun - ya , menghindari terlalu banyak lapisan abstraksi itu penting!

Semua abstraksi non-sepele, sampai taraf tertentu, bocor. - Hukum Abstraksi Kebocoran.

Sebagai contoh, saya tidak setuju dengan asumsi yang dibuat dalam jawaban mmmaaa bahwa "Anda tidak perlu yo-yo untuk [(mengunjungi)] kelas ZipCode untuk memahami kelas Alamat". Pengalaman saya adalah yang Anda lakukan - setidaknya beberapa kali pertama Anda membaca kode. Namun, seperti orang lain telah mencatat, ada yang kalanya ZipCodekelas sesuai.

YAGNI (Ya Apakah tidak Akan Butuh Ini) adalah pola yang lebih baik untuk mengikuti untuk menghindari kode Lasagna (kode dengan terlalu banyak lapisan) - abstraksi, seperti jenis dan kelas yang ada untuk membantu programmer, dan tidak boleh digunakan kecuali mereka yang sebuah pertolongan.

Saya pribadi bertujuan untuk "menyimpan baris kode" (dan tentu saja yang terkait "menyimpan file / modul / kelas", dll). Saya yakin ada beberapa orang yang akan memberi saya julukan "terobsesi primitif" - saya merasa lebih penting untuk memiliki kode yang mudah dipikirkan daripada khawatir tentang label, pola, dan anti-pola. Pilihan yang tepat kapan membuat fungsi, modul / file / kelas, atau meletakkan fungsi di lokasi umum sangat situasional. Saya bertujuan kira-kira untuk fungsi 3-100 baris, 80-500 file baris, dan "1, 2, n" untuk kode perpustakaan yang dapat digunakan kembali ( SLOC - tidak termasuk komentar atau boilerplate; Saya biasanya ingin setidaknya 1 tambahan minimum SLOC per baris wajib) boilerplate).

Sebagian besar pola positif muncul dari pengembang yang melakukan hal itu, ketika mereka membutuhkannya . Jauh lebih penting untuk mempelajari cara menulis kode yang dapat dibaca daripada mencoba menerapkan pola tanpa masalah yang sama untuk dipecahkan. Setiap pengembang yang baik dapat menerapkan pola pabrik tanpa pernah melihatnya sebelumnya dalam kasus yang tidak umum di mana itu cocok untuk masalah mereka. Saya telah menggunakan pola pabrik, pola pengamat, dan mungkin ratusan selain itu, tanpa mengetahui nama mereka (yaitu, apakah ada "pola penugasan variabel"?). Untuk percobaan yang menyenangkan - lihat berapa banyak pola GoF yang dibangun ke dalam bahasa JS - Saya berhenti menghitung setelah sekitar 12-15 pada tahun 2009. Pola Pabrik semudah mengembalikan objek dari konstruktor JS, misalnya - tidak perlu untuk sebuah WidgetFactory.

Jadi - ya , terkadang ZipCode kelasnya bagus. Namun, tidak , masalah yo-yo tidak sepenuhnya relevan.

Iiridayn
sumber
0

Masalah yo-yo hanya relevan jika Anda harus bolak-balik. Itu disebabkan oleh satu atau dua hal (terkadang keduanya):

  1. Penamaan yang buruk. ZipCode tampaknya baik-baik saja, ZoneImprovementPlanCode akan membutuhkan tampilan oleh kebanyakan orang (dan beberapa yang tidak akan terkesan).
  2. Kopling tidak tepat. Katakanlah Anda kelas ZipCode memiliki pencarian kode area. Anda mungkin berpikir itu masuk akal karena berguna, tetapi itu tidak benar-benar terkait dengan Kode Pos, dan memasukkannya ke dalamnya berarti bahwa sekarang orang tidak tahu ke mana harus mencari sesuatu.

Jika Anda dapat melihat nama dan memiliki ide yang masuk akal tentang apa yang dilakukannya, dan metode dan properti melakukan hal-hal yang cukup jelas, Anda tidak perlu melihat kode, Anda bisa menggunakannya. Itulah inti seluruh kelas di tempat pertama - mereka adalah potongan kode modular yang dapat digunakan dan dikembangkan secara terpisah. Jika Anda harus melihat apa pun selain API untuk kelas untuk melihat apa yang dilakukannya, itu paling baik merupakan kegagalan parsial.

jmoreno
sumber
-1

Ingat, tidak ada peluru perak. Jika Anda menulis aplikasi yang sangat sederhana yang perlu dirayapi dengan cepat, maka string sederhana dapat melakukan pekerjaan itu. Namun dalam 98% kesempatan, Value Object seperti yang dijelaskan oleh Eric Evans dalam DDD, akan sangat cocok. Anda dapat dengan mudah melihat semua manfaat yang disediakan benda Nilai dengan membaca sekitar.

Alexios Plomaritis
sumber