chapter three

3 A log story

 

This chapter covers

  • Understanding the need for a logger
  • Implementing a 3-level logger
  • Using an integer-based new type to create an enum
  • Publishing a library with a stable exposed API
  • Implementing closed-box testing and internal testing
  • Understanding package-level exposition

Coding time: 2h

The night is dark. Your colleague Susan and you have been working on trying to fix this bug for 2 hours straight. You don't understand what's happening with that count variable that should have the value 1, but the result of the program seems to indicate that the value there is 2 instead. It’s late. You try to read the code, but the problem isn’t obvious. Is count really 2? You decide to add a small line in the code, and relaunch everything, to get a better insight as to what's going on. The line you add will help you, at least, understand what the variable’s value is. You use:

fmt.Printf("counting entries, current value is %d\n", count)

We’ve all been there. Having the code say something we can understand at specific steps is our easiest way of following the program as it executes.

Then Susan notes - wouldn’t it have been nice to have this information from the initial run, without needing to redeploy an updated code? But then, would you also want to deploy this unconditional fmt.Printf (hint: the answer is an absolute no)? Were there other options that could have made your life simpler?

3.1 Define the API

3.1.1 Expose the supported levels

3.1.2 Object-oriented Go (gooo?)

3.1.3 The New() function

3.1.4 And what about testing?

3.1.5 Documenting code

3.2 Implement the exposed methods

3.2.1 Default implementation

3.2.2 Interfacing

3.2.3 Refactoring

3.3 The functional options pattern

3.3.1 Create configurations