Angular 2 vs React: The Ultimate Dance Off

Sunset Breaks - Alí Marín (CC BY-NC-ND 2.0)

La maggior parte delle persone che mi seguono sanno che preferisco personalmente React, ma ovviamente mi piace che le mie decisioni siano educate, non basate su pregiudizi non informati. Ultimamente, ho esplorato Angular 2 in modo approfondito. Ecco come si confronta con React secondo me.

Nota: a volte abbrevierò Angular 2 "ng2", una pratica comune nella comunità.

Let's Dance

Voglio concentrarmi sull'esperienza degli sviluppatori, quindi diamo un'occhiata a come si sentono gli sviluppatori nell'usare rispettivamente ng2 e React. A proposito di Angular 2 e React, ho chiesto ai miei follower "Lo useresti di nuovo?":

Solo il 17% ha dichiarato di utilizzare nuovamente Angular 2.

Il 56% ha dichiarato di utilizzare nuovamente React.

Questo è tutto. Gioco finito. Destra? Bene, non proprio. La maggior parte degli intervistati non ha ancora usato Angular 2, quindi per renderlo giusto, dobbiamo davvero rimuovere quel gruppo dal sondaggio.

Quando rimuoviamo il gruppo che non li ha ancora utilizzati, i punteggi sembrano entrambi migliori:

Reagire: 84%

Angolare 2: 38%

React vince chiaramente il sondaggio sulla soddisfazione del cliente. Ma questo non è scientifico. Questi sono solo i miei follower e i follower delle persone che hanno ritwittato i sondaggi e parlo principalmente di React - ma poiché questi sono utenti reali che condividono la loro esperienza reale, penso che sia sicuro dire che mentre i numeri non saranno esattamente gli stessi in tutta la popolazione generale degli utenti, ci danno una buona idea di cosa aspettarsi.

Diamo un'occhiata più da vicino alle differenze e al motivo per cui le persone potrebbero sentirsi in questo modo.

Prestazione

Tante persone pensano che le selezioni tecnologiche debbano riguardare le prestazioni. Gli articoli React vs Angular 1 tendevano a incentrarsi sulle prestazioni (React ha vinto facilmente a causa dei cicli di controllo e digest sporchi di Angular 1). Ma Angular 2 ha ripulito il suo atto. È veloce. Nei miei test sia per React che per Angular 2, le prestazioni non sono state un grosso problema con entrambi. Ognuno di essi ha i suoi avvertimenti, ma non li approfondirò.

Come per tutti gli altri problemi di perf CS: se devi ripetere molte volte operazioni costose, l'app rallenterà. Allo stesso modo per React & ng2, ciò significa che dovresti evitare gli aggiornamenti del DOM quando puoi, evitare l'iterazione dello stato profondo se puoi, evitare di creare / demolire eccessivamente oggetti e componenti, ecc ... ai fini di questo articolo, assumeremo che noi stai confrontando un paio di supercar e sono entrambi dei demoni della velocità. Il tuo chilometraggio può variare.

Detto questo, apprezzo le prestazioni del team tanto quanto le prestazioni delle app. Questo confronto si concentrerà sull'esperienza degli sviluppatori e sui problemi di prestazioni del team di sviluppatori. In definitiva, il tuo team deve essere in grado di muoversi rapidamente e apportare rapidi cambiamenti. Esploreremo come ciascuno di questi strumenti si confronta su quei fronti.

Come Angular 1 ha trasformato il front-end

Angular 1 ha combinato le idee di Backbone, Knockout e le emergenti specifiche di Web Components e ha portato i componenti personalizzati alle masse tramite ng1 direttive personalizzate. Ha portato anche un modello comune da OOP: il contenitore di iniezione di dipendenza.

Dovrebbe essere ovvio ora, ma IMO, la cosa più trasformativa resa popolare da Angular 1 erano i componenti personalizzati. Oggi, tutti i popolari framework front-end supportano componenti personalizzati.

Come React ha trasformato il front-end

Quando è stato rilasciato React, MV * e l'associazione dati a 2 vie stavano prendendo d'assalto il front-end. La spina dorsale e il knockout erano colpi pesanti. Angular 1 era il nuovo ragazzo del blocco.

React non ha fornito alcun concetto integrato di modello e il team ha raccomandato di utilizzarlo insieme all'architettura Flux. Flux è un'architettura UI che prescrive flusso di dati unidirezionale e stato transazionale. Ho coperto i numerosi vantaggi di entrambi in dettaglio in "10 Suggerimenti per una migliore architettura Redux". Se non hai familiarità con React, Flux e Redux, ti consiglio vivamente di leggerlo prima di continuare con questo articolo.

React fu trasformativo perché fece sembrare MVC da solo una tecnologia obsoleta e scatenò un flusso unidirezionale sulle masse.

Secondo me, questa è la trasformazione più significativa dell'architettura front-end da HTML e JavaScript.

Fortunatamente, è stato così trasformativo, non è più unico per React. Puoi ottenerlo anche in ng2.

Roba in Angular 2 che non troverai in React

Naturalmente, entrambi i framework supportano la creazione di componenti personalizzati. Angular 2 ha alcune cose extra sotto il cofano, ma essenzialmente esistono entrambe per creare interfacce utente sul front-end dello stack dell'applicazione. Angular 2 ha solo più prescrizioni e filosofia "batterie incluse".

Diamo un'occhiata ad alcune delle prescrizioni di Angular 2.

Dattiloscritto

Ho una relazione di amore / odio con TypeScript. Uno dei miei animali domestici è l'idea popolare che TypeScript salverà la tua app da ogni sorta di bug. Ho una brutta notizia per te: non lo farà.

Leggi "Il segreto scioccante sui tipi statici". La riduzione dei bug non è quella in cui i tipi statici sono bravi.

La correttezza del tipo non garantisce la correttezza del programma.
  • Ci sono molti bug che i tipi statici non colpiranno.
  • Esistono modi oggettivamente migliori per rilevare i bug (TDD, revisioni del codice) e quelli che rilevano la maggior parte degli errori di tipo.

Risultato? È vero che i tipi statici possono eliminare una classe di bug, ma a costo di una maggiore complessità del codice e l'impatto complessivo sulla riduzione dei bug sul progetto è ridotto.

I tipi statici sono ottimi principalmente per gli strumenti per sviluppatori. È molto bello ottenere la documentazione in linea su cose come le firme delle chiamate di funzione mentre si codifica. Ma non hai sempre bisogno di annotazioni incorporate ovunque per farlo.

Mi piace l'idea di specificare le annotazioni dei tipi quando è necessario per chiarezza, documentazione per gli sviluppatori e strumenti avanzati per gli sviluppatori, ma per la maggior parte ho una forte preferenza per l'inferenza dei tipi. Le dichiarazioni di tipo in linea hanno la tendenza a ingombrare il codice e rendono più difficile la lettura.

La buona notizia è che TypeScript è abbastanza bravo nell'inferenza del tipo e, se vuoi, ti farà affidare all'inferenza per la maggior parte del tempo. Le sue capacità di inferenza sembrano migliori di Tern e gli strumenti di sviluppo per Atom e Microsoft Code sono molto meglio dei plug-in Tern comparabili. In effetti, arriverei al punto di dire che TypeScript offre la migliore esperienza di sviluppo di intellisense disponibile oggi nel mondo JavaScript. Potresti innamorartene.

TypeScript offre la migliore esperienza di sviluppo intellettuale disponibile oggi nel mondo JavaScript.

Se solo potessi usare TypeScript esclusivamente per le sue capacità di deduzione del tipo e saltare gli errori di generazione di moduli non dichiarati e parametri ambigui, lo userei sempre su normali file JavaScript. Scelta facile.

Se solo le annotazioni dei tipi vivessero sempre in file separati (come i file `d.ts` sicuramente digitati) per convenzione con zero config, userei anche più annotazioni e mi piacerebbe molto di più TypeScript. È possibile integrare più facilmente TypeScript con qualsiasi flusso di lavoro, perché sarebbe letteralmente "solo JavaScript". È possibile compilare con qualsiasi compilatore che supporti JavaScript standard.

In realtà, TypeScript aggiunge un sacco di sovraccarico a grandi progetti, compreso l'overhead di configurazione (tenere traccia di tutte le tipizzazioni della libreria per prevenire errori di importazione del modulo), sovraccarico di sintassi (le tipizzazioni sono generalmente dichiarate in linea), molti `qualsiasi` tratteggi di escape, eccetera…

Per chiarire `qualsiasi` tratteggio di escape, TypeScript supporta i generici usando la sintassi dello stile del costruttore di tipi, ma non è sempre chiaro o facile far funzionare le cose usando costrutti di stile di programmazione funzionale, osservabili, cambiando le funzioni di ordine superiore, ecc ...

Invece di capire il modo giusto di scrivere le cose, gli sviluppatori ricorrono comunemente all'utilizzo di "any". Sostanzialmente è come rinunciare al controllo del tipo e dire semplicemente "qualsiasi tipo funzionerà qui", anche quando ciò non è strettamente vero.

Tutti i tratteggi di overhead e di escape aggiungono più superficie per nascondere i bug. È comune vedere progetti TypeScript in cui vi sono errori TypeScript che vengono ignorati dai team. A volte centinaia o migliaia di errori.

Come dimostrato dall'HTML, se fai qualcosa che funziona quando ci sono errori, gli errori prolifereranno.

Ogni volta che ci sono errori che vengono ignorati, gli errori cessano di essere utili e si trasformano semplicemente in rumore. I sostenitori di TypeScript probabilmente sono già tutti nei commenti che mi dicono come questi team stanno sbagliando, e hanno davvero bisogno di correggere gli errori, e hanno ragione, ma.

Non è sempre ovvio come correggere rapidamente gli errori e, nel frattempo, i project manager stanno perseguitando gli sviluppatori per ottenere le loro funzionalità. Poiché TypeScript è in grado di compilare build funzionanti anche in presenza di errori, è possibile, forse probabile, che progetti di grandi dimensioni entrino in quella situazione indipendentemente dal fatto che gli sviluppatori gradiscano e siano d'accordo con essa. Se chiedi ai singoli contributori su quel progetto se avrebbero mai permesso al progetto di entrare in quello stato se fosse stato per loro, probabilmente il 100% direbbe "no".

Ma non è così che funzionano i grandi progetti con grandi team.

"Sappiamo che fa schifo, ma lo ripareremo più tardi." - Ogni vero team di sviluppo che sia mai esistito.

È possibile che TSLint e una migliore documentazione possano risolvere questo problema. Questo resta da vedere.

Quindi, dovrei usare TypeScript sul mio prossimo progetto? Mentre adoro gli strumenti per sviluppatori, trovo che il sovraccarico sia più un problema che un valore.

Più uso TypeScript, più penso che mi rallenta più di quanto mi acceleri. E se non mi sta accelerando e non riduce molto la densità dei bug, perché ___ lo sto usando?

Detto questo, potresti ancora innamorarti di TypeScript.

Potrebbe rallentarti, (ricorda, non ne ho la prova - solo una sensazione fastidiosa) ma potresti pensare che ti renda più produttivo. A volte i sentimenti e le cose di simpatia contano molto.

La felicità degli sviluppatori è importante. Potresti scoprire che quando non hai a che fare con le limitazioni di TypeScript:

L'uso di TypeScript ti rende felice.

C'è qualcosa di soddisfacente nella costruzione di un'interfaccia di funzione tipizzata e nel sapere che il prossimo sviluppatore che verrà saprà come chiamare la funzione senza leggere documenti o guardare il codice sorgente.

Entra semplicemente sapendo che aggiungerà un sacco di spese generali al tuo progetto e sapendo che non ti aiuterà a ridurre molto i bug.

Che cosa farà? Magia dello strumento di sviluppo.

So di aver fatto incazzare un sacco di fan di TypeScript. Non sto dicendo "TypeScript fa schifo, non usarlo". Sto dicendo: "TypeScript è bello e ha ottimi strumenti di sviluppo, ma ha anche grandi compromessi di cui gli sviluppatori devono essere consapevoli e potrebbe non fornire tutti i benefici previsti. "

Iniezione di dipendenza

Innanzitutto, adoro l'iniezione di dipendenza. Io lo uso per tutto il tempo. Ma Angular 2 ti batte in testa con l'iniezione di dipendenza. Leggendo i documenti e le ricette di unit test, troverai ogni sorta di roba su provider e dipendenze beffarde e test di unità con "beforeEachProviders ()" e ci vorrà del tempo per avvolgerti la testa. C'è molta magia in atto sotto il cofano per estrarre ng2 iniettabili e incomprensioni su come tutto funzioni e su come dovresti usare i provider può essere un vero punto critico per i principianti.

C'è un modo più semplice. Invece di importare le dipendenze e fare affidamento su un framework per inserirle automagicamente nella firma del costruttore della classe, basta scrivere una funzione che prenda la propria dipendenza. È davvero semplice e funziona così:

I sostenitori di Dependency Injection (DI) diranno che sto semplificando eccessivamente (sono d'accordo) e che non sto affrontando l'istanza (sono d'accordo). Sto dicendo che non importa.

In pratica, quello che si finisce con Angular 2 è che invece di deridere solo una manciata di cose che in realtà hanno bisogno di essere derise (accesso alla rete, accesso al disco, timer), finisci per deridere un sacco di cose che dovrebbero essere in scatola nera dettagli di implementazione.

L'ho detto molte volte prima, ma continuerò a dirlo fino a quando non sarà noto:

Deridere è un odore di codice.

Ovviamente a volte è richiesto il derisione, ma se la tua app è piena di file `* .mock.ts`, stai facendo qualcosa di sbagliato. La tua app è troppo strettamente accoppiata (ironicamente, l'idea di DI è di renderla meno accoppiata) o stai cercando di deridere un sacco di cose che non hanno bisogno di essere derise.

Non è necessario iniettare e deridere il mondo intero.

Gelsomino

Leggi "Perché uso il nastro anziché la moka e così dovresti". Gran parte si applica a Jasmine.

Jasmine fornisce un'API che tenta male di leggere come frasi inglesi e fornisce un sacco di campane e fischietti. Il risultato è che ci sono milioni di modi per scrivere test e asserzioni, il che significa che potresti dover leggere attentamente ognuno per capire cosa sta facendo.

Stai meglio limitandoti a una manciata di affermazioni fondamentali. Principalmente controlli di uguaglianza. In una grande squadra? Buona fortuna.

Jasmine incoraggia anche molta dipendenza da `beforeEach ()` e `afterEach ()`, che può accidentalmente incoraggiare lo stato condiviso: un problema molto comune nei test unitari che può causare fallimenti di test casuali (i test Jasmine vengono eseguiti correttamente in ordine casuale per scoraggiare l'uso di stato condiviso e dipendenze dall'ordine di prova).

Oltre a quelle critiche, Jasmine ha un altro difetto che mi fa impazzire 3 @ + $ # | +. Quando si confrontano due oggetti per uguaglianza, serializza e stampa entrambi gli oggetti su una grande linea. In altre parole, l'output del reporter predefinito è praticamente # $%! @ # $ Senza valore.

[Nota del redattore: abbiamo dovuto tagliare circa 8 paragrafi che non erano altro che! @ # $ Bip da questa parte dell'articolo. Condividiamo la trascrizione completa, ma potrebbe far piangere i bambini e i cuccioli si nascondono sotto i divani.]

Chai stampa belle differenze. Il nastro lo stampa:

non ok 1 dovrebbe essere lo stesso
---
operatore: uguale
atteso: | -
{x: 1, y: {z: 3}}
attuale: | -
{x: 1, y: {z: 2}}
...

Per piccoli oggetti posso facilmente vedere le differenze. Esistono reporter plug-in che lo rendono ancora migliore:

Gli sviluppatori hanno bisogno di resoconti chiari e ovvi per le differenze quando i test falliscono e Jasmine si mostra piatto in quel reparto. Se sai come collegare un buon reporter nel browser per risolvere questo problema, commenta.

Se stai aspettando che sia fissato nel nucleo, non trattenere il respiro. Un problema aperto per questo problema è in sospeso dal 2014.

Altre cose

Ci sono anche un sacco di cose angolari. Moduli e validatori, ecc ... ma ovviamente tutte queste cose sono disponibili per gli utenti di React se vogliono usarle. La grande differenza è che gli utenti di React non troveranno sempre le migliori soluzioni nei luoghi ovvi (come la documentazione di React). Al contrario, gli utenti di React si affidano maggiormente alle migliori pratiche della community, agli articoli di blog e ad altre risorse di apprendimento per identificare le scelte migliori.

Tutte le "altre cose" extra gonfiano il bundle Angular 2. Angular 2 + RxJS è piuttosto grande. Quasi 800k minimizzati. È circa 4 volte più grande di React + Redux e non lascia molto respiro al codice dell'app se desideri che l'app venga caricata e visualizzata rapidamente.

Questa è l'unica grande differenza di prestazione evidente che penso sia davvero importante, e conta un po '. Il miglioramento dei tempi di caricamento migliorerà radicalmente i KPI della tua app su tutta la linea. La riduzione dei millisecondi dei tempi di caricamento può spostare gli aghi su importanti metriche aziendali.

4 volte più grande (quasi un megabyte!) È davvero un grosso problema. Se non ti serve, non caricarlo.

EDIT: Come hanno sottolineato diversi commentatori, ng2 ha la capacità di fare la compilazione di Ahead Of Time (AOT) e il tree-shaking. Con una build di produzione correttamente configurata, puoi ridurre drasticamente le dimensioni del bundle utilizzando solo le funzionalità effettivamente utilizzate nella tua app, che conferiscono al bundle finale un ingombro molto più ridotto. Consiglio vivamente di configurare correttamente il pacchetto di produzione. Avrà un impatto potenzialmente drammatico su tassi di rimbalzo, tassi di conversione, soddisfazione del cliente e abbandono.

Roba da reagire che non troverai in Angular 2

Angular 2, proprio come Angular 1, si basa su modelli HTML.

La cosa buona dei modelli ng2 è che sono sostanzialmente una forma avanzata di HTML standard.

La cosa brutta dei modelli ng2 è che devi imparare un po 'di DSL angolare. Cose come `* ngIf` e` * ngFor`.

La cosa brutta dei modelli ng2 è che quando si commette un errore, falliscono in fase di esecuzione. A volte in silenzio. Il debug dei modelli Angular 2 può essere una seccatura.

Modifica: mi è stato detto che è stato risolto nelle versioni più recenti di Angular 2 quando si utilizza AOT. Gli errori del modello verranno segnalati al momento della compilazione. Non ho ancora avuto l'opportunità di testare la correzione.

React non ha modelli. Invece, ha JSX, che si compila in JavaScript al momento della compilazione.

La cosa grandiosa di JSX è che quando si commette un errore, è probabile che venga catturato in fase di progettazione da una linter o in fase di compilazione, invece di attendere il runtime. Babel, ESLint e molti strumenti di editor hanno il supporto integrato per JSX.

Un'altra cosa grandiosa di JSX è che puoi scegliere come target più di un semplice HTML. Puoi scegliere come target markup personalizzati, puoi scegliere come target il canvas, puoi persino scegliere come target un'interfaccia utente mobile nativa.

La cosa negativa di JSX è che non si allinea esattamente 1: 1 con tag HTML. È un ibrido Frankenstein di API JavaScript e markup. Ciò significa che devi imparare le sue stranezze, come usare `className` invece di` class` - ma dal momento che puoi abbastanza liberamente mescolare il semplice vecchio JavaScript con JSX per loop, condizionali, ecc ... Penso che batte ng2 per l'apprendimento.

Che dire dello stato?

Sia Angular 2 che React possono usare qualunque livello di gestione dei dati ti piaccia. Se non ti dispiace rinunciare all'associazione dati bidirezionale (che, comunque, IMO è una cosa negativa), puoi portare la tua gestione dello stato su ng2. Raccomando ngrx / store, che è fondamentalmente Redux + osservabili.

Per React, prova Redux (per la maggior parte delle app di grandi dimensioni) o MobX (per le app meno complesse che non richiedono uno stato transazionale).

Per ulteriori dettagli sulla moderna gestione dello stato per le app JavaScript, dai un'occhiata a "10 suggerimenti per una migliore architettura Redux".

Cosa dovresti scegliere?

Dopo aver usato entrambi pesantemente per un po '(reagire molto più a lungo, ovviamente), mi sembra ovvio che Angular 2 richiede molto più acquisto tecnologico e molta più targa nelle app.

Se ami le scelte tecnologiche e puoi vivere con l'overhead della piastra aggiuntiva, scegli Angular 2.

Se non sei soddisfatto di alcune delle scelte tecniche di Angular 2 e desideri qualcosa di più sottile e meno prescrittivo, scegli React.

Naturalmente, ci sono altre opzioni (alcune molto buone), ma c'è un valore in un grande ecosistema e comunità di sviluppatori, e React & Angular dominano l'utilizzo. Non c'è nemmeno un terzo vicino. L'unica libreria più popolare di queste due è jQuery (sì, ancora).

Continua a ballare.

Inizia la tua lezione gratuita su EricElliottJS.com

Eric Elliott è l'autore dei libri, "Software di composizione" e "Programmazione di applicazioni JavaScript". Come co-fondatore di EricElliottJS.com e DevAnywhere.io, insegna agli sviluppatori le abilità di sviluppo software essenziali. Crea e consiglia team di sviluppo per progetti crittografici e ha contribuito alle esperienze software per Adobe Systems, Zumba Fitness, The Wall StreetJournal, ESPN, BBC e i migliori artisti discografici tra cui Usher, Frank Ocean, Metallica e molti altri.

Gode ​​di uno stile di vita remoto con la donna più bella del mondo.