How I Learned to Stop Worrying and Love Types

Last year I posted my opinion on how Javascript’s Lack of Static Types Improves Code Quality. One year later, having been burned by a relatively large Node.JS projectI’m now using Typescript and Go for all my new pet projects. While I still believe in writing small, modular code, I will now eat my words and list the reasons why I once again prefer to work with typed languages, and hopefully help you avoid the same mistakes I made.

Types are Contractual Documentation

Typesare a form of documentation that is “built-in” to the code. While in Javascript, types are often formally or informally documented in comments, it’s easy for a function signature to change and suddenly the comment is out of date. But the compiler won’t tell you, in fact it’s up to the developer making the change tonotice that there is a comment there and take the time to update it. When deadlines are tight, this task often falls to the bottom of the priority list until another poor soul has to waste their time working outwhy the comment doesn’t match the signature. The knowledge that types provide to the compiler can also be taken advantage of by documentation generators (and IDEs, if that’s how you roll), helping give an overview of the code to new developers. A great example of this is Go’s godoc.

Types Are a Form of Investment

Dynamic languages are seductive because they let you move quickly in the beginning. But as the codebase grows, types help you move quickly and break things while still having confidence in your code. Code debt is an inevitable part of software development. Types are a form of time investment that help offsetthat debt.Working with a type system often means more verbose code, more wrestling with the compiler in the early stages, but it also means you can have much more confidence down the track when things get sticky.

Types Slow You Down

When designing an interface in Go for instance, you need to take the time to think through what that interface will do. Which pieces of functionality will belong to that interface, and who will be using it? This upfront thinking can take some time, but it pays off in the long run. While fast, iterative, agile development is essentially the norm in software these days, that does not mean you should sacrifice code quality for shipping. Dynamic languages let you hack things together quickly, which can be invaluable for small tools, prototypes, and even MVPs. But for products that need to be maintained over time, types save time later at the expense of slowing down the first code cutter.

Modern Type Systems Are Not That Bad

Gone are the days when the type system was there just to help the compiler. Type systems in modern languages help the programmer too. The type system in Go provides just the right amount of assurance without feeling too restrictive. Interfaces in Go allow functions to easily accept multiple types, instead asking what the parameter should be capable of rather than what it is (similar to duck-typing in dynamic languages, but here with compile-time assurance). Typescript allows optional types, happily accepting pure Javascript so that the legacy JS can be progressively converted to Typescript for additional assurances.

For me, the takeaway is this: Don’t expect or rely on types to do your work for you. Rely on them to help you make assurances, to feel confident about your code, and to help your colleagues when they inevitably need to dig into your braindump.