Code QualityWe 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.
“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, and
“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 manualUnsatisfied 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.
Enter WebpackWebpack 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.orgReact 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.
On the ServerOne natural consequence of world domination is running on both ends of a web site: the front and the back end. We’ve been using node.js to run a variety of services. The combination of a built-in event loop with an enormous selection of third-party packages makes node an ideal system for implementing webhooks, bridging APIs, or even providing our own. We use TypeScript and TSLint on the server as well to ensure that both halves of our systems — producer and consumer — are communicating consistently with each other. In addition, some of our bigger backend systems are now running in Docker containers. Our automated build systems produce an authoritative image of the server, and the ephemeral nature of containers means that deployments are reduced to a mere restart of the container environment. Thanks to Docker Compose, our local development environment has near-perfect parity with the production stack, surrounded by locally-accessible tools that make it easier to debug or monitor a running server. Services like MailHog or Minio can be run with less stringent protections.