What practices can I use to maintain the code clean and avoid series of if/else cluttering the code
Anche se il tuo piano originale sembra un po 'pazzo, se sostituisci il requisito di "ogni ticket" con "molte caratteristiche diverse", le domande sopra riportate rendono IMHO molto più sensato. Secondo la mia esperienza, la chiave per mantenere il codice gestibile quando si hanno molte opzioni di configurazione diverse è
scomposizione di caratteristiche diverse in sottofunzioni molto piccole, per lo più ortogonali .
"Ortogonale" qui significa che ogni sottofunzione è indipendente l'una dall'altra. Se lasci che l'utente finale abbia accesso diretto all'interruttore di ogni sottofunzione, o se raggruppi sottofunzionalità e lasci che l'utente scelga solo tra alcuni "pacchetti di configurazione di sottofunzioni" completi, dipende da te, ma l'ortogonalità assicurerà che l'intera operazione continui continua a essere testabile. Ad esempio, se hai 3 clienti e 10 sottofunzionamenti diversi, per il cliente A li abiliti tutti, per il cliente B li disabiliti tutti e per il cliente C attivi ogni secondo caratteristica - questo rende 3 bundle, e puoi fornire un set di configurazione "config A", "B" o "C" come gruppo.
E anche se ci sono alcune dipendenze tra le sottofunzioni, purché le dipendenze siano locali e puoi esprimerle in termini come "questo elenco di sottofunzioni è disponibile solo quando la sottofunzione X è attiva", tale configurazione può ancora essere gestita.
Questa non è teoria. Attualmente sto lavorando a un prodotto in cui almeno parti sono altamente configurabili, con centinaia di opzioni diverse, e ha fatto non diventare un disastro perché ci siamo concentrati rigorosamente sull'ortogonalità laddove possibile. Oppure guarda l'elenco delle opzioni di configurazione disponibili in un software come Firefox Internet Browser ("about: config"). Un tale livello di configurabilità è IMHO possibile solo prestando attenzione all'ortogonalità.
Tuttavia, questo tipo di design non emerge automaticamente dai tuoi "ticket". Per ogni ticket (o requisito, o "user story"), devi pensare a se e come ha senso mapparlo ad alcune caratteristiche configurabili (s) o sottofunzione (s). E devi anche prendere una decisione individuale su come implementarlo nel codice (forse un condizionale è la strada da seguire, magari sottoclasse / polimorfismo, magari utilizzando una tabella decisionale) - non esiste una soluzione "one size fits all". Questa è una delle parti importanti del design del software: abbattere i requisiti per le astrazioni nel codice.