timeNow func() time.Time
mock.Close
method that we deferred.*os.File
Close
method can be responsible for actually flushing to the file, so if an error occurs at that point, the whole write might be aborted! 😱const
are allowed. Period. This means also, no init
functions.reflect
or unsafe
Packagesreflect
tend to be very slow. For testing code, it's fine to use reflect.:
or lack of it.golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
in future. There was even Go 2 proposal for disabling this in the language itself, but was rejected:append
in between instead of just one if you preallocate.There should be one-- and preferably only one --obvious way to do it
and DRY
rules. If you have more ways of doing something than one, it means you have a wider interface, allowing more opportunities for errors, ambiguity and maintenance burden.return
statements with named return parameters. This compiles but it makes returning values implicit and thus more prone to surprises.level.Debug|Warn
etc and fmt.Fprint*
...string
) arguments to be filled in pairs, e.g:else
else
. You can usually use continue
, break
or return
to end an if
block. This enables having one less indent and better consistency so code is more readable.pkg/errors
package for errors
. We prefer it over standard wrapping with fmt.Errorf
+ %w
, as errors.Wrap
is explicit. It's easy to by accident replace %w
with %v
or to add extra inconsistent characters to the string.pkg/errors.Wrap
to wrap errors for future context when errors occur. It's recommended to add more interesting variables to add context using errors.Wrapf
, e.g. file names, IDs or things that fail, etc.Errorf,Warpf
put arguments at the end to make it easyer to read and use %v
to reduce human error if the argument type changed.failed...
, couldn't...
or error occurred while...
. Just describe what we wanted to do when the failure occurred. Those prefixes are just noise. We are wrapping error, so it's obvious that some error occurred, right? (: Improve readability and consider avoiding those._
lowercase
(readability and consistency) and all struct keys are using camelCase
. It's suggested to keep key names short and consistent. For example, if we always use block
for block ID, let's not use in the other single log message id
.msg
field. It should be used only for important events that we expect to happen not toomsg
field. It can be a bit more spammy, but should not be everywhere as well. Use itmsg
or err
or both fields. They should warn about events that are suspicious and to investigatevalue will be skipped
msg
or err
or both fields. Use it only for a critical event.TODO(<github name>): <something, with GitHub issue link ideally>
.time
package.timeNow func() time.Time
field. For production code, you can initialize the field with time.Now
. For test code, you can set a custom time that will be used by the struct.print
. Always use a passed go-kit/log.Logger
.