kami memiliki banyak klien dengan kebutuhan berbeda. Meskipun perangkat lunak kami dimodulasi ke tingkat tertentu, hampir dapat dipastikan bahwa kami perlu menyesuaikan logika bisnis setiap modul di sana-sini sedikit untuk setiap pelanggan. Perubahannya mungkin terlalu kecil untuk membenarkan pemisahan modul menjadi modul (fisik) yang berbeda untuk setiap klien, saya khawatir ada masalah dengan build, kekacauan yang menghubungkan. Namun, perubahan itu terlalu besar dan terlalu banyak untuk mengkonfigurasinya dengan sakelar di beberapa file konfigurasi, karena ini akan menyebabkan masalah selama penyebaran dan mungkin banyak masalah dukungan, terutama dengan admin tipe tinker.
Saya ingin agar sistem build membuat banyak build, satu untuk setiap klien, di mana perubahan terkandung dalam versi khusus dari modul fisik tunggal yang dimaksud. Jadi saya punya beberapa pertanyaan:
Apakah Anda menyarankan membiarkan sistem build membuat banyak build? Bagaimana saya harus menyimpan berbagai penyesuaian dalam kontrol sumber, khususnya svn?
#ifdef
berhasil untuk Anda?Jawaban:
Yang Anda butuhkan adalah fitur kode-seperti organisasi kode. Dalam skenario spesifik Anda, ini harus disebut percabangan trunk khusus untuk Klien karena Anda mungkin akan menggunakan percabangan fitur saat Anda mengembangkan hal-hal baru (atau menyelesaikan bug).
http://svnbook.red-bean.com/en/1.5/svn.branchmerge.commonpatterns.html
Idenya adalah untuk memiliki kode batang dengan cabang fitur baru digabung menjadi. Maksud saya semua fitur non-spesifik klien.
Kemudian Anda juga memiliki cabang khusus klien di mana Anda juga menggabungkan cabang fitur yang sama seperti yang diperlukan (memetik ceri jika Anda mau).
Cabang klien ini memang terlihat mirip dengan cabang fitur meskipun mereka tidak sementara atau berumur pendek. Mereka dipertahankan dalam jangka waktu yang lebih lama dan sebagian besar hanya digabung. Seharusnya ada sesedikit mungkin pengembangan cabang fitur khusus klien.
Cabang khusus klien adalah cabang paralel untuk trunk dan aktif selama trunk itu sendiri dan bahkan tidak digabung secara keseluruhan di mana saja.
sumber
Jangan lakukan ini dengan cabang SCM. Jadikan kode umum proyek terpisah yang menghasilkan perpustakaan atau artefak kerangka proyek. Setiap proyek pelanggan adalah proyek terpisah yang kemudian tergantung pada yang umum sebagai ketergantungan.
Ini paling mudah jika aplikasi basis umum Anda menggunakan kerangka kerja injeksi ketergantungan seperti Spring, sehingga Anda dapat dengan mudah menyuntikkan varian penggantian objek yang berbeda di setiap proyek pelanggan karena fitur khusus diperlukan. Bahkan jika Anda belum memiliki kerangka kerja DI, menambahkannya dan melakukannya dengan cara ini mungkin merupakan pilihan yang paling tidak menyakitkan.
sumber
Simpan perangkat lunak untuk semua klien dalam satu cabang. Tidak perlu menyimpang dari perubahan yang dibuat untuk klien yang berbeda. Paling lilkely, Anda ingin perangkat lunak Anda memiliki kualitas terbaik untuk semua klien, dan perbaikan bug untuk infrastruktur inti Anda harus memengaruhi semua orang tanpa perlu menggabungkan biaya overhead, yang juga dapat memperkenalkan lebih banyak bug.
Modularisasi kode umum, dan terapkan kode yang berbeda dalam file yang berbeda atau jaga dengan definisi yang berbeda. Jadikan sistem build Anda memiliki target spesifik untuk setiap klien, setiap target menyusun versi dengan hanya kode yang terkait dengan satu klien. Jika kode Anda adalah C, misalnya, Anda mungkin ingin menjaga fitur untuk klien yang berbeda dengan "
#ifdef
" atau mekanisme apa pun yang dimiliki bahasa Anda untuk membangun manajemen konfigurasi, dan menyiapkan serangkaian definisi yang berkaitan dengan jumlah fitur yang telah dibayar oleh klien.Jika Anda tidak suka
ifdef
, gunakan "antarmuka dan implementasi", "functors", "file objek" atau alat apa pun yang disediakan bahasa Anda untuk menyimpan berbagai hal di satu tempat.Jika Anda mendistribusikan sumber ke klien Anda, yang terbaik adalah membuat skrip bangunan Anda memiliki "target distribusi sumber" khusus. Setelah Anda memanggil target seperti itu, itu menciptakan versi khusus sumber perangkat lunak Anda, menyalinnya ke folder terpisah sehingga Anda dapat mengirimkannya, dan tidak mengkompilasinya.
sumber
Seperti yang telah dinyatakan oleh banyak orang: faktorkan kode Anda dengan benar dan sesuaikan berdasarkan kode umum — ini akan meningkatkan rawatan secara signifikan. Apakah Anda menggunakan bahasa / sistem yang berorientasi objek atau tidak, ini dimungkinkan (meskipun sedikit lebih sulit untuk dilakukan di C daripada sesuatu yang benar-benar berorientasi objek). Inilah jenis masalah yang harus diselesaikan oleh warisan dan enkapsulasi!
sumber
Dengan sangat hati-hati
Bercabang Fitur adalah pilihan tetapi saya merasa agak berat. Itu juga membuat modifikasi yang mendalam mudah yang dapat mengarah pada forking outking dari aplikasi Anda jika tidak tetap terkendali. Idealnya Anda ingin mendorong sebanyak mungkin kustomisasi dalam upaya untuk menjaga basis kode inti Anda sebagai umum dan generik mungkin.
Berikut adalah bagaimana saya akan melakukannya walaupun saya tidak tahu apakah itu berlaku untuk basis kode Anda tanpa modifikasi dan re-faktoring berat. Saya memiliki proyek serupa di mana fungsi dasarnya sama, tetapi setiap pelanggan memerlukan serangkaian fitur yang sangat spesifik. Saya membuat satu set modul dan wadah yang kemudian saya kumpulkan melalui konfigurasi (à la IoC).
kemudian untuk setiap pelanggan saya membuat proyek yang pada dasarnya berisi konfigurasi dan skrip build untuk membuat instalasi yang sepenuhnya dikonfigurasi untuk situs mereka. Kadang-kadang saya menempatkan di sana juga beberapa komponen yang dibuat khusus untuk klien ini. Tetapi ini jarang terjadi dan bila memungkinkan saya mencoba membuatnya dalam bentuk yang lebih umum dan menekannya sehingga proyek lain dapat menggunakannya.
Hasil akhirnya adalah saya mendapatkan tingkat penyesuaian yang saya butuhkan, saya mendapatkan skrip instalasi yang disesuaikan sehingga ketika saya sampai di situs pelanggan saya tidak terlihat seperti saya tweeking sistem sepanjang waktu dan sebagai tambahan bonus SANGAT signifikan saya dapatkan untuk dapat membuat tes regresi langsung ketagihan. Dengan cara ini, setiap saat saya mendapatkan bug yang spesifik untuk pelanggan, saya dapat menulis tes yang akan menegaskan sistem saat dikerahkan dan dengan demikian dapat melakukan TDD bahkan pada tingkat itu.
singkatnya:
Jika dilakukan dengan benar, perakitan produk Anda harus berisi semua kecuali beberapa file konfigurasi.
Setelah menggunakan ini untuk sementara waktu, saya akhirnya menciptakan paket meta yang merakit sistem yang paling banyak digunakan atau penting sebagai unit inti dan menggunakan paket meta ini untuk rakitan pelanggan. Setelah beberapa tahun saya akhirnya memiliki kotak peralatan besar yang dapat saya kumpulkan dengan sangat cepat untuk menciptakan solusi pelanggan. Saat ini saya sedang mencari di Spring Roo dan melihat apakah saya tidak bisa mendorong ide sedikit lebih jauh berharap suatu hari saya dapat membuat konsep pertama dari sistem dengan pelanggan dalam wawancara pertama kami ... Saya kira Anda bisa menyebutnya User Driven Pengembangan ;-).
Semoga ini bisa membantu
sumber
IMO, mereka tidak boleh terlalu kecil. Jika memungkinkan, saya akan memfaktorkan kode khusus klien menggunakan pola strategi di mana-mana. Ini akan mengurangi jumlah kode yang harus bercabang, dan mengurangi penggabungan yang diperlukan untuk menjaga sinkronisasi kode umum untuk semua klien. Ini juga akan menyederhanakan pengujian ... Anda dapat menguji kode umum menggunakan strategi default, dan menguji kelas khusus klien secara terpisah.
Jika modul Anda dikodekan sehingga menggunakan kebijakan X1 di modul A mengharuskan menggunakan kebijakan X2 di modul B, pikirkan tentang refactoring sehingga X1 dan X2 dapat digabungkan ke dalam satu kelas kebijakan tunggal.
sumber
Anda bisa menggunakan SCM Anda untuk memelihara cabang. Jaga agar cabang master tetap bersih dari kode khusus klien. Lakukan pengembangan utama pada cabang ini. Untuk setiap versi aplikasi yang disesuaikan mempertahankan cabang yang terpisah. Setiap alat SCM yang baik akan sangat baik dengan menggabungkan cabang (Git datang ke pikiran). Pembaruan apa pun di cabang master harus digabungkan ke cabang yang dikustomisasi, tetapi kode khusus klien dapat tetap berada di cabang sendiri.
Padahal, jika memungkinkan, cobalah untuk mendesain sistem dengan cara yang modular dan dapat dikonfigurasi. Kelemahan dari cabang-cabang khusus ini bisa jadi itu bergerak terlalu jauh dari inti / master.
sumber
Jika Anda menulis dalam huruf C, berikut adalah cara yang agak jelek untuk melakukannya.
Kode umum (misalnya unit "frangulator.c")
kode khusus klien, potongan yang kecil dan hanya digunakan untuk setiap klien.
dalam kode unit utama, gunakan #ifdef dan #include untuk melakukan sesuatu seperti
Gunakan ini sebagai pola berulang-ulang di semua unit kode yang membutuhkan kustomisasi khusus klien.
Ini SANGAT jelek, dan mengarah ke beberapa masalah lain tetapi juga sederhana, dan Anda dapat membandingkan file-file khusus klien satu dengan yang lainnya dengan sangat mudah.
Ini juga berarti bahwa semua bagian khusus klien terlihat jelas (masing-masing dalam file sendiri) setiap saat, dan ada hubungan yang jelas antara file kode utama dan bagian khusus klien dari file tersebut.
Jika Anda benar-benar pintar, Anda dapat mengatur makefile untuk membuat definisi klien yang benar jadi seperti:
membuat klien
akan membangun untuk client_a, dan "make clientb" akan membuat untuk client_b dan seterusnya.
(dan "membuat" tanpa target yang disediakan dapat mengeluarkan peringatan atau deskripsi penggunaan.)
Saya telah menggunakan ide yang sama sebelumnya, perlu beberapa saat untuk mengatur tetapi ini bisa sangat efektif. Dalam kasus saya satu pohon sumber membangun sekitar 120 produk yang berbeda.
sumber
Dalam git, cara saya akan melakukannya adalah memiliki cabang master dengan semua kode umum, dan cabang untuk setiap klien. Setiap kali perubahan kode inti dilakukan, rebase semua cabang khusus klien di atas master, sehingga Anda memiliki satu set tambalan untuk klien yang diterapkan di atas garis dasar saat ini.
Setiap kali Anda membuat perubahan untuk klien, dan melihat bug yang harus dimasukkan dalam cabang lain, Anda dapat memilih itu menjadi master, atau ke cabang lain yang perlu diperbaiki (meskipun cabang klien yang berbeda berbagi kode , Anda mungkin harus memiliki keduanya bercabang dari cabang yang sama dari master).
sumber