Kode bersih: konsekuensi dari metode pendek dengan beberapa parameter


15

Baru-baru ini selama tinjauan kode saya menemukan kode, ditulis oleh seorang rekan baru, yang berisi pola dengan bau. Saya menduga bahwa keputusan kolega saya didasarkan pada aturan yang diusulkan oleh buku Kode Bersih yang terkenal (dan mungkin juga oleh buku-buku serupa lainnya).

Ini adalah pemahaman saya bahwa konstruktor kelas sepenuhnya bertanggung jawab atas pembuatan objek yang valid dan bahwa tugas utamanya adalah penugasan properti (pribadi) objek. Tentu saja dapat terjadi bahwa nilai properti opsional dapat ditetapkan dengan metode selain konstruktor kelas, tetapi situasi seperti itu agak jarang terjadi (walaupun tidak selalu salah, asalkan seluruh kelas mempertimbangkan sifat opsional properti tersebut). Ini penting, karena memungkinkan untuk memastikan bahwa objek selalu dalam keadaan valid.

Namun, dalam kode yang saya temui, sebagian besar nilai properti sebenarnya ditentukan oleh metode lain selain konstruktor. Nilai yang dihasilkan dari perhitungan ditugaskan ke properti yang akan digunakan dalam beberapa metode pribadi di seluruh kelas. Penulis tampaknya menggunakan properti kelas seolah-olah mereka adalah variabel global yang harus dapat diakses di seluruh kelas, alih-alih parameterisasi nilai-nilai ini ke fungsi yang membutuhkannya. Selain itu, metode kelas harus dipanggil dalam urutan tertentu, karena kelas tidak akan berbuat banyak sebaliknya.

Saya menduga bahwa kode ini telah terinspirasi oleh saran untuk menjaga metode tetap pendek (<= 5 baris kode), untuk menghindari daftar parameter besar (<3 parameter) dan bahwa konstruktor tidak boleh melakukan pekerjaan (seperti melakukan perhitungan semacam yang penting untuk validitas objek).

Sekarang tentu saja saya bisa membuat kasus terhadap pola ini jika saya bisa membuktikan bahwa semua jenis kesalahan yang tidak terdefinisi berpotensi muncul ketika metode tidak dipanggil dalam urutan tertentu. Namun, saya memperkirakan bahwa respons terhadap hal ini adalah menambahkan validasi yang memverifikasi bahwa properti harus disetel begitu metode dipanggil yang membutuhkan properti tersebut diatur.

Namun saya lebih suka mengusulkan untuk sepenuhnya mengubah kode, sehingga kelas menjadi cetak biru menjadi objek aktual, daripada serangkaian metode yang harus dipanggil (secara prosedural) dalam urutan tertentu.

Saya merasa bahwa kode yang saya temukan berbau. Bahkan, saya percaya ada perbedaan yang agak jelas tentang kapan harus menyimpan nilai di properti kelas dan kapan memasukkannya ke dalam parameter untuk metode yang berbeda untuk digunakan - Saya tidak benar-benar percaya mereka bisa menjadi alternatif satu sama lain . Saya mencari kata-kata untuk perbedaan ini.


6
1. Bermain advokat iblis untuk sesaat ... Apakah kode itu benar-benar berfungsi? Karena Objek Transfer Data adalah teknik yang benar-benar valid, dan jika hanya itu ...
Robert Harvey

7
2. Jika Anda tidak memiliki kata-kata untuk menggambarkan masalah, maka Anda tidak memiliki cukup pengalaman untuk membantah posisi rekan Anda.
Robert Harvey

4
3. Jika Anda memiliki beberapa kode kerja yang dapat Anda poskan, poskan ke Peninjauan Kode, dan biarkan mereka melihatnya. Kalau tidak, ini hanyalah generalisasi yang mengembara.
Robert Harvey

5
@RobertHarvey "Nilai yang dihasilkan dari perhitungan ditugaskan ke properti yang akan digunakan di dalam beberapa metode pribadi di seluruh kelas" tidak terdengar seperti DTO harga diri bagi saya. Saya setuju bahwa sedikit lebih spesifik akan membantu.
topo Reinstate Monica

4
Selain itu: Kedengarannya seperti seseorang belum benar-benar membaca Kode Bersih sebelum memukulnya. Saya hanya memindainya lagi, dan tidak dapat menemukan tempat di mana ia menyarankan "konstruktor seharusnya tidak bekerja" (beberapa contoh sebenarnya melakukan pekerjaan), dan solusi yang disarankan untuk menghindari terlalu banyak parameter adalah membuat objek parameter yang dikonsolidasikan terkait grup parameter, jangan bastardkan fungsi Anda. Dan buku ini memang menyarankan kode refactoring untuk menghindari ketergantungan temporal antara metode. Saya pikir bias Anda terhadap beberapa gaya kode pilihannya telah mewarnai persepsi Anda tentang buku itu.
Eric King

Jawaban:


13

Sebagai seseorang yang telah membaca Kode Bersih dan menonton seri Clean Coders, berkali-kali, dan sering mengajar dan melatih orang lain dalam menulis kode pembersih, saya memang dapat memastikan bahwa pengamatan Anda benar - metrik yang Anda tunjukkan semuanya disebutkan dalam buku .

Namun, buku ini terus membuat poin lain yang juga harus diterapkan di samping pedoman yang Anda tunjukkan. Ini tampaknya diabaikan dalam kode yang Anda hadapi. Ini mungkin terjadi karena kolega Anda masih dalam tahap belajar, dalam hal ini, sebanyak yang diperlukan untuk menunjukkan bau kode mereka, ada baiknya untuk diingat bahwa mereka melakukannya dengan niat baik, belajar dan mencoba untuk menulis kode yang lebih baik.

Clean Code mengusulkan bahwa metode harus pendek, dengan sesedikit mungkin argumen. Tetapi di sepanjang pedoman itu, disarankan agar kita harus mengikuti prinsip-prinsip S OLID, meningkatkan kohesi dan mengurangi sambungan .

The S di tribun SOLID untuk Tanggung Jawab Single Prinsip, yang menyatakan bahwa sebuah objek harus bertanggung jawab untuk satu hal. "Hal" bukanlah istilah yang sangat tepat, sehingga deskripsi dari prinsip ini sangat bervariasi. Namun, Paman Bob, penulis Clean Code, juga adalah orang yang menciptakan prinsip ini, menggambarkannya sebagai: "Kumpulkan bersama hal-hal yang berubah karena alasan yang sama. Pisahkan hal-hal yang berubah karena alasan berbeda." Dia melanjutkan dengan mengatakan apa yang dia maksud dengan alasan untuk berubah di sini dan di sini(penjelasan yang lebih lama di sini akan terlalu banyak). Jika prinsip ini diterapkan pada kelas yang Anda hadapi, sangat mungkin bahwa potongan-potongan yang berurusan dengan perhitungan akan dipisahkan dari yang berhubungan dengan holding state, dengan membagi kelas menjadi dua atau lebih, tergantung pada berapa banyak alasan untuk mengubah perhitungan tersebut miliki.

Juga, kelas-kelas Clean haruslah kohesif , artinya sebagian besar metodenya menggunakan sebagian besar atributnya. Dengan demikian, kelas kohesif maksimal adalah kelas di mana semua metode menggunakan semua atributnya; sebagai contoh, dalam aplikasi grafis Anda mungkin memiliki Vectorkelas dengan atribut Point adan Point b, di mana satu-satunya metode yang scaleBy(double factor)dan printTo(Canvas canvas), baik operasi pada kedua atribut. Sebaliknya, kelas kohesif minimal adalah satu di mana setiap atribut digunakan dalam satu metode saja, dan tidak pernah lebih dari satu atribut digunakan oleh masing-masing metode. Secara rata-rata, sebuah kelas menyajikan "kelompok" non-kohesif bagian kohesif - yaitu beberapa metode menggunakan atribut a, bdan c, sementara sisanya menggunakan cdand - artinya jika kita membagi kelas menjadi dua, kita berakhir dengan dua objek kohesif.

Akhirnya, kelas Bersih harus mengurangi kopling sebanyak mungkin. Meskipun ada banyak jenis sambungan yang perlu dibahas di sini, tampaknya kode yang ada sebagian besar menderita kopling sementara , di mana, seperti yang Anda tunjukkan, metode objek hanya akan berfungsi seperti yang diharapkan ketika mereka dipanggil dalam urutan yang benar. Dan seperti dua pedoman yang disebutkan di atas, solusi untuk ini biasanya melibatkan pemisahan kelas menjadi dua atau lebih, objek kohesif . Strategi pemisahan dalam kasus ini biasanya melibatkan pola seperti Builder atau Factory, dan dalam kasus yang sangat kompleks, State-Machines.

TL; DR: Pedoman Kode Bersih yang diikuti kolega Anda baik, tetapi hanya jika juga mengikuti prinsip, praktik, dan pola yang tersisa yang disebutkan oleh buku. The Clean versi "kelas" Anda melihat akan dibagi menjadi beberapa kelas, masing-masing dengan tanggung jawab tunggal, metode kohesif dan tidak ada kopling temporal. Ini adalah konteks di mana metode-metode kecil dan argumen yang tidak ada artinya masuk akal.


1
Anda dan topo morto telah menulis jawaban yang baik, tetapi saya hanya dapat menerimanya. Saya suka bahwa Anda membahas SRP, kekompakan dan kopling. Ini adalah istilah berguna yang dapat saya gunakan dalam ulasan kode. Memisahkan objek menjadi objek yang lebih kecil dengan tanggung jawab mereka sendiri jelas merupakan cara yang harus dilakukan. Salah satu (non-konstruktor) metode yang menginisialisasi nilai ke sekelompok properti kelas adalah hadiah mati bahwa objek baru harus dikembalikan. Saya seharusnya melihat itu.
user2180613

1
SRP adalah pedoman terpenting; satu cincin untuk menguasai mereka semua dan semua itu. SRP yang dilakukan dengan baik secara alami menghasilkan metode yang lebih pendek. Contoh: Saya memiliki kelas yang menghadap ke depan dengan hanya 2 publik dan sekitar 8 metode non-publik. Tidak ada yang lebih dari ~ 3 baris; seluruh kelas adalah sekitar 35 LOC. Tapi saya menulis kelas ini terakhir! Pada saat semua kode yang mendasarinya ditulis, kelas ini pada dasarnya menulis sendiri dan saya tidak perlu, memang tidak bisa, membuat metode lebih besar. Tidak pernah saya katakan, "Saya akan menulis metode ini dalam 5 baris jika itu membunuh saya." Setiap kali Anda menerapkan SRP, itu terjadi begitu saja.
radarbob

11

Ini adalah pemahaman saya bahwa konstruktor kelas sepenuhnya bertanggung jawab atas pembuatan objek yang valid dan bahwa tugas utamanya adalah penugasan properti (pribadi) objek.

Ini biasanya bertanggung jawab untuk menempatkan objek ke dalam keadaan awal yang valid, ya; properti atau metode lain kemudian dapat mengubah negara ke negara lain yang valid.

Namun, dalam kode yang saya temui, sebagian besar nilai properti sebenarnya ditentukan oleh metode lain selain konstruktor. Nilai yang dihasilkan dari perhitungan ditugaskan ke properti yang akan digunakan dalam beberapa metode pribadi di seluruh kelas. Penulis tampaknya menggunakan properti kelas seolah-olah mereka adalah variabel global yang harus dapat diakses di seluruh kelas, alih-alih parameterisasi nilai-nilai ini ke fungsi yang membutuhkannya. Selain itu, metode kelas harus dipanggil dalam urutan tertentu, karena kelas tidak akan berbuat banyak sebaliknya.

Serta masalah dengan keterbacaan dan pemeliharaan yang Anda singgung, sepertinya ada beberapa tahap aliran data / transformasi yang terjadi di dalam kelas itu sendiri, yang dapat menunjukkan bahwa kelas tersebut melanggar prinsip tanggung jawab tunggal.

menduga bahwa kode ini telah terinspirasi oleh saran untuk menjaga metode tetap pendek (<= 5 baris kode), untuk menghindari daftar parameter besar (<3 parameter) dan bahwa konstruktor tidak boleh melakukan pekerjaan (seperti melakukan perhitungan semacam itu yang sangat penting untuk validitas objek).

Mengikuti beberapa pedoman pengkodean sementara mengabaikan yang lain sering menyebabkan kode konyol. Jika kita ingin menghindari seorang konstruktor melakukan pekerjaan, misalnya, cara yang masuk akal biasanya adalah melakukan pekerjaan sebelum konstruksi dan meneruskan hasil pekerjaan itu ke konstruktor. (Satu argumen untuk pendekatan itu mungkin adalah bahwa Anda menghindari memberi kelas Anda dua tanggung jawab: pekerjaan inisialisasi, dan 'pekerjaan utamanya', apa pun itu.)

Dalam pengalaman saya, membuat kelas dan metode menjadi kecil jarang merupakan sesuatu yang harus saya ingat sebagai pertimbangan terpisah - lebih tepatnya, itu mengikuti secara alami dari tanggung jawab tunggal.

Namun saya lebih suka mengusulkan untuk sepenuhnya mengubah kode, sehingga kelas menjadi cetak biru menjadi objek aktual, daripada serangkaian metode yang harus dipanggil (secara prosedural) dalam urutan tertentu.

Anda mungkin benar untuk melakukannya. Tidak ada yang salah dengan menulis kode prosedur langsung; ada masalah dalam menyalahgunakan paradigma OO untuk menulis kode prosedural yang membingungkan.

Saya percaya ada perbedaan yang agak jelas tentang kapan harus menyimpan nilai dalam properti kelas dan kapan memasukkannya ke dalam parameter untuk metode yang berbeda untuk digunakan - Saya tidak benar-benar percaya mereka bisa menjadi alternatif satu sama lain. Saya mencari kata-kata untuk perbedaan ini.

Biasanya , Anda seharusnya tidak meletakkan nilai dalam bidang sebagai cara meneruskannya dari satu metode ke metode lainnya; nilai dalam bidang harus menjadi bagian yang bermakna dari keadaan suatu objek pada waktu tertentu. (Saya dapat memikirkan beberapa pengecualian yang valid, tetapi bukan yang metodenya bersifat publik atau di mana ada ketergantungan pesanan yang harus diketahui oleh pengguna kelas)


2
upvote karena: 1. Menekankan SRP. "... metode kecil ... ikuti secara alami" 2. Tujuan konstruktor - keadaan valid. 3. "Mengikuti beberapa pedoman pengkodean sementara mengabaikan yang lain." Ini adalah Walking Dead dari coding.
radarbob

6

Anda kemungkinan besar mencerca pola yang salah di sini. Fungsi kecil dan arity rendah jarang bermasalah sendiri. Masalah sebenarnya di sini adalah kopling yang menyebabkan ketergantungan urutan antara fungsi, jadi cari cara untuk mengatasinya tanpa membuang manfaat dari fungsi kecil.

Kode berbicara lebih keras daripada kata-kata. Orang-orang menerima koreksi semacam ini jauh lebih baik jika Anda benar-benar dapat melakukan bagian dari refactoring dan menunjukkan peningkatan, mungkin sebagai latihan pemrograman pasangan. Ketika saya melakukan ini, saya sering merasa lebih sulit daripada yang saya kira untuk mendapatkan desain yang benar, menyeimbangkan semua kriteria.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.