Ask any front-end developer today and they’ll tell you React is all the hotness. React can work on the web, your mobile device, your watch, and eventually your hair dryer, fridge, and internet-connected T-shirt. While I like working with React just as much as the next front-end developer, I also have a pretty long history with Angular.
After picking it up in 2012, Angular was the first framework to give me a taste of what a JavaScript framework even is. Now that Angular 6 is out and all the chaos regarding the name change and framework change is behind us, I’m convinced that for large-scale web applications, Angular is not only the best solution, but the only scalable one that can be used no matter how large you foresee your application becoming.
React still has a place for smaller and mid-sized applications. In fact, in that category it outshines Angular because of its cross-platform portability through React Native and also its ease of use as a framework with a shorter learning curve. However, scalability challenges occur much sooner with React than with Angular. Most recently (and famously), Airbnb chose to sunset React Native because of (among other issues) the difficulty with refactoring React code, along with the relatively steep learning curve and boilerplate involved with Redux.
Honestly, if you think the learning curve with Redux is steep, the learning curve with Angular is even steeper. So in that respect, there isn’t a large advantage in using Angular. However, good programmers are known for focusing on long-term thinking as opposed to short-term. In the long run, once you get past the steep learning curve, here are a few ways that Angular 6 notably outshines and outperforms React.js, and why it’s worth learning despite how long it takes to pick up.
1. Slick Tooling
Like many languages and frameworks Google makes, Angular also has really slick tooling. Want to scaffold out a component? The Angular CLI makes it very easy to pinpoint exactly the folder you want to put it in, which module it should be imported into, and a basic unit test for making sure it renders properly. A karma test runner, a styling language of your choice, and now even adding custom templating languages like Pug is very easy to do with Angular 6. Being able to use Pug so easily reminds me of the good old days when I first started with the Angular.js Fullstack Generator. Ah, good times.
Angular 6 also adds two very important superpowers to the CLI: Schematics and Libraries. Schematics allow you to reduce your boilerplate code to a custom schematic that you can create for your own modules and components. Meanwhile, the new library generator makes it much easier to contribute open-source modules. Without it, I would still be largely working on closed-source projects rather than go through the hassle of making specific components very reusable and open-sourced. If it weren’t for the Angular 6 CLI and the convenience it provides, many developers like me who have their plates full already writing code for more than 60 hours per week, would probably not contribute to open source.
Finally, when you use Angular and Typescript with a good text editor like Visual Studio Code, your code gains magical abilities to automatically enter your thoughts and figure out which variable you are trying to use, automatically import it, and use it. You also get the ability to auto-complete your classes with their attached methods that you didn’t even know existed, import modules that you didn’t know were included, and just have to read documentation much less frequently because everything you need to read is right next to your code inside your editor.
2. Type Safety that Leads to Easier Refactoring
Typescript was my first statically typed OOP Language. There, I said it. Like many JavaScript developers, my background was not in formal Computer Science. My first Computer Science course was a Python class on Coursera. Naturally, Python isn’t statically typed either, and I liked it that way. Once I got comfortable with debugging, I felt very nimble in writing code that just worked in Python, especially for scripting and CSV reading.
Well, turns out that with JavaScript, something that “just works” in one situation often requires careful pre-planning and design beforehand to make sure it will also work in future situations as requirements change and products become more complex. Almost every JavaScript developer makes this mistake of underestimating future changes to code at some point. Regardless, as I continued to dive deeper into JavaScript and became more proficient with React and Redux, I definitely appreciated the effort by the community to provide not only best practices for UI elements, but also state management. That’s probably the single best characteristic about React: the thriving developer community.
However, as I would refactor my react code, I’d often be stuck about when to return a reference to a method versus a function that returns that method versus calling that method in my class outright. For example, imagine we have a parent App Component calling a Child.
import React, {Component} from 'react'; import Child from './child';
export default class App extends Component { handleClick(event) { console.log('Child clicked from ' + event.target.value); }
render() { return ( <Child onClick={this.handleClick} /> ) } }
In these cases, event will be undefined because we aren’t explicitly bubbling it up from the Child component. However, we can replace the line
<Child onClick={this.handleClick} />
with<Child onClick={(event) => this.handleClick(event)}
and things would magically seem to work. Oh, except for binding ‘this’ to the handleClick method (eh, small detail). In the child, we would need to specifically reference the parent callback attached to props, so if the child was a simple button, it might look something like
export default const Child = (props) => { return ( <button onClick={props.onClick}>Default text</button> ); }
In order to handle situations like this, react used to come bundled with a handy library called… prop-types (now a separate install). In other words, react also acknowledged the importance of having types in your code to make things more sane and sort out subtle differences like these. However, unlike in React, types are a first-class construct in Angular with Typescript. Might as well bite the bullet and start adding types to our JavaScript code (especially for enterprise-scale apps).
At first it seemed tedious trying to learn Typescript and Angular at the same time, and definitely added to the learning curve of a new framework (yes, despite Angular being on version 6, it’s still a much newer framework than React since it’s nothing like Angular 1). However, after a few months of becoming familiar with the project you work with and easing into the not-quite-JS syntax going through a strict compiler, the ease of refactoring existing code is worth the trouble of adding types many times over because types only need to be added once, whereas refactoring is an ongoing process that occurs continuously over several years.
3. Built-in Data Streaming
Another pain point that new Angular developers face is that promises no longer seem to be first class citizens. What?!? No promises?!? Shocking. You can still use promises if you really want, but Angular installs RxJS for us, which is an asynchronous programming library that favors Observables over promises. At first it took some time to wrap my head around Observables, and I’m not sure I’ve fully unlocked their capabilities still.
The main difference is that whereas promises allow us to listen to asynchronous data once, Observables allow us to continue listening for new data and make changes automatically as the data changes. Observables are also very easy to pass around and run several data-formatting operations on without even receiving the data.
With Angular 6, RxJS also received a big update and seems to be following Angular’s semantic versioning now. More importantly, RxJS 6 allows RxJS to be used in any JavaScript environment, with or without Angular. After transitioning to Observables and away from promises, I’m convinced they give any software developer much more flexibility around dealing with Asynchronous code.
Streams are a very natural way to think about data flow, whereas promises felt a bit out of place and felt like they were not powerful enough to handle more real-time functionality like notifications, instant changes based on user actions, among other things. Compound that with the large scale of enterprise applications where, often, two large modules need some bridge to communicate specific pieces of information with each other. RxJS, when used properly and thoughtfully, allows you to build strong, durable bridges across different modules of your Angular application.
Conclusion
Built-in data streaming, type safety, and a modular CLI are hallmarks of what makes Angular such an opinionated framework. However, considering that this is the framework that helps even the largest of technology companies manage their enterprise applications, combined with a commitment from Google to introduce no more breaking changes, now is a better time than ever to learn Angular. Be warned, there is at least a few months of learning involved before you feel proficient enough to start building non-static content, but it’s worth it. When I think about how painless it was to upgrade Angular versions versus how painful it is to upgrade React dependencies, that alone makes the switch more productive for me.