Saya punya proyek. Dalam proyek ini saya ingin memperbaiki itu untuk menambahkan fitur, dan saya refactored proyek untuk menambahkan fitur.
Masalahnya adalah ketika saya selesai, ternyata saya perlu membuat sedikit perubahan antarmuka untuk mengakomodasi itu. Jadi saya membuat perubahan. Dan kemudian kelas konsumsi tidak dapat diimplementasikan dengan antarmuka saat ini dalam hal yang baru, sehingga perlu antarmuka baru juga. Sekarang tiga bulan kemudian, dan saya harus memperbaiki masalah yang tidak berhubungan yang tak terhitung banyaknya, dan saya sedang mencari penyelesaian masalah yang dipetakan selama satu tahun dari sekarang atau hanya terdaftar sebagai tidak akan diperbaiki karena kesulitan sebelum hal itu dikompilasi lagi.
Bagaimana saya bisa menghindari jenis refactor cascading di masa depan? Apakah ini hanya gejala dari kelas saya sebelumnya yang terlalu bergantung satu sama lain?
Sunting singkat: Dalam hal ini, refactor adalah fitur, karena refactor meningkatkan ekstensibilitas potongan kode tertentu dan mengurangi beberapa kopling. Ini berarti bahwa pengembang eksternal dapat berbuat lebih banyak, yang merupakan fitur yang ingin saya sampaikan. Jadi refactor asli itu sendiri seharusnya tidak menjadi perubahan fungsional.
Sunting yang lebih besar yang saya janjikan lima hari yang lalu:
Sebelum saya memulai refactor ini, saya memiliki sistem di mana saya memiliki antarmuka, tetapi dalam implementasinya, saya hanya dynamic_cast
melalui semua kemungkinan implementasi yang saya kirimkan. Ini jelas berarti bahwa Anda tidak bisa hanya mewarisi dari antarmuka, untuk satu hal, dan kedua, bahwa tidak mungkin bagi siapa pun tanpa akses implementasi untuk mengimplementasikan antarmuka ini. Jadi saya memutuskan bahwa saya ingin memperbaiki masalah ini dan membuka antarmuka untuk konsumsi publik sehingga siapa pun dapat menerapkannya dan mengimplementasikan antarmuka adalah seluruh kontrak yang diperlukan - jelas merupakan peningkatan.
Ketika saya menemukan dan membunuh-dengan-api semua tempat yang telah saya lakukan ini, saya menemukan satu tempat yang terbukti menjadi masalah khusus. Itu tergantung pada detail implementasi dari semua berbagai kelas turunan dan fungsi duplikat yang sudah dilaksanakan tetapi lebih baik di tempat lain. Itu bisa saja diimplementasikan dalam hal antarmuka publik dan digunakan kembali implementasi yang ada dari fungsi itu. Saya menemukan bahwa diperlukan sepotong konteks untuk berfungsi dengan benar. Secara kasar, penerapan implementasi sebelumnya tampak seperti
for(auto&& a : as) {
f(a);
}
Namun, untuk mendapatkan konteks ini, saya perlu mengubahnya menjadi sesuatu yang lebih mirip
std::vector<Context> contexts;
for(auto&& a : as)
contexts.push_back(g(a));
do_thing_now_we_have_contexts();
for(auto&& con : contexts)
f(con);
Ini berarti bahwa untuk semua operasi yang dulunya merupakan bagian dari f
, beberapa dari mereka perlu dibuat menjadi bagian dari fungsi baru g
yang beroperasi tanpa konteks, dan beberapa dari mereka harus dibuat dari bagian yang ditangguhkan sekarang f
. Tetapi tidak semua metode f
membutuhkan atau menginginkan konteks ini - beberapa dari mereka memerlukan konteks berbeda yang mereka peroleh melalui cara yang berbeda. Jadi untuk semua yang pada f
akhirnya memanggil (yang secara kasar, hampir semuanya ), saya harus menentukan apa, jika ada, konteks yang mereka butuhkan, dari mana mereka seharusnya mendapatkannya, dan bagaimana memecahnya dari yang lama f
menjadi baru f
dan baru g
.
Dan begitulah akhirnya saya sampai di tempat saya sekarang. Satu-satunya alasan saya terus maju adalah karena saya memerlukan refactoring ini karena alasan lain.