Sebagai seorang programmer, saya menemukan diri saya dalam dilema di mana saya ingin membuat program saya sebagai abstrak dan umum mungkin.
Melakukan hal itu biasanya akan memungkinkan saya untuk menggunakan kembali kode saya dan memiliki solusi yang lebih umum untuk masalah yang mungkin (atau mungkin tidak) muncul lagi.
Lalu suara ini di kepalaku berkata, pecahkan saja masalah dummy-nya semudah itu! Mengapa menghabiskan lebih banyak waktu dari yang seharusnya?
Kita semua memang menghadapi pertanyaan ini di mana Abstraksi ada di bahu kanan Anda dan Solve-it-bodoh duduk di sebelah kiri.
Yang harus didengarkan dan seberapa sering? Apa strategi Anda untuk ini? Haruskah Anda abstrak semuanya?
time-management
problem-solving
abstraction
Bryan Harrington
sumber
sumber
Jawaban:
Jangan pernah abstrak sampai Anda harus.
Di Java, misalnya, Anda harus menggunakan antarmuka. Mereka adalah abstraksi.
Dalam Python Anda tidak memiliki antarmuka, Anda memiliki Bebek Mengetik, dan Anda tidak perlu tingkat abstraksi yang tinggi. Jadi kamu tidak.
Jangan abstrak sampai Anda sudah menulisnya tiga kali.
Sekali - baik - sekali. Pecahkan saja dan lanjutkan.
Dua kali adalah indikasi bahwa mungkin ada pola di sini. Atau mungkin tidak. Itu bisa saja kebetulan.
Tiga kali adalah awal dari suatu pola. Sekarang itu melampaui kebetulan. Sekarang Anda dapat abstrak.
Tidak.
Memang, Anda tidak boleh mengabstraksikan apa pun sampai Anda memiliki bukti absolut bahwa Anda melakukan abstraksi yang tepat. Tanpa "Aturan Tiga Pengulangan", Anda akan menulis hal-hal yang tidak berguna yang diabstraksikan dengan cara yang tidak membantu.
Ini adalah asumsi yang sering salah. Abstraksi mungkin tidak membantu sama sekali. Itu bisa dilakukan dengan buruk. Karena itu, jangan lakukan itu sampai Anda harus.
sumber
Ah, YAGNI. Konsep pemrograman yang paling disalahgunakan.
Ada perbedaan antara membuat kode Anda generik dan melakukan pekerjaan ekstra. Haruskah Anda menghabiskan waktu ekstra untuk membuat kode Anda digabungkan secara longgar dan mudah diadaptasi untuk melakukan hal-hal lain? Benar. Haruskah Anda menghabiskan waktu mengimplementasikan fungsi yang tidak dibutuhkan? Tidak. Haruskah Anda menghabiskan waktu agar kode Anda berfungsi dengan kode lain yang belum diimplikasikan? Tidak.
Seperti kata pepatah "Lakukan hal paling sederhana yang mungkin bisa berhasil". Masalahnya adalah bahwa orang selalu bingung sederhana dengan mudah . Kesederhanaan butuh kerja. Tapi itu sepadan dengan usaha.
Bisakah Anda berlebihan? Tentu saja. Tetapi pengalaman saya adalah bahwa beberapa perusahaan membutuhkan lebih banyak sikap "menyelesaikannya sekarang" daripada yang sudah mereka miliki. Sebagian besar perusahaan membutuhkan lebih banyak orang yang akan memikirkan segalanya terlebih dahulu. Kalau tidak, mereka selalu berakhir dengan masalah mandiri di mana tidak ada yang punya waktu untuk apa pun, semua orang selalu terburu-buru, dan tidak ada yang menyelesaikan sesuatu.
Pikirkan seperti ini: kemungkinan bagus bahwa kode Anda akan digunakan lagi entah bagaimana. Tapi Anda tidak akan memprediksi dengan benar seperti itu. Jadi buat kode Anda bersih, abstrak, dan digabungkan secara longgar. Tapi jangan coba-coba membuat kode Anda berfungsi dengan fungsionalitas spesifik apa pun yang belum ada. Bahkan jika Anda tahu itu akan ada di masa depan.
sumber
simple
daneasy
!Silogisme:
Generalitas itu mahal.
Anda menghabiskan uang orang lain.
Karena itu biaya generalisasi harus dibenarkan kepada para pemangku kepentingan.
Tanyakan pada diri Anda apakah Anda benar - benar menyelesaikan masalah yang lebih umum untuk menghemat uang para pemangku kepentingan nanti, atau jika Anda hanya menemukan itu tantangan intelektual untuk membuat solusi umum yang tidak perlu.
Jika sifat umum ditentukan untuk diinginkan maka harus dirancang dan diuji seperti fitur lainnya . Jika Anda tidak dapat menulis tes yang menunjukkan bagaimana generalitas yang Anda terapkan menyelesaikan masalah yang diperlukan oleh spesifikasi maka jangan repot-repot melakukannya! Fitur yang tidak memenuhi kriteria desain dan tidak dapat diuji adalah fitur yang tidak dapat diandalkan oleh siapa pun.
Dan akhirnya, tidak ada yang namanya "seumum mungkin". Misalkan Anda menulis perangkat lunak dalam C #, hanya demi argumen. Apakah Anda akan membuat setiap kelas mengimplementasikan antarmuka? Setiap kelas kelas dasar abstrak dengan setiap metode metode abstrak? Itu cukup umum, tetapi tidak ada yang mendekati "seumum mungkin". Itu hanya memungkinkan orang untuk mengubah implementasi metode apa pun melalui subclassing. Bagaimana jika mereka ingin mengubah implementasi metode tanpa subklas? Anda bisa membuat setiap metode sebenarnya properti tipe delegasi, dengan setter sehingga orang bisa mengubah setiap metode menjadi sesuatu yang lain. Tetapi bagaimana jika seseorang ingin menambahkan lebih banyak metode? Sekarang setiap objek harus diperluas.
Pada titik ini Anda harus meninggalkan C # dan merangkul JavaScript. Tetapi Anda masih belum mendekati cukup umum; bagaimana jika seseorang ingin mengubah cara pencarian anggota bekerja untuk objek khusus ini? Mungkin Anda harus menulis semuanya dengan Python.
Meningkatnya generalitas seringkali berarti mengabaikan prediktabilitas dan meningkatkan biaya pengujian secara besar-besaran untuk memastikan bahwa generalisasi yang diterapkan benar-benar berhasil dalam memenuhi kebutuhan pengguna yang sebenarnya . Apakah biaya-biaya itu dibenarkan dengan manfaatnya bagi para pemangku kepentingan yang membayarnya? Mungkin mereka; terserah Anda untuk berdiskusi dengan para pemangku kepentingan. Stakeholder saya sama sekali tidak bersedia bagi saya untuk meninggalkan pengetikan statis dalam mengejar tingkat generalisasi yang sama sekali tidak perlu dan sangat mahal, tetapi mungkin milik Anda.
sumber
Hanya untuk memperjelas, membuat sesuatu digeneralisasi dan mengimplementasikan abstraksi adalah dua hal yang sepenuhnya berbeda.
Misalnya, pertimbangkan fungsi yang menyalin memori.
Fungsi ini adalah abstraksi yang menyembunyikan bagaimana 4 byte disalin.
int copy4Bytes (char * pSrc, char * pDest)
Generalisasi akan membuat fungsi ini menyalin sejumlah byte.
int copyBytes (char * pSrc, char * pDest, int numBytesToCopy)
Abstraksi cenderung digunakan kembali, sedangkan generalisasi hanya membuat abstraksi berguna dalam lebih banyak kasus.
Lebih khusus terkait dengan pertanyaan Anda, Abstraksi tidak hanya berguna dari perspektif penggunaan kembali kode. Seringkali jika dilakukan dengan benar akan membuat kode Anda lebih mudah dibaca dan dipelihara. Dengan menggunakan contoh di atas, apa yang lebih mudah dibaca dan dipahami jika Anda membaca sekilas kode copyBytes () atau loop untuk iterasi melalui array yang memindahkan data satu indeks pada suatu waktu? Abstraksi dapat memberikan semacam dokumentasi mandiri yang menurut saya membuat kode lebih mudah untuk dikerjakan.
Sebagai aturan praktis saya sendiri, jika saya bisa menghasilkan nama fungsi yang bagus yang menggambarkan dengan tepat apa yang saya ingin lakukan, maka saya menulis sebuah fungsi untuk itu terlepas dari apakah saya pikir saya akan menggunakannya lagi atau tidak.
sumber
Aturan umum yang baik untuk hal semacam ini adalah Zero, One, Infinity. Artinya, jika Anda membutuhkan apa yang Anda tulis lebih dari sekali, Anda dapat menganggap Anda akan membutuhkannya lebih banyak dan menggeneralisasi. Aturan ini menyiratkan bahwa Anda tidak repot-repot dengan abstraksi saat pertama kali Anda menulis sesuatu.
Alasan bagus lainnya untuk aturan ini adalah bahwa saat pertama kali Anda menulis kode, Anda tidak perlu tahu apa yang harus diabstraksi karena Anda hanya memiliki satu contoh. Hukum Murphy menyiratkan bahwa jika Anda menulis kode abstrak pertama kali, contoh kedua akan memiliki perbedaan yang tidak Anda antisipasi.
sumber
Eric Lippert menunjukkan tiga hal yang menurut saya berlaku dalam artikelnya di masa depan yang membuktikan sebuah desain . Saya pikir jika Anda mengikutinya Anda akan berada dalam kondisi yang baik.
sumber
Itu tergantung pada mengapa Anda mengkode, tujuan dari proyek Anda. Jika nilai kode Anda adalah yang memecahkan masalah nyata, maka keinginan Anda menyelesaikannya dan beralih ke masalah berikutnya. Jika ada hal-hal cepat dan mudah yang dapat Anda lakukan untuk membuat segalanya lebih mudah bagi pengguna kode masa depan (termasuk diri Anda sendiri) maka dengan segala cara, buatlah akomodasi yang masuk akal.
Di sisi lain, ada beberapa kasus di mana kode yang Anda tulis memiliki tujuan yang lebih umum. Misalnya, ketika Anda menulis perpustakaan untuk programmer lain, yang akan menggunakannya dalam berbagai aplikasi. Calon pengguna tidak diketahui dan Anda tidak bisa menanyakan apa yang mereka inginkan. Tetapi Anda ingin menjadikan perpustakaan Anda bermanfaat secara luas. Dalam kasus seperti itu, saya akan menghabiskan lebih banyak waktu untuk mencoba mendukung solusi umum.
sumber
Saya penggemar berat prinsip KISS.
Saya fokus pada memberikan apa yang saya diminta untuk lakukan, dan bukan pada apa solusi terbaik. Saya harus melepaskan perfeksionisme (dan OCD), karena itu membuat saya sengsara.
sumber
Saya tidak setuju dengan "selesaikan itu bodoh" , saya pikir itu bisa lebih "selesaikan itu pintar" .
Apa yang lebih pintar:
Pilihan default harus yang kedua. Kecuali Anda dapat menunjukkan perlunya generasi.
Solusi umum harus hanya ketika Anda tahu bahwa itu adalah sesuatu yang akan digunakan dalam berbagai proyek / kasus.
Biasanya saya menemukan solusi umum yang terbaik dilayani sebagai "Core Library Code"
sumber