Blog Insights
JavaScript is Taking Over the World, and It’s Got Us Too
Code Quality
We want to be 100% certain that our code is ready to ship, whether we’re working on the first line of code or the ten thousandth. To ensure this, we’ve adopted TypeScript and TSLint as our quality checking tools of choice.TypeScript
“The main purpose of a type system is to reduce possibilities for bugs in computer programs by defining interfaces between different parts of a computer program, and then checking that the parts have been connected in a consistent way.” – Wikipedia: Type system.
Type checking is an important part of any large-scale project, whether you realize it or not. All code makes assumptions: mathematical functions accept and return numbers, regular expression functions work on strings, andReactDOM.render() accepts a ReactElement<P>, an Element | null
, and an optional callback in one of its eight overloads. Why keep track of this yourself when a computer can do it for you?
Since 2014, we’ve been working with the National Assessment of Educational Progress (NAEP) to build reports for the Nation’s Report Card, which is the largest ongoing assessment of what U.S. students know and can do. And we’ve been building these reports with TypeScript. We retrieve NAEP data from an API, and having type definitions for this data has been a real life-saver. The records the API returns have varying shapes based on what kinds of comparisons we ask the server to do. A data comparison between two jurisdictions will have different fields than a data comparison between two years, and the TypeScript compiler will refuse to allow code that mixes up the two kinds of results.
As a result of this type checking, we’ve had to fix fewer bugs overall since many were prevented from even being written. This success is driven by both the language and its community. We owe a huge debt to the DefinitelyTyped project. It has been around for a long time, and is now the official source for type definitions of npm libraries. The community has produced thousands of definitions for libraries like d3, React, jQuery, and more. These serve as the bridge between our own TypeScript code and the broader JavaScript ecosystem.
TSLint
“The lint utility attempts to detect features of the named C program files that are likely to be bugs, to be non-portable, or to be wasteful.” – the lint manual
Unsatisfied with mere type checking for our projects, we added TSLint to our bug-catching toolkit. The term “lint” generally refers to an undesired bit of program behavior that might be allowed by the language but is nevertheless considered suspicious or potentially error-prone. TSLint covers a wide range of possible lints, from stylistic concerns like variable naming conventions and proper curly brace usage, to safety concerns like preventing access to eval() or the with statement, to even more sophisticated analyses like object model coherence. Linting becomes increasingly important when working with a team of developers. As with writers, all developers come to a project with different styles of coding which, in and of itself, is not bad. But the ultimate goal of a solid codebase is to have some semblance of standardization. We recently wrapped up work on City Health Dashboard for the Department of Population Health at NYU Langone Health, which is a complex project that looks at 37 health metrics across the 500 largest cities in the United States. It enables users to compare metrics between cities, look for correlations between them, and see maps that visually show variances by census tract for any given city. With a sizable team of developers contributing code to the project, having linting in place helped to ensure that the formatting of our code was consistent, which in turn allowed us to focus on the substance of pull requests. By enforcing good coding guidelines with TSLint (and making it part of our build), we ensure that all code is written in a way that we believe to be robust and maintainable.Build Tooling
JavaScript applications have a lot of dependencies. In addition to third-party libraries, applications depend on non-code assets like images. Managing all these dependencies requires playing well with both users’ browsers as well as the content delivery networks that are caching these applications.Enter Webpack
Webpack is a build tool for the modern Web. It reads in your application sources, analyzes the dependencies, and outputs files containing only the code needed to run. This system is extensible: we are able to add processors (called “loaders” in Webpack-speak) to handle bundling style sheets, images, and even things like CSV files. We have a default configuration for all projects that ensures a good developer experience along with build output that follows best practices. For example, when it’s time to do a production build, we automatically optimize images. This configuration evolves with our needs. We’re looking at integrating pre-rendering plugins for better search engine visibility, and tuning build times on large projects by using multi-threaded builds. (As it turns out, an easy way to speed up doing a lot of small tasks one-by-one is to distribute the workload. Who knew?)In the Browser: React
“React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.” – reactjs.org
React is a declarative framework for web applications. Instead of using view classes or templates to build up an interface, React expects a description of an interface. The rendering engine (the reconciler, in React parlance) then uses this description, compares it to the current state on the page, and then updates the page on an as-needed basis. Because React is only a user interface library, its maintainers are able to make it perform as efficiently as possible while allowing developers a great deal of flexibility to handle their applications’ logic and data sources without needing an extra integration layer to deal with.