mempertahankan basis kode yang berkembang dan beragam dengan integrasi yang berkelanjutan


10

Saya membutuhkan bantuan dengan filosofi dan desain pengaturan integrasi berkelanjutan.

Pengaturan CI kami saat ini menggunakan buildbot. Ketika saya mulai mendesainnya, saya mewarisi (yah, tidak sepenuhnya, karena saya terlibat dalam desainnya setahun sebelumnya) seorang pembangun CI yang dipesan lebih dahulu yang dirancang untuk menjalankan seluruh bangunan sekaligus, semalam. Setelah beberapa saat, kami memutuskan bahwa ini tidak cukup, dan mulai mengeksplorasi berbagai kerangka kerja CI, akhirnya memilih buildbot. Salah satu tujuan saya dalam transisi ke buildbot (selain bisa menikmati semua ekstra jagoan) adalah untuk mengatasi beberapa kekurangan dari pembangun malam kami yang dipesan lebih dahulu.

Humor saya sejenak, dan izinkan saya menjelaskan apa yang saya warisi. Basis kode untuk perusahaan saya adalah hampir 150 unik c ++ aplikasi Windows, yang masing-masing memiliki ketergantungan pada satu atau lebih selusin perpustakaan internal (dan banyak juga pada perpustakaan pihak ke-3 juga). Beberapa perpustakaan ini saling tergantung, dan memiliki aplikasi tergantung yang (sementara mereka tidak ada hubungannya satu sama lain) harus dibangun dengan membangun perpustakaan yang sama. Setengah dari aplikasi dan perpustakaan ini dianggap "warisan" dan tidak dapat diangkut, dan harus dibangun dengan beberapa konfigurasi berbeda dari kompiler IBM (yang mana saya telah menulis subkelas unik Compile), dan setengah lainnya dibangun dengan studio visual.ShellCommands, karena tidak ada dukungan untuk VSS).

Pembangun malam kami yang asli hanya mencatat sumber untuk semuanya, dan membangun barang-barang dalam urutan tertentu. Tidak ada cara untuk membangun hanya satu aplikasi, atau memilih revisi, atau mengelompokkan beberapa hal. Itu akan meluncurkan mesin virtual untuk membangun sejumlah aplikasi. Itu tidak terlalu kuat, tidak bisa didistribusikan. Itu tidak bisa diperpanjang. Saya ingin dapat mengatasi semua keterbatasan ini di buildbot.

Cara saya melakukan ini pada awalnya adalah membuat entri untuk masing-masing aplikasi yang ingin kita bangun (semuanya 150an), kemudian membuat penjadwal yang dipicu yang dapat membangun berbagai aplikasi sebagai grup, dan kemudian merangkum kelompok-kelompok itu di bawah penjadwal pembangunan malam secara keseluruhan. Ini bisa berjalan pada budak yang berdedikasi (tidak ada lagi kecurangan mesin virtual), dan jika saya mau, saya bisa menambahkan budak baru. Sekarang, jika kita ingin membuat jadwal yang lengkap, hanya satu klik, tetapi kita juga dapat membangun satu aplikasi jika kita menginginkannya.

Namun, ada empat kelemahan dari pendekatan ini. Salah satunya adalah web dependensi pohon sumber kami yang kompleks. Untuk menyederhanakan konfigurasi config, semua pembangun dihasilkan dari kamus besar. Ketergantungan diambil dan dibangun dengan cara yang tidak terlalu kuat (yaitu, penguncian hal-hal tertentu dalam kamus build-target saya). Yang kedua adalah bahwa setiap build memiliki antara 15 dan 21 langkah build, yang sulit dijelajahi dan dilihat di antarmuka web, dan karena ada sekitar 150 kolom, perlu selamanya memuat (pikirkan dari 30 detik hingga beberapa menit). Ketiga, kami tidak lagi memiliki autodiscovery untuk membangun target (walaupun, sebanyak salah satu rekan kerja saya mengomel mengenai hal ini, saya tidak melihat apa yang membuat kami menjadi yang pertama). Akhirnya,

Sekarang, pindah ke pengembangan baru, kita mulai menggunakan g ++ dan subversi (bukan porting repositori lama, ingatlah - hanya untuk barang baru). Selain itu, kami mulai melakukan lebih banyak pengujian unit ("lebih" mungkin memberikan gambaran yang salah ... lebih seperti apa pun ), dan pengujian integrasi (menggunakan python). Saya mengalami kesulitan mencari tahu bagaimana menyesuaikan ini ke dalam konfigurasi saya yang ada.

Jadi, di mana saya secara filosofis salah? Bagaimana cara terbaik untuk maju (dengan buildbot - itu satu-satunya bagian dari puzzle yang saya miliki lisensi untuk dikerjakan) sehingga konfigurasi saya sebenarnya dapat dipertahankan? Bagaimana cara mengatasi beberapa kelemahan desain saya? Apa yang benar-benar berfungsi dalam hal strategi CI untuk basis kode yang besar, (mungkin berlebihan)?

EDIT:

Saya pikir saya menjelaskan masalah saya, tetapi jelas saya tidak cukup jelas. Saya tidak mencari saran untuk mengubah platform CI. Itu tidak akan terjadi, dan jawaban yang menyarankan itu tidak akan diterima. Yang ingin saya ketahui adalah bagaimana orang lain mengelola basis kode yang rumit menggunakan CI. Saya memiliki selusin produk yang berbeda, dan saya memiliki ketergantungan yang tersebar ke angin, dan semuanya berbeda. INI adalah apa yang saya ingin tahu bagaimana menghadapinya.


Saya juga ingin tahu jawabannya. Lingkungan kami tidak serumit lingkungan Anda, tetapi kami memiliki dependensi dependensi dependensi (dalam kasus proyek setup, ia memiliki dependensi sedalam empat lapis). Saya tidak tahu apakah setiap proyek harus menjadi proyek CI, atau jika saya harus menggunakan file .sln Visual Studio untuk mengurusnya agar saya tidak perlu membuat kembali pohon dependensi untuk setiap proyek (dan proyek masa depan).
Moswald

Tidak dapat membangun di mesin lokal Anda membuat misi server CI Anda penting untuk bisnis Anda. Anda mungkin ingin memikirkan kembali ini.
Thorbjørn Ravn Andersen

Jawaban:


3

Meskipun saya belum menghadapi situasi yang seburuk yang Anda gambarkan, saya telah mempertahankan konfigurasi CI dengan puluhan komponen, di antaranya ada beberapa dependensi 'sederhana'. Saya berharap bahwa pendekatan saya dapat memberi Anda beberapa petunjuk untuk melanjutkan. Masalahnya jelas tidak hanya terkait dengan pilihan server CI, tetapi juga dengan keseluruhan proses pembangunan dan struktur proyek.

Saya akan memecah masalah menjadi 2 bagian: Bangunan dan CI.

Bangunan

Untuk "Bangunan" yang saya maksud adalah proses, mengubah kode sumber yang ada di tangan ke artefak akhir. Perusahaan kami terutama menggunakan Java dalam pengembangan, dan alat bantu yang kami gunakan adalah Maven. Anda mungkin tidak dapat menggunakannya karena sifat proyek Anda, tetapi ada beberapa konsep berharga di Maven yang perlu diperhatikan:

1) Di dunia Maven, setiap artefak (lib, program sebenarnya, dll) harus diisolasi dan dipisahkan dengan jelas. Ketergantungan antara artefak harus jelas. Saya harus menekankan, ketergantungan berantakan, terutama ketergantungan melingkar antara artefak build Anda akan membuat proses build berantakan.

Sebagai contoh, saya melihat beberapa proyek java sebelum itu, meskipun setelah seluruh proses pembangunan ada beberapa JAR (Anda dapat menganggapnya sebagai lib / dll di Jawa) dibangun, mereka sebenarnya saling bergantung. Seperti, A.jar menggunakan hal-hal dalam B.jar, dan sebaliknya. 'Modularisasi' semacam itu sama sekali tidak ada artinya. A.jar dan B.jar selalu perlu dikerahkan dan digunakan bersama. Implikasinya adalah, nanti jika Anda ingin membuatnya dipisahkan menjadi proyek yang berbeda (untuk digunakan kembali dalam proyek lain misalnya), Anda tidak akan dapat melakukannya, karena Anda tidak dapat menentukan proyek mana, A atau B, yang akan dibangun terlebih dahulu.

Ya, itu perlu dipenuhi dalam desain perangkat lunak Anda, tetapi saya selalu percaya bahwa, daripada membayar waktu untuk membuat alat bangunan / model yang rumit bekerja dalam proyek yang berantakan, saya lebih suka menghabiskan waktu untuk mengatur kembali desain untuk menggunakan model bangunan sederhana.

2) Dependensi harus bersifat deklaratif. Ada banyak proses membangun yang saya lihat sebelumnya, yang mencakup semua lib yang dibutuhkan secara lokal dalam proyek. Ini akan membuat proses pembuatan menjadi sangat merepotkan jika beberapa lib sebenarnya adalah artefak lain yang perlu Anda bangun.

3) Penyimpanan "Terpusat" untuk artefak untuk mendapatkan dependensi, atau untuk menyebarkan artefak setelah dikompilasi. Tidak perlu "terpusat" untuk seluruh kantor (akan lebih bagus jika itu), hanya direktori lokal sudah akan baik-baik saja.

Penjelasan lebih lanjut tentang 2 dan 3. Sebagai contoh, saya telah menemukan sebuah proyek yang melibatkan 3 proyek independen. Setiap proyek dibangun berdasarkan pada sumber, ditambah lib di bawah direktori lib / di direktori sumber. Proyek A akan membangun beberapa lib, yang pada gilirannya digunakan oleh proyek B dan C. Ada beberapa kekurangan: prosedur pembuatannya rumit dan sulit untuk diotomatisasi; kontrol sumber semakin membengkak dengan JAR duplikasi yang tidak perlu digunakan kembali dalam proyek yang berbeda

Di dunia Maven, yang dilakukan adalah, proyek B dan C tidak benar-benar mengandung A.jar (dan dependensi lainnya, seperti lib pihak ke-3 lainnya) di sumber proyek. Itu deklaratif. Misalnya, dalam konfigurasi pembangunan proyek B, ia hanya menyatakan bahwa ia membutuhkan: A.lib v1.0, xyz.lib v2.1 dll, dan skrip build akan mencari lib dari /A/1.0/A. jar dan /xyz/2.1/xyz.lib

Untuk dunia non-Maven, direktori artifak ini hanya perlu satu atau dua direktori dengan struktur direktori yang disepakati. Anda dapat menempatkan semua lib pihak ke-3 ke lokasi berbagi dan membiarkan pengembang menyinkronkan atau menyalin ke mesin lokal mereka. Dalam proyek C ++ saya yang saya lakukan bertahun-tahun sebelumnya, apa yang saya lakukan adalah mengatur lib dan header ke $ {artifact_dir} / lib_name / ver, dan dengan artifact_id dinyatakan sebagai variabel lingkungan.

Ketika proyek A dibangun, ia akan memiliki salinan hasilnya di artifact_dir itu, sehingga ketika kita membangun proyek B, B bisa mendapatkan hasil A secara otomatis, tanpa menyalin secara manual.

4) rilis tidak bisa berubah. Setelah Anda merilis A.lib 1.0, itu saja, Anda tidak akan mengharapkan perubahan konten A.lib 1.0 setelah 1 bulan hanya karena ada beberapa perbaikan bug. Dalam hal demikian, seharusnya A.lib 1.1. Artefak dari basis kode yang berubah harus mempertimbangkan "versi" khusus, yang dalam Maven kami menyebutnya snapshot.

Rilis yang tidak bisa berubah lebih merupakan masalah etika. Tapi apa yang dipecahkan jelas: Ketika Anda memiliki banyak proyek, menggunakan lib yang sama, Anda tahu versi lib yang Anda gunakan, dan Anda akan yakin bahwa, versi lib yang sama yang digunakan dalam proyek yang berbeda, memang sama . Saya pikir banyak dari kita telah melalui masalah: Mengapa proyek X dan Y sama-sama menggunakan lib A tetapi hasil build berbeda? (dan ternyata lib A yang digunakan oleh X dan Y sebenarnya berbeda setelah menggali konten atau ukuran file lib).


Semua ini memastikan bahwa proyek Anda dapat membangun secara mandiri, tanpa banyak trik manual seperti, membangun proyek A terlebih dahulu, menyalin A.lib ke proyek B, dan kemudian membangun proyek ...

Setelah melalui latihan seperti ini, misalnya, ketika Anda membangun proyek A, itu akan mencoba untuk mendapatkan dependensi dari penyimpanan artefak terpusat. Dalam hal beberapa dependensi (yang merupakan proyek lain dari perusahaan Anda, mis. Proyek B) tidak ditemukan, yang perlu Anda lakukan adalah, dapatkan sumber proyek B, bangun (yang akan digunakan untuk penyimpanan terpusat setelah berhasil), dan kemudian bangun proyek A lagi.


CI

Dengan sistem build yang mudah, dengan dependensi yang jelas, CI akan jauh lebih mudah. Saya berharap server CI Anda melayani persyaratan berikut:

1) Monitor kontrol sumber, hanya checkout + build ketika ada perubahan sumber

2) Dapat mengatur ketergantungan antar proyek

Dengan ketergantungan yang jelas untuk proyek, Anda hanya perlu mengatur proyek di CI sesuai dengan proyek Anda yang sebenarnya, mengatur ketergantungan proyek CI sesuai dengan ketergantungan proyek Anda. Server CI Anda harus diatur untuk membangun proyek tergantung sebelum membangun proyek apa pun (dan tentu saja, membangun hanya terjadi jika sumber proyek benar-benar berubah).

Jika semuanya berjalan dengan baik, Anda harus memiliki CI yang besar, kompleks, tetapi masih dapat dikelola (dan yang lebih penting, struktur proyek yang dapat dikelola)


Saya suka ke mana jawaban ini pergi, tetapi bisakah Anda menjelaskan lebih detail di bagian 'bangunan'? Artinya, berikan beberapa contoh, jelaskan beberapa konsep lebih lengkap, rumit.
Nate

hm ... suka bagian mana? Saya mencoba mengedit posting untuk memberikan lebih detail dari setiap bagian. Akan lebih baik jika Anda bisa memberi tahu saya bagian mana yang menurut Anda perlu dielaborasi. Omong-omong, jika Anda menggunakan Java juga, lihat di maven.apache.org. Maven mungkin bukan hal yang paling mudah untuk diadopsi tetapi memaksa Anda untuk membuat barang-barang Anda bersih dan teratur.
Adrian Shum

1

Apa yang berhasil dalam situasi yang sama bagi saya:

  • Abstraksi tingkat aplikasi dengan memangkas beberapa bagian dari build ke aplikasi build khusus (dalam kasus kami ini adalah skrip PHP yang dipanggil dari build utama). Ini dapat mengurangi beberapa lusin garis langkah pembangunan menjadi satu langkah pembangunan.
  • Bangun abstraksi tingkat dengan membuat skrip sub-build yang diluncurkan dari skrip build utama. Tidak tahu apakah itu relevan untuk buildbot (tidak ada pengalaman dengan produk itu).

Saya menyarankan agar Anda memperlakukan build itu sendiri sebagai proyek pengembangan perangkat lunak. Ini berarti bahwa Anda perlu memodulasi basis kode pembuatan dan menulis beberapa tes otomatis untuknya (mis. Buat nomor revisi yang diketahui dan periksa apakah itu menghasilkan hasil yang benar).


0

Saya akan mempertimbangkan Jenkins sebagai server CI, Anda dapat melihat fitur-fiturnya di sini:

https://wiki.jenkins-ci.org/display/JENKINS/Meet+Jenkins

Mengapa? Sangat mudah untuk menginstal, memiliki antarmuka yang luar biasa, mudah untuk mengkonfigurasi dan memperluas dan ada BANYAK plugin siap untuk hampir semuanya:

https://wiki.jenkins-ci.org/display/JENKINS/Plugins

Cobalah :)


2
Saya rasa Anda membaca judul pertanyaan saya, tetapi tidak membaca isi ... Saya tidak mencari saran produk. Saya telah memilih produk. Saya mencari cara mengatur pengaturan CI yang kompleks.
Nate

Nate, saya membaca semua posting Anda dan saya pikir Anda telah memilih produk yang salah, itu sebabnya saya menyarankan Jenkins. Saya menggunakan Jenkins di tempat kerja untuk berbagai jenis pengujian produk C ++ (bahkan tes yang ditulis dalam berbagai bahasa) dengan pengelompokan pada beberapa mesin dan itu berjalan sangat baik. Sangat mudah untuk mengelola dan mengonfigurasi. Sungguh, coba saja :)
Patrizio Rullo

Lihat juga posting blog ini: vperic.blogspot.com/2011/05/...
Patrizio Rullo

0

Kami sekarang menggunakan Go by ThoughtWorks sebelum itu, kami menggunakan CruiseControl.Net . Ini berguna mengingat kami memiliki dua tim yang setengah dunia jauh dari satu sama lain dan ada perbedaan zona waktu yang besar di antara kami.

Kami mengelola beberapa proyek dan sebagian besar tugas melibatkan tumpang tindih antara dua pengembang di kedua sisi dunia, jadi kami harus ingat bahwa semua file tidak boleh merusak bangunan orang lain.

Juga manajemen lebih mudah dengan Go dan menjadi Agile Process diehard, itu telah memberi kami sakit kepala yang lebih sedikit setelah kami menginstalnya. Pengujian juga telah diintegrasikan dengan Go.

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.