Type-checking, linting, formatting: Gates of Power

Simon Janes
The Accepted Forest
3 min readAug 17, 2018

Writing software systems is a complicated dance between the product owner, the ecosystem of tools and services, and your ability to learn and solve problems. You could make a checklist of all the things you wish were true about the quality of your code, but you would never actually spend the time evaluating it mentally — you need all the “bandwidth” you can get from your mind just for solving the problem.

Automation of your pain here is perhaps masochistic (or sadistic if you’re a particularly good at designing continuous integration pipelines!) but the consistency of having problems do your checklists for you — consistently — ratchets up your system-quality.

Do things the hard way in practice,
Do things the easy way in crisis. But…
THERE IS ALWAYS CRISIS.
Therefore, always do it the hard way.

Today we’re going to explore this idea with Microsoft’s TypeScript. TypeScript is identical to JavaScript and will happily treat it just like that.

Type-checking (what the data means)

All the types for data and function interfaces will be inferred for you, but you should start habitually annotating. When you skip annotations TypeScript assumes the type any. If you receive a value of type any you have to then make decisions at run-time what you have to do.

Rapid prototyping can get away for a while with using any as a type, but as you understand your problems you should move away from any as soon as possible. This gives your compiler an explicit idea how to check your code for semantic mistakes — passing in a number when a function only works with strings. Or, even worse, passing in a filename (represented by a string) when you wanted an HTML template fragment (also… representable by a string). Take the primitives of the language and package them up with some semantics. Type aliases are good for this.

type Filename = string
type HtmlTemplate = string
function fileFrobber(name: Filename) { ... }
function templateFrobber(template: HtmlTemplate) { ... }

Fully-annotated code moves all of the run-time behavior checks into development — and your code gets faster and more-reliable. What’s not to like?

Oh, the pain of type-checking. Keep doing it, and you get better and the feedback from the compiler is infinitely more desirable than the feedback of a million error reports per hour captured from a deployed application. Remember, practice the hard things and do the easy things in crisis — but in software development there is always crisis (so always do the hard things.)

Code linting (remove lax behaviors)

Unfortunately, there are many things that will pass the compiler but may have semantic issues. Here a tool like tslint maintains a checklist for the “human factors” of software development. Not all types are desirable so they can be banned from use. Conditional assignments of values? Get rid of that. Used a language keyword as a variable name? Drop that.

Use JavaScript eval ? EXPLODE THE COMPILER.

Well, perhaps not that extreme.

Code formatting (uniformity and consistency)

tslint also gives you a two-for one bang for the buck: code formatting. When you have this in your quality pipeline another benefit becomes visible in teams: branching and merging code becomes easier because no one is fighting with the positioning of curly brackets and white space.

You just have to decide in advance to use the formatting and if you have already existing “legacy code” in the arbitrary format. Go ahead and go through the pain of reformatting that merge and tool configuration. Short term pain, long term benefit for your teams.

Conclusion

Fluency in a language is nice but getting the computer some of the work for you makes your code stronger, faster and more reliable. These are safety nets that enable fearless refactoring. And we haven’t even talked about unit testing (which you should also be doing).

Are you working on the silicon_prairie? Perhaps you want the shirt! Yes… buy the shirt! https://teespring.com/silicon-prairie

--

--