Sono in un progetto di sistema distribuito scritto in java dove abbiamo alcune classi che corrispondono a oggetti di business del mondo reale molto complessi. Questi oggetti hanno molti metodi corrispondenti alle azioni che l'utente (o qualche altro agente) può applicare a quegli oggetti. Di conseguenza, queste classi sono diventate molto complesse.
L'approccio all'architettura generale del sistema ha portato a molti comportamenti concentrati su poche classi e su molti possibili scenari di interazione.
Come esempio e per mantenere le cose semplici e chiare, diciamo che Robot e Car erano classi nel mio progetto.
Quindi, nella classe Robot avrei molti metodi nel seguente schema:
- sleep (); isSleepAvaliable ();
- sveglio (); isAwakeAvaliable ();
- di cammino (direzione); isWalkAvaliable ();
- shoot (direzione); isShootAvaliable ();
- turnOnAlert (); isTurnOnAlertAvailable ();
- turnOffAlert (); isTurnOffAlertAvailable ();
- di ricarica (); isRechargeAvailable ();
- poweroff (); isPowerOffAvailable ();
- stepInCar (Car); isStepInCarAvailable ();
- stepOutCar (Car); isStepOutCarAvailable ();
- Autodistruzione (); isSelfDestructAvailable ();
- die (); isDieAvailable ();
- isAlive (); è sveglio(); isAlertOn (); GetBatteryLevel (); getCurrentRidingCar (); getAmmo ();
- ...
Nella classe Car, sarebbe simile:
- turnOn (); isTurnOnAvaliable ();
- bivio (); isTurnOffAvaliable ();
- di cammino (direzione); isWalkAvaliable ();
- rifornimento (); isRefuelAvailable ();
- Autodistruzione (); isSelfDestructAvailable ();
- incidente (); isCrashAvailable ();
- isOperational (); Ison (); getFuelLevel (); getCurrentPassenger ();
- ...
Ciascuno di questi (Robot e Car) è implementato come una macchina a stati, dove alcune azioni sono possibili in alcuni stati e altre no. Le azioni cambiano lo stato dell'oggetto. I metodi azioni generano IllegalStateException
quando vengono chiamati in uno stato non valido e i metodi isXXXAvailable()
indicano se l'azione è possibile al momento. Sebbene alcuni siano facilmente deducibili dallo stato (ad esempio, nello stato di sonno, il risveglio è disponibile), alcuni non lo sono (per sparare, deve essere sveglio, vivo, munito di munizioni e non in auto).
Inoltre, anche le interazioni tra gli oggetti sono complesse. Ad esempio, l'auto può contenere solo un passeggero Robot, quindi se un altro tenta di entrare, deve essere lanciata un'eccezione; Se l'auto si schianta, il passeggero dovrebbe morire; Se il robot è morto all'interno di un veicolo, non può uscire, anche se l'auto stessa è ok; Se il robot è all'interno di un'auto, non può entrare in un altro prima di uscire; ecc.
Il risultato di questo, è come ho già detto, queste classi sono diventate davvero complesse. Per peggiorare le cose, ci sono centinaia di possibili scenari quando il robot e l'auto interagiscono. Inoltre, gran parte di questa logica ha bisogno di accedere a dati remoti in altri sistemi. Il risultato è che il collaudo delle unità è diventato molto difficile e abbiamo molti problemi di test, uno che provoca l'altro in un circolo vizioso:
- I setup delle serie di test sono molto complessi, perché hanno bisogno di creare un mondo significativamente complesso da esercitare.
- Il numero di test è enorme.
- La suite di test richiede alcune ore per essere eseguita.
- La copertura del nostro test è molto bassa.
- Il codice di prova tende a essere scritto settimane o mesi dopo il codice che testano, o mai del tutto.
- Anche molti test sono stati interrotti, principalmente perché i requisiti del codice testato sono cambiati.
- Alcuni scenari sono così complessi, che non riescono a scadere durante l'installazione (abbiamo configurato un timeout in ciascun test, nei casi peggiori di 2 minuti e anche questa volta sono scaduti i timeout, abbiamo assicurato che non si tratta di un ciclo infinito ).
- I bug scivolano regolarmente nell'ambiente di produzione.
Lo scenario di Robot e auto è una grossolana semplificazione eccessiva di ciò che abbiamo nella realtà. Chiaramente, questa situazione non è gestibile. Quindi, sto chiedendo aiuto e suggerimenti per: 1, ridurre la complessità delle classi; 2. Semplificare gli scenari di interazione tra i miei oggetti; 3. Ridurre il tempo di test e il codice del test da testare.
EDIT:
Penso di non essere stato chiaro sulle macchine di stato. il robot è a sua volta una macchina a stati, con stati "dormendo", "sveglio", "ricarica", "morto", ecc. La macchina è un'altra macchina a stati.
EDIT 2: Nel caso in cui sei curioso di sapere qual'è il mio sistema, le classi che interagiscono sono cose come Server, IPAddress, Disk, Backup, User, SoftwareLicense, ecc. Lo scenario Robot and Car è solo un caso che ho scoperto che sarebbe stato abbastanza semplice da spiegare il mio problema.