Come evitare le classi di controller di Dio e mantenere il principio di responsabilità singola?

2

L'attività consiste nel creare un migratore dal vecchio DB al nuovo DB utilizzando il principio di responsabilità singola di OOP.

Il mio problema è come posso farlo senza rendere il controller una God Class o rompere la singola responsabilità.

Ho pensato a due metodi per implementare questo

  1. Scorrere attraverso ciascuna riga di proprietà e collegarsi in cascata a sottodivisioni e proprietari nel controller e chiamare un migratore di riga per ogni tipo di entità

    • È stato detto che sta dando troppa responsabilità al controllore e lo renderebbe una classe di Dio
  2. Aggiungi le iterazioni all'interno di ogni Entità (ad esempio Proprietà iterates Sottodivisioni, Sottodivisioni iterate Proprietari)

    • È stato detto che sta infrangendo il principio di responsabilità singola

In questo momento sembra che tutto ciò che penso sia troppo complicato o infrange le regole. Forse ho capito i principi sbagliati o c'è una terza via.

Aggiornamento 1

Normalmente lo farei con uno script ma i requisiti sono di usare un'API poiché il nuovo DB si trova su una piattaforma diversa e la logica addAddress () e addOwner () saranno in un componente API.

    
posta Stefan Rogin 29.07.2015 - 08:45
fonte

2 risposte

4

L'OOP non è sempre la scelta migliore per le attività ETL, quindi non starei fedele all'OOP "puro" qui. E fintanto che il tuo modello è semplice come mostrato nell'esempio con solo tre tabelle da migrare, eviterei di sovradimensionarlo - avendo un solo Controller che orchestra la migrazione di sole tre tabelle e che usa classi diverse "Row Migrator" , come hai scritto, non mi sembra che il controllore abbia "troppe responsabilità".

Tuttavia ci sono alcune opzioni per distribuire le responsabilità. Per un programma ETL, suggerirei di dividere le responsabilità tra le parti "E (xtract)", "T (ransform)" e "L (oad)" della migrazione - la classe "Extractor" è l'unica che si connette al vecchio DB e fornisce i dati da migrare, la classe "Load" è l'unica che si collega al nuovo database / utilizza l'API e la classe "Transform" che esegue la trasformazione, ma non sa nulla sull'origine o la destinazione dei tuoi dati. Inoltre, quando il tuo modello è molto più grande nella realtà, come mostrato nel tuo esempio, potresti prendere in considerazione di suddividere la classe "Transform" in "sub-trasformatori" più piccoli.

Se la seconda opzione ha senso, IMHO dipende se si intende utilizzare le classi di entità esclusivamente nel contesto della migrazione o se si desidera mantenerle riutilizzabili e mantenibili per diversi contesti. Per quest'ultimo, non aggiungerei alcuna logica di business lì che è utile solo per questo caso d'uso molto speciale "migrazione".

    
risposta data 29.07.2015 - 14:38
fonte
4

Non hai bisogno di un "controller", hai bisogno di un "servizio".

Un Controller controlla il flusso dell'applicazione in base all'input dell'utente e ad altri eventi che si verificano nei livelli inferiori. Un Servizio fa semplicemente in modo ingenuo i suoi affari facendo ciò che è stato detto.

L'oggetto del servizio di migrazione avrebbe l'intelligenza per estrarre i dati dal vecchio schema e persistere nel nuovo schema tramite un servizio Web, se necessario, o un'API completamente diversa. Questo servizio dovrebbe avere la quantità minima di dipendenze per portare a termine il lavoro:

  • Classi di modelli di dominio per ogni database
  • Classi di accesso ai dati per ogni database
  • Metodi o altre classi che associano un modello di dominio a un altro

Il PropertyMigrationService ha le seguenti responsabilità

  • Sapere dove estrarre i dati da
  • Sapere dove salvare i dati in
  • Avere accesso agli oggetti di mappatura per mappare un modello di dominio a un altro

Avrebbe bisogno di:

  • OldDataAccess - Una classe per le operazioni CRUD sul vecchio DB
    • Property - Il modello di dominio per la "proprietà" nel vecchio DB
    • Subdivision - Modello di dominio per le suddivisioni nel vecchio DB
    • Owner - Modello di dominio per proprietari nel vecchio DB
  • NewDataAccess - Una classe per le operazioni CRUD sul nuovo DB / servizio web
    • Address - Modello di dominio per le proprietà nel nuovo DB
    • Owner - Modello di dominio per proprietari nel nuovo DB
  • PropertyToAddressMapper - Mappatura Property oggetti nel vecchio DB in Address oggetti per il nuovo DB
  • SubdivisionToAddressMapper - Mappatura Subdivision oggetti nel vecchio DB in Address oggetti per il nuovo DB
  • OwnerToOwnerMapper : mappa gli oggetti proprietario da un DB all'altro

Finirai con questa gerarchia di oggetti:

  • %codice%
    • PropertyMigrationService
    • OldDataAccess
    • NewDataAccess
    • PropertyToAddressMapper
    • SubdivisionToAddressMapper

Il servizio di migrazione potrebbe avere un unico metodo pubblico chiamato OwnerToOwnerMapper che esegue la migrazione.

Avendo affrontato schemi legacy, non sai mai in che modo la follia e il caos si incontreranno. Architettando la soluzione in questo modo, in concomitanza con il fatto che le classi di accesso ai dati implementino un'interfaccia e che void migrate() utilizzi tali oggetti tramite la loro interfaccia, è possibile rendere testabile l'intero processo di migrazione.

Ora puoi lanciare un sacco di test a questo per condizioni di errore note e rendere davvero questa cosa a prova di proiettile (bene, resistente ai proiettili).

Dopo averlo racchiuso in un oggetto servizio, hai una certa flessibilità per quando e dove viene richiamato:

  • Da un "controller" in un'applicazione web
  • Da uno script avviato come cron job in Linux o in un'attività pianificata in Windows

Il processo di migrazione diventa sia proattivo (l'utente fa clic su un pulsante sulla pagina Web e fa la migrazione) o passivo (un'attività di pianificazione viene eseguita a mezzanotte e fa questi record in gruppi di, ad esempio, 1.000).

    
risposta data 29.07.2015 - 14:49
fonte