Esattamente, trasformare lo stato globale in oggetti passati come parametri è il modo standard per rendere una funzione verificabile.
Quindi da questo:
var globalList = [];
function doSomething() {
...
}
Andremmo a:
var globalList = [];
function doSomething() {
return doSomethingTestable(globalList);
}
function doSomethingTestable(list) {
...
}
Abbiamo quindi introdotto una seam in un progetto in cui possiamo inserire dati di test e rivedere i risultati.
Mantenendo invariata la vecchia funzione (come wrapper attorno alla nuova funzione testabile), non è necessario aggiornare immediatamente i dipendenti di questa funzione. Quindi questo refactoring è limitato a quella funzione ed è quindi a basso rischio. In futuro (quando avremo migliori test unitari), possiamo cambiare le altre parti per utilizzare la funzione parametrizzata. Alla fine, il codice è ridotto a:
function doSomethingTestable(list) {
...
}
(Una nota sulla denominazione: la vecchia funzione e la nuova funzione essenzialmente vogliono lo stesso nome. In realtà non raccomando un ...Testable
o ...improved
suffisso per disambiguarli! A volte questo può essere risolto non aggiungendo un'altra funzione, e solo un parametro con un valore predefinito.A volte il nome originale era cattivo, e questa è una buona opportunità per rinominare. abbiamo trovato il modo migliore per descrivere il parametro extra, ad esempio sendMessage()
potrebbe diventare sendMessageToQueue(queue)
.)
Invece di passare i dati nudi come parametro, è spesso meglio considerare quale tipo di operazioni vengono eseguite su questi dati e incapsulare tali operazioni. Dovremmo quindi passare un oggetto, dove i metodi su questo oggetto documentano alcune intenzioni del nostro codice. Ad esempio, potremmo non aver bisogno di tutte le operazioni per un elenco (come l'indicizzazione e l'iterazione) e vogliamo solo push()
e pop()
elementi.
Offrire un insieme limitato di metodi con nomi auto-documentanti tende a rendere il codice più ovvio e solido. Rende inoltre più semplice il test del codice, poiché non è necessario convalidare uno stato di risultato specifico e invece è possibile convalidare le azioni di quel codice. (Anche se spesso convalidare lo stato completo dell'output è ancora la soluzione più semplice.)