When to warn

If the software you’re developing has a problem then you want to know about it. We use log messages at runtime, build messages at compile time and we can run extra tools to tell us even more about our code. However there can be so many messages they you don’t end up reading them, at least not the ones that count.

Fatal errors

I like fatal errors. That is, I don’t like getting fatal errors but it’s much better than spending days tracking down a bug. As this is a fatal error is it still a warning? I’m going to say yes. The message attached is the warning and there should be an attached warning.

I’m use to having a set of logging functions like this:

void log::Debug(const std::string& format, ...);
void log::Info(const std::string& format, ...);
void log::Warning(const std::string& format, ...);
void log::Error(const std::string& format, ...);
void log::Fatal(const std::string& format, ...);

And that last one logs a message and exits the program. You might come at it from the other direction and have exit functions like this:

void ExpectedExit();
void UnexpectedExit(int code, const std::string& format, ...);

I wouldn’t just use exit because then someone can forget to use a message. Generally speaking if someone can do something they are going to do it at some point.

This is when something catastrophic has gone wrong and continuing makes no sense. What this means depends on the product.

Recently I’ve been working on batch processes which powered a web service. That meant exiting made sense even with fairly simple things such as the configuration file being missing. The end user wasn’t able to touch the configuration directly so the file really should have been there. The web front end was still there to interact with the user.

If your process is interacting directly with the user then a fatal error is less useful. Ideally if something goes wrong you tell the user with a status message or dialogue box and continue, a warning can go to the log file as well. However depending on what the “something” is continuing may or may not be possible. Again, to avoid wasting time tracking down bugs it’s better to detect an error and exit than just crash.

Warnings everywhere

It helps if the team has a clear idea of what each logging level is used for. What is the difference between log::Debug and log::Info? Maybe the first has low level details including variables and the second shows more general program flow. What is the difference between log::Warning and log::Error? Maybe the later is the underlying problem and the former is the chaos that is caused.

It’s fairly common to end up drowning in messages. Be especially careful with log::Warning and log::Error. If you it’s possible do some extra processing to weed out red herrings. Ideally these messages should really mean something. Seeing one should make you stop and investigate… otherwise you run the risk of habituating to them. Once you’re use to warnings it’s very easy to miss new ones when they really matter. This is where log::Fatal has an advantage because it’s impossible to ignore.

I think the most common occurrence of this is with build systems. A lot of systems, especially legacy systems, have so many build warnings they cease to have meaning. If possible start your project by switching on “warnings as errors”. This will force you to go the extra step and keep a clean build. That means potential problems that do appear will be caught immediately. Of course, it normally means jumping through some extra hoops in your code to satisfy the compiler. It’s a bit of extra work but rarely hard.

A particularly annoying situation here is changing or updating your compiler. All of a sudden code that was “clean” is now flagged as problematic. I didn’t like some of my recent experience with automatic compiler updates. It meant that whomever was updated first suddenly had a broken build. Mixing their original branch with this fix can be confusing and may end up duplicating work if someone else hits the same update. Really fixing the build in this situation is a separate task. Ideally it could be noticed and scheduled rather than dropping in unexpectedly.

And now SonarQube

SonarQube is my original inspiration for this post. It’s a code analysis tool that can integrate with your build system and give you feedback on a variety of problems, both actual and potential. In many ways it’s good although I don’t always agree with every rule. Imagine a code review but a knowledgable but pedantic colleague. Maybe a bit irritating on minor issues but helpful in the long run?

My experience was that it’s a bit like the situation with automatic updates. In an instant the codebase went from being warning free to having hundreds of issues. No bugs or security issues but many code smells. It’s good that we could know about them but very distracting that we suddenly did know about them:

  • Some are easy to fix, some are hard.
  • Some are important, some really aren’t.
  • Some warnings need fixing, some need suppressing.
  • Should they be fixed now or when nearby code is changed?
  • Who is responsible for each one?

With hundreds of warnings to fix it’s very easy to focus on getting rid of them now rather than getting rid of them right. In the end we ended up with more complicated branches, multiple fixes for individual smells and the wrong fixes for some of them. Months later there were still a couple of hundred of the harder ones left.

In retrospect starting with all the warnings is probably a mistake for an existing project. Using a configuration that restricted what was reported would have made it easier to focus. Choosing a set of smells to worry about and only checking for them. Indeed the branch that enabled a set of checks could also be where those smells are fixed.

Warning can be very useful. We do want to know when something is wrong. However too many warnings can be just as problematic as too few. If you dealing with lots of warnings but they don’t mean much or with no warnings but lots of problems then maybe stop and think about what is actually going on.






Leave a Reply

Your email address will not be published. Required fields are marked *