Interpretasi prinsip KERING


10

Saat ini saya sedang berjuang dengan konsep KERING ini (Jangan Ulangi Diri Sendiri) dalam pengkodean saya. Saya membuat fungsi ini di mana saya khawatir ini menjadi terlalu rumit tetapi saya mencoba untuk mengikuti prinsip KERING.

createTrajectoryFromPoint(A a,B b,C c,boolean doesSomething,boolean doesSomething2)

Fungsi ini saya katakan membutuhkan 3 parameter input, dan kemudian fungsi akan melakukan sesuatu yang sedikit berbeda mengingat kombinasi boolean doesSomethingdan doesSomething2. Namun masalah yang saya alami adalah bahwa fungsi ini tumbuh dalam kompleksitas sangat dengan setiap parameter boolean baru yang ditambahkan.

Jadi pertanyaan saya adalah, apakah lebih baik untuk memiliki banyak fungsi yang berbeda yang memiliki banyak logika yang sama (karena itu melanggar prinsip KERING) atau satu fungsi yang berperilaku sedikit berbeda diberikan sejumlah parameter tetapi membuatnya jauh lebih kompleks (tetapi melestarikan KERING)?


3
Dapatkah logika bersama / umum difaktorkan ke dalam fungsi pribadi yang oleh createTrajectory...semua fungsi publik disebut?
FrustratedWithFormsDesigner

Itu bisa saja tetapi fungsi-fungsi pribadi itu masih perlu untuk mendapatkan parameter boolean
Albinoswordfish

2
Saya pikir ini akan / akan jauh lebih mudah untuk dijawab dengan memberikan semacam contoh nyata. Reaksi langsung saya adalah bahwa dikotomi yang Anda gambarkan tidak sepenuhnya nyata - yaitu, itu bukan satu-satunya dua pilihan. Sebagai tambahan, saya akan mempertimbangkan penggunaan booleanparameter sebagai agak mencurigakan.
Jerry Coffin


Eh, mengapa Anda tidak memfaktorkan hal-hal bersyarat ke dalam fungsinya sendiri?
Rig

Jawaban:


19

argumen boolean untuk memicu jalur kode yang berbeda dalam satu fungsi / metode adalah bau kode yang mengerikan .

Apa yang Anda lakukan melanggar prinsip Longgar Coupling dan Kohesi Tinggi dan Tanggung Jawab Tunggal , yang jauh lebih penting daripada KERING diutamakan.

Itu berarti bahwa segala sesuatu harus bergantung pada hal-hal lain hanya ketika mereka harus ( Kopling ) dan bahwa mereka harus melakukan satu hal dan hanya satu hal (sangat baik) ( Kohesi ).

Dengan kelalaian Anda sendiri, ini terlalu erat digabungkan (semua bendera boolean adalah jenis ketergantungan negara, yang merupakan salah satu yang terburuk!) Dan memiliki terlalu banyak tanggung jawab individu yang saling terkait (terlalu rumit).

Apa yang Anda lakukan tidak dalam semangat KERING pula. KERING lebih tentang pengulangan ( Rkepanjangan dari REPEAT). Menghindari menyalin dan menempel adalah bentuk paling dasar. Apa yang Anda lakukan tidak terkait dengan pengulangan.

Masalah Anda adalah penguraian kode Anda tidak pada tingkat yang benar. Jika Anda pikir Anda akan memiliki kode duplikat, maka itu harus menjadi fungsi / metode sendiri yang sesuai parameter, tidak menyalin dan menempel, dan yang lainnya harus dinamai secara deskriptif dan mendelegasikan ke fungsi / metode inti.


Ok sepertinya cara saya menulis tidak terlalu baik (kecurigaan awal saya). Saya tidak begitu yakin apa 'Sprit of DRY' ini
Albinoswordfish


4

Fakta bahwa Anda memberikan boolean untuk membuat fungsi melakukan hal-hal yang berbeda merupakan pelanggaran terhadap Prinsip Tanggung Jawab Tunggal. Suatu fungsi harus melakukan satu hal. Seharusnya hanya melakukan satu hal, dan itu harus dilakukan dengan baik.

Baunya seperti Anda perlu membaginya menjadi beberapa fungsi yang lebih kecil dengan nama deskriptif, memisahkan jalur kode yang sesuai dengan nilai-nilai boolean tersebut.

Setelah Anda melakukannya, Anda harus mencari kode umum dalam fungsi yang dihasilkan, dan memasukkannya ke dalam fungsinya sendiri. Bergantung pada seberapa kompleksnya hal ini, Anda bahkan mungkin dapat memperhitungkan satu atau dua kelas.

Tentu saja, ini mengasumsikan bahwa Anda menggunakan sistem kontrol versi, dan bahwa Anda memiliki test suite yang baik, sehingga Anda dapat melakukan refactor tanpa takut merusak sesuatu.


3

Mengapa Anda tidak akan membuat fungsi lain yang berisi semua logika di fungsi Anda sebelum Anda memutuskan untuk melakukan sesuatu atau sesuatu2 dan kemudian memiliki tiga fungsi seperti:

createTrajectoryFromPoint(A a,B b,C c){...}

dosomething(A a, B b, C c){...}

dosomething2(A a, B b, C c){...}

Dan sekarang dengan meneruskan tiga tipe parameter yang sama ke tiga fungsi yang berbeda, Anda akan mengulangi diri Anda lagi, jadi Anda harus mendefinisikan sebuah struct atau kelas yang mengandung A, B, C.

Atau Anda dapat membuat kelas yang berisi parameter A, B, C dan daftar operasi yang harus dilakukan. Tambahkan operasi mana (sesuatu, sesuatu2) yang Anda inginkan terjadi dengan parameter ini (A, B, C) dengan mendaftarkan operasi dengan objek. Kemudian miliki metode untuk memanggil semua operasi terdaftar pada objek Anda.

public class MyComplexType
{
    public A a{get;set;}
    public B b{get;set;}
    public C c{get;set;}

    public delegate void Operation(A a, B b, C c);
    public List<Operation> Operations{get;set;}

    public MyComplexType(A a, B b, C c)
    {
        this.a = a;
        this.b = b;
        this.c = c   
        Operations = new List<Operation>();
    }

    public CallMyOperations()
    {
        foreach(var operation in Operations)
        {
            operation(a,b,c);
        }
    }
}

Untuk menjelaskan kemungkinan kombinasi nilai untuk dosomething booleans dan dosomething2, Anda akan membutuhkan 4 fungsi, bukan 2, selain fungsi base createTrajectoryFromPoint. Pendekatan ini tidak skala dengan baik karena jumlah opsi meningkat, dan bahkan penamaan fungsi menjadi membosankan.
JGWeissman

2

KERING dapat diambil terlalu jauh, yang terbaik untuk menggunakan prinsip tanggung jawab tunggal (SRP) dalam hubungannya dengan KERING. Menambahkan bool flags ke suatu fungsi untuk membuatnya melakukan versi yang sedikit berbeda dari kode yang sama dapat menjadi tanda Anda melakukan terlalu banyak dengan satu fungsi. Dalam hal ini saya akan menyarankan untuk membuat fungsi terpisah untuk setiap case yang diwakili oleh flag Anda, maka ketika Anda memiliki setiap fungsi yang dituliskan, itu harus cukup jelas jika ada bagian umum yang dapat dipindahkan ke fungsi pribadi tanpa melewati semua flag. , jika tidak ada bagian kode yang jelas, maka Anda benar-benar tidak mengulanginya sendiri, Anda memiliki beberapa kasus yang berbeda tetapi serupa.


1

Saya biasanya melewati beberapa langkah dengan masalah ini, berhenti ketika tidak tahu bagaimana melangkah lebih jauh.

Pertama, lakukan apa yang telah Anda lakukan. Go hard dengan KERING. Jika Anda tidak berakhir dengan kekacauan besar berbulu, Anda sudah selesai. Jika, seperti dalam kasus Anda, Anda tidak memiliki kode duplikat tetapi setiap boolean memiliki nilainya diperiksa di 20 tempat yang berbeda, lanjutkan ke langkah berikutnya.

Kedua, pisahkan kodenya menjadi blok. Para boolean masing-masing direferensikan hanya sekali (well, mungkin dua kali kadang-kadang) untuk mengarahkan eksekusi ke blok yang tepat. Dengan dua booleans, Anda berakhir dengan empat blok. Setiap blok hampir identik. KERING sudah hilang. Jangan jadikan setiap blok metode terpisah. Itu akan lebih elegan, tetapi menempatkan semua kode dalam satu metode membuatnya lebih mudah, atau bahkan mungkin, bagi siapa pun yang melakukan pemeliharaan untuk melihat bahwa mereka harus membuat setiap perubahan di empat tempat. Dengan kode yang terorganisir dengan baik dan monitor yang tinggi, perbedaan dan kesalahan akan hampir jelas. Anda sekarang memiliki kode yang dapat dipelihara dan akan berjalan lebih cepat daripada kekacauan asli yang kusut.

Ketiga, cobalah untuk mengambil duplikat baris kode dari masing-masing blok Anda dan menjadikannya metode yang bagus dan sederhana. Terkadang kamu tidak bisa melakukan apa-apa. Terkadang kamu tidak bisa berbuat banyak. Tetapi setiap sedikit yang Anda lakukan bergerak Anda kembali ke KERING dan membuat kode sedikit lebih mudah untuk diikuti dan lebih aman untuk dipelihara. Idealnya, metode asli Anda mungkin berakhir tanpa kode duplikat. Pada titik itu, Anda mungkin ingin membaginya menjadi beberapa metode tanpa parameter boolean atau Anda mungkin tidak. Kenyamanan kode panggilan sekarang menjadi perhatian utama.

Saya menambahkan jawaban saya ke sejumlah besar sudah ada di sini karena langkah kedua. Saya benci kode duplikat, tetapi jika itu satu-satunya cara yang dapat dipahami untuk menyelesaikan masalah, lakukanlah sedemikian rupa sehingga siapa pun akan tahu sekilas apa yang Anda lakukan. Gunakan banyak blok dan hanya satu metode. Buat blok seidentik mungkin dalam nama, spasi, keberpihakan, ... semuanya. Perbedaan kemudian harus melompat pada pembaca. Mungkin membuatnya jelas bagaimana menulis ulang dengan cara KERING, dan jika tidak, mempertahankannya akan cukup mudah.


0

Pendekatan alternatif adalah mengganti parameter boolean dengan parameter antarmuka, dengan kode untuk menangani nilai-nilai boolean yang berbeda di-refactored ke dalam implementasi antarmuka. Jadi kamu akan melakukannya

createTrajectoryFromPoint(A a,B b,C c,IX x,IY y)

di mana Anda memiliki implementasi IX dan IY yang mewakili nilai yang berbeda untuk boolean. Di tubuh fungsi, di mana pun Anda miliki

if (doesSomething)
{
     ...
}
else
{
     ...
}

Anda menggantinya dengan panggilan ke metode yang didefinisikan pada IX, dengan implementasi yang berisi blok kode yang dihilangkan.

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.