Part 3 Correctness

Writing good software is hard, and it’s hard in many dimensions. We often hear about the importance of simplicity, but we tend to hear less about simplicity’s sibling: correctness. Writing simple code is an admirable goal, but without correctness, even the world’s most beautiful and simple code can still be wrong. We tend to hide complexity behind abstractions, but complexity is everywhere, always, even when hidden, so we must ensure we retain correctness.

Correctness is both qualitative and quantitative. Whether code is correct depends on how well the API is specified and whether the API’s definition and implementations match. For example, I can write an adder function that accepts two parameters and returns their sum, but it should also correctly handle edge cases, such as overflows, signedness, bad inputs, and so on. For our adder to correctly handle those cases, they need to be specified. Unspecified behavior is the enemy of correctness.

In the upcoming chapters, we’ll discuss testing strategies for guaranteeing correctness in your code. By writing tests for your code, you can also reveal weaknesses in specifications by finding ambiguities, in addition to verifying the correctness of your implementations.