Monorepositori: tolong, harus

Monorepositori: tolong, harus

Terjemahan artikel disiapkan untuk mahasiswa kursus "Praktik dan alat DevOps" dalam proyek pendidikan OTUS.

Anda harus memilih monorepositori karena perilaku yang dipromosikan dalam tim Anda adalah transparansi dan tanggung jawab bersama, terutama seiring pertumbuhan tim. Apa pun yang terjadi, Anda harus berinvestasi pada perkakas, namun akan lebih baik jika perilaku default adalah perilaku yang Anda inginkan dalam perintah Anda.

Mengapa kita membicarakan hal ini?

Matt Klein menulis artikel itu "Monorepos: Tolong jangan!"  (catatan penerjemah: terjemahan di Habré “Monorepositori: tolong jangan”). Saya suka Matt, menurut saya dia sangat pintar dan Anda harus membaca sudut pandangnya. Dia awalnya memposting jajak pendapat di Twitter:

Monorepositori: tolong, harus

Terjemahan:
Di Tahun Baru ini, saya akan berdebat tentang betapa konyolnya monorepositori. 2019 dimulai dengan tenang. Sehubungan dengan hal ini, saya menawarkan Anda sebuah survei. Siapakah orang-orang yang sangat fanatik? Pendukung:
- Monorepo
- Karat
- Jajak pendapat salah/keduanya

Tanggapan saya adalah, “Saya sebenarnya adalah kedua orang tersebut.” Daripada membicarakan bagaimana Rust adalah obat, mari kita lihat mengapa menurut saya dia salah tentang monorepositori. Sedikit tentang dirimu. Saya CTO Chef Software. Kami memiliki sekitar 100 insinyur, basis kode sekitar 11-12 tahun, dan 4 produk utama. Beberapa kode ini ada di polirepositori (posisi awal saya), ada pula yang ada di monorepositori (posisi saya saat ini).

Sebelum saya mulai: setiap argumen yang saya buat di sini akan berlaku untuk kedua jenis repositori. Menurut pendapat saya, tidak ada alasan teknis mengapa Anda harus memilih satu jenis repositori dibandingkan yang lain. Anda dapat membuat pendekatan apa pun berhasil. Saya senang membicarakannya, tetapi saya tidak tertarik dengan alasan teknis yang dibuat-buat mengapa yang satu lebih unggul dari yang lain.

Saya setuju dengan bagian pertama dari poin Matt:

Karena dalam skala besar, monorepositori akan menyelesaikan semua masalah yang sama seperti yang diselesaikan polirepositori, tetapi pada saat yang sama memaksa Anda untuk memasangkan kode secara erat dan memerlukan upaya luar biasa untuk meningkatkan skalabilitas sistem kontrol versi Anda.

Anda harus menyelesaikan masalah yang sama terlepas dari apakah Anda memilih monorepositori atau polirepositori. Bagaimana Anda merilis rilis? Apa pendekatan Anda terhadap pembaruan? Kompatibilitas terbalik? Ketergantungan lintas proyek? Gaya arsitektur apa yang dapat diterima? Bagaimana Anda mengelola infrastruktur pembangunan dan pengujian Anda? Daftarnya tidak ada habisnya. Dan Anda akan menyelesaikan semuanya seiring pertumbuhan Anda. Tidak ada keju gratis.

Saya pikir argumen Matt serupa dengan pandangan yang dianut oleh banyak insinyur (dan manajer) yang saya hormati. Hal ini terjadi dari sudut pandang insinyur yang mengerjakan komponen atau tim yang mengerjakan komponen tersebut. Anda mendengar hal-hal seperti:

  • Basis kodenya besar - saya tidak membutuhkan semua sampah ini.
  • Lebih sulit untuk mengujinya karena saya harus menguji semua sampah yang tidak saya perlukan ini.
  • Lebih sulit untuk bekerja dengan ketergantungan eksternal.
  • Saya memerlukan sistem kontrol versi virtual saya sendiri.

Tentu saja, semua poin ini bisa dibenarkan. Hal ini terjadi dalam kedua kasus - di polirepositori saya memiliki sampah saya sendiri, selain yang diperlukan untuk pembuatan... Saya mungkin juga memerlukan sampah lainnya. Jadi saya “hanya” membuat alat yang memeriksa keseluruhan proyek. Atau saya membuat monorepositori palsu dengan submodul. Kita bisa berjalan-jalan sepanjang hari. Namun menurut saya argumen Matt tidak memenuhi alasan utama, yang kemudian saya ubah menjadi monorepositori:

Ini memprovokasi komunikasi dan menunjukkan masalah

Ketika kita memisahkan repositori, kita menciptakan masalah koordinasi dan transparansi secara de facto. Hal ini sesuai dengan cara kita berpikir tentang tim (terutama cara berpikir masing-masing anggota tentang tim): kita bertanggung jawab atas komponen tertentu. Kami bekerja dalam isolasi yang relatif. Batasannya telah ditetapkan pada tim saya dan komponen yang sedang kami kerjakan.

Ketika arsitektur menjadi lebih kompleks, satu tim tidak dapat lagi mengelolanya sendirian. Sangat sedikit insinyur yang memikirkan keseluruhan sistem. Katakanlah Anda mengelola komponen A bersama yang digunakan oleh Tim B, C, dan D. Tim A sedang melakukan pemfaktoran ulang, meningkatkan API, dan juga mengubah implementasi internal. Akibatnya, perubahan tersebut tidak kompatibel ke belakang. Saran apa yang Anda punya?

  • Temukan semua tempat di mana API lama digunakan.
  • Apakah ada tempat di mana API baru tidak dapat digunakan?
  • Bisakah Anda memperbaiki dan menguji komponen lain untuk memastikan komponen tersebut tidak rusak?
  • Bisakah tim ini menguji perubahan Anda saat ini?

Harap dicatat bahwa pertanyaan-pertanyaan ini tidak bergantung pada jenis repositori. Anda perlu menemukan tim B, C dan D. Anda perlu berbicara dengan mereka, mencari tahu waktunya, memahami prioritas mereka. Setidaknya kami berharap Anda melakukannya.

Tidak ada seorang pun yang benar-benar ingin melakukan ini. Ini jauh lebih menyenangkan daripada sekadar memperbaiki API sialan itu. Itu semua manusiawi dan berantakan. Dalam polirepositori, Anda cukup membuat perubahan, memberikannya kepada orang yang mengerjakan komponen tersebut (mungkin bukan B, C, atau D) untuk ditinjau, dan melanjutkan. Tim B, C, dan D tetap menggunakan versi mereka saat ini untuk saat ini. Mereka akan diperbarui ketika mereka menyadari kejeniusan Anda!

Dalam monorepositori, tanggung jawab dialihkan secara default. Tim A mengubah komponennya dan, jika tidak hati-hati, segera merusak B, C, dan D. Hal ini menyebabkan B, C, dan D muncul di depan pintu A, bertanya-tanya mengapa Tim A merusak perakitan. Ini mengajarkan A bahwa mereka tidak boleh melewatkan daftar saya di atas. Mereka harus membicarakan apa yang akan mereka lakukan. Bisakah B, C dan D bergerak? Bagaimana jika B dan C bisa, tapi D terkait erat dengan efek samping dari perilaku algoritma lama?

Kemudian kita harus membicarakan bagaimana kita keluar dari situasi ini:

  1. Mendukung beberapa API internal, dan akan menandai algoritme lama sebagai tidak digunakan lagi hingga D dapat berhenti menggunakannya.
  2. Dukungan untuk beberapa versi rilis, satu dengan antarmuka lama, satu lagi dengan yang baru.
  3. Tunda rilis perubahan A hingga B, C, dan D dapat menerimanya secara bersamaan.

Katakanlah kita telah memilih 1, beberapa API. Dalam hal ini kita memiliki dua buah kode. Lama dan baru. Cukup nyaman dalam beberapa situasi. Kami memeriksa kembali kode lama, menandainya sebagai tidak digunakan lagi, dan menyetujui jadwal penghapusan dengan tim D. Pada dasarnya identik untuk repositori poli dan mono.

Untuk merilis beberapa versi, kita memerlukan cabang. Sekarang kita memiliki dua komponen - A1 dan A2. Tim B dan C menggunakan A2 dan D menggunakan A1. Kami memerlukan setiap komponen siap untuk dirilis karena pembaruan keamanan dan perbaikan bug lainnya mungkin diperlukan sebelum D dapat melanjutkan. Dalam polirepositori, kita bisa menyembunyikannya di cabang berumur panjang yang terasa nyaman. Dalam monorepositori, kami memaksa kode dibuat di modul baru. Tim D masih harus melakukan perubahan pada komponen "lama". Semua orang dapat melihat biaya yang kami bayarkan di sini - kami sekarang memiliki kode dua kali lebih banyak, dan perbaikan bug apa pun yang berlaku untuk A1 dan A2 harus berlaku untuk keduanya. Dengan pendekatan percabangan dalam polirepositori, hal ini tersembunyi di balik cherry-pick. Kami menilai biayanya lebih rendah karena tidak ada duplikasi. Dari sudut pandang praktis, biayanya sama: Anda akan membangun, merilis, dan memelihara dua basis kode yang sebagian besar identik hingga Anda dapat menghapus salah satunya. Perbedaannya adalah dengan monorepositori, rasa sakit ini langsung dan terlihat. Ini bahkan lebih buruk lagi, dan itu bagus.

Akhirnya kita sampai pada poin ketiga. Penundaan rilis. Ada kemungkinan bahwa perubahan yang dilakukan oleh A akan meningkatkan kehidupan Tim A. Penting, namun tidak mendesak. Bisakah kita menundanya saja? Di polirepositori, kami mendorong ini untuk menyematkan artefak. Tentu saja kami memberitahukan hal ini kepada Tim D. Tetap gunakan versi lama sampai Anda mengejar ketinggalan! Ini membuat Anda siap untuk berperan sebagai pengecut. Tim A terus mengerjakan komponennya, mengabaikan fakta bahwa Tim D menggunakan versi yang semakin ketinggalan jaman (itu masalah Tim D, mereka bodoh). Sementara itu, Tim D berbicara buruk tentang sikap ceroboh Tim A terhadap stabilitas kode, jika mereka membicarakannya. Bulan-bulan berlalu. Akhirnya, Tim D memutuskan untuk melihat kemungkinan pembaruan, namun A hanya memiliki lebih banyak perubahan. Tim A hampir tidak ingat kapan atau bagaimana mereka menghancurkan D. Peningkatannya lebih menyakitkan dan memakan waktu lebih lama. Yang mengirimkannya lebih jauh ke bawah tumpukan prioritas. Hingga suatu saat kami mengalami masalah keamanan di A yang memaksa kami untuk membuat cabang. Tim A harus kembali ke masa lalu, menemukan titik ketika D stabil, memperbaiki masalah di sana, dan menyiapkannya untuk dirilis. Ini adalah pilihan yang secara de facto diambil oleh banyak orang, dan sejauh ini merupakan pilihan terburuk. Tampaknya ini baik untuk Tim A dan Tim D selama kita bisa mengabaikan satu sama lain.

Dalam monorepositori, yang ketiga sebenarnya bukanlah suatu pilihan. Anda terpaksa menghadapi situasi ini dengan salah satu dari dua cara. Anda perlu melihat biaya untuk memiliki dua cabang rilis. Belajarlah untuk melindungi diri Anda dari pembaruan yang merusak kompatibilitas ke belakang. Namun yang terpenting: Anda tidak dapat menghindari percakapan yang sulit.

Menurut pengalaman saya, ketika tim menjadi besar, tidak mungkin lagi memikirkan keseluruhan sistem, dan itulah bagian terpenting. Anda harus meningkatkan visibilitas perselisihan dalam sistem. Anda harus bekerja secara aktif untuk membuat tim mengalihkan pandangan dari komponen mereka dan melihat pekerjaan tim lain dan konsumen.

Ya, Anda dapat membuat alat yang mencoba memecahkan masalah polirepositori. Namun pengalaman saya mengajar pengiriman berkelanjutan dan otomatisasi di perusahaan besar memberi tahu saya hal ini: perilaku default tanpa menggunakan alat tambahan adalah perilaku yang Anda harapkan terlihat. Perilaku default polirepositori adalah isolasi, itulah intinya. Perilaku default dari monorepositori adalah tanggung jawab dan transparansi bersama, itulah intinya. Dalam kedua kasus tersebut, saya akan membuat alat yang akan menghaluskan bagian tepi yang kasar. Sebagai seorang pemimpin, saya akan memilih monorepositori setiap saat karena alatnya perlu memperkuat budaya yang saya inginkan, dan budaya berasal dari keputusan kecil dan kerja tim sehari-hari.

Hanya pengguna terdaftar yang dapat berpartisipasi dalam survei. Masuk, silakan.

Siapa yang paling fanatik? Pendukung:

  • Monorepo

  • Karat

  • Jajak pendapat salah/keduanya

33 pengguna memilih. 13 pengguna abstain.

Sumber: www.habr.com

Tambah komentar