Dubbi sul modello architettonico per l'applicazione aziendale standard personalizzabile [duplicato]

3

La mia azienda deve creare un'applicazione da implementare per molti clienti. Questo software avrà molti moduli e funzionalità, ma alcuni di questi avranno bisogno di aggiustamenti specifici per alcune aziende. Tali aggiustamenti potrebbero essere di natura minore (come un nuovo input in un modulo) o potrebbero essere le principali personalizzazioni, come cambiare l'intero modulo con diversi passaggi e regole aziendali prima di salvare / modificare / eliminare. Ci si può aspettare che la personalizzazione possa anche portare ad alcune modifiche a livello di database, come nuove colonne.

L'applicazione esiste già, ma non abbiamo ancora incluso queste modifiche. L'applicazione utilizza .NET, WebApi, AngularJs. Come modello di progettazione dell'architettura software utilizziamo microservizi e un approccio DDD (Domain Driven Design). La struttura delle soluzioni di Visual Studio è la seguente:

  • WebApp: rotte, JS, CSS, html.
  • Interfaccia modulo: controller e servizi WebApi
  • Dominio del modulo: contesti limitati, radici di aggregazione, dominio.
  • Infrastruttura del modulo: unità di lavori, archivi, validatori di persistenza, mappatura delle entità

Un'idea per controllare questo scenario complesso utilizza diversi rami (su git) per ogni cliente. Ma questo potrebbe portare al problema che abbiamo bisogno di mantenere diverse applicazioni in futuro.

Pensiamo che sia molto meglio mantenere tutto in un unico ramo. Ma abbiamo molti dubbi su come realizzarlo in maniera positiva (best practice?).

Ad esempio, immagina un CRUD per il dominio "Utente" che può avere regole aziendali diverse su client diversi. Problemi che vediamo:

  • Abbiamo bisogno di creare diversi metodi di salvataggio sul dominio degli utenti? Come "saveForClient1", "saveForClient2" ...?

    • Temiamo che l'ereditarietà dei domini possa avere un impatto negativo sul nostro approccio DDD per questo problema.
  • Se la personalizzazione è così grande che è necessario creare file HTML / Javascript e file .cs diversi, ma anche usare codice già esistente, come può essere organizzato in un modo "carino"?

Aggiornato (18/10/2016)

Ho cambiato lavoro prima di andare più a fondo nella soluzione, ma ci sono commenti che chiedono quale strategia scegliamo.

Utilizzare diversi rami è l'idea peggiore. La strategia migliore è controllare le differenze nel codice, creando diversi pacchetti, file e percorsi delle risorse REST per organizzare questo codice e partecipare alle funzionalità specifiche. Utilizzare le interfacce e l'iniezione delle dipendenze per mantenere lo stesso contratto nel sistema ma con diverse implementazioni per i client. DDD può aiutarti a isolare questi casi in cui alcune informazioni dal database sono specifiche del cliente.

Nel front-end, è una buona idea scegliere una libreria indolore per aiutarti a costruire interfacce, ottenendo flessibilità per creare interfacce diverse riutilizzando gli stessi componenti (come React).

    
posta Dherik 30.03.2015 - 16:20
fonte

1 risposta

2

La personalizzazione è semplice o complessa come l'introduzione di qualsiasi altro requisito. Ogni volta che aggiungi una regola aziendale personalizzata o una regola delle regole aziendali all'applicazione, analizza come rendere questa regola visibile o invisibile, attiva o inattiva, disponibile o non disponibile da una specie di opzione di runtime. Pensa al passaggio di personalizzazione come a un requisito separato e separato e gestisci ciascuno di questi switch run-time esattamente come con qualsiasi altro requisito: analizza le opzioni su come implementarlo, prendi decisioni tecniche, pianifica lo sforzo, sviluppare, testare e distribuire la funzionalità. Chiediti

  • quale impatto avrà la decisione sulla base di codice esistente
  • quali modifiche saranno necessarie nel tuo database (forse hai bisogno di alcuni campi personalizzati usati solo per alcuni dei tuoi clienti, forse hai bisogno di una tabella diversa, forse devi rendere il tuo modello più generico ecc.)

Non aspettatevi una soluzione "taglia unica": i diversi requisiti aziendali porteranno a diverse forme di personalizzazione, quindi dovrete ripetere questi passaggi con ogni nuova funzione personalizzata. Evitare di raggruppare le personalizzazioni "per client" come "saveForClient1", "saveForClient2". Invece, aggiungi le personalizzazioni "per funzionalità" - che ti offre una granularità molto migliore. Ad esempio, si assume che le regole aziendali nel primo caso siano le regole di convalida del metodo di salvataggio. Potresti avere un solo metodo di salvataggio con un elenco personalizzato di convalida prima che il salvataggio avvenga, potresti avere un metodo di salvataggio con parametri aggiuntivi per controllare la convalida, potresti avere due metodi di salvataggio diversi come "saveWithDefaultValidation" e "saveWithSpecialValidation", potresti avere una bandiera nell'oggetto Utente o da qualche altra parte nel modello dati per controllare quali regole di convalida si applicheranno e ci sono molte più soluzioni possibili. Come opzione aggiuntiva, potresti anche pensare a un sistema di plugin, in cui le funzionalità extra sono rese disponibili da alcuni moduli aggiuntivi venduti solo ai clienti che pagano per loro (ma il tuo prodotto principale rimane il 100% lo stesso per ogni cliente) . Scegli quello più adatto al tuo scopo.

Dovrebbe essere ovvio che dovrai pianificare se i tuoi clienti devono essere in grado di cambiare le opzioni di personalizzazione specifiche da soli (ad esempio, da qualche file di configurazione), o se lo fai per loro, o se hai bisogno di prendere alcune misure tecniche per impedire ai clienti di attivare funzionalità che non hanno pagato. Il sistema di plugin sopra può essere una misura del genere. Tuttavia, consiglio di evitare diverse distribuzioni core per diversi client, se possibile.

EDIT: Mi piace aggiungere che sono d'accordo con l'OP su non utilizzando filiali per-client nel VCS per questo scopo. Il problema che si verifica è che ogni volta che viene aggiunta una nuova funzionalità nel trunk, lo sviluppatore che aggiunge la funzione non può vedere immediatamente se questo si scontrerà con qualsiasi codice degli altri rami e se c'è qualcosa da cambiare, o se è necessaria una soluzione più generale che funzioni anche per le versioni specifiche per i trunk e . Se sei fortunato, potresti notarlo più tardi, quando provi a propagare le modifiche dal tronco ai rami del client e ottenere le collisioni di fusione. Se non si è così fortunati, non si verificano collisioni di fusione, ma una delle versioni client ha ora un bug grave. Forse i tuoi test automatici prenderanno questo, forse il tuo test manuale, o nel peggiore dei casi il cliente è il primo a notarlo, ma dovrebbe essere chiaro che il tuo sforzo di test si moltiplica con ogni cliente. Questo perché quando si autorizzano modifiche arbitrarie in ogni ramo, si dovrà effettuare un test di integrazione completo con l'intero prodotto dopo una modifica nel tronco per ciascun ramo.

    
risposta data 30.03.2015 - 19:35
fonte

Leggi altre domande sui tag