Bagaimana Anda mengatur perangkat lunak yang sangat khusus?

28

Saya sedang mengerjakan proyek perangkat lunak besar yang sangat disesuaikan untuk berbagai pelanggan di seluruh dunia. Ini berarti bahwa kami mungkin memiliki kode 80% yang umum di antara berbagai pelanggan, tetapi juga banyak kode yang harus diubah dari satu pelanggan ke pelanggan lainnya. Di masa lalu kami melakukan pengembangan dalam repositori terpisah (SVN) dan ketika sebuah proyek baru dimulai (kami memiliki sedikit, tetapi pelanggan besar) menciptakan repositori lain berdasarkan proyek apa pun yang memiliki basis kode terbaik untuk kebutuhan kita, apa pun proyek masa lalu. Ini telah berhasil di masa lalu, tetapi kami mengalami beberapa masalah:

  • Bug yang diperbaiki dalam satu repositori tidak ditambal dalam repositori lain. Ini mungkin masalah organisasi, tapi saya merasa sulit untuk memperbaiki dan menambal bug di 5 repositori yang berbeda, mengingat bahwa tim yang mengelola repositori ini mungkin ada di bagian lain dunia dan kami tidak memiliki lingkungan pengujian mereka , tidak tahu jadwal mereka atau persyaratan apa yang mereka miliki ("bug" di satu negara mungkin merupakan "fitur" di negara lain).
  • Fitur dan perbaikan yang dibuat untuk satu proyek, yang mungkin juga berguna untuk proyek lain hilang atau jika mereka digunakan dalam proyek lain sering menyebabkan sakit kepala besar menggabungkan mereka dari satu basis kode ke yang lain (karena kedua cabang mungkin telah dikembangkan secara mandiri selama satu tahun ).
  • Perbaikan dan peningkatan kode yang dibuat dalam satu cabang pengembangan hilang atau menyebabkan lebih banyak kerugian daripada manfaat jika Anda harus menggabungkan semua perubahan ini di antara cabang-cabang.

Kami sekarang sedang mendiskusikan bagaimana menyelesaikan masalah ini dan sejauh ini muncul dengan ide-ide berikut tentang bagaimana menyelesaikannya:

  1. Pertahankan pengembangan di cabang-cabang terpisah tetapi kelola lebih baik dengan memiliki repositori pusat tempat perbaikan bug umum digabungkan ke dalam dan mintalah semua proyek menggabungkan perubahan dari repositori pusat ini ke milik mereka sendiri secara teratur (misalnya setiap hari). Ini membutuhkan disiplin besar dan banyak upaya untuk bergabung di antara cabang-cabang. Jadi saya tidak yakin itu akan berhasil dan kita bisa menjaga disiplin ini, terutama ketika tekanan waktu masuk.

  2. Abaikan cabang pengembangan yang terpisah dan miliki repositori kode pusat tempat semua kode kita hidup dan lakukan kustomisasi kita dengan memiliki modul pluggable dan opsi konfigurasi. Kami sudah menggunakan wadah Dependency Injection untuk menyelesaikan dependensi dalam kode kami dan kami mengikuti pola MVVM di sebagian besar kode kami untuk memisahkan logika bisnis dari UI kami.

Pendekatan kedua tampaknya lebih elegan, tetapi kami memiliki banyak masalah yang belum terpecahkan dalam pendekatan ini. Misalnya: bagaimana menangani perubahan / penambahan dalam model / basis data Anda. Kami menggunakan .NET dengan Entity Framework untuk memiliki entitas yang sangat diketik. Saya tidak melihat bagaimana kami dapat menangani properti yang diperlukan untuk satu pelanggan tetapi tidak berguna untuk pelanggan lain tanpa mengacaukan model data kami. Kami berpikir untuk menyelesaikan ini dalam database dengan menggunakan tabel satelit (memiliki tabel terpisah di mana kolom tambahan kami untuk entitas tertentu hidup dengan pemetaan 1: 1 ke entitas asli), tetapi ini hanya database. Bagaimana Anda menangani ini dalam kode? Model data kami tinggal di perpustakaan pusat yang kami tidak akan dapat memperluas untuk setiap pelanggan menggunakan pendekatan ini.

Saya yakin bahwa kami bukan satu-satunya tim yang berjuang dengan masalah ini dan saya terkejut menemukan begitu sedikit materi tentang topik ini.

Jadi pertanyaan saya adalah sebagai berikut:

  1. Pengalaman apa yang Anda miliki dengan perangkat lunak yang sangat khusus, pendekatan apa yang Anda pilih dan bagaimana cara kerjanya untuk Anda?
  2. Pendekatan apa yang Anda rekomendasikan dan mengapa? Apakah ada pendekatan yang lebih baik?
  3. Apakah ada buku atau artikel bagus tentang topik yang dapat Anda rekomendasikan?
  4. Apakah Anda memiliki rekomendasi khusus untuk lingkungan teknis kami (.NET, Entity Framework, WPF, DI)?

Edit:

Terima kasih atas semua sarannya. Sebagian besar ide cocok dengan yang sudah kami miliki di tim kami, tetapi sangat membantu untuk melihat pengalaman yang Anda miliki dengan mereka dan tips untuk menerapkannya dengan lebih baik.

Saya masih tidak yakin ke arah mana kita akan pergi dan saya tidak membuat keputusan (sendirian), tetapi saya akan meneruskan ini dalam tim saya dan saya yakin itu akan membantu.

Saat ini tenor tampaknya menjadi repositori tunggal menggunakan berbagai modul khusus pelanggan. Saya tidak yakin arsitektur kami mencapai ini atau berapa banyak yang harus kami investasikan untuk membuatnya cocok, jadi beberapa hal mungkin tinggal di repositori terpisah untuk sementara waktu, tetapi saya pikir itu satu-satunya solusi jangka panjang yang akan bekerja.

Jadi, terima kasih sekali lagi untuk semua tanggapan!

aKzenT
sumber
Pertimbangkan memperlakukan tabel database sebagai kode.
Kami sudah melakukan ini dalam arti bahwa kami memiliki skrip database kami di repositori subversi kami, tetapi itu tidak benar-benar menyelesaikan masalah yang disebutkan di atas. Kami tidak ingin memiliki tabel gaya Nilai Kunci di model database kami karena mereka datang dengan banyak masalah. Jadi, bagaimana Anda mengizinkan penambahan pada model Anda untuk masing-masing pelanggan sambil tetap mempertahankan repositori kode bersama untuk semuanya?
aKzenT

Jawaban:

10

Kedengarannya seperti masalah mendasar bukan hanya pemeliharaan repositori kode, tetapi kurangnya arsitektur yang sesuai .

  1. Apa inti / esensi dari sistem, yang akan selalu dibagikan oleh semua sistem?
  2. Penyempurnaan / penyimpangan apa yang dibutuhkan oleh setiap pelanggan?

Kerangka kerja atau pustaka standar meliputi yang pertama, sedangkan yang kedua akan diimplementasikan sebagai add-on (plugins, subclass, DI, apa pun yang masuk akal untuk struktur kode).

Sistem kontrol sumber yang mengelola cabang dan pengembangan yang didistribusikan mungkin akan membantu juga; Saya penggemar Mercurial, yang lain lebih suka Git. Kerangka kerja akan menjadi cabang utama, setiap sistem yang disesuaikan akan menjadi cabang pembantu, misalnya.

Teknologi spesifik yang digunakan untuk mengimplementasikan sistem (.NET, WPF, apa pun) sebagian besar tidak penting.

Mendapatkan ini dengan benar tidak mudah , tetapi sangat penting untuk kelangsungan hidup jangka panjang. Dan tentu saja semakin lama Anda menunggu, semakin besar utang teknis yang harus Anda tangani.

Anda dapat menemukan buku Arsitektur Perangkat Lunak: Prinsip dan Pola Organisasi berguna.

Semoga berhasil!

Steven A. Lowe
sumber
3
Ya. Arsitektur seringkali lebih merupakan hal psikologis daripada hal teknis sekalipun. Jika Anda benar-benar fokus pada produk, maka Anda akan berakhir dengan gangguan kerja di mana komponen hanya berguna untuk produk itu. Jika, di sisi lain, Anda fokus membangun satu set perpustakaan yang akan lebih bermanfaat secara umum, maka Anda membangun serangkaian kemampuan yang dapat digunakan dalam berbagai situasi yang lebih luas. Kuncinya, tentu saja, adalah menemukan keseimbangan yang tepat antara kedua ekstrem ini untuk situasi khusus Anda.
William Payne
Saya pikir ada bagian besar yang dibagi antara banyak cabang kami (> 90%), tetapi 10% terakhir selalu di tempat yang berbeda, jadi ada sangat sedikit komponen di mana saya tidak bisa membayangkan beberapa perubahan spesifik pelanggan kecuali untuk beberapa perpustakaan utilitas yang tidak mengandung logika bisnis apa pun.
aKzenT
@ aKzenT: hmmm ... jangan bayangkan, ukur saja. Survei kode dan lihat semua tempat di mana kustomisasi telah terjadi, buat daftar komponen yang dimodifikasi, perhatikan seberapa sering setiap komponen telah dimodifikasi, dan pikirkan tentang jenis dan pola modifikasi yang sebenarnya telah dilakukan. Apakah itu kosmetik atau algoritmik? Apakah mereka menambah atau mengubah fungsi basis? Apa alasan untuk setiap jenis perubahan? Sekali lagi, ini adalah kerja keras , dan Anda mungkin tidak menyukai implikasi dari apa yang Anda temukan.
Steven A. Lowe
1
Saya menerima ini sebagai jawabannya, karena kita tidak dapat mengambil keputusan ini sebelum berpikir lebih banyak tentang arsitektur kita, mengidentifikasi bagian-bagian yang umum atau yang HARUS umum dan kemudian melihat apakah kita dapat hidup dengan repositori tunggal atau jika forking diperlukan (untuk paling tidak saat ini). Jawaban ini mencerminkan IMO terbaik ini. Terima kasih untuk semua posting lainnya!
aKzenT
11

Satu perusahaan tempat saya bekerja memiliki masalah yang sama, dan pendekatan untuk mengatasi masalah ini adalah ini: Kerangka kerja umum untuk semua proyek baru telah dibuat; ini termasuk semua hal yang harus sama di setiap proyek. Misalnya alat penghasil formulir, ekspor ke Excel, pencatatan. Upaya diambil untuk memastikan bahwa kerangka kerja umum ini hanya ditingkatkan (ketika proyek baru membutuhkan fitur baru), tetapi tidak pernah bercabang dua.

Berdasarkan kerangka kerja itu, kode khusus pelanggan dipertahankan dalam repositori terpisah. Bila berguna atau perlu, perbaikan bug dan peningkatan disalin-salin antara proyek (dengan semua peringatan yang dijelaskan dalam pertanyaan). Perbaikan yang bermanfaat secara global masuk ke dalam kerangka kerja umum.

Memiliki semuanya dalam basis kode yang sama untuk semua pelanggan memiliki beberapa keuntungan, tetapi di sisi lain, membaca kode menjadi sulit ketika ada banyak yang ifmembuat program berperilaku berbeda untuk setiap pelanggan.

EDIT: Satu anekdot untuk menjadikan ini lebih dimengerti:

Domain perusahaan itu adalah manajemen gudang, dan satu tugas sistem manajemen gudang adalah menemukan lokasi penyimpanan gratis untuk barang yang masuk. Kedengarannya mudah, tetapi dalam praktiknya, banyak kendala dan strategi harus diperhatikan.

Pada satu titik waktu, manajemen meminta seorang programmer untuk membuat modul yang fleksibel dan parameterisable untuk menemukan lokasi penyimpanan, yang menerapkan beberapa strategi berbeda dan seharusnya digunakan dalam semua proyek berikutnya. Upaya mulia menghasilkan modul yang kompleks, yang sangat sulit dipahami dan dipelihara. Dalam proyek berikutnya, pimpinan proyek tidak dapat menemukan cara untuk membuatnya bekerja di gudang itu, dan pengembang modul tersebut hilang, jadi ia akhirnya mengabaikannya dan menulis algoritma khusus untuk tugas itu.

Beberapa tahun kemudian, tata letak gudang tempat modul ini awalnya digunakan berubah, dan modul dengan semua fleksibilitasnya tidak sesuai dengan persyaratan baru; jadi saya menggantinya dengan algoritma khusus di sana juga.

Saya tahu LOC bukanlah pengukuran yang baik, tetapi bagaimanapun: ukuran modul "fleksibel" adalah ~ 3000 LOC (PL / SQL), sementara modul khusus untuk tugas yang sama membutuhkan ~ 100..250 LOC. Oleh karena itu, mencoba menjadi fleksibel sangat meningkatkan ukuran basis kode, tanpa mendapatkan usabilitas yang kami harapkan.

pengguna281377
sumber
Terima kasih atas tanggapan Anda. Ini merupakan perpanjangan dari solusi pertama yang dijelaskan dan kami memikirkan hal ini juga. Namun karena sebagian besar perpustakaan kami menggunakan beberapa entitas inti dan entitas inti ini biasanya diperluas untuk satu pelanggan atau yang lain, saya pikir kami hanya dapat menempatkan sedikit perpustakaan di repositori inti ini. Misalnya, kita memiliki entitas "Pelanggan" yang ditentukan dan ORM dipetakan dalam satu perpustakaan yang digunakan oleh hampir semua perpustakaan dan program kami yang lain. Tetapi setiap klien memiliki beberapa bidang tambahan yang mereka perlu tambahkan ke "Pelanggan" sehingga kami harus memotong perpustakaan ini dan karenanya semua perpustakaan bergantung padanya.
aKzenT
3
Gagasan kami untuk menghindari "seandainya" yang tak terhitung jumlahnya adalah untuk menggunakan injeksi ketergantungan secara ekstensif dan bertukar modul lengkap untuk pelanggan yang berbeda. Tidak yakin bagaimana ini akan berhasil. Bagaimana pendekatan ini bekerja untuk Anda?
aKzenT
+1, ini pada dasarnya sesuai dengan pengalaman saya tentang proyek yang telah menangani ini dengan baik. Jika Anda akan menggunakan pendekatan 'jika untuk pelanggan yang berbeda', 2 poin: 1. Jangan lakukan jika (pelanggan1) ..., sebaliknya lakukan jika (konfigurasiOpsi1) ... dan memiliki opsi konfigurasi per-pelanggan. 2. Cobalah untuk tidak melakukannya! Mungkin 1% dari waktu yang akan menjadi pilihan yang lebih baik (lebih dimengerti / mudah dikelola) daripada memiliki modul konfigurasi khusus.
vaughandroid
@ Baqueta: Hanya untuk memperjelas: Anda merekomendasikan penggunaan modul per-pelanggan daripada opsi konfigurasi (jika), kan? Saya suka ide Anda untuk membedakan antara fitur dan bukan pelanggan. Jadi kombinasi keduanya adalah memiliki berbagai "modul fitur" yang dikendalikan oleh opsi konfigurasi. Pelanggan kemudian hanya direpresentasikan sebagai satu set modul fitur independen. Saya suka pendekatan ini banyak, tapi saya tidak yakin bagaimana merancang ini. DI menyelesaikan masalah pemuatan dan pertukaran modul, tetapi bagaimana Anda mengelola model data yang berbeda antara pelanggan?
aKzenT
Yup, modul per-fitur dan kemudian konfigurasi / pemilihan fitur per-pelanggan. DI akan ideal. Sayangnya saya tidak pernah harus menggabungkan persyaratan kustomisasi besar per pelanggan Anda dengan satu pustaka data, jadi saya tidak yakin saya bisa banyak membantu di sana ...
vaughandroid
5

Salah satu proyek yang saya kerjakan pada banyak platform yang didukung (lebih dari 5) di sejumlah besar rilis produk. Banyak tantangan yang Anda gambarkan adalah hal-hal yang kami hadapi, meskipun dengan cara yang sedikit berbeda. Kami memiliki DB berpemilik, jadi kami tidak memiliki jenis masalah yang sama di arena itu.

Struktur kami mirip dengan milik Anda, tetapi kami memiliki satu repositori untuk kode kami. Kode spesifik platform masuk ke folder proyek mereka sendiri di dalam pohon kode. Kode umum hidup di dalam pohon berdasarkan pada lapisan apa itu.

Kami memiliki kompilasi bersyarat, berdasarkan pada platform yang sedang dibangun. Mempertahankan itu agak merepotkan, tetapi itu hanya harus dilakukan ketika modul baru ditambahkan pada lapisan platform tertentu.

Memiliki semua kode dalam satu repositori membuatnya mudah bagi kami untuk melakukan perbaikan bug di beberapa platform dan rilis pada saat yang sama. Kami memiliki lingkungan build otomatis untuk semua platform untuk dijadikan sebagai backstop jika kode baru merusak platform yang dianggap tidak terkait.

Kami mencoba untuk mencegahnya, tetapi akan ada kasus di mana platform membutuhkan perbaikan berdasarkan bug khusus platform yang ada dalam kode umum. Jika kita dapat mengganti kompilasi secara kondisional tanpa membuat modul terlihat buruk, kita akan melakukannya terlebih dahulu. Jika tidak, kami akan memindahkan modul dari wilayah umum dan mendorongnya ke platform tertentu.

Untuk database, kami memiliki beberapa tabel yang memiliki kolom / modifikasi platform khusus. Kami akan memastikan bahwa setiap versi platform dari tabel memenuhi tingkat fungsionalitas dasar sehingga kode umum dapat merujuknya tanpa khawatir tentang ketergantungan platform. Permintaan / manipulasi khusus platform didorong ke dalam lapisan proyek platform.

Jadi, untuk menjawab pertanyaan Anda:

  1. Banyak, dan itu adalah salah satu tim terbaik yang pernah bekerja dengan saya. Basis kode pada waktu itu sekitar 1M loc. Saya tidak bisa memilih pendekatan, tetapi berhasil dengan sangat baik. Bahkan di belakang, saya belum melihat cara yang lebih baik dalam menangani berbagai hal.
  2. Saya merekomendasikan pendekatan kedua yang Anda sarankan dengan nuansa yang saya sebutkan dalam jawaban saya.
  3. Tidak ada buku yang bisa saya pikirkan, tetapi saya akan meneliti pengembangan multi-platform sebagai starter.
  4. Melembagakan pemerintahan yang kuat. Ini adalah kunci untuk memastikan standar pengkodean Anda diikuti. Mengikuti standar-standar itu adalah satu-satunya cara untuk menjaga hal-hal dapat dikelola dan dikelola. Kami memiliki bagian dari permohonan kami yang berapi-api untuk mematahkan model yang kami ikuti, tetapi tidak satu pun dari permohonan itu yang pernah mempengaruhi seluruh tim pengembangan senior.

sumber
Terima kasih telah berbagi pengalaman Anda. Untuk lebih memahami: Bagaimana platform didefinisikan dalam kasus Anda. Windows, Linux, X86 / x64? Atau sesuatu yang lebih terkait dengan pelanggan / lingkungan yang berbeda? Anda membuat poin yang bagus dalam 4) Saya pikir ini adalah salah satu masalah yang kita miliki. Kami memiliki tim yang terdiri dari orang-orang yang sangat pintar dan berkualitas, tetapi setiap orang memiliki gagasan yang sedikit berbeda tentang cara melakukan sesuatu. Tanpa seseorang yang jelas bertanggung jawab atas arsitektur, sulit untuk menyetujui strategi bersama dan Anda berisiko kehilangan diri dalam diskusi tanpa mengubah apa pun.
aKzenT
@ aKzenT - ya, maksud saya perangkat keras fisik dan OS sebagai platform. Kami memiliki serangkaian fitur besar, beberapa di antaranya dapat dipilih oleh modul lisensi. Dan kami mendukung beragam perangkat keras. Terkait dengan itu, kami memiliki direktori lapisan umum yang memiliki banyak perangkat dengan direktori mereka sendiri di lapisan itu untuk pohon kode. Jadi keadaan kita sebenarnya tidak terlalu jauh dari tempatmu sekarang. Para pengembang senior kami akan memicu debat satu sama lain, tetapi begitu keputusan kolektif dibuat, semua orang setuju untuk melakukannya.
4

Saya bekerja selama bertahun-tahun pada aplikasi Administrasi Pensiun yang memiliki masalah serupa. Rencana pensiun sangat berbeda antara perusahaan, dan membutuhkan pengetahuan yang sangat khusus untuk menerapkan logika perhitungan dan laporan dan juga desain data yang sangat berbeda. Saya hanya bisa memberikan deskripsi singkat tentang bagian dari arsitektur, tetapi mungkin itu akan memberikan cukup banyak ide.

Kami memiliki 2 tim terpisah: tim pengembangan inti , yang bertanggung jawab atas kode sistem inti (yang akan menjadi 80% kode bersama Anda di atas), dan tim implementasi , yang memiliki keahlian domain dalam sistem pensiun, dan bertanggung jawab untuk mempelajari klien persyaratan dan skrip skrip dan laporan untuk klien.

Kami memiliki semua tabel kami yang ditentukan oleh Xml (ini sebelum waktu ketika kerangka kerja entitas diuji-waktu dan umum). Tim implementasi akan mendesain semua tabel dalam Xml, dan aplikasi inti dapat diminta untuk menghasilkan semua tabel di Xml. Ada juga file skrip VB terkait, Crystal Reports, Word docs dll untuk setiap klien. (Ada juga model warisan yang dibangun ke dalam Xml untuk memungkinkan penggunaan kembali implementasi lain).

Aplikasi inti (satu aplikasi untuk semua klien), akan men-cache semua hal spesifik klien ketika permintaan untuk klien itu datang, dan itu menghasilkan objek data umum (seperti kumpulan catatan ADO jarak jauh), yang dapat diserialisasi dan disahkan sekitar.

Model data ini kurang apik dari objek entitas / domain, tetapi sangat fleksibel, universal, dan dapat diproses oleh satu set kode inti. Mungkin dalam kasus Anda, Anda bisa mendefinisikan objek entitas dasar Anda hanya dengan bidang umum, dan memiliki Kamus tambahan untuk bidang khusus (tambahkan beberapa jenis set deskriptor data ke objek entitas Anda sehingga memiliki meta data untuk bidang kustom. )

Kami memiliki repositori sumber terpisah untuk kode sistem inti dan untuk kode implementasi.

Sistem inti kami sebenarnya memiliki logika bisnis yang sangat sedikit, selain beberapa modul perhitungan umum yang sangat standar. Sistem inti berfungsi sebagai: generator layar, script runner, generator laporan, akses data dan lapisan transport.

Mengelompokkan logika inti dan logika khusus adalah tantangan yang sulit. Namun, kami selalu merasa lebih baik memiliki satu sistem inti yang menjalankan banyak klien, daripada beberapa salinan dari sistem yang berjalan untuk setiap klien.

Sam Goldberg
sumber
Terima kasih untuk umpan baliknya. Saya suka gagasan memiliki bidang tambahan dalam kamus. Ini akan memungkinkan kami untuk memiliki definisi tunggal dari suatu entitas dan memasukkan semua hal spesifik klien ke dalam kamus. Saya tidak yakin apakah ada cara yang baik untuk membuatnya bekerja dengan pembungkus ORM kami (Entity Framework). Dan saya juga tidak yakin apakah itu benar-benar ide yang baik untuk memiliki model data yang dibagikan secara global alih-alih memiliki model untuk setiap fitur / modul.
aKzenT
2

Saya telah bekerja pada sistem yang lebih kecil (20 kloc), dan menemukan bahwa DI dan konfigurasi keduanya merupakan cara yang bagus untuk mengelola perbedaan antara klien, tetapi tidak cukup untuk menghindari forking sistem. Basis data dibagi antara bagian spesifik aplikasi, yang memiliki skema tetap, dan bagian bergantung klien, yang didefinisikan melalui dokumen konfigurasi XML kustom.

Kami telah menyimpan cabang tunggal dalam lincah yang dikonfigurasi seolah-olah itu dapat dikirimkan, tetapi bermerek dan dikonfigurasi untuk klien fiksi. Perbaikan bug diarahkan pada proyek itu, dan pengembangan baru fungsi inti hanya terjadi di sana. Pers untuk klien yang sebenarnya adalah cabang dari itu, disimpan dalam repositori mereka sendiri. Kami melacak perubahan besar pada kode melalui nomor versi yang ditulis secara manual dan melacak perbaikan bug menggunakan nomor komit.

Dan Monego
sumber
apakah Anda membedakan antara perpustakaan inti yang sama antara pelanggan atau apakah Anda memotong pohon lengkap? Apakah Anda secara teratur bergabung dari jalur utama ke garpu individual? Dan jika ya, berapa lama waktu yang diperlukan untuk menggabungkan rutinitas harian dan bagaimana Anda menghindari prosedur ini berantakan ketika tekanan waktu dimulai (seperti yang selalu terjadi pada satu titik dalam proyek)? Maaf untuk banyak pertanyaan: p
aKzenT
Kami memotong seluruh pohon, terutama karena permintaan klien datang sebelum membangun integritas sistem. Penggabungan dari sistem utama terjadi secara manual menggunakan alat-alat merkuri dan lainnya, dan biasanya terbatas pada bug penting atau pembaruan fitur besar. Kami mencoba menyimpan pembaruan untuk bongkahan besar yang jarang terjadi, baik karena biaya penggabungan, dan karena banyak klien meng-host sistem mereka sendiri dan kami tidak ingin memasukkan biaya pemasangan ke mereka tanpa memberikan nilai.
Dan Monego
Saya ingin tahu: IIRC lincah adalah DVCS mirip dengan git. Apakah Anda melihat ada keuntungan melakukan penggabungan antara cabang dibandingkan dengan Subversion atau VCS tradisional lainnya? Saya baru saja menyelesaikan proses penggabungan yang sangat menyakitkan antara 2 cabang yang dikembangkan sepenuhnya terpisah menggunakan subversi dan berpikir apakah akan lebih mudah jika kita menggunakan git.
aKzenT
Penggabungan dengan mercurial jauh lebih mudah daripada menggabungkan dengan alat kami sebelumnya, yaitu Vault. Salah satu keuntungan utama adalah bahwa lincah sangat bagus untuk menempatkan sejarah perubahan di bagian depan dan tengah dalam aplikasi, yang membuatnya mudah untuk melacak apa yang dilakukan di mana. Bagian yang paling sulit bagi kami adalah memindahkan cabang yang ada - jika Anda menggabungkan dua cabang, mercurial mengharuskan keduanya memiliki root yang sama, jadi untuk menyiapkannya diperlukan satu penggabungan manual yang terakhir.
Dan Monego
2

Saya khawatir bahwa saya tidak memiliki pengalaman langsung tentang masalah yang Anda uraikan, tetapi saya memiliki beberapa komentar.

Opsi kedua, menyatukan kode ke dalam repositori pusat (sebanyak mungkin), dan merancang kustomisasi (sekali lagi, sebanyak mungkin) hampir pasti merupakan cara untuk pergi dalam jangka panjang.

Masalahnya adalah bagaimana Anda berencana untuk sampai di sana, dan berapa lama waktu yang dibutuhkan.

Dalam situasi ini, mungkin OK untuk (sementara) memiliki lebih dari satu salinan aplikasi dalam repositori sekaligus.

Ini akan memungkinkan Anda untuk secara bertahap pindah ke arsitektur yang secara langsung mendukung kustomisasi tanpa harus melakukannya sekaligus.

William Payne
sumber
2

Pendekatan kedua tampaknya lebih elegan, tetapi kami memiliki banyak masalah yang belum terpecahkan dalam pendekatan ini.

Saya yakin semua masalah itu dapat diselesaikan, satu demi satu. Jika Anda buntu, tanyakan di sini atau di SO tentang masalah spesifik.

Seperti yang telah ditunjukkan orang lain, memiliki satu basis kode pusat / satu repositori adalah opsi yang harus Anda pilih. Saya mencoba menjawab pertanyaan contoh Anda.

Misalnya: bagaimana menangani perubahan / penambahan dalam model / basis data Anda. Kami menggunakan .NET dengan Entity Framework untuk memiliki entitas yang sangat diketik. Saya tidak melihat bagaimana kami dapat menangani properti yang diperlukan untuk satu pelanggan tetapi tidak berguna untuk pelanggan lain tanpa mengacaukan model data kami.

Ada beberapa kemungkinan, semuanya telah saya lihat di sistem dunia nyata. Yang mana yang akan dipilih tergantung pada situasi Anda:

  • hidup dengan kekacauan sampai tingkat tertentu
  • perkenalkan tabel "CustomAttributes" (menggambarkan nama dan tipe) dan "CustomAttributeValues" (untuk nilai-nilai, misalnya disimpan sebagai representasi string, bahkan jika itu adalah angka). Itu akan memungkinkan untuk menambahkan atribut tersebut pada waktu instal atau waktu berjalan, memiliki nilai individual untuk setiap pelanggan. Jangan memaksakan setiap atribut khusus dimodelkan "terlihat" di model data Anda.

  • sekarang harus jelas bagaimana menggunakannya dalam kode: hanya memiliki kode umum untuk mengakses tabel-tabel itu, dan kode individual (mungkin dalam DLL plug-in yang terpisah, terserah Anda) untuk menafsirkan atribut itu dengan benar

  • alternatif lain adalah memberi setiap tabel entitas bidang string besar di mana Anda dapat menambahkan XML-string individual.
  • mencoba menggeneralisasi beberapa konsep, sehingga bisa lebih mudah digunakan kembali di berbagai pelanggan. Saya merekomendasikan buku Martin Fowler " Pattern analysis ". Meskipun buku ini bukan tentang menyesuaikan sendiri peranti lunak, mungkin juga bermanfaat bagi Anda.

Dan untuk kode spesifik: Anda juga dapat mencoba memperkenalkan bahasa skrip ke dalam produk Anda, terutama untuk menambahkan skrip khusus pelanggan. Dengan cara itu Anda tidak hanya membuat garis yang jelas antara kode Anda dan kode khusus pelanggan, Anda juga dapat memungkinkan pelanggan Anda untuk menyesuaikan sistem sampai tingkat tertentu sendiri.

Doc Brown
sumber
Masalah yang saya lihat dengan menambahkan kolom CustomAttributes atau XML untuk menyimpan properti khusus adalah kemampuannya sangat terbatas. Misalnya melakukan penyortiran, pengelompokan atau penyaringan berdasarkan atribut ini sangat menantang. Saya pernah bekerja pada sistem yang menggunakan tabel atribut ekstra dan menjadi semakin kompleks untuk mempertahankan dan menangani atribut khusus ini. Untuk alasan ini saya berpikir alih-alih meletakkan atribut ini sebagai kolom dalam tabel tambahan yang dipetakan 1: 1 ke aslinya. Masalah tentang cara mendefinisikan, meminta dan mengelola ini masih sama.
aKzenT
@ aKzenT: Kustomisasi tidak datang secara gratis, Anda harus menukar kemudahan penggunaan dengan kustomisasi. Saran umum saya adalah bahwa Anda tidak memperkenalkan dependensi di mana bagian inti dari sistem tergantung dengan cara apa pun dari bagian kustom, hanya sebaliknya. Misalnya, ketika memperkenalkan "tabel tambahan" ini untuk pelanggan 1, dapatkah Anda menghindari penggunaan tabel itu dan kode terkait untuk pelanggan 2? Jika jawabannya ya, maka solusinya ok.
Doc Brown
0

Saya hanya membangun satu aplikasi seperti itu. Saya akan mengatakan bahwa 90% dari unit yang terjual terjual apa adanya, tanpa modifikasi. Setiap pelanggan memiliki kulit khusus mereka sendiri dan kami melayani sistem di dalam kulit itu. Ketika ada mod yang mempengaruhi bagian inti, kami mencoba menggunakan IF branching . Ketika mod # 2 masuk untuk bagian yang sama kami beralih ke logika CASE yang diizinkan untuk ekspansi di masa depan. Ini tampaknya menangani sebagian besar permintaan kecil.

Permintaan khusus minor apa pun ditangani dengan menerapkan logika Kasus.

Jika mod dua radikal, kami membangun klon (terpisah termasuk) dan melampirkan KASUS di sekitarnya untuk memasukkan modul yang berbeda.

Perbaikan bug dan modifikasi pada intinya mempengaruhi semua pengguna. Kami diuji secara menyeluruh dalam pengembangan sebelum pergi ke produksi. Kami selalu mengirimkan pemberitahuan email yang menyertai perubahan dan TIDAK PERNAH, TIDAK PERNAH, TIDAK PERNAH diposting perubahan produksi pada hari Jumat ... TIDAK PERNAH.

Lingkungan kami adalah ASP Klasik dan SQL Server. Kami BUKAN toko kode spageti ... Semuanya modular menggunakan Termasuk, Subroutine, dan Fungsi.

Michael Riley - AKA Gunny
sumber
-1

Ketika saya diminta untuk memulai pengembangan B yang berbagi fungsionalitas 80% dengan A, saya akan:

  1. Klon A dan memodifikasinya.
  2. Ekstrak fungsionalitas yang dibagikan A dan B ke dalam C yang akan mereka gunakan.
  3. Jadikan A cukup dapat dikonfigurasi untuk memenuhi kebutuhan B dan dirinya sendiri (oleh karena itu B disematkan dalam A).

Anda memilih 1, dan sepertinya tidak cocok dengan situasi Anda. Misi Anda adalah untuk memprediksi mana dari 2 dan 3 yang lebih cocok.

Moshe Revah
sumber
1
Kedengarannya mudah, tetapi bagaimana melakukan ini dalam praktek? Bagaimana Anda membuat perangkat lunak Anda begitu dapat dikonfigurasi tanpa mengacaukannya dengan "if (customer1)", yang menjadi tidak dapat dipelihara setelah beberapa waktu.
aKzenT
@ aKzenT Itu sebabnya saya meninggalkan 2 dan 3 untuk Anda pilih. Jika jenis perubahan yang diperlukan untuk membuat proyek customer1 mendukung kebutuhan pelanggan2 melalui konfigurasi akan membuat kode tidak dapat dipelihara maka jangan lakukan 3.
Moshe Revah
Saya lebih suka melakukan "if (option1)" daripada "if (customer1)". Dengan cara ini dengan opsi N saya dapat mengatur banyak pelanggan yang mungkin. Misalnya dengan opsi N boolean Anda dapat mengelola 2 ^ N pelanggan, hanya memiliki N 'jika' ... tidak mungkin dikelola dengan strategi "jika (pelanggan1)" yang membutuhkan 2 ^ N 'jika'.
Fil