Sto tentando di ridefinire qualche codice legacy che è un bel casino. Stiamo parlando di una classe con 7000 linee e una manciata di metodi che stanno violando il Principio di Responsabilità Unica, così tanto da far male. Sono riuscito a suddividerlo un po ', ma trovo che sto principalmente rimescolando il codice in classi separate - la complessità è ancora lì. I miei metodi stanno ottenendo enormi liste di parametri perché tutto è così intricato.
Il mio obiettivo è aggiungere test di unità, ma anche rendere il codice più gestibile come risultato.
Sto lavorando attraverso il codice dai "punti più bassi" (quelli che toccano un database) e cercando di ricalcolarli in classi che fanno cose specifiche. L'accesso al database è semplice e facile, posso inserirlo in una classe "DataAccess".
Tuttavia, ho problemi con alcuni altri metodi. Ci sono alcune aree che stanno facendo un'unica cosa generale, ad esempio: caricamento di alcuni dati. Il mio problema è che questi metodi si chiamano tutti in una lunga catena.
Ad esempio, ecco alcuni esempi di psudocode che dimostrano ciò che ho:
class SensorDataLoader
{
//injected dependency for data access
private readonly DataAccess dataAccess;
// loads all sensors
public void LoadAllSensorData(int dataSetId, LoadParametersObject loadParameters, DataStoreObject dataStore, Configuration configuration, Report report)
{
foreach (var sensorDataStore in dataStore.sensorsToLoad)
{
if (!sensorDataStore.HasDataToLoad) continue; // these parameters have lots of complexity. I've cut out a lot of stuff like this that access the configuration objects, or the data store objects.
LoadSensorData(dataSetId, sensorDataStore, configuration.SensorConfiguration);
}
}
// load a single sensor (i.e. all it's 'tracks')
public void LoadSensorData(int dataSetId, SensorDataStoreObject sensorDataStore, SensorConfiguration sensorConfiguration, Report report)
{
foreach (var trackDataStore in sensorDataStore.tracks)
{
// here I've tried to create some dependencies that I can mock to test later methods
var trackNumberAllocator = new TrackNumberAllocator(trackDataStore.trackId, sensorConfiguration);
var postProcessor = new TrackPostProcessor(sensorConfiguration, trackDataStore.trackId, trackNumberAllocator);
if (sensorConfiguration.someCondition)
{
LoadTrackData(dataSetId, trackDataStore, postProcessor, sensorConfiguration, report);
}
else
{
report.Report(...);
}
}
}
// loads a single 'track' in the sensor
public void LoadTrackData(int dataSetId, TrackDataStoreObject trackDataStore, PostProcessor postProcessor, SensorConfiguration sensorConfiguration, Report report)
{
//get the data
var data = this.dataAccess.GetData(dataSetId, sensorConfiguration);
postProcessor.PostProcess(data);
postProcessor.CalculateOffsets(data);
report.Report(...);
}
}
Ho tre metodi, quell'area tutto carica un sensore (se li divido in classi separate ho praticamente bisogno di avere una classe separata per ogni singolo metodo in questo codice!)
Voglio testare i metodi separatamente, così posso testare le funzionalità di ognuno, ma sono concatenati insieme.
Dopo aver lottato per districare questo codice, ho anche realizzato che la struttura di queste classi è anche realmente accoppiata con la strucutre degli oggetti di configurazione e degli oggetti 'data store'.
Tutti questi metodi prendono un oggetto molto complesso e lo mutano in qualche modo. È davvero complicato districarli a causa di ciò.
Ci sono schemi di progettazione che potrebbero aiutarmi con questo? Penso di essere un po 'troppo ingenuo nel solo tentativo di suddividerli in classi separate e qualcosa di più drastico è necessario per separare le preoccupazioni, ma sto cercando di trovare un modello di design che si adatti.