facebook

Blog

Resta aggiornato

Come influenzano il nostro codice gli oggetti immutabili?
Parlando di HttpClient in Angular: immutabile o non immutabile, questo è il problema!
mercoledì 24 Ottobre 2018

Durante il porting di Raptor.UI (il front-end Angular del nostro framework), abbiamo usato il nuovo HttpClient Angular (come discusso qui), senza, in apparenza, nessuna breaking change.

Andando più nel dettaglio, abbiamo convertito UrlSearchParams del modulo @angular/http con HttpParams di @angular/common/http. Il codice era il seguente:

const params = new UrlSearchParams(); 
params.set('Direction', parameters.Direction === 'desc' ? '0' : '1'); 
params.set('ElementCount', parameters.ElementCount); 
params.set('FieldsExcludedFromTheSearch', parameters.FieldsExcludedFromTheSearch); 
params.set('Language', language); 
params.set('OrderBy', parameters.OrderBy); 
params.set('PageNumber', parameters.PageNumber); 
params.set('PageSize', parameters.PageSize);
params.set('Pages', parameters.Pages); 
params.set('SearchText', parameters.SearchText); 
params.set('RelatedId', parameters.RelatedId);

Che abbiamo convertito nel seguente codice senza errori di compilazione:

const params = new HttpParams(); 
params.set('Direction', parameters.Direction === 'desc' ? '0' : '1'); 
params.set('ElementCount', parameters.ElementCount); 
params.set('FieldsExcludedFromTheSearch', parameters.FieldsExcludedFromTheSearch); 
params.set('Language', language) params.set('OrderBy', parameters.OrderBy); 
params.set('PageNumber', parameters.PageNumber); 
params.set('PageSize', parameters.PageSize); 
params.set('Pages', parameters.Pages); 
params.set('SearchText', parameters.SearchText); 
params.set('RelatedId', parameters.RelatedId);

Peccato che però non funzioni, perché HttpParams è immutabile, quindi il metodo set crea e restituisce una nuova istanza dei parametri. Il codice corretto è il seguente:

const params = new HttpParams() 
    .set('Direction', parameters.Direction === 'desc' ? '0' : '1')
    .set('ElementCount', parameters.ElementCount)
    .set('FieldsExcludedFromTheSearch', parameters.FieldsExcludedFromTheSearch)
    .set('Language', language) .set('OrderBy', parameters.OrderBy)
    .set('PageNumber', parameters.PageNumber)
    .set('PageSize', parameters.PageSize)
    .set('Pages', parameters.Pages)
    .set('SearchText', parameters.SearchText)
    .set('RelatedId', parameters.RelatedId);

Ok, funziona, ma abbiamo creato 11 istanze di HttpParams invece di una… Il problema può essere facilmente risolto come segue:

const direction: string = parameters.Direction === 'desc' ? '0' : '1'; 
const params = { 
    Direction: [direction], 
    ElementCount: [parameters.ElementCount], 
    FieldsExcludedFromTheSearch: [parameters.FieldsExcludedFromTheSearch], 
    Language: [ language ], 
    OrderBy: [ parameters.OrderBy ], 
    PageNumber: [ parameters.PageNumber], 
    PageSize: [ parameters.PageSize], 
    Pages: [ parameters.Pages ], 
    SearchText: [ parameters.SearchText ], 
    RelatedId: [ parameters.RelatedId ] 
}

La domanda rimane: perché? Perché i miei oggetti dovrebbero essere immutabili? E la questione va al di là dei parametri del HttpClient di Angular.

Ho discusso di questa cosa con alcuni amici, che per hobby si occupano anche di programmazione funzionale, ma dobbiamo spostare la discussione nel mondo della filosofia (dei programmatori).

Nella programmazione funzionale, l’immutabilità degli oggetti è una necessità, perché la mutabilità dello stato di un oggetto può causare effetti collaterali nel mondo asincrono: dovremmo bloccare l’accesso alle risorse per prevenire che altri thread cambino lo stato dell’oggeto durante le nostre modifiche. Ma se gli oggetti sono immutabili, ogni cambiamento ad essi creerebbe nuovi oggetti. Ovviamente questo meccanismo crea problemi in termini di memoria allocata, ci sono alcune tecniche per limitare le risorse richieste, ma il problema rimane.

La documentazione ufficiale di Angular parla della scelta dell’immutabilità quando illustra gli interceptors, potete leggerlo qui: https://angular.io/guide/http#immutability. La cosa ha senso in quel caso, ma nel nostro esempio non ci sono problemi di concorrenza, quindi l’uso di oggetti immutabili crea solo un inutile spreco di memoria.

Happy coding!