Correctness

Code that is correct is code which conforms to a set of expectations and requirements. If I write a function to validate email addresses, then the expectation is that the function can be called with all types of email addresses and correctly establish their validity or invalidity as follows:

isValidEmail('[email protected]');     // => true
isValidEmail('[email protected]'); // => true
isValidEmail('john@thecompany.$$$'); // => false
isValidEmail('this is not an email'); // => false

To write correct code, we must first have an idea of what the requirements are. Requirements are our formalized expectations for how the code will behave. For the previous case of an email validation function, we might have the following requirements:

  • The function will return true when a valid email address is passed as the first argument
  • The function will otherwise return false

The first requirement is ambiguous though. We need to discern what it means for an email address to even be valid. Email addresses are a seemingly simple format; however, there are in fact many edge cases and oddly valid manifestations. For example, the following email addresses are technically valid according to the RFC 5322 specification:

To know whether our function should align fully with the RFC specification, we first need to understand its true use case. Is it a utility for email client software, or is it perhaps utilized in user registration for a social media website? In the latter case, we may want to establish the more exotic email addresses as invalid, similar to those listed previously. We may even want to ping the mail server at the domain to confirm its existence. The point is to discern what exact requirements will provide for us the meaning of correct.

Incidentally, composing your own email validation function is very ill-advised, as there are many edge cases that need to be taken into account. This highlights an important consideration in our quest for reliability; often, we can achieve the highest level of reliability by using existing tried-and-tested open source libraries and utilities. In Chapter 17, Other Peoples' Code, we discuss the process of selecting third-party code in detail, and what to look out for.

The requirements we are coding should always derive directly from how our code will be used. It is vital to start with the user and their problem; from that, we can establish a set of clear requirements that can be independently tested. Testing our code is necessary so that we can confirm, to ourselves and our stakeholders, that our code fulfills all of the distinct requirements.

With the previous example of email address validation, a good set of tests would encompass many variations of email addresses, ensuring that all edge cases are fully accounted for. In Chapter 13The Landscape of Testing, we discuss testing in far more detail. For now, however, it's sufficient to simply reflect on the importance of correctness and the ways in which we can establish and confirm it:

  • Understand the problem being solved and what users want
  • Refine your requirements until it's explicitly clear what's required
  • Test your code to verify its correctness

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.95.74