Kyle Chui's Blog

Taste (6 months)

Through my (very short) time working in software, I've picked up a certain "taste" for things. After reading through a post by Chris Kiehl, I felt inspired to write them down. I have only been working professionally for ~6 months, so the following are just current thoughts based on my (very limited) experience so far and subject to change!

Current Tastes

Prioritize Simplicity

While abstractions enable you to accomplish more with less code, they can make things more difficult to understand. I have seen a few examples of code that is very difficult to navigate and reason about, due to too many layers of inheritance and imports from other packages. When working with a codebase, view complexity as a currency and try to spend it as wisely as possible.

Optimize code for readers, not writers

Code is generally read (by oneself and others) many more times than it is written, so it is worth keeping your future readers in mind. Allowing them to understand your code more easily will make future modifications more simple.

A corollary is that I try to leave more comments in my code; my general rule of thumb is to add comments if I think they would improve clarity. I do not generally agree with the sentiment "rewrite your code to make comments unnecessary", since following that blindly can lead to code that is harder to read.

One particular example I have seen is over-extraction of blocks of code into their own methods, where short 2--3 line sections are pulled into different functions. While this sounds fine at first, if that function is only ever called in one place, all we are doing is moving closely related code further apart. When reading code in the browser (as is often the case for code reviews), it is annoying to scroll back and forth (or worse, open multiple tabs) just to understand one function that could have been a contiguous block with a couple of comments sprinkled in.

Static types > Dynamic types

Statically typed languages (and static analysis in general) help "move" errors from compile-time to runtime, where they are cheaper to diagnose and fix. While some may say that the increased verbosity is tedious, I think that explicit types can serve as documentation to the reader. Moreover, types have something over other forms of documentation: they are verified by the compiler and as a result are kept up-to-date (assuming the type checker passes).

Tooling is very important

Knowing your tools better not only allows you to move faster, but also enables you to do different things altogether. When mundane tasks become trivial to do, it frees up your attention to think about other, more difficult problems. Here's a few examples I think are worth highlighting:

Tools can also help groups of people reach consensus by acting as an "unbiased" third party. Formatters help teams get over the minutiae of the syntax on the screen, and focus on the semantics of what is written. I think that more opinionated tools are also better, since they do not allow for different "interpretations" by different people (e.g. black).

Implementation inheritance is bad

Dynamic dispatch makes it unclear what code is actually getting executed at runtime, making programs much more difficult to understand by just reading them. There have been many cases where reading through a codebase inevitably leads me to some interface implemented by multiple classes, making it a hassle to find the actual implementation.

Another issue with inheritance is that it couples together code that may only be incidentally the same (e.g. configurations for two different services). Issues arise when code evolves over time, and what once was code de-duplication quickly becomes a nest of exceptions to the rule. Don't shy away from code duplication if it makes things easier to read and maintain.

Potpourri

Here are some more concrete opinions (with some repeats from before):

Things I Want To Develop Taste For

Tasteful Resources