Defensive Programming - Improving Readability
Defensive programming is all about designing software that behaves as intended even in unintended situations. One way to help keep your code running smoothly is by being to be intentional about naming and organization. By making your code easier to read it then also becomes easier to review. Doing this can can help your future self and others while reviewing a pull request.
Use specific nomenclature
One thing I see quite often is variable and function names that are not specific enough. I always try to ensure my names are specific. I can always refactor later to a more abstract name if required. Lets take a look at a common naming practice that I think can be improved.
fun validDob(date: Date): Boolean {
//CODE GOES HERE
}
I would prefer to write this method in the following manner.
fun isOver21(birthday: Date): Boolean {
//CODE GOES HERE
}
By describing the business case in the name of the method it will help the reader understand what the method should be doing both inside the method and in the context of where its being used.
Prefer single if statements
Another common practice I see is chaining multiple if statements together. Lets look at the following example.
fun validateForm() {
if (isValidDob(birthday) && isValidCC(cardNumber)) {
submitForm()
} else {
//INVALID FORM
}
}
As your application grows you will often find these chained statements growing along with your form. When I encounter this I often find it better to use more specific naming and break up the statements so I can read it inline.
fun isFormValid(): Boolean {
if (!isOver21(birthday)) {
//INVALID BIRTHDAY
return false
}
if (!isValidCreditCard(cardNumber)) {
//INVALID CARD
return false
}
return true
}
With this change the reader can walk through each step independently rather than parsing what combination of statements leads to true. It also allows you to independently handle errors at the exact site without further nesting.
Combine related code in the same commit
When reviewing code I find it helpful to work through changes commit by commit. This helps limit the amount of change I need to keep in my head at any given time. I try to combine my code and the test code together in a single commit so its easier to review. If I write a method to check isOver21(birthday: Date) I would then in the same commit write two tests named something like isOver21(birthday: Date) and isUnder21(birthday: Date) that call the method I wrote.