Saya mengurus bisnis saya sendiri di rumah dan istri saya mendatangi saya dan berkata
Sayang .. Bisakah Anda mencetak semua Day Light Savings di seluruh dunia untuk tahun 2018 di konsol? Saya perlu memeriksa sesuatu.
Dan saya sangat senang karena itulah yang telah saya tunggu sepanjang hidup saya dengan pengalaman Java saya dan datang dengan:
import java.time.*;
import java.util.Set;
class App {
void dayLightSavings() {
final Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
availableZoneIds.forEach(
zoneId -> {
LocalDateTime dateTime = LocalDateTime.of(
LocalDate.of(2018, 1, 1),
LocalTime.of(0, 0, 0)
);
ZonedDateTime now = ZonedDateTime.of(dateTime, ZoneId.of(zoneId));
while (2018 == now.getYear()) {
int hour = now.getHour();
now = now.plusHours(1);
if (now.getHour() == hour) {
System.out.println(now);
}
}
}
);
}
}
Tapi kemudian dia bilang dia baru saja menguji saya apakah saya seorang insinyur perangkat lunak yang terlatih secara etis, dan mengatakan kepada saya sepertinya saya tidak sejak itu (diambil dari sini ) ..
Perlu dicatat bahwa tidak ada insinyur perangkat lunak yang terlatih secara etis yang akan menyetujui untuk menulis prosedur DestroyBaghdad. Etika profesional dasar malah mengharuskannya untuk menulis prosedur DestroyCity, yang dapat diberikan Baghdad sebagai parameter.
Dan saya seperti, baik, ok, Anda punya saya .. Lewati setiap tahun yang Anda suka, ini dia:
import java.time.*;
import java.util.Set;
class App {
void dayLightSavings(int year) {
final Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
availableZoneIds.forEach(
zoneId -> {
LocalDateTime dateTime = LocalDateTime.of(
LocalDate.of(year, 1, 1),
LocalTime.of(0, 0, 0)
);
ZonedDateTime now = ZonedDateTime.of(dateTime, ZoneId.of(zoneId));
while (year == now.getYear()) {
// rest is same..
Tetapi bagaimana saya tahu berapa banyak (dan apa) yang harus diukur? Bagaimanapun, dia mungkin berkata ..
- dia ingin melewati pemformat string khusus, mungkin dia tidak suka format yang sudah saya cetak:
2018-10-28T02:00+01:00[Arctic/Longyearbyen]
void dayLightSavings(int year, DateTimeFormatter dtf)
- dia hanya tertarik pada periode bulan tertentu
void dayLightSavings(int year, DateTimeFormatter dtf, int monthStart, int monthEnd)
- dia tertarik pada periode jam tertentu
void dayLightSavings(int year, DateTimeFormatter dtf, int monthStart, int monthEnd, int hourStart, int hourend)
Jika Anda mencari pertanyaan konkret:
Jika destroyCity(City city)
lebih baik daripada destroyBaghdad()
, apakah takeActionOnCity(Action action, City city)
lebih baik? Kenapa / mengapa tidak?
Setelah semua, saya pertama kali bisa menyebutnya dengan Action.DESTROY
itu Action.REBUILD
, bukan?
Tetapi mengambil tindakan di kota tidak cukup bagi saya, bagaimana takeActionOnGeographicArea(Action action, GeographicalArea GeographicalArea)
? Lagi pula, saya tidak ingin menelepon:
takeActionOnCity(Action.DESTORY, City.BAGHDAD);
kemudian
takeActionOnCity(Action.DESTORY, City.ERBIL);
dan seterusnya ketika saya bisa melakukan:
takeActionOnGeographicArea(Action.DESTORY, Country.IRAQ);
ps Saya hanya membangun pertanyaan saya berdasarkan kutipan yang saya sebutkan, saya tidak menentang negara, agama, ras atau apa pun di dunia. Saya hanya mencoba membuat suatu poin.
sumber
destroyCity(target)
jauh lebih tidak etis daripadadestroyBagdad()
! Monster apa yang menulis program untuk memusnahkan sebuah kota, apalagi kota di dunia? Bagaimana jika sistem itu dikompromikan? Juga, apa hubungan manajemen waktu / sumber daya (upaya yang diinvestasikan) dengan etika? Selama kontrak lisan / tertulis diselesaikan sesuai kesepakatan.Jawaban:
Ini kura-kura sepanjang jalan.
Atau abstraksi dalam hal ini.
Pengkodean praktik yang baik adalah sesuatu yang dapat diterapkan tanpa batas, dan pada titik tertentu Anda melakukan abstraksi untuk mengabstraksi, yang berarti Anda telah mengambilnya terlalu jauh. Menemukan garis itu bukanlah sesuatu yang mudah untuk diterapkan, karena sangat tergantung pada lingkungan Anda.
Sebagai contoh, kami memiliki pelanggan yang dikenal untuk meminta aplikasi sederhana terlebih dahulu tetapi kemudian meminta ekspansi. Kami juga memiliki pelanggan yang menanyakan apa yang mereka inginkan dan umumnya tidak pernah kembali kepada kami untuk ekspansi.
Pendekatan Anda akan bervariasi per pelanggan. Untuk pelanggan pertama, itu akan membayar untuk pra-emptively abstrak kode karena Anda cukup yakin bahwa Anda harus meninjau kembali kode ini di masa depan. Untuk pelanggan kedua, Anda mungkin tidak ingin menginvestasikan upaya ekstra jika Anda mengharapkan mereka untuk tidak ingin memperluas aplikasi pada titik mana pun (catatan: ini tidak berarti bahwa Anda tidak mengikuti praktik yang baik, tetapi hanya bahwa Anda menghindari melakukan lebih dari yang diperlukan saat ini .
Bagaimana saya tahu fitur mana yang harus diterapkan?
Alasan saya menyebutkan hal di atas adalah karena Anda sudah jatuh dalam perangkap ini:
"Dia mungkin berkata" bukan persyaratan bisnis saat ini. Ini dugaan pada kebutuhan bisnis di masa depan. Sebagai aturan umum, jangan mendasarkan diri pada dugaan, hanya mengembangkan apa yang saat ini diperlukan.
Namun, konteks berlaku di sini. Saya tidak kenal istrimu. Mungkin Anda secara akurat mengukur bahwa dia sebenarnya menginginkan ini. Tetapi Anda harus tetap mengkonfirmasi dengan pelanggan bahwa ini memang yang mereka inginkan, karena jika tidak, Anda akan menghabiskan waktu mengembangkan fitur yang pada akhirnya tidak akan Anda gunakan.
Bagaimana saya tahu arsitektur mana yang harus diimplementasikan?
Ini lebih sulit. Pelanggan tidak peduli dengan kode internal, jadi Anda tidak bisa bertanya apakah mereka membutuhkannya. Pendapat mereka tentang masalah ini sebagian besar tidak relevan.
Namun, Anda masih dapat mengonfirmasi perlunya melakukannya dengan mengajukan pertanyaan yang tepat kepada pelanggan. Alih-alih bertanya tentang arsitektur, tanyakan pada mereka tentang ekspektasi mereka akan pengembangan di masa depan atau perluasan basis kode. Anda juga dapat menanyakan apakah sasaran saat ini memiliki tenggat waktu, karena Anda mungkin tidak dapat mengimplementasikan arsitektur mewah Anda dalam jangka waktu yang diperlukan.
Bagaimana saya tahu kapan harus mengabstraksi kode saya lebih lanjut?
Saya tidak tahu di mana saya membacanya (jika ada yang tahu, beri tahu saya dan saya akan memberikan kredit), tetapi aturan praktis yang baik adalah bahwa pengembang harus menghitung seperti manusia gua: satu, dua banyak .
XKCD # 764
Dengan kata lain, ketika algoritma / pola tertentu sedang digunakan untuk ketiga kalinya, itu harus diabstraksikan sehingga dapat digunakan kembali (= dapat digunakan berkali- kali).
Untuk lebih jelasnya, saya tidak menyiratkan bahwa Anda tidak boleh menulis kode yang dapat digunakan kembali ketika hanya ada dua contoh algoritma yang digunakan. Tentu saja Anda dapat mengabstraksikan itu juga, tetapi aturannya adalah bahwa untuk tiga contoh Anda harus mengabstraksikan.
Sekali lagi, ini faktor dalam harapan Anda. Jika Anda sudah tahu bahwa Anda perlu tiga kali atau lebih, tentu saja Anda dapat langsung abstrak. Tetapi jika Anda hanya menebak bahwa Anda mungkin ingin menerapkannya lebih sering, kebenaran penerapan abstraksi sepenuhnya bergantung pada kebenaran dugaan Anda.
Jika Anda menebak dengan benar, Anda menghemat waktu. Jika Anda salah menebak, Anda menyia-nyiakan waktu dan tenaga Anda dan mungkin membahayakan arsitektur Anda untuk mengimplementasikan sesuatu yang pada akhirnya tidak Anda perlukan.
Itu sangat tergantung pada banyak hal:
takeActionOnCity
metode tunggal .Perlu diketahui juga bahwa jika Anda secara abstrak mengabstraksikan ini, Anda akan berakhir dengan metode yang sangat abstrak sehingga tidak lebih dari sebuah wadah untuk menjalankan metode lain, yang berarti Anda membuat metode Anda tidak relevan dan tidak berarti.
Jika seluruh
takeActionOnCity(Action action, City city)
badan metode Anda berakhir menjadi tidak lebih dariaction.TakeOn(city);
, Anda harus bertanya-tanya apakahtakeActionOnCity
metode tersebut benar-benar memiliki tujuan atau bukan hanya lapisan tambahan yang tidak menambah nilai.Pertanyaan yang sama muncul di sini:
Jika Anda dapat secara pasti menjawab "ya" untuk ketiganya, maka abstraksi dijamin.
sumber
Praktek
Ini adalah Rekayasa Perangkat Lunak SE, tetapi membuat perangkat lunak lebih banyak seni daripada rekayasa. Tidak ada algoritma universal untuk diikuti atau pengukuran untuk mengetahui berapa banyak reusability sudah cukup. Seperti halnya apa pun, semakin banyak latihan yang Anda dapatkan dalam merancang program, semakin baik Anda melakukannya. Anda akan mendapatkan perasaan yang lebih baik tentang apa yang "cukup" karena Anda akan melihat apa yang salah dan bagaimana kesalahannya ketika Anda mengukur terlalu banyak atau terlalu sedikit.
Itu tidak terlalu membantu sekarang , jadi bagaimana dengan beberapa panduan?
Lihat kembali pertanyaan Anda. Ada banyak "dia mungkin berkata" dan "aku bisa". Banyak pernyataan berteori tentang beberapa kebutuhan masa depan. Manusia malu memprediksi masa depan. Dan Anda (kemungkinan besar) adalah manusia. Masalah besar dari desain perangkat lunak adalah mencoba menjelaskan masa depan yang tidak Anda ketahui.
Pedoman 1: Anda Tidak Akan Membutuhkannya
Serius. Berhenti saja. Lebih sering daripada tidak, bahwa masalah masa depan yang dibayangkan tidak muncul - dan itu pasti tidak akan muncul seperti yang Anda bayangkan.
Pedoman 2: Biaya / Manfaat
Keren, program kecil itu butuh waktu beberapa jam untuk menulis, mungkin? Jadi bagaimana jika istri Anda tidak datang kembali dan meminta hal-hal? Kasus terburuk, Anda menghabiskan beberapa jam lagi untuk bergabung bersama program lain untuk melakukannya. Untuk kasus ini, tidak terlalu banyak waktu untuk membuat program ini lebih fleksibel. Dan itu tidak akan menambah banyak kecepatan runtime atau penggunaan memori. Tetapi program non-sepele memiliki jawaban yang berbeda. Skenario yang berbeda memiliki jawaban yang berbeda pula. Pada titik tertentu, biaya jelas tidak sepadan dengan manfaatnya bahkan dengan keterampilan menceritakan masa depan yang tidak sempurna.
Pedoman 3: Fokus pada konstanta
Lihat kembali pertanyaannya. Di kode asli Anda, ada banyak int konstan.
2018
,1
. Int konstan, string konstan ... Mereka adalah hal yang paling mungkin perlu tidak konstan . Lebih baik lagi, mereka hanya membutuhkan sedikit waktu untuk membuat parameter (atau setidaknya mendefinisikan sebagai konstanta aktual). Tetapi hal lain yang harus diwaspadai adalah perilaku konstan . ItuSystem.out.println
sebagai contoh. Asumsi semacam itu tentang penggunaan cenderung menjadi sesuatu yang berubah di masa depan dan cenderung sangat mahal untuk diperbaiki. Bukan hanya itu, tetapi IO seperti ini membuat fungsi tidak murni (bersama dengan zona waktu mengambil agak). Parameterisasi perilaku itu dapat membuat fungsi lebih murni yang mengarah pada peningkatan fleksibilitas dan pengujian. Manfaat besar dengan biaya minimal (terutama jika Anda membuat kelebihan yang digunakanSystem.out
secara default).sumber
Pertama: Tidak ada pengembang perangkat lunak yang berpikiran keamanan akan menulis metode DestroyCity tanpa melewati Token Otorisasi untuk alasan apa pun.
Saya juga bisa menulis apa pun sebagai keharusan yang memiliki kebijaksanaan jelas tanpa itu dapat diterapkan dalam konteks lain. Mengapa perlu mengesahkan penggabungan string?
Kedua: Semua kode ketika dieksekusi harus ditentukan sepenuhnya .
Tidak masalah apakah keputusan itu dikodekan dengan keras, atau ditangguhkan ke lapisan lain. Pada titik tertentu ada sepotong kode dalam beberapa bahasa yang tahu apa yang harus dihancurkan dan bagaimana cara menginstruksikannya.
Itu bisa di file objek yang sama
destroyCity(xyz)
, dan itu bisa dalam file konfigurasi:,destroy {"city": "XYZ"}"
atau mungkin serangkaian klik dan penekanan tombol di UI.Ketiga:
adalah serangkaian persyaratan yang sangat berbeda untuk:
Sekarang persyaratan kedua jelas membuat alat yang lebih fleksibel. Ini memiliki target audiens yang lebih luas, dan ranah aplikasi yang lebih luas. Bahayanya di sini adalah bahwa aplikasi yang paling fleksibel di dunia sebenarnya adalah kompiler untuk kode mesin. Ini benar-benar sebuah program sehingga generik dapat membangun apa pun untuk membuat komputer apa pun yang Anda inginkan (dalam batasan perangkat kerasnya).
Secara umum orang yang membutuhkan perangkat lunak tidak menginginkan sesuatu yang generik; mereka menginginkan sesuatu yang spesifik. Dengan memberikan lebih banyak pilihan, Anda sebenarnya membuat hidup mereka lebih rumit. Jika mereka menginginkan kompleksitas itu, mereka malah akan menggunakan kompiler, bukan meminta Anda.
Istri Anda meminta fungsionalitas, dan persyaratannya tidak ditentukan untuk Anda. Dalam hal ini sepertinya sengaja, dan secara umum itu karena mereka tidak tahu apa-apa. Kalau tidak, mereka hanya akan menggunakan kompiler sendiri. Jadi masalah pertama adalah Anda tidak meminta rincian lebih lanjut tentang apa yang ingin ia lakukan. Apakah dia ingin menjalankan ini selama beberapa tahun yang berbeda? Apakah dia menginginkannya dalam file CSV? Anda tidak menemukan keputusan apa yang ingin dia buat sendiri, dan apa yang dia minta agar Anda pikirkan dan putuskan. Setelah Anda mengetahui keputusan apa yang perlu ditangguhkan, Anda dapat mengetahui bagaimana mengkomunikasikan keputusan tersebut melalui parameter (dan cara-cara lain yang dapat dikonfigurasi).
Yang sedang berkata, sebagian besar klien salah berkomunikasi, menganggap, atau tidak mengetahui detail tertentu (alias. Keputusan) bahwa mereka benar-benar ingin membuat diri mereka sendiri, atau bahwa mereka benar-benar tidak ingin membuat (tetapi kedengarannya luar biasa). Inilah sebabnya mengapa metode kerja seperti PDSA (rencana-kembangkan-studi-tindakan) penting. Anda telah merencanakan pekerjaan sesuai dengan persyaratan, dan kemudian Anda mengembangkan serangkaian keputusan (kode). Sekarang saatnya mempelajarinya, baik sendiri atau dengan klien Anda dan mempelajari hal-hal baru, dan ini menginformasikan pemikiran Anda ke depan. Terakhir, tindak lanjuti wawasan baru Anda - perbarui persyaratan, perbaiki proses, dapatkan alat baru, dll ... Kemudian mulai perencanaan lagi. Ini akan mengungkapkan persyaratan tersembunyi dari waktu ke waktu, dan membuktikan kemajuan bagi banyak klien.
Akhirnya. Waktu Anda penting ; ini sangat nyata dan sangat terbatas. Setiap keputusan yang Anda buat melibatkan banyak keputusan tersembunyi lainnya, dan ini adalah tentang pengembangan perangkat lunak. Menunda keputusan sebagai argumen dapat membuat fungsi saat ini lebih sederhana, tetapi itu membuat tempat lain lebih kompleks. Apakah keputusan itu relevan di lokasi lain itu? Apakah ini lebih relevan di sini? Keputusan siapa yang benar-benar dibuat? Anda memutuskan ini; ini coding. Jika Anda sering mengulangi set keputusan, ada manfaat yang sangat nyata dalam menyusunnya dalam beberapa abstraksi. XKCD memiliki perspektif yang bermanfaat di sini. Dan ini relevan pada level sistem baik itu fungsi, modul, program, dll.
Nasihat di awal menyiratkan bahwa keputusan yang tidak berhak dilakukan oleh fungsi Anda harus diajukan sebagai argumen. Masalahnya adalah suatu
DestroyBaghdad
fungsi sebenarnya adalah fungsi yang memiliki hak tersebut.sumber
Ada banyak jawaban panjang lebar di sini, tapi jujur saya pikir itu sangat sederhana
jadi dalam fungsi Anda
Kamu punya:
Jadi saya akan memindahkan semua ini ke parameter dalam satu bentuk atau lainnya. Anda bisa berpendapat bahwa zoneIds tersirat dalam nama fungsi, mungkin Anda ingin membuatnya lebih dengan mengubahnya menjadi "DaylightSavingsAroundTheWorld" atau sesuatu
Anda tidak memiliki string format, jadi menambahkan satu adalah permintaan fitur dan Anda harus merujuk istri Anda ke instance Jira keluarga Anda. Ini dapat dimasukkan ke dalam simpanan dan diprioritaskan pada pertemuan komite manajemen proyek yang sesuai.
sumber
Singkatnya, jangan merekayasa perangkat lunak Anda untuk dapat digunakan kembali karena tidak ada pengguna akhir yang peduli jika fungsi Anda dapat digunakan kembali. Sebaliknya, insinyur untuk kelengkapan desain - apakah kode saya mudah bagi orang lain atau masa depan saya yang pelupa untuk mengerti? - dan fleksibilitas desain- ketika saya mau tidak mau harus memperbaiki bug, menambah fitur, atau memodifikasi fungsionalitas, seberapa banyak kode saya akan menolak perubahan? Satu-satunya hal yang diperhatikan pelanggan Anda adalah seberapa cepat Anda dapat merespons ketika dia melaporkan bug atau meminta perubahan. Mengajukan pertanyaan ini tentang desain Anda secara tidak sengaja cenderung menghasilkan kode yang dapat digunakan kembali, tetapi pendekatan ini membuat Anda tetap fokus pada menghindari masalah nyata yang akan Anda hadapi sepanjang umur kode tersebut sehingga Anda dapat melayani pengguna akhir dengan lebih baik daripada mengejar yang tinggi, tidak praktis. "rekayasa" cita-cita untuk menyenangkan jenggot leher.
Untuk sesuatu yang sederhana seperti contoh yang Anda berikan, implementasi awal Anda baik-baik saja karena betapa kecilnya, tetapi desain langsung ini akan menjadi sulit untuk dipahami dan rapuh jika Anda mencoba memasukkan terlalu banyak fleksibilitas fungsional (sebagai lawan dari fleksibilitas desain) ke dalam satu prosedur. Di bawah ini adalah penjelasan saya tentang pendekatan yang saya sukai untuk merancang sistem yang kompleks untuk kelengkapan dan fleksibilitas yang saya harap akan menunjukkan apa yang saya maksud dengan mereka. Saya tidak akan menggunakan strategi ini untuk sesuatu yang dapat ditulis dalam kurang dari 20 baris dalam satu prosedur karena sesuatu yang sangat kecil sudah memenuhi kriteria saya untuk kelengkapan dan fleksibilitas.
Objek, bukan Prosedur
Daripada menggunakan kelas-kelas seperti modul old-school dengan banyak rutinitas yang Anda panggil untuk melakukan hal-hal yang seharusnya dilakukan perangkat lunak Anda, pertimbangkan untuk memodelkan domain sebagai objek yang berinteraksi dan bekerja sama untuk menyelesaikan tugas yang ada. Metode-metode dalam paradigma Berorientasi Objek pada awalnya diciptakan untuk menjadi sinyal di antara objek-objek sehingga
Object1
dapatObject2
menentukan untuk melakukan hal tersebut, apa pun itu, dan mungkin menerima sinyal balik. Ini karena paradigma Berorientasi Objek secara inheren tentang pemodelan objek domain Anda dan interaksinya daripada cara mewah untuk mengatur fungsi dan prosedur lama yang sama dari paradigma Imperatif. Dalam halvoid destroyBaghdad
misalnya, alih-alih mencoba menulis metode yang kurang umum konteks untuk menangani penghancuran Baghdad atau hal lain (yang dapat dengan cepat tumbuh kompleks, sulit dipahami, dan rapuh), setiap hal yang dapat dihancurkan harus bertanggung jawab untuk memahami bagaimana untuk menghancurkan dirinya sendiri. Misalnya, Anda memiliki antarmuka yang menggambarkan perilaku hal-hal yang dapat dihancurkan:Maka Anda memiliki kota yang mengimplementasikan antarmuka ini:
Tidak ada yang menyerukan penghancuran instance
City
akan pernah peduli bagaimana itu terjadi, jadi tidak ada alasan untuk kode itu ada di mana pun di luarCity::destroy
, dan memang, pengetahuan intim tentang cara kerja bagian dalamCity
dari dirinya sendiri akan menjadi kopling ketat yang mengurangi karena Anda harus mempertimbangkan elemen-elemen luar itu jika Anda perlu memodifikasi perilakuCity
. Ini adalah tujuan sebenarnya di balik enkapsulasi. Anggap saja seperti setiap objek memiliki API sendiri yang memungkinkan Anda untuk melakukan apa pun yang Anda butuhkan sehingga Anda dapat membiarkannya khawatir tentang memenuhi permintaan Anda.Delegasi, bukan "Kontrol"
Sekarang, apakah kelas implementasi Anda
City
atauBaghdad
tergantung pada seberapa umum proses menghancurkan kota itu ternyata. Dalam semua kemungkinan, aCity
akan terdiri dari potongan-potongan kecil yang perlu dihancurkan secara individual untuk mencapai kehancuran total kota, jadi dalam hal itu, masing-masing potongan juga akan diterapkanDestroyable
, dan mereka masing-masing akan diperintahkan olehCity
untuk menghancurkan sendiri dengan cara yang sama seseorang dari luar memintaCity
untuk menghancurkan dirinya sendiri.Jika Anda ingin menjadi benar-benar gila dan menerapkan gagasan
Bomb
yang dijatuhkan di lokasi dan menghancurkan segala sesuatu dalam radius tertentu, itu mungkin terlihat seperti ini:ObjectsByRadius
mewakili seperangkat objek yang dihitung untukBomb
dari input karenaBomb
tidak peduli bagaimana perhitungan itu dibuat selama ia dapat bekerja dengan objek. Ini dapat digunakan kembali secara tidak disengaja, tetapi tujuan utamanya adalah untuk mengisolasi perhitungan dari proses menjatuhkanBomb
dan menghancurkan objek sehingga Anda dapat memahami setiap bagian dan bagaimana mereka cocok bersama-sama dan mengubah perilaku masing-masing bagian tanpa harus membentuk kembali seluruh algoritma .Interaksi, bukan Algoritma
Alih-alih mencoba menebak pada jumlah parameter yang tepat untuk algoritma yang kompleks, lebih masuk akal untuk memodelkan proses sebagai satu set objek yang berinteraksi, masing-masing dengan peran yang sangat sempit, karena itu akan memberi Anda kemampuan untuk memodelkan kompleksitas kompleksitas Anda. proses melalui interaksi antara objek yang terdefinisi dengan baik, mudah dipahami, dan hampir tidak berubah ini. Ketika dilakukan dengan benar, ini membuat bahkan beberapa modifikasi paling kompleks sepele seperti mengimplementasikan satu atau dua antarmuka dan pengerjaan ulang objek mana yang dipakai dalam
main()
metode Anda .Saya akan memberi Anda sesuatu untuk contoh asli Anda, tetapi saya jujur tidak tahu apa artinya "mencetak ... Penghematan Day Light." Apa yang bisa saya katakan tentang kategori masalah itu adalah bahwa setiap kali Anda melakukan perhitungan, yang hasilnya dapat diformat dengan beberapa cara, cara saya yang lebih disukai untuk menguraikannya adalah seperti ini:
Karena contoh Anda menggunakan kelas dari perpustakaan Java yang tidak mendukung desain ini, Anda bisa menggunakan API
ZonedDateTime
secara langsung. Idenya di sini adalah bahwa setiap perhitungan dirangkum dalam objeknya sendiri. Itu tidak membuat asumsi tentang berapa kali harus berjalan atau bagaimana harus memformat hasilnya. Ini secara khusus berkaitan dengan melakukan bentuk perhitungan yang paling sederhana. Ini membuatnya mudah dipahami dan fleksibel untuk diubah. Demikian juga,Result
secara eksklusif berkaitan dengan merangkum hasil perhitungan, danFormattedResult
secara eksklusif berkaitan dengan berinteraksi denganResult
memformatnya sesuai dengan aturan yang kami tetapkan. Lewat sini,kita dapat menemukan jumlah argumen yang sempurna untuk masing-masing metode kita karena masing-masing memiliki tugas yang jelas . Ini juga jauh lebih mudah untuk memodifikasi bergerak maju selama antarmuka tidak berubah (yang tidak mungkin dilakukan jika Anda meminimalkan tanggung jawab objek Anda dengan benar).main()
Metodekamimungkin terlihat seperti ini:Faktanya, Pemrograman Berorientasi Objek diciptakan khusus sebagai solusi untuk masalah kompleksitas / fleksibilitas paradigma Imperatif karena tidak ada jawaban yang baik (bahwa setiap orang dapat menyetujui atau tiba secara mandiri, bagaimanapun) untuk bagaimana mengoptimalkan secara optimal tentukan fungsi dan prosedur Imperatif dalam idiom.
sumber
Pengalaman , Pengetahuan Domain , dan Ulasan Kode.
Dan, terlepas dari seberapa banyak atau sedikit pengalaman , pengetahuan domain , atau tim yang Anda miliki, Anda tidak dapat menghindari kebutuhan untuk refactor sesuai kebutuhan.
Dengan Pengalaman , Anda akan mulai mengenali pola dalam metode spesifik domain (dan kelas) yang Anda tulis. Dan, jika Anda benar-benar tertarik pada kode KERING, Anda akan merasakan perasaan buruk ketika Anda tentang menulis metode yang secara naluriah Anda tahu Anda akan menulis variasi di masa depan. Jadi, Anda secara intuitif akan menulis denominator paling umum yang parametrize sebagai gantinya.
(Pengalaman ini dapat mentransfer secara naluriah ke beberapa objek dan metode domain Anda juga.)
Dengan Pengetahuan Domain , Anda akan merasakan konsep bisnis yang terkait erat, konsep mana yang memiliki variabel, yang cukup statis, dll.
Dengan Ulasan Kode, parametriasi di bawah dan di atas akan lebih mungkin ditangkap sebelum menjadi kode produksi, karena rekan-rekan Anda (semoga) memiliki pengalaman dan perspektif yang unik, baik pada domain dan pengkodean secara umum.
Yang mengatakan, pengembang baru umumnya tidak akan memiliki Sense Spidey ini atau sekelompok teman sebaya berpengalaman untuk bersandar langsung. Dan, bahkan pengembang yang berpengalaman pun mendapat manfaat dari disiplin dasar untuk membimbing mereka melalui persyaratan baru - atau melalui hari yang berkabut di otak. Jadi, inilah yang saya sarankan sebagai permulaan :
(Sertakan parameter apa pun yang sudah Anda tahu Anda perlukan, jelas ...)
Langkah-langkah ini tidak harus terjadi dalam urutan yang ditentukan. Jika Anda duduk untuk menulis metode yang sudah Anda ketahui sangat berlebihan dengan metode yang sudah ada , lompat langsung ke refactoring jika itu nyaman. (Jika tidak akan membutuhkan waktu lebih lama untuk melakukan refactor daripada hanya menulis, menguji, dan memelihara dua metode.)
Tapi, selain hanya memiliki banyak pengalaman dan sebagainya, saya menyarankan kode yang cukup minimalis KERING. Tidak sulit untuk memperbaiki pelanggaran yang jelas. Dan, jika Anda terlalu bersemangat , Anda bisa berakhir dengan kode "terlalu KERING" yang bahkan lebih sulit untuk dibaca, dipahami, dan dipelihara daripada yang setara dengan "BASAH".
sumber
If destoryCity(City city) is better than destoryBaghdad(), is takeActionOnCity(Action action, City city) even better?
? Itu adalah pertanyaan ya / tidak, tetapi tidak memiliki jawaban, bukan? Atau anggapan awal yang salah,destroyCity(City)
mungkin tidak perlu lebih baik dan itu benar-benar tergantung ? Jadi bukan berarti saya bukan insinyur perangkat lunak yang tidak terlatih secara etis karena saya langsung mengimplementasikannya tanpa parameter? Maksud saya apa jawaban untuk pertanyaan konkret yang saya tanyakan?destroyBaghdad()
metode. Apa konteksnya? Apakah ini video game di mana akhir pertandingan mengakibatkan Baghdad dihancurkan ??? Jika demikian ...destroyBaghdad()
mungkin metode nama / tanda tangan yang masuk akal ...It should be noted that no ethically-trained software engineer would ever consent to write a DestroyBaghdad procedure.
Jika Anda berada di ruangan bersama Nathaniel Borenstein, Anda akan membantahnya bahwa itu benar-benar tergantung dan pernyataannya tidak benar? Maksud saya indah bahwa banyak orang yang menjawab, menghabiskan waktu dan energi mereka, tetapi saya tidak melihat satu jawaban konkret di mana pun. Spidey-indra, ulasan kode .. Tapi apa jawabannyais takeActionOnCity(Action action, City city) better?
null
?Jawaban yang sama dengan kualitas, kegunaan, hutang teknis dll:
Dapat digunakan kembali seperti Anda, pengguna, 1 membutuhkannya
Ini pada dasarnya panggilan penilaian - apakah biaya merancang dan memelihara abstraksi akan dibayar kembali dengan biaya (= waktu dan usaha) itu akan menghemat Anda.
1 Ini adalah konstruksi kode, jadi Anda adalah "pengguna" dalam hal ini - pengguna kode sumber
sumber
Ada proses yang jelas yang dapat Anda ikuti:
Ini muncul dengan - setidaknya menurut pendapat beberapa orang - kode yang cukup optimal, karena sekecil mungkin, setiap fitur selesai membutuhkan waktu sesedikit mungkin (yang mungkin atau mungkin tidak benar jika Anda melihat selesai) produk setelah refactoring), dan memiliki cakupan pengujian yang sangat baik. Ini juga secara nyata menghindari metode atau kelas yang terlalu umum-direkayasa.
Ini juga memberi Anda instruksi yang sangat jelas kapan membuat sesuatu menjadi generik dan kapan harus mengkhususkan diri.
Saya menemukan contoh kota Anda aneh; Saya kemungkinan besar tidak akan pernah meng-hardcode nama kota. Sangat jelas bahwa kota-kota tambahan akan dimasukkan nanti, apa pun yang Anda lakukan. Tapi contoh lain adalah warna. Dalam beberapa keadaan, hardcoding "merah" atau "hijau" akan menjadi suatu kemungkinan. Misalnya, lampu lalu lintas adalah warna di mana-mana sehingga Anda bisa lolos begitu saja (dan Anda selalu bisa refactor). Perbedaannya adalah bahwa "merah" dan "hijau" memiliki makna universal, "hardcoded" di dunia kita, sangat tidak mungkin hal itu akan pernah berubah, dan tidak ada alternatif lain juga.
Metode penghematan siang hari pertama Anda benar-benar rusak. Sementara itu sesuai dengan spesifikasi, hardcoded 2018 sangat buruk karena a) tidak disebutkan dalam "kontrak" teknis (dalam nama metode, dalam kasus ini), dan b) itu akan keluar dari tanggal segera, jadi kerusakan sudah termasuk sejak awal. Untuk hal-hal yang berkaitan dengan waktu / tanggal, sangat jarang masuk akal untuk meng-hardcode nilai tertentu karena, well, waktu terus berjalan. Namun terlepas dari itu, segala sesuatu yang lain untuk diskusi. Jika Anda memberikan tahun yang sederhana dan kemudian selalu menghitung tahun yang lengkap, silakan. Sebagian besar hal-hal yang Anda daftarkan (pemformatan, pilihan rentang yang lebih kecil, dll.) Berteriak bahwa metode Anda melakukan terlalu banyak, dan itu seharusnya mungkin mengembalikan daftar / array nilai sehingga pemanggil dapat melakukan pemformatan / pemfilteran sendiri.
Tetapi pada akhirnya, sebagian besar dari ini adalah opini, rasa, pengalaman dan bias pribadi, jadi jangan terlalu khawatir tentang hal itu.
sumber
Saya berpendapat bahwa ada dua jenis kode yang dapat digunakan kembali:
Jenis usabilitas pertama seringkali merupakan ide yang bagus. Ini berlaku untuk hal-hal seperti daftar, hashmaps, key / value store, pencocokan string (mis. Regex, glob, ...), tuple, unifikasi, pohon pencarian (kedalaman-pertama, luas-pertama, iterasi-mendalam, ...) , pengurai parser, cache / memoiser, pembaca / penulis format data (s-ekspresi, XML, JSON, protobuf, ...), antrian tugas, dll.
Hal-hal ini sangat umum, dengan cara yang sangat abstrak, sehingga digunakan kembali di semua tempat dalam pemrograman sehari-hari. Jika Anda menemukan diri Anda menulis kode tujuan khusus yang akan lebih sederhana jika dibuat lebih abstrak / umum (misalnya jika kita memiliki "daftar pesanan pelanggan", kita dapat membuang barang-barang "pesanan pelanggan" untuk mendapatkan "daftar" ) maka mungkin ide yang bagus untuk menariknya keluar. Bahkan jika itu tidak digunakan kembali, itu memungkinkan kita memisahkan fungsi yang tidak terkait.
Jenis kedua adalah di mana kita memiliki beberapa kode konkret, yang memecahkan masalah nyata, tetapi melakukannya dengan membuat sejumlah besar keputusan. Kita dapat membuatnya lebih umum / dapat digunakan kembali dengan "soft-coding" keputusan-keputusan itu, misalnya mengubahnya menjadi parameter, menyulitkan implementasi dan membuat detail yang lebih konkret (yaitu pengetahuan tentang kait mana yang mungkin kita inginkan untuk ditimpa). Contoh Anda tampaknya seperti ini. Masalah dengan penggunaan kembali semacam ini adalah bahwa kita mungkin pada akhirnya mencoba untuk menebak kasus penggunaan orang lain, atau diri kita di masa depan. Akhirnya kita mungkin memiliki banyak parameter sehingga kode kita tidak dapat digunakan, apalagi bisa digunakan kembali! Dengan kata lain, saat menelepon dibutuhkan lebih banyak upaya daripada hanya menulis versi kita sendiri. Di sinilah YAGNI (Kamu Tidak Akan Membutuhkannya) penting. Sering kali, upaya seperti itu pada kode "dapat digunakan kembali" berakhir tidak digunakan kembali, karena mungkin tidak dapat dibandingkan dengan kasus-kasus penggunaan lebih mendasar daripada parameter dapat menjelaskan, atau para pengguna potensial lebih suka menggulung sendiri (sih, lihat semua standar dan perpustakaan di luar sana yang penulisnya diawali dengan kata "Sederhana", untuk membedakan mereka dari para pendahulu!).
Bentuk kedua "reusability" ini pada dasarnya harus dilakukan atas dasar yang diperlukan. Tentu, Anda dapat menempel beberapa parameter "jelas" di sana, tetapi jangan mulai mencoba memprediksi masa depan. YAGNI.
sumber
destroyBaghdad
adalah skrip satu kali (atau setidaknya, ini idempoten). Mungkin menghancurkan kota mana pun akan menjadi peningkatan, tetapi bagaimana jikadestroyBaghdad
bekerja dengan membanjiri Tigris? Itu mungkin dapat digunakan kembali untuk Mosul dan Basra, tetapi tidak untuk Mekah atau Atlanta.static
metode) yang murni fungsional dan tingkat rendah, dan berbeda dengan itu, memutuskan tentang "mengonfigurasi parameter dan kait" biasanya di mana Anda harus membangun beberapa struktur yang meminta dibenarkan.Sudah ada banyak jawaban yang bagus dan rumit. Beberapa dari mereka masuk ke dalam rincian spesifik, menjabarkan sudut pandang tertentu tentang metodologi pengembangan perangkat lunak secara umum, dan beberapa dari mereka tentu saja memiliki unsur kontroversial atau "pendapat".
The jawaban dengan Warbo sudah menunjukkan berbagai jenis usabilitas. Yaitu, apakah sesuatu dapat digunakan kembali karena itu adalah blok bangunan fundamental, atau apakah sesuatu dapat digunakan kembali karena itu "generik" dalam beberapa cara. Mengacu pada yang terakhir, ada sesuatu yang saya anggap sebagai semacam ukuran untuk digunakan kembali:
Apakah satu metode dapat meniru yang lain.
Mengenai contoh dari pertanyaan: Bayangkan metode itu
adalah implementasi dari fungsi yang diminta oleh pelanggan. Jadi itu akan menjadi sesuatu yang seharusnya digunakan oleh programmer lain , dan dengan demikian, menjadi metode publik , seperti pada
public
void dayLightSavings()
Ini bisa diterapkan seperti yang Anda tunjukkan dalam jawaban Anda. Sekarang, seseorang ingin mengukurnya dengan tahun. Jadi Anda bisa menambahkan metode
public
void dayLightSavings(int year)
dan mengubah implementasi asli menjadi adil
"Permintaan fitur" selanjutnya dan generalisasi mengikuti pola yang sama. Jadi jika dan hanya jika ada permintaan untuk bentuk yang paling umum, Anda dapat mengimplementasikannya, mengetahui bahwa bentuk yang paling umum ini memungkinkan untuk implementasi sepele dari yang lebih spesifik:
Jika Anda telah mengantisipasi ekstensi mendatang dan permintaan fitur, dan memiliki waktu yang Anda inginkan dan ingin menghabiskan akhir pekan yang membosankan dengan generalisasi (berpotensi tidak berguna), Anda bisa mulai dengan yang paling umum sejak dari awal. Tetapi hanya sebagai metode pribadi . Selama Anda hanya mengekspos metode sederhana yang diminta oleh pelanggan sebagai metode publik , Anda aman.
tl; dr :
Pertanyaannya sebenarnya bukan "seberapa bisa digunakannya suatu metode". Pertanyaannya adalah seberapa besar reusability ini diekspos, dan seperti apa API itu. Membuat API andal yang tahan uji waktu (bahkan ketika persyaratan lebih lanjut muncul kemudian) adalah seni dan kerajinan, dan topiknya terlalu rumit untuk dibahas di sini. Lihatlah presentasi ini oleh Joshua Bloch atau wiki buku desain API untuk memulai.
sumber
dayLightSavings()
menelepondayLightSavings(2018)
sepertinya bukan ide yang bagus untukku.dayLightSavings(computeCurrentYear());
...Aturan praktis yang baik adalah: metode Anda harus dapat digunakan kembali seperti ... dapat digunakan kembali.
Jika Anda berharap bahwa Anda akan memanggil metode Anda hanya di satu tempat, seharusnya hanya memiliki parameter yang diketahui ke situs panggilan dan yang tidak tersedia untuk metode ini.
Jika Anda memiliki lebih banyak penelepon, Anda dapat memperkenalkan parameter baru selama penelepon lain dapat melewati parameter tersebut; jika tidak, Anda perlu metode baru.
Karena jumlah penelepon dapat bertambah seiring waktu, Anda harus bersiap untuk melakukan refactoring atau overloading. Dalam banyak kasus itu berarti Anda harus merasa aman untuk memilih ekspresi dan menjalankan tindakan "ekstrak parameter" dari IDE Anda.
sumber
Jawaban ultra singkat: Semakin sedikit sambungan atau ketergantungan pada kode lain, modul generik Anda akan semakin dapat digunakan kembali.
Contoh Anda hanya bergantung pada
jadi secara teori itu bisa sangat dapat digunakan kembali.
Dalam praktiknya saya tidak berpikir bahwa Anda akan memiliki usecase kedua yang memerlukan kode ini sehingga mengikuti prinsip yagni saya tidak akan membuatnya dapat digunakan kembali jika tidak ada lebih dari 3 projets berbeda yang memerlukan kode ini.
Aspek lain yang dapat digunakan kembali adalah kemudahan penggunaan dan dokumentasi yang berhubungan dengan Test Driven Development : Sangat membantu jika Anda memiliki unit-test sederhana yang menunjukkan / mendokumentasikan penggunaan mudah modul generik Anda sebagai contoh pengkodean untuk pengguna lib Anda.
sumber
Ini adalah kesempatan yang baik untuk menyatakan aturan yang saya buat baru-baru ini:
Menjadi programmer yang baik berarti bisa memprediksi masa depan.
Tentu saja, ini sangat mustahil! Lagi pula, Anda tidak pernah tahu pasti generalisasi apa yang menurut Anda berguna nantinya, tugas terkait apa yang ingin Anda lakukan, fitur baru apa yang diinginkan pengguna Anda, & c. Tetapi pengalaman terkadang memberi Anda gambaran kasar tentang apa yang mungkin berguna.
Faktor-faktor lain yang harus Anda imbangi adalah berapa banyak waktu dan usaha ekstra yang akan terlibat, dan seberapa rumit hal itu akan membuat kode Anda. Terkadang Anda beruntung, dan menyelesaikan masalah yang lebih umum sebenarnya lebih sederhana! (Setidaknya secara konseptual, jika tidak dalam jumlah kode.) Tetapi lebih sering, ada biaya kerumitan serta salah satu waktu dan usaha.
Jadi, jika Anda berpikir generalisasi sangat mungkin diperlukan, sering kali layak dilakukan (kecuali jika itu menambah banyak pekerjaan atau kompleksitas); tetapi jika tampaknya jauh lebih kecil kemungkinannya, maka itu mungkin tidak (kecuali sangat mudah dan / atau menyederhanakan kode).
(Sebagai contoh baru-baru ini: minggu lalu saya diberikan spek. Untuk tindakan, sistem seharusnya memakan waktu tepat 2 hari setelah sesuatu kedaluwarsa. Jadi tentu saja saya menjadikan parameter 2 hari sebagai parameter. Minggu ini para pelaku bisnis senang, karena mereka akan meminta peningkatan itu! Saya beruntung: itu adalah perubahan yang mudah, dan saya kira itu sangat mungkin diinginkan. Seringkali lebih sulit untuk dinilai. Tetapi masih layak untuk diprediksi, dan pengalaman sering merupakan panduan yang baik. .)
sumber
Pertama, jawaban terbaik untuk 'Bagaimana saya tahu bagaimana reusable metode saya seharusnya? "Adalah" pengalaman. "Lakukan ini beberapa ribu kali, dan Anda biasanya mendapatkan jawaban yang tepat. Tetapi sebagai penggoda, saya dapat memberikan yang terakhir baris jawaban ini: Pelanggan Anda akan memberi tahu Anda berapa banyak fleksibilitas dan berapa banyak lapisan generalisasi yang harus Anda cari.
Banyak dari jawaban ini memiliki saran khusus. Saya ingin memberikan sesuatu yang lebih umum ... karena ironi itu terlalu menyenangkan untuk dilewatkan!
Seperti yang dicatat oleh beberapa jawaban, generalitas itu mahal. Namun, sebenarnya tidak. Tidak selalu. Memahami biaya sangat penting untuk memainkan permainan reusability.
Saya fokus pada menempatkan berbagai hal dalam skala dari "tidak dapat diubah" menjadi "dapat dibalik." Skala ini halus. Satu-satunya hal yang benar-benar tidak dapat diubah adalah "waktu yang dihabiskan untuk proyek." Anda tidak akan pernah mendapatkan sumber daya itu kembali. Situasi yang sedikit kurang dapat dibalik mungkin merupakan situasi "borgol emas" seperti Windows API. Fitur yang sudah tidak digunakan lagi tetap ada di API itu selama beberapa dekade karena model bisnis Microsoft menghendaki hal itu. Jika Anda memiliki pelanggan yang hubungannya akan rusak secara permanen dengan membatalkan beberapa fitur API, maka itu harus diperlakukan sebagai tidak dapat dipulihkan. Melihat ujung skala yang lain, Anda memiliki hal-hal seperti kode prototipe. Jika Anda tidak suka ke mana perginya, Anda bisa membuangnya. Sedikit kurang dapat dibalikkan mungkin menggunakan API internal. Mereka dapat di refactored tanpa mengganggu pelanggan,waktu (sumber daya yang paling tidak dapat dipulihkan dari semua!)
Jadi, letakkan ini dalam skala. Sekarang Anda dapat menerapkan heuristik: semakin banyak sesuatu yang dapat dibalik, semakin banyak Anda dapat menggunakannya untuk kegiatan yang tampak di masa depan. Jika sesuatu tidak dapat dipulihkan, gunakan saja untuk tugas-tugas yang digerakkan oleh pelanggan. Inilah sebabnya mengapa Anda melihat prinsip-prinsip seperti itu dari pemrograman ekstrem yang menyarankan hanya melakukan apa yang diminta pelanggan dan tidak lebih. Prinsip-prinsip ini bagus untuk memastikan Anda tidak melakukan sesuatu yang Anda sesali.
Hal-hal seperti prinsip KERING menyarankan cara untuk memindahkan keseimbangan itu. Jika Anda mendapati diri Anda mengulangi sendiri, itu adalah kesempatan untuk membuat apa yang pada dasarnya API internal. Tidak ada pelanggan yang melihatnya, jadi Anda selalu bisa mengubahnya. Setelah Anda memiliki API internal ini, sekarang Anda dapat mulai bermain dengan hal-hal yang tampak ke depan. Menurut Anda, berapa banyak tugas berdasarkan zona waktu yang berbeda yang akan diberikan istri Anda? Apakah Anda memiliki pelanggan lain yang mungkin menginginkan tugas berbasis zona waktu? Fleksibilitas Anda di sini dibeli oleh permintaan konkret dari pelanggan Anda saat ini, dan mendukung permintaan potensial pelanggan di masa depan.
Pendekatan berpikir berlapis ini, yang datang secara alami dari KERING secara alami memberikan generalisasi yang Anda inginkan tanpa limbah. Tetapi apakah ada batasannya? Tentu saja ada. Tetapi untuk melihatnya, Anda harus melihat hutan untuk pepohonan.
Jika Anda memiliki banyak lapisan fleksibilitas, sering menyebabkan kurangnya kontrol langsung terhadap lapisan yang dihadapi pelanggan Anda. Saya memiliki perangkat lunak di mana saya memiliki tugas yang brutal untuk menjelaskan kepada pelanggan mengapa mereka tidak dapat memiliki apa yang mereka inginkan karena fleksibilitas dibangun dalam 10 lapisan ke bawah yang tidak pernah mereka lihat. Kami menulis sendiri ke sudut. Kami mengikat diri kami dengan semua fleksibilitas yang kami pikir kami butuhkan.
Jadi, ketika Anda melakukan trik generalisasi / KERING ini, selalu perhatikan pelanggan Anda . Menurut Anda apa yang akan diminta istri Anda selanjutnya? Apakah Anda menempatkan diri Anda pada posisi untuk memenuhi kebutuhan itu? Jika Anda memiliki bakat, pelanggan akan secara efektif memberi tahu Anda kebutuhan mereka di masa depan. Jika Anda tidak memiliki bakat, well, kebanyakan dari kita hanya mengandalkan dugaan! (terutama dengan pasangan!) Beberapa pelanggan akan menginginkan fleksibilitas yang besar, dan bersedia menerima biaya tambahan dari pengembangan Anda dengan semua lapisan ini karena mereka secara langsung mendapat manfaat dari fleksibilitas lapisan-lapisan itu. Pelanggan lain lebih suka memperbaiki persyaratan yang tidak tergoyahkan, dan mereka lebih suka pengembangan yang lebih langsung. Pelanggan Anda akan memberi tahu Anda berapa banyak fleksibilitas dan berapa banyak lapisan generalisasi yang harus Anda cari.
sumber
Your customer will tell you how much flexibility and how many layers of generalization you should seek.
dunia apa ini?Ini adalah sesuatu yang dikenal di kalangan rekayasa perangkat lunak canggih sebagai "lelucon". Lelucon tidak harus menjadi apa yang kita sebut "benar", walaupun untuk menjadi lucu mereka umumnya harus mengisyaratkan sesuatu yang benar.
Dalam kasus khusus ini, "lelucon" tidak "benar". Pekerjaan yang terlibat dalam penulisan prosedur umum untuk menghancurkan kota mana pun adalah, kita dapat dengan aman berasumsi, urutan besarnya yang diperlukan untuk menghancurkan satu kota tertentukota. Kalau tidak, siapa pun yang telah menghancurkan satu atau beberapa kota (Yosua dalam Alkitab, akan kita katakan, atau Presiden Truman) dapat dengan sepele menggeneralisasi apa yang mereka lakukan dan dapat menghancurkan secara mutlak kota mana pun sesuka hati. Sebenarnya ini bukan masalahnya. Metode yang dua orang terkenal digunakan untuk menghancurkan sejumlah kecil kota tertentu tidak harus bekerja di sembarang kota kapan saja. Kota lain yang temboknya memiliki frekuensi resonansi berbeda atau yang pertahanan udara di ketinggiannya lebih baik, akan membutuhkan perubahan pendekatan kecil atau mendasar (terompet atau roket dengan nada berbeda).
Ini juga mengarah pada pemeliharaan kode terhadap perubahan dari waktu ke waktu: ada banyak kota sekarang yang akan jatuh ke kedua pendekatan tersebut, berkat metode konstruksi modern dan radar di mana-mana.
Mengembangkan dan menguji cara yang sepenuhnya umum yang akan menghancurkan kota mana pun , sebelum Anda setuju untuk menghancurkan hanya satu kota, adalah pendekatan yang sangat tidak efisien. Tidak ada insinyur perangkat lunak yang terlatih secara etis akan mencoba untuk menggeneralisasi masalah sampai taraf yang membutuhkan pesanan lebih besar daripada yang harus dibayar oleh majikan / klien mereka, tanpa persyaratan yang diperlihatkan.
Jadi apa yang benar? Terkadang menambahkan generalitas itu sepele. Haruskah kita selalu menambahkan generalitas ketika itu sepele untuk melakukannya? Saya masih akan berdebat "tidak, tidak selalu", karena masalah pemeliharaan jangka panjang. Misalkan pada saat penulisan, semua kota pada dasarnya sama, jadi saya melanjutkan dengan DestroyCity. Setelah saya menulis ini, bersama dengan tes integrasi yang (karena ruang input yang tak terhitung jumlahnya) iterate atas setiap kota yang dikenal dan pastikan fungsi bekerja pada masing-masing (tidak yakin bagaimana itu bekerja. Mungkin panggilan City.clone () dan menghancurkan klon?
Dalam prakteknya fungsi ini digunakan hanya untuk menghancurkan Baghdad, misalkan seseorang membangun kota baru yang tahan terhadap teknik saya (itu jauh di bawah tanah atau sesuatu). Sekarang saya memiliki kegagalan pengujian integrasi untuk kasus penggunaan yang bahkan tidak benar-benar ada , dan sebelum saya dapat melanjutkan kampanye teror saya terhadap warga sipil Irak yang tidak bersalah, saya harus mencari cara untuk menghancurkan Subterrania. Tidak peduli apakah ini etis atau tidak, itu bodoh dan buang-buang waktu saja .
Jadi, apakah Anda benar-benar menginginkan fungsi yang dapat menghasilkan penghematan siang hari untuk setiap tahun, hanya untuk menghasilkan data untuk 2018? Mungkin, tetapi tentu saja akan membutuhkan sedikit usaha ekstra hanya dengan menyusun kasus uji. Mungkin membutuhkan banyak upaya untuk mendapatkan basis data zona waktu yang lebih baik daripada yang Anda miliki. Jadi misalnya pada tahun 1908, kota Port Arthur, Ontario memiliki periode DST dimulai pada tanggal 1 Juli. Apakah itu di basis data zona waktu OS Anda? Saya kira tidak, jadi fungsi umum Anda salah . Tidak ada yang etis tentang penulisan kode yang membuat janji tidak bisa ditepati.
Baiklah, jadi, dengan peringatan yang sesuai, mudah untuk menulis fungsi yang melakukan zona waktu selama bertahun-tahun, katakan tahun 1970-sekarang. Tapi itu sama mudahnya untuk mengambil fungsi yang sebenarnya Anda tulis, dan menggeneralisasikannya untuk parameterisasi tahun. Jadi tidak benar-benar lebih etis / masuk akal untuk menggeneralisasi sekarang, bahwa itu adalah untuk melakukan apa yang Anda lakukan dan kemudian menggeneralisasi jika dan ketika Anda membutuhkannya.
Namun, jika Anda tahu mengapa istri Anda ingin memeriksa daftar DST ini, maka Anda akan memiliki pendapat tentang apakah dia kemungkinan akan mengajukan pertanyaan yang sama lagi di tahun 2019 dan, jika demikian, apakah Anda dapat keluar dari lingkaran itu dengan memberikan dia fungsi yang bisa dia panggil, tanpa perlu mengkompilasi ulang. Setelah Anda melakukan analisis itu, jawaban untuk pertanyaan "haruskah ini digeneralisasikan ke tahun-tahun terakhir" mungkin "ya". Tetapi Anda menciptakan masalah lain untuk diri Anda sendiri, yaitu bahwa data zona waktu di masa depan hanya bersifat sementara, dan karena itu jika dia menjalankannya untuk 2019 hari ini, Dia mungkin atau mungkin tidak menyadari bahwa itu memberinya tebakan terbaik. Jadi Anda masih harus menulis banyak dokumentasi yang tidak diperlukan untuk fungsi yang kurang umum ("data berasal dari basis data zona waktu bla bla inilah tautan untuk melihat kebijakan mereka dalam mendorong pembaruan bla bla"). Jika Anda menolak kasus khusus, maka sepanjang waktu Anda melakukan itu, dia tidak bisa melanjutkan tugas yang dia butuhkan data 2018, karena omong kosong tentang 2019 dia bahkan belum peduli.
Jangan melakukan hal-hal sulit tanpa memikirkannya dengan baik, hanya karena lelucon yang menyuruh Anda melakukannya. Apakah itu berguna? Apakah cukup murah untuk kegunaan seperti itu?
sumber
Ini adalah garis yang mudah untuk menggambar karena kegunaan kembali sebagaimana didefinisikan oleh astronot arsitektur adalah bollocks.
Hampir semua kode yang dibuat oleh pengembang aplikasi sangat spesifik untuk domain. Ini bukan tahun 1980. Hampir semua hal yang layak repot sudah dalam kerangka.
Abstraksi dan konvensi membutuhkan dokumentasi dan upaya pembelajaran. Mohon berhenti membuat yang baru hanya demi itu. (Saya melihat Anda , orang JavaScript!)
Mari kita menikmati fantasi yang tidak masuk akal bahwa Anda telah menemukan sesuatu yang benar-benar harus ada dalam kerangka pilihan Anda. Anda tidak bisa hanya menggedor kode seperti yang biasa Anda lakukan. Oh tidak, Anda memerlukan cakupan pengujian tidak hanya untuk penggunaan yang dimaksudkan tetapi juga untuk keberangkatan dari penggunaan yang dimaksudkan, untuk semua kasus tepi yang diketahui, untuk semua mode kegagalan yang dapat dibayangkan, uji kasus untuk diagnostik, data uji, dokumentasi teknis, dokumentasi pengguna, dokumentasi rilis, manajemen rilis, dukungan skrip, tes regresi, manajemen perubahan ...
Apakah majikan Anda senang membayar semua itu? Saya akan mengatakan tidak.
Abstraksi adalah harga yang kami bayar untuk fleksibilitas. Itu membuat kode kita lebih kompleks dan lebih sulit untuk dipahami. Kecuali jika fleksibilitas melayani kebutuhan nyata dan saat ini, hanya saja tidak, karena YAGNI.
Mari kita lihat contoh dunia nyata yang harus saya tangani: HTMLRenderer. Itu tidak scaling dengan benar ketika saya mencoba membuat konteks perangkat printer. Butuh waktu seharian untuk menemukan bahwa secara default menggunakan GDI (yang tidak skala) daripada GDI + (yang tidak, tetapi tidak antialias) karena saya harus mengarungi enam tingkat tipuan dalam dua majelis sebelum saya menemukan kode yang melakukan apa saja .
Dalam hal ini saya akan memaafkan penulis. Abstraksi sebenarnya diperlukan karena ini adalah kode kerangka kerja yang menargetkan lima target render yang sangat berbeda: WinForms, WPF, dotnet Core, Mono dan PdfSharp.
Tapi itu hanya menggarisbawahi poin saya: Anda hampir pasti tidak melakukan sesuatu yang sangat kompleks (rendering HTML dengan stylesheet) menargetkan beberapa platform dengan tujuan kinerja tinggi pada semua platform.
Kode Anda hampir pasti merupakan kisi-kisi basis data lain dengan aturan bisnis yang hanya berlaku untuk perusahaan Anda dan aturan pajak yang hanya berlaku di negara Anda, dalam aplikasi yang tidak untuk dijual.
Semua tipuan itu memecahkan masalah yang tidak Anda miliki dan membuat kode Anda lebih sulit dibaca, yang secara besar-besaran meningkatkan biaya pemeliharaan dan merupakan kerugian besar bagi majikan Anda. Untungnya orang-orang yang seharusnya mengeluh tentang ini tidak dapat memahami apa yang Anda lakukan pada mereka.
Argumen tandingannya adalah bahwa abstraksi semacam ini mendukung pengembangan yang digerakkan oleh pengujian, tetapi saya pikir TDD juga mengecewakan, karena mengandaikan bahwa bisnis memiliki pemahaman yang jelas, lengkap dan benar mengenai persyaratannya. TDD bagus untuk NASA dan mengendalikan perangkat lunak untuk peralatan medis dan mobil self-driving, tetapi terlalu mahal untuk semua orang.
Secara kebetulan, tidak mungkin untuk memprediksi semua penghematan siang hari di dunia. Israel khususnya memiliki sekitar 40 transisi setiap tahun yang melompati semua tempat karena kita tidak bisa membuat orang berdoa pada waktu yang salah dan Tuhan tidak melakukan penghematan siang hari.
sumber
Jika Anda menggunakan setidaknya java 8, Anda akan menulis kelas WorldTimeZones untuk memberikan apa yang pada dasarnya tampak sebagai kumpulan zona waktu.
Kemudian tambahkan metode filter (Predicate filter) ke kelas WorldTimeZones. Ini memberikan kemampuan bagi penelepon untuk memfilter apa pun yang mereka inginkan dengan melewatkan ekspresi lambda sebagai parameter.
Pada dasarnya, metode filter tunggal mendukung pemfilteran pada apa pun yang terkandung dalam nilai yang diteruskan ke predikat.
Sebagai alternatif, tambahkan metode stream () ke kelas WorldTimeZones Anda yang menghasilkan aliran zona waktu saat dipanggil. Kemudian penelepon dapat memfilter, memetakan dan mengurangi sesuai keinginan tanpa Anda menulis spesialisasi sama sekali.
sumber