Untuk memberi Anda sedikit latar belakang: Saya bekerja untuk sebuah perusahaan dengan sekitar dua belas pengembang Ruby on Rails (+/- interns). Pekerjaan jarak jauh adalah hal biasa. Produk kami terbuat dari dua bagian: inti yang agak gemuk, dan menipis ke proyek pelanggan besar yang dibangun di atasnya. Proyek pelanggan biasanya memperluas inti. Timpa fitur utama tidak terjadi. Saya dapat menambahkan bahwa inti memiliki beberapa bagian yang agak buruk yang membutuhkan refactoring. Ada spesifikasi, tetapi sebagian besar untuk proyek pelanggan. Bagian terburuk dari inti tidak diuji (tidak seperti yang seharusnya ...).
Pengembang dibagi menjadi dua tim, bekerja dengan satu atau dua PO untuk setiap sprint. Biasanya, satu proyek pelanggan secara ketat dikaitkan dengan salah satu tim dan PO.
Sekarang masalah kita: Lebih sering, kita saling menghancurkan barang. Seseorang dari Tim A memperluas atau refaktor fitur inti Y, menyebabkan kesalahan tak terduga untuk salah satu proyek pelanggan Tim B. Sebagian besar, perubahan tidak diumumkan pada tim, sehingga bug yang terjadi hampir selalu tidak terduga. Tim B, termasuk PO, berpikir tentang fitur Y menjadi stabil dan tidak mengujinya sebelum melepaskan, tidak menyadari perubahan.
Bagaimana cara mengatasi masalah tersebut? 'Teknik pengumuman' seperti apa yang bisa Anda rekomendasikan kepada saya?
Jawaban:
Saya akan merekomendasikan membaca Bekerja Efektif dengan Legacy Code oleh Michael C. Feathers . Ini menjelaskan bahwa Anda benar-benar membutuhkan pengujian otomatis, bagaimana Anda dapat dengan mudah menambahkannya, jika Anda belum memilikinya, dan "kode apa yang baunya" untuk diperbaiki dengan cara apa.
Selain itu, masalah inti lain dalam situasi Anda tampaknya adalah kurangnya komunikasi antara kedua tim. Seberapa besar tim-tim ini? Apakah mereka mengerjakan backlog yang berbeda?
Hampir selalu merupakan praktik buruk untuk memecah tim berdasarkan arsitektur Anda. Misalnya tim inti dan tim non-inti. Sebaliknya, saya akan membuat tim di domain fungsional, tetapi lintas komponen.
sumber
Ini masalahnya. Refactoring yang efisien sangat tergantung pada paket pengujian otomatis. Jika Anda tidak memilikinya, masalah yang Anda uraikan mulai muncul. Ini sangat penting jika Anda menggunakan bahasa dinamis seperti Ruby, di mana tidak ada kompiler untuk menangkap kesalahan dasar terkait dengan meneruskan parameter ke metode.
sumber
Jawaban sebelumnya yang mengarahkan Anda ke unit test yang lebih baik adalah baik, tetapi saya merasa bahwa mungkin ada masalah yang lebih mendasar untuk ditangani. Anda memerlukan antarmuka yang jelas untuk mengakses kode inti dari kode untuk proyek pelanggan. Dengan cara ini jika Anda memperbaiki kode inti tanpa mengubah perilaku seperti yang diamati melalui antarmuka , kode tim lain tidak akan rusak. Ini akan membuatnya lebih mudah untuk mengetahui apa yang bisa "dengan aman" dire-refored, dan apa yang perlu, mungkin antarmuka, desain ulang.
sumber
Jawaban lain telah menyoroti poin-poin penting (lebih banyak tes unit, tim fitur, antarmuka yang bersih ke komponen-komponen inti), tetapi ada satu poin yang saya temukan hilang, yaitu versi.
Jika Anda membekukan perilaku inti Anda dengan melakukan rilis 1 dan Anda menempatkan rilis itu ke dalam sistem manajemen artefak pribadi 2 , maka setiap proyek pelanggan dapat menyatakan ketergantungannya pada inti versi X , dan itu tidak akan rusak oleh rilis berikutnya X + 1 .
"Kebijakan pengumuman" kemudian hanya mengurangi memiliki file PERUBAHAN bersama dengan setiap rilis, atau memiliki pertemuan tim untuk mengumumkan semua fitur dari setiap rilis inti baru.
Juga, saya pikir Anda perlu mendefinisikan lebih baik apa itu "inti", dan apa bagian dari itu adalah "kunci". Anda tampaknya (dengan benar) menghindari membuat banyak perubahan pada "komponen utama", tetapi Anda mengizinkan perubahan yang sering ke "inti". Untuk mengandalkan sesuatu, Anda harus tetap stabil; jika ada sesuatu yang tidak stabil, jangan menyebutnya inti. Mungkin saya bisa menyarankan menyebutnya komponen "pembantu"?
EDIT : Jika Anda mengikuti konvensi dalam sistem Semantic Versioning , maka setiap perubahan yang tidak kompatibel dalam API inti harus ditandai oleh perubahan versi utama . Yaitu, ketika Anda mengubah perilaku inti yang sudah ada sebelumnya, atau menghapus sesuatu, bukan hanya menambahkan sesuatu yang baru. Dengan konvensi itu, pengembang tahu bahwa memperbarui dari versi '1.1' ke '1.2' adalah aman, tetapi beralih dari '1.X' ke '2.0' berisiko dan harus ditinjau dengan cermat.
1: Saya pikir ini disebut permata, di dunia Ruby
2: Setara dengan Nexus di Jawa atau PyPI dalam Python
sumber
Seperti yang dikatakan orang lain, serangkaian uji unit yang baik tidak akan menyelesaikan masalah Anda: Anda akan mengalami masalah saat menggabungkan perubahan, meskipun setiap suite uji tim lulus.
Sama untuk TDD. Saya tidak melihat bagaimana itu bisa menyelesaikan ini.
Solusi Anda bersifat non teknis. Anda perlu mendefinisikan dengan jelas batas "inti" dan menetapkan peran "anjing penjaga" untuk seseorang, baik itu pemimpin dev atau arsitek. Setiap perubahan pada inti harus melewati pengawas ini. Dia bertanggung jawab untuk memastikan setiap output dari semua tim akan bergabung tanpa terlalu banyak kerusakan jaminan.
sumber
Sebagai perbaikan jangka panjang, Anda juga membutuhkan komunikasi yang lebih baik dan lebih tepat waktu antar tim. Setiap tim yang akan memanfaatkan, misalnya, fitur inti Y, perlu dilibatkan dalam membangun testcases yang direncanakan untuk fitur tersebut. Perencanaan ini, dengan sendirinya, akan menyoroti berbagai kasus penggunaan yang melekat dalam fitur Y antara kedua tim. Setelah bagaimana fitur harus bekerja dipakukan, dan testcases diimplementasikan dan disepakati, ada perubahan tambahan dalam skema implementasi Anda yang diperlukan. Tim yang melepaskan fitur diperlukan untuk menjalankan testcase, bukan tim yang akan menggunakannya. Tugas, jika ada, yang harus menyebabkan tabrakan, adalah penambahan testcase baru dari salah satu tim. Ketika seorang anggota tim memikirkan aspek baru dari fitur yang tidak diuji, mereka harus bebas menambahkan testcase yang telah mereka verifikasi lewat di kotak pasir mereka sendiri. Dengan cara ini, satu-satunya tabrakan yang akan terjadi akan berada pada tingkat niat, dan harus dipaku sebelum fitur refactored dilepaskan ke alam liar.
sumber
Sementara setiap sistem membutuhkan rangkaian pengujian yang efektif (yang berarti, antara lain, otomatisasi), dan sementara pengujian ini, jika digunakan secara efektif, akan menangkap konflik ini lebih cepat daripada yang ada sekarang, ini tidak mengatasi masalah yang mendasarinya.
Pertanyaan itu mengungkapkan setidaknya dua masalah mendasar: praktik memodifikasi 'inti' untuk memenuhi persyaratan bagi pelanggan individu, dan kegagalan tim untuk berkomunikasi dan mengoordinasikan niat mereka untuk melakukan perubahan. Tidak satu pun dari ini adalah akar penyebab, dan Anda harus memahami mengapa ini dilakukan sebelum Anda bisa memperbaikinya.
Salah satu hal pertama yang harus ditentukan adalah apakah pengembang dan manajer menyadari ada masalah di sini. Jika setidaknya ada yang melakukannya, maka Anda perlu mencari tahu mengapa mereka berpikir mereka tidak bisa berbuat apa-apa, atau memilih untuk tidak melakukannya. Bagi mereka yang tidak, Anda dapat mencoba meningkatkan kemampuan mereka untuk mengantisipasi bagaimana tindakan mereka saat ini dapat menciptakan masalah di masa depan, atau menggantinya dengan orang-orang yang bisa. Sampai Anda memiliki tenaga kerja yang menyadari bagaimana segala sesuatunya salah, Anda tidak mungkin dapat memperbaiki masalah (dan mungkin bahkan tidak, setidaknya dalam jangka pendek.)
Mungkin sulit untuk menganalisis masalah secara abstrak, setidaknya pada awalnya, jadi fokuslah pada insiden tertentu yang mengakibatkan masalah, dan cobalah untuk menentukan bagaimana itu terjadi. Karena orang-orang yang terlibat kemungkinan akan bersikap defensif, Anda harus waspada terhadap justifikasi yang melayani diri sendiri dan pasca-hoc untuk mengetahui apa yang sebenarnya terjadi.
Ada satu kemungkinan yang saya ragu untuk disebutkan karena sangat tidak mungkin: persyaratan pelanggan sangat berbeda sehingga tidak ada cukup kesamaan untuk membenarkan kode inti bersama. Jika demikian, maka Anda sebenarnya memiliki beberapa produk terpisah, dan Anda harus mengelolanya seperti itu, dan tidak membuat kopling buatan di antara mereka.
sumber
Kita semua tahu bahwa tes unit adalah cara yang harus dilakukan. Tetapi kita juga tahu bahwa secara retro-pas ini untuk suatu inti adalah sulit.
Teknik khusus yang mungkin berguna bagi Anda ketika memperluas fungsionalitas adalah mencoba untuk sementara dan memverifikasi lokal bahwa fungsi yang ada belum diubah. Ini bisa dilakukan seperti ini:
Kode semu asli:
Kode uji sementara di tempat:
Jalankan versi ini melalui tes level sistem apa pun yang ada. Jika semuanya baik-baik saja, Anda tahu Anda tidak merusak barang-barang dan kemudian dapat melanjutkan untuk menghapus kode lama. Perhatikan bahwa ketika Anda memeriksa kecocokan hasil lama dan baru, Anda mungkin juga menambahkan kode untuk menganalisis perbedaan untuk menangkap kasus yang Anda tahu harus berbeda karena perubahan yang dimaksudkan seperti perbaikan bug.
sumber
"Sebagian besar, perubahan tidak diumumkan pada tim, jadi bug yang menyerang hampir selalu tidak terduga"
Masalah komunikasi, siapa pun? Bagaimana dengan (selain apa yang orang lain telah tunjukkan, bahwa Anda harus melakukan pengujian yang ketat) memastikan bahwa ada komunikasi yang tepat? Bahwa orang-orang dibuat sadar bahwa antarmuka yang mereka tulis akan berubah dalam rilis berikutnya dan apa perubahan itu nantinya?
Dan memberi mereka akses ke setidaknya dummy interace (dengan implementasi kosong) sesegera mungkin selama pengembangan sehingga mereka dapat mulai menulis kode mereka sendiri.
Tanpa semua itu, unit test tidak akan berbuat banyak kecuali menunjukkan selama tahap akhir bahwa ada sesuatu yang tidak beres antara bagian-bagian dari sistem. Anda ingin mengetahuinya, tetapi Anda ingin mengetahuinya sejak dini, sangat dini, dan meminta tim berbicara satu sama lain, mengoordinasikan upaya, dan benar-benar memiliki akses yang sering ke pekerjaan yang dilakukan tim lain (jadi komit reguler, tidak satu pun masif komit setelah beberapa minggu atau bulan, 1-2 hari sebelum pengiriman).
Bug Anda BUKAN dalam kode, tentu saja tidak dalam kode tim lain yang tidak tahu Anda bermain-main dengan antarmuka yang mereka tulis. Bug Anda dalam proses pengembangan Anda, kurangnya komunikasi dan kolaborasi antara orang-orang. Hanya karena Anda duduk di ruangan yang berbeda tidak berarti Anda harus mengisolasi diri dari orang lain.
sumber
Terutama, Anda memiliki masalah komunikasi (mungkin juga terkait dengan masalah pembangunan tim ), jadi saya pikir solusi untuk kasus Anda harus difokuskan pada ... well, komunikasi, daripada teknik pengembangan.
Saya menerima begitu saja bahwa tidak mungkin untuk membekukan atau garpu modul inti ketika memulai proyek pelanggan (jika tidak maka Anda hanya perlu mengintegrasikan dalam jadwal perusahaan Anda beberapa proyek yang tidak berhubungan dengan pelanggan yang bertujuan memperbarui modul inti).
Jadi kita pergi dengan masalah mencoba meningkatkan komunikasi antara tim. Ini dapat diatasi dengan dua cara:
Anda dapat menemukan lebih banyak tentang CI sebagai proses komunikasi di sini .
Akhirnya, Anda masih memiliki masalah dengan kurangnya kerja tim di tingkat perusahaan. Saya bukan penggemar acara membangun tim, tapi sepertinya ini berguna. Apakah Anda melakukan pertemuan di seluruh pengembang secara teratur? Bisakah Anda mengundang orang-orang dari tim lain ke retrospektif proyek Anda? Atau kadang minum bir Jumat malam?
sumber