Parlando di HttpClient in Angular 5: immutabile o non immutabile, questo è il problema!

Come influenzano il nostro codice gli oggetti immutabili?

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 ] 
}

Ma la domanda rimane: Perchè? E la questione va più in là dei parametri del HttpClient di Angular. Perchè i miei oggetti dovrebbero essere immutabili?

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.

Chiunque la veda in maniera differente o vuole commentare le mie considerazioni è il benvenuto: uno degli obiettivi del mio blog è confrontarmi con altre persone per imparare cose nuove e migliorare.

A presto.