Sto tentando di ridefinire un componente di un grande progetto, che attualmente ha molte dipendenze dallo stato globale dell'ambiente del progetto. L'obiettivo (per i miei gusti) è un'architettura "SOLIDA", in cui tutto può essere testato correttamente.
A volte la dipendenza può essere semplicemente una stringa o un valore: una directory specifica, un nome di macchina, a volte forse una matrice.
Tuttavia, la dipendenza non può essere iniettata come valore semplice in fase di costruzione, perché il valore potrebbe non essere ancora disponibile.
Il valore potrebbe provenire da un contenitore di iniezione delle dipendenze, dal sistema di configurazione, ecc. Attualmente la classe stessa chiama a funzioni legacy o metodi statici di questi sottosistemi, per ottenere i rispettivi valori. Ciò è negativo a causa della dipendenza globale dello stato e perché il componente sa troppo di questi sottosistemi.
Idea
Quindi la mia idea era di creare un'interfaccia "fornitore di dati" per dipendenza, con diverse implementazioni per "reale" e "falso". Un'interfaccia esprime uno dei bisogni di un componente che dipende da esso, non di più. Quindi, molti di loro hanno solo un metodo. Alcuni vengono riutilizzati, ma non molto.
Anche la funzionalità principale è suddivisa in sotto-componenti con interfacce. Alcuni di loro hanno decoratori di cache o buffer. Una parte è divisa in una catena di processori, che implementano un "(Name) ProcessorInterface".
Problema: troppe classi e interfacce.
Funziona alla grande, e tutto è super-testabile.
Uso sempre lo stesso stile nei miei progetti e non esiterei a farlo di nuovo qui.
Ma qui non è una mia scelta. Questo è un enorme progetto OSS, con una grande comunità di sviluppatori, che devo convincere, se voglio farlo in questo modo. E il resto del codice, per la maggior parte, non assomiglia a questo.
Il numero di classi e interfacce sta diventando molto alto. E molti di loro sono solo "interni", quindi non sono intesi come parte di un'API pubblica.
Ecco un esempio di classi che sto / stavo per aggiungere . Questo è troppo grande per postare qui. L'originale era semplicemente una chiamata a drupal_get_profile()
, che ovviamente rende il test molto più difficile.
O ho sbagliato, o ho bisogno di un modo migliore per venderlo.
Domande
Per riassumere le domande principali:
- È un problema se alcune interfacce non sono pensate per la "public API", ma solo per "internal"?
- C'è un problema ci sono troppe classi? La complessità dovrebbe essere misurata in numero di classi o dimensione media di ogni singola classe?
- C'è un modo per ridurre il numero di classi e avere ancora i vantaggi di un'architettura "solida"?
Ho la mia risposta per la maggior parte di questi, ma ho la sensazione che questo non sia sufficiente per convincere nessuno.
Altri pensieri
Un'alternativa sarebbe avere più interfacce "generiche", ad es. "StringProviderInterface" invece di "ProfileNameInterface". Ma poi perderei la specificità semantica. Solo perché restituiscono tutte le stringhe, non le rende intercambiabili.
Forse le interfacce saranno riutilizzate più spesso, se più codice si trasforma in questo stile.
Aggiornamento
Mentre la discussione procede, una preoccupazione importante e ripetuta che sento è che ogni nuova interfaccia deve essere retrocompatibile, anche se è pensata per qualcosa di "interno". Sono tecnicamente d'accordo con questo, ma penso che si possa dire lo stesso delle classi e dei metodi pubblici. Quindi mi chiedo se questa è davvero una preoccupazione valida. Forse il vero problema è avere delle interfacce un po 'strane che penzolano intorno.