Birden fazla müşteri için aynı yazılımın farklı, özelleştirilmiş sürümleri nasıl korunur


46

farklı ihtiyaçları olan birden fazla müşterimiz var. Yazılımımız bir dereceye kadar modüler hale getirilmiş olsa da, hemen hemen her modülün iş mantığını burada ve her müşteri için biraz ayarlamamız gerektiği kesindir. Değişiklikler muhtemelen modülü her bir müşteri için ayrı (fiziksel) bir modüle bölmeyi haklı çıkarmak için çok ufak, derlemeyle ilgili sorunlardan korkuyorum, bağlantı kaosundan korkuyorum. Ancak, bu değişiklikler, bazı yapılandırma dosyalarındaki anahtarlarla bunları yapılandıramayacak kadar büyüktür, çünkü bu dağıtım sırasında sorunlara ve özellikle de tinker tipi yöneticilerle çok fazla destek sorununa yol açacaktır.

Yapı sisteminin, her bir müşteri için bir tane olmak üzere, değişikliklerin söz konusu tek bir fiziksel modülün özel bir sürümünde bulunduğu birden fazla yapı oluşturmasını istiyorum. Bu yüzden bazı sorularım var:

Yapı sisteminin birden çok yapı oluşturmasına izin vermenizi tavsiye eder misiniz? Farklı özelleştirmeleri, özellikle svn kaynak kontrolünde nasıl saklamalıyım?


4
Sizin için #ifdefçalışıyor mu
saat

6
Önişlemci direktifleri hızla çok karmaşık bir hal alabilir ve kodun okunmasını zorlaştırır ve hata ayıklamasını zorlaştırır.
Falcon

1
Daha iyi cevaplar için gerçek platform ve uygulama türü (masaüstü / web) hakkındaki ayrıntıları içermelisiniz. Bir masaüstünde C ++ uygulamasında özelleştirme yapmak PHP web uygulamasından tamamen farklıdır.
GrandmasterB

2
@Falcon: 2011'de bir cevap seçtiğimden beri şüphelerim var, aralarında önerilen şekilde SVN kullanma konusunda herhangi bir deneyiminiz olup olmadığını söyleyebilir misiniz? İtirazlarım kötümser mi?
Doc Brown,

2
@Doc Brown: Dallanma ve birleşme sıkıcı ve karmaşıktı. O zamanlar, müşteriye özel eklentileri ya da davranış ve konfigürasyonları değiştiren "yamaları" içeren bir eklenti sistemi kullandık. Tepegözünüz olacak ama Dependendy Injection ile yönetilebilir.
Şahin,

Yanıtlar:


7

İhtiyacınız olan şey dallanma benzeri kod organizasyonu. Özel senaryonuzda buna Müşteriye özel ana dallanma adı verilmelidir, çünkü yeni şeyler geliştirirken (veya hataları giderirken) büyük olasılıkla özellik dallandırma kullanacaksınız.

http://svnbook.red-bean.com/en/1.5/svn.branchmerge.commonpatterns.html

Buradaki fikir yeni özelliklerin dallarının birleştiği bir kod gövdesine sahip olmak. Müşteriye özel olmayan tüm özellikleri kastediyorum.

Daha sonra, müşteriye özel şubeleriniz de vardır ; burada aynı özelliklere sahip şubeleri de gerektiği gibi birleştirirsiniz (kirazlı toplama).

Bu müşteri dalları, geçici ya da kısa ömürlü olmasalar da özellik dallarına benzer. Uzun bir süre boyunca korunurlar ve esas olarak sadece birleştirilirler. Müşteriye özgü özellik dalı gelişimi mümkün olduğunca az olmalıdır.

Müşteriye özel şubeler gövdeye paralel şubelerdir ve gövdenin kendisi kadar etkindirler ve hatta hiçbir yerde bütünleşmezler.

            feature1
            ———————————.
                        \
trunk                    \
================================================== · · ·
      \ client1            \
       `========================================== · · ·
        \ client2            \
         `======================================== · · ·
              \ client2-specific feature   /
               `——————————————————————————´

7
Özel dallanma için +1. Her müşteri için de bir dal kullanabilirsiniz. Tek bir şey önermek isterim: Bunu başarmak için SVN / CVS yerine dağıtılmış bir VCS (hg, git, bzr) kullanın;)
Herberth Amaral

42
-1. “Özellik dalları” bunun için değildir; "bir özelliğin geliştirilmesi sona erdiğinde birleşen geçici dallar" olarak tanımlarıyla çelişir.
P

13
Tüm bu deltaları kaynak kontrolünde tutmanız ve onları düzenli tutmanız gerekir - sonsuza dek. Kısa vadede bu işe yarayabilir. Uzun vadede korkunç olabilir.
hızla_

4
-1, bu bir adlandırma problemi değil - farklı istemciler için farklı dallar kullanmak sadece başka bir kod çoğaltma yöntemi. Bu IMHO'nun bir anti-paterni, nasıl yapılmayacağı örneği.
Doc Brown,

6
Robert, bence düzenlemeden önce bile ne önerdiğini çok iyi anladım, ama bence bu korkunç bir yaklaşım. N müşteriniz olduğunu varsayalım, ne zaman bagaja yeni bir çekirdek özellik eklerseniz, SCM'nin yeni özelliği N dallarına yaymayı kolaylaştıracağı görülüyor. Ancak dalları bu şekilde kullanmak, müşteriye özgü değişikliklerin açık bir şekilde ayrılmasını önlemeyi çok kolaylaştırır. Sonuç olarak, şimdi bagajdaki her değişiklik için bir birleştirme çatışması elde etmek için N şansınız var. Ayrıca, şimdi bir tane yerine N entegrasyon testini uygulamanız gerekiyor.
Doktor Brown

37

Bunu SCM şubeleri ile yapma. Ortak kodu, bir kütüphane veya proje iskeleti eseri üreten ayrı bir proje yapın. Her müşteri projesi daha sonra ortak olana bağımlılık olarak bağlı olan ayrı bir projedir.

Ortak taban uygulamanız Spring gibi bir bağımlılık enjeksiyon çerçevesi kullanıyorsa, bu özellik en kolay olanıdır, böylece her bir müşteri projesinde farklı nesnelerin özel varyantlarını istediğiniz gibi kolayca değiştirebilirsiniz. Zaten bir DI çerçeveniz olmasa bile, bir tane eklemek ve bu şekilde yapmak en az acı verici tercihiniz olabilir.


İşleri basit tutmak için bir başka yaklaşım, aynı projede hem ortak kodu hem de özelleştirmeleri (miras, kısmi sınıflar veya olaylar kullanarak) koruyarak bağımlılık enjeksiyonunu kullanmak yerine miras (ve tek bir proje) kullanmaktır. Bu tasarımla, müşteri dalları iyi çalışır (seçilen cevapta açıklandığı gibi) ve biri müşteri kodu her zaman ortak kodu güncelleyerek güncelleyebilirdi.
drizin

Eğer bir şeyi kaçırmazsam, önerdiğin şey, 100 müşterin varsa, yaratacağın (100 x NumberOfChangedProjects ) ve onları yönetmek için DI kullanacaksın. Öyle olsaydı, kesinlikle bu tür bir çözümden uzak
dururdum,

12

Tüm müşteriler için yazılımı tek bir dalda saklayın. Farklı müşteriler için yapılan değişiklikleri saptırmaya gerek yoktur. Daha da önemlisi, yazılımınızın tüm müşteriler için en iyi kalitede olmasını istersiniz ve çekirdek altyapınızdaki hata, gereksiz ek yük olmadan herkesi etkilemelidir, bu da daha fazla hataya neden olabilir.

Ortak kodu modüler hale getirin ve farklı dosyalarda farklı olan kodu uygulayın veya farklı tanımlarla koruyun. Yapı sisteminizin her bir müşteri için belirli hedefleri olmasını sağlayın, her bir hedef yalnızca bir müşteriyle ilgili kod içeren bir sürüm derler. Örneğin, kodunuz C ise, farklı istemciler için özellikleri " #ifdef" veya dilinizin yapılandırma yönetimi oluşturmak için kullandığı mekanizmalarla korumak ve müşterinin ödediği özelliklerin miktarına karşılık gelen bir dizi tanım hazırlamak isteyebilirsiniz.

Eğer böyle yapmazsanız ifdefs, kullanım "arayüzleri ve uygulamalar", "funktorlar", "nesne dosyaları" ya da her türlü araçları Dil tek bir yerde farklı şeyler saklamak için sağlar.

Kaynakları müşterilerinize dağıtırsanız, derleme komut dosyalarınızın özel "kaynak dağıtım hedefleri" olmasını sağlamak en iyisidir. Böyle bir hedefi çağırdığınızda , yazılımınızın kaynaklarının özel bir versiyonunu yaratır , onları ayrı bir klasöre kopyalar, böylece onları gönderebilirsiniz ve bunları derlemez.


8

Birçoğunun belirttiği gibi: kodunuzu doğru şekilde değerlendirin ve ortak koda göre özelleştirin ; Nesne yönelimli bir dil / sistem kullanıyor olsanız da olmasanız da, bu mümkündür (C içinde yapmak gerçekten nesne yönelimli bir şeyden biraz daha zor olsa da). Bu tam olarak miras ve kapsüllemenin çözülmesine yardım ettiği bir problem türüdür!


5

Çok dikkatli

Özellik Branching bir seçenek ama biraz ağır buluyorum. Ayrıca, kontrol altında tutulmadığı takdirde uygulamanızın tamamında çatallaşmaya yol açabilecek derin değişiklikleri kolaylaştırır. İdeal olarak, çekirdek kod tabanınızı olabildiğince yaygın ve genel tutmaya çalışırken, özelleştirmeleri mümkün olduğunca yükseltmek istersiniz.

Burada, ciddi değişiklikler ve tekrar etmenler olmadan kod tabanınıza uygulanabilir olup olmadığını bilmiyorum. Temel işlevselliğin aynı olduğu benzer bir projem vardı ancak her müşteri çok özel bir dizi özellik gerektiriyordu. Konfigürasyon ile birleştirdiğim bir modül ve kaplar seti oluşturdum (à la IoC).

daha sonra her müşteri için, temelde yapılandırmaları ve derleme betiğini kendi siteleri için yapılandırılmış bir kurulum oluşturmak için içeren bir proje oluşturdum. Bazen o müşteriye özel yapılmış bazı bileşenleri de oraya yerleştiririm. Ancak bu nadirdir ve ne zaman mümkün olursa, onu daha genel bir biçimde yapmaya çalışıyorum ve aşağı itiyorum, böylece diğer projeler bunları kullanabilir.

Sonuçta, ihtiyacım olan özelleştirme seviyesine sahibim, özelleştirilmiş kurulum komut dosyaları aldım, böylece müşteri sitesine ulaştığımda, sistemi her zaman arayacağım gibi görünmüyorum ve ek olarak ÇOK önemli bir bonus kazanıyorum. Doğrudan yapıya bağlı olan regresyon testleri oluşturabilmek. Bu şekilde, müşteriye özel bir hata aldığımda, sistemi devreye alındığı zaman sistemi savunacak bir test yazabilirim ve böylece bu seviyede bile TDD yapabilirim.

kısaca:

  1. Düz proje yapısı ile ağır modüler sistem.
  2. Her konfigürasyon profili için bir proje oluşturun (müşteri, birden fazla profil paylaşabilmesine rağmen)
  3. Gerekli işlevsellik setlerini farklı bir ürün olarak toplayın ve ona göre davranın.

Doğru şekilde yapılırsa, ürün montajınız birkaç yapılandırma dosyasını içermeli.

Bunu bir süre kullandıktan sonra, en çok kullanılan ya da temel sistemleri çekirdek ünite olarak birleştiren ve bu montaj paketini müşteri montajları için kullanan meta paketler oluşturdum. Birkaç yıl sonra, müşteri çözümleri oluşturmak için çok hızlı bir şekilde monte edebileceğim büyük bir alet kutusuna sahip oldum. Şu anda Spring Roo'ya bakıyorum ve bir gün daha umut ediyorum, fikrimin biraz daha ilerlememesini isteyip istemediğimi görüyorum, ilk görüşmemizde müşteriyle birlikte sistemin ilk taslağını oluşturabilirim ... Geliştirme ;-)

Umarım bu yardımcı oldu


3

Değişiklikler muhtemelen modülü her bir müşteri için ayrı (fiziksel) bir modüle bölmeyi haklı çıkarmak için çok ufak, derlemeyle ilgili sorunlardan korkuyorum, bağlantı kaosundan korkuyorum.

IMO, çok küçük olamazlar. Mümkünse, hemen hemen her yerde strateji modelini kullanarak müşteriye özel kodu çıkartacağım. Bu, dallandırılması gereken kod miktarını azaltacak ve genel kodu tüm istemciler için senkronize tutmak için gereken birleşmeyi azaltacaktır. Ayrıca testi basitleştirecektir ... genel kodu varsayılan stratejileri kullanarak test edebilir ve müşteriye özel sınıfları ayrı ayrı test edebilirsiniz.

Modülleriniz A modülünde X1 politikasını kullanmanın B modülünde X2 politikasını kullanmasını gerektirecek şekilde kodlanmışsa, yeniden düzenlemeyi düşünün, böylece X1 ve X2 tek bir politika sınıfında birleştirilebilir.


1

Şubeleri korumak için SCM'nizi kullanabilirsiniz. Ana dalı bozulmamış / müşteri özel kodundan temiz tutun. Bu dalda ana gelişme yapın. Uygulamanın her özelleştirilmiş sürümü için ayrı dallar bulundurun. İyi bir SCM aracı dalları birleştirmek konusunda gerçekten başarılı olacak (Git akla geliyor). Ana daldaki tüm güncellemeler özelleştirilmiş dallarla birleştirilmelidir, ancak müşteriye özel kod kendi dalında kalabilir.


Yine de, eğer mümkünse, sistemi modüler ve yapılandırılabilir bir şekilde tasarlamaya çalışın. Bu özel dalların dezavantajı çekirdek / ana birimden çok uzağa hareket etmesi olabilir.


1

Düz C ile yazıyorsanız, işte yapmanın oldukça çirkin bir yoludur.

  • Ortak kod (örneğin, "frangulator.c" birimi)

  • müşteriye özel kod, küçük ve sadece her müşteri için kullanılan parçalar.

  • Ana ünite kodunda, #ifdef ve #include komutlarını kullanın.

#ifdef İSTEMCİ = İSTEMCİ
#include "frangulator_client_a.c"
#endif

Bunu, müşteriye özel kişiselleştirme gerektiren tüm kod birimlerinde tekrar tekrar kullanmak için kullanın.

Bu ÇOK çirkin ve bazı diğer sıkıntılara yol açıyor ancak aynı zamanda basit ve müşteriye özel dosyaları birbiriyle oldukça kolay bir şekilde karşılaştırabilirsiniz.

Ayrıca, müşteriye özel parçaların hepsinin her zaman açıkça görülebildiği (her biri kendi dosyasında) ve ana kod dosyası ile dosyanın müşteriye özel kısmı arasında açık bir ilişki olduğu anlamına gelir.

Eğer gerçekten akıllı olursanız, doğru müşteri tanımını oluşturmak için makefiles'i ayarlayabilirsiniz.

klibi yapmak

client_a için inşa edecek ve "clientb yap", client_b için yapacaktır.

(ve sağlanan hiçbir hedef olmadan "make" bir uyarı veya kullanım açıklaması verebilir.)

Daha önce de benzer bir fikir kullandım, kurulması biraz zaman alıyor ama çok etkili olabilir. Benim durumumda bir kaynak ağacı yaklaşık 120 farklı ürün üretti.


0

Git'de, benim yaptığım yol, tüm ortak kodun bulunduğu bir ana şubeye ve her müşteriye yönelik bir şubeye sahip olmak. Çekirdek kodunda bir değişiklik yapıldığında, yalnızca ana istemciye müşteriye özel dalları yeniden derleyin; böylece geçerli taban çizgisine uygulanan istemciler için bir dizi hareketli düzeltme eki elde edersiniz.

Bir müşteri için değişiklik yaptığınızda ve diğer şubelere dahil edilmesi gereken bir hatayı fark ettiğinizde, bunu ana veya ana müşterinin düzeltmesi gereken diğer şubelere koyabilirsiniz (farklı müşteri şubelerinin kod paylaşmasına rağmen) Muhtemelen her ikisinin de efendiden ortak bir şubeden dalmalarını sağlamalısınız).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.