Podcast #128: We chat with Kent C Dodds about why he loves React and discuss what life was like in the dark days before Git. Listen now.
4 Adding "warning" logging level
source | link

Never use asserts to check public API preconditions, especially if you develop a library.

You don't control how other people call your library. Every crash in your library is a bug in that library. A library shouldn't crash just because it received bad input, it should return an error instead. Think about fuzz testing: it generates invalid input to check that your software can recover from it, which is the normal behavior.

Let me take an example: I once had a crash on Microsoft Word when opening a specific document. OpenOffice at that time could open it and helped me recover my data. Even if I had an assertion in Word telling the file was badly formed, which program do you think did a better job? This is not specific to the desktop world. I worked on embedded systems (Set Top Boxes) where you had multimedia files to process and display: you not allowed to crash because a media file is corrupted, at worse you just trigger an error and don't play the media.

You think asserting helps getting to the place where the error happened? Use logging and you'll get the same effect, but without crashing forcedly. The assertion doesn't make a distinction beween recoverable and non-recoverable errors: you always stop. But logging allows you to know where and why it failed and lets you decide if you can continue or not.

Think of your customer that wants its app running, and each time a certain condition happens, it crashes. I think the customer may prefer to have some log or error showing up and the rest of the application resuming if the error is not a fatal one. You don't want any crashers in prodution code and an assert is that an intentional crasher. If assertions are disabled in production then it gets worse: your whole error-handling logic disappeared, and instead of crashing with an assertion message you're now crashing (maybe much much) later with no message, just because you didn't detect bad input and continued to process it.

If you're developping your own application, you might want to use assert to check for your own bugs however, in your internal calls, but for a library it's a no-no.

As for your options:

  1. errno: I agree that errno doesn't fit current programming practices, especially with multithreading
  2. Return code, or return code + pointer to error is good. That is what GLib does. The pointer to error is optional but can be used to get a relevant message and return the error on layers above. In the cas of your "get_index_of_object", that isn't even necessary: an index is never negative so just returning -1 is enough to say your object was not found.
  3. Disabling asserts in production: this breaks your logging logic, as people won't do logging + assert, they'll think the assert is enough. Again, you need logging in production and avoid crashes at all costs, so you can't rely on assertions.
  4. Return early is what the GLib does. Look at g_return_if_fail or g_return_val_if_fail. You want to have a trace of runtime errors: again use logging, with different levels (debug, warning, info, error). And if that error is considered fatal and can't be recovered, then yes, stop.
  5. Be pragmatic. Sometimes the error code is enough, sometimes no and you'll need a location for a more specific error code and error message. Sometimes you use functions that return errors to errno and will have to cope with that internally but can wrap the errors before returning them to the layer above.

All in all, I just recommend you to give a look to the GLib and GTK+ libraries. I learned a lot looking at their source code.

Never use asserts to check public API preconditions, especially if you develop a library.

You don't control how other people call your library. Every crash in your library is a bug in that library. A library shouldn't crash just because it received bad input, it should return an error instead. Think about fuzz testing: it generates invalid input to check that your software can recover from it, which is the normal behavior.

Let me take an example: I once had a crash on Microsoft Word when opening a specific document. OpenOffice at that time could open it and helped me recover my data. Even if I had an assertion in Word telling the file was badly formed, which program do you think did a better job? This is not specific to the desktop world. I worked on embedded systems (Set Top Boxes) where you had multimedia files to process and display: you not allowed to crash because a media file is corrupted, at worse you just trigger an error and don't play the media.

You think asserting helps getting to the place where the error happened? Use logging and you'll get the same effect, but without crashing forcedly. The assertion doesn't make a distinction beween recoverable and non-recoverable errors: you always stop. But logging allows you to know where and why it failed and lets you decide if you can continue or not.

Think of your customer that wants its app running, and each time a certain condition happens, it crashes. I think the customer may prefer to have some log or error showing up and the rest of the application resuming if the error is not a fatal one. You don't want any crashers in prodution code and an assert is that an intentional crasher. If assertions are disabled in production then it gets worse: your whole error-handling logic disappeared, and instead of crashing with an assertion message you're now crashing (maybe much much) later with no message, just because you didn't detect bad input and continued to process it.

If you're developping your own application, you might want to use assert to check for your own bugs however, in your internal calls, but for a library it's a no-no.

As for your options:

  1. errno: I agree that errno doesn't fit current programming practices, especially with multithreading
  2. Return code, or return code + pointer to error is good. That is what GLib does. The pointer to error is optional but can be used to get a relevant message and return the error on layers above. In the cas of your "get_index_of_object", that isn't even necessary: an index is never negative so just returning -1 is enough to say your object was not found.
  3. Disabling asserts in production: this breaks your logging logic, as people won't do logging + assert, they'll think the assert is enough. Again, you need logging in production and avoid crashes at all costs, so you can't rely on assertions.
  4. Return early is what the GLib does. Look at g_return_if_fail or g_return_val_if_fail. You want to have a trace of runtime errors: again use logging, with different levels (debug, info, error). And if that error is considered fatal and can't be recovered, then yes, stop.
  5. Be pragmatic. Sometimes the error code is enough, sometimes no and you'll need a location for a more specific error code and error message. Sometimes you use functions that return errors to errno and will have to cope with that internally but can wrap the errors before returning them to the layer above.

All in all, I just recommend you to give a look to the GLib and GTK+ libraries. I learned a lot looking at their source code.

Never use asserts to check public API preconditions, especially if you develop a library.

You don't control how other people call your library. Every crash in your library is a bug in that library. A library shouldn't crash just because it received bad input, it should return an error instead. Think about fuzz testing: it generates invalid input to check that your software can recover from it, which is the normal behavior.

Let me take an example: I once had a crash on Microsoft Word when opening a specific document. OpenOffice at that time could open it and helped me recover my data. Even if I had an assertion in Word telling the file was badly formed, which program do you think did a better job? This is not specific to the desktop world. I worked on embedded systems (Set Top Boxes) where you had multimedia files to process and display: you not allowed to crash because a media file is corrupted, at worse you just trigger an error and don't play the media.

You think asserting helps getting to the place where the error happened? Use logging and you'll get the same effect, but without crashing forcedly. The assertion doesn't make a distinction beween recoverable and non-recoverable errors: you always stop. But logging allows you to know where and why it failed and lets you decide if you can continue or not.

Think of your customer that wants its app running, and each time a certain condition happens, it crashes. I think the customer may prefer to have some log or error showing up and the rest of the application resuming if the error is not a fatal one. You don't want any crashers in prodution code and an assert is that an intentional crasher. If assertions are disabled in production then it gets worse: your whole error-handling logic disappeared, and instead of crashing with an assertion message you're now crashing (maybe much much) later with no message, just because you didn't detect bad input and continued to process it.

If you're developping your own application, you might want to use assert to check for your own bugs however, in your internal calls, but for a library it's a no-no.

As for your options:

  1. errno: I agree that errno doesn't fit current programming practices, especially with multithreading
  2. Return code, or return code + pointer to error is good. That is what GLib does. The pointer to error is optional but can be used to get a relevant message and return the error on layers above. In the cas of your "get_index_of_object", that isn't even necessary: an index is never negative so just returning -1 is enough to say your object was not found.
  3. Disabling asserts in production: this breaks your logging logic, as people won't do logging + assert, they'll think the assert is enough. Again, you need logging in production and avoid crashes at all costs, so you can't rely on assertions.
  4. Return early is what the GLib does. Look at g_return_if_fail or g_return_val_if_fail. You want to have a trace of runtime errors: again use logging, with different levels (debug, warning, info, error). And if that error is considered fatal and can't be recovered, then yes, stop.
  5. Be pragmatic. Sometimes the error code is enough, sometimes no and you'll need a location for a more specific error code and error message. Sometimes you use functions that return errors to errno and will have to cope with that internally but can wrap the errors before returning them to the layer above.

All in all, I just recommend you to give a look to the GLib and GTK+ libraries. I learned a lot looking at their source code.

3 added 648 characters in body
source | link

Never use asserts to check public API preconditions, especially if you develop a library.

You don't control how other people call your library. Every crash in your library is a bug in that library. A library shouldn't crash just because it received bad input, it should return an error instead. Think about fuzz testing: it generates invalid input to check that your software can recover from it, which is the normal behavior.

Let me take an example: I once had a crash on Microsoft Word when opening a specific document. OpenOffice at that time could open it and helped me recover my data. Even if I had an assertion in Word telling the file was badly formed, which program do you think did a better job? This is not specific to the desktop world. I worked on embedded systems (Set Top Boxes) where you had multimedia files to process and display: you not allowed to crash because a media file is corrupted, at worse you just trigger an error and don't play the media.

You think asserting helps getting to the place where the error happened? Use logging and you'll get the same effect, but without crashing forcedly. The assertion doesn't make a distinction beween recoverable and non-recoverable errors: you always stop. But logging allows you to know where and why it failed and lets you decide if you can continue or not.

Think of your customer that wants its app running, and each time a certain condition happens, it crashes. I think the customer may prefer to have some log or error showing up and the rest of the application resuming if the error is not a fatal one. You don't want intentionnalany crashers in prodution code (andand an assert is that an intentional crasher. If assertions are disabled in production then it gets worse: your whole error-handling logic disappeared, and instead of crashing with an assertion message you're now crashing (maybe much much) later with no message, just because you didn't detect bad input and continued to process it.

If you're developping your own application, you maymight want to use assert to check for your own bugs however, forin your internal calls, but for a library it's a no-no.

As for your options:

  1. errno: I agree that errno doesn't fit current programming practices, especially with multithreading
  2. Return code, or return code + pointer to error is good. That is what GLib does. The pointer to error is optional but can be used to get a relevant message and return the error on layers above. In the cas of your "get_index_of_object", that isn't even necessary: an index is never negative so just returning -1 is enough to say your object was not found.
  3. Disabling asserts in production: this breaks your logging logic, as people won't do logging + assert, they'll think the assert is enough. Again, you need logging in production and avoid crashes at all costs, so you can't rely on assertions.
  4. Return early is what the GLib does. Look at g_return_if_fail or g_return_val_if_fail. You want to have a trace of runtime errors: again use logging, with different levels (debug, info, error). And if that error is considered fatal and can't be recovered, then yes, stop.
  5. Be pragmatic. Sometimes the error code is enough, sometimes no and you'll need a location for a more specific error code and error message. Sometimes you use functions that return errors to errno and will have to cope with that internally but can wrap the errors before returning them to the layer above.

All in all, I just recommend you to give a look to the GLib and GTK+ libraries. I learned a lot looking at their source code.

Never use asserts to check public API preconditions, especially if you develop a library.

You don't control how other people call your library. Every crash in your library is a bug in that library. A library shouldn't crash just because it received bad input, it should return an error instead. Think about fuzz testing: it generates invalid input to check that your software can recover from it, which is the normal behavior. I once had a crash on Microsoft Word when opening a specific document. OpenOffice at that time could open it and helped me recover my data. Even if I had an assertion in Word telling the file was badly formed, which program do you think did a better job?

You think asserting helps getting to the place where the error happened? Use logging and you'll get the same effect, but without crashing forcedly. The assertion doesn't make a distinction beween recoverable and non-recoverable errors: you always stop. But logging allows you to know where and why it failed and lets you decide if you can continue or not.

Think of your customer that wants its app running, and each time a certain condition happens, it crashes. I think the customer may prefer to have some log or error showing up and the rest of the application resuming if the error is not a fatal one. You don't want intentionnal crashers in prodution code (and an assert is that an intentional crasher).

If you're developping your own application, you may use assert to check for your own bugs however, for your internal calls, but for a library it's a no-no.

As for your options:

  1. errno: I agree that errno doesn't fit current programming practices, especially with multithreading
  2. Return code, or return code + pointer to error is good. That is what GLib does. The pointer to error is optional but can be used to get a relevant message and return the error on layers above. In the cas of your "get_index_of_object", that isn't even necessary: an index is never negative so just returning -1 is enough to say your object was not found.
  3. Disabling asserts in production: this breaks your logging logic, as people won't do logging + assert, they'll think the assert is enough. Again, you need logging in production and avoid crashes at all costs, so you can't rely on assertions.
  4. Return early is what the GLib does. Look at g_return_if_fail or g_return_val_if_fail. You want to have a trace of runtime errors: again use logging, with different levels (debug, info, error). And if that error is considered fatal and can't be recovered, then yes, stop.
  5. Be pragmatic. Sometimes the error code is enough, sometimes no and you'll need a location for a more specific error code and error message. Sometimes you use functions that return errors to errno and will have to cope with that internally but can wrap the errors before returning them to the layer above.

All in all, I just recommend you to give a look to the GLib and GTK+ libraries. I learned a lot looking at their source code.

Never use asserts to check public API preconditions, especially if you develop a library.

You don't control how other people call your library. Every crash in your library is a bug in that library. A library shouldn't crash just because it received bad input, it should return an error instead. Think about fuzz testing: it generates invalid input to check that your software can recover from it, which is the normal behavior.

Let me take an example: I once had a crash on Microsoft Word when opening a specific document. OpenOffice at that time could open it and helped me recover my data. Even if I had an assertion in Word telling the file was badly formed, which program do you think did a better job? This is not specific to the desktop world. I worked on embedded systems (Set Top Boxes) where you had multimedia files to process and display: you not allowed to crash because a media file is corrupted, at worse you just trigger an error and don't play the media.

You think asserting helps getting to the place where the error happened? Use logging and you'll get the same effect, but without crashing forcedly. The assertion doesn't make a distinction beween recoverable and non-recoverable errors: you always stop. But logging allows you to know where and why it failed and lets you decide if you can continue or not.

Think of your customer that wants its app running, and each time a certain condition happens, it crashes. I think the customer may prefer to have some log or error showing up and the rest of the application resuming if the error is not a fatal one. You don't want any crashers in prodution code and an assert is that an intentional crasher. If assertions are disabled in production then it gets worse: your whole error-handling logic disappeared, and instead of crashing with an assertion message you're now crashing (maybe much much) later with no message, just because you didn't detect bad input and continued to process it.

If you're developping your own application, you might want to use assert to check for your own bugs however, in your internal calls, but for a library it's a no-no.

As for your options:

  1. errno: I agree that errno doesn't fit current programming practices, especially with multithreading
  2. Return code, or return code + pointer to error is good. That is what GLib does. The pointer to error is optional but can be used to get a relevant message and return the error on layers above. In the cas of your "get_index_of_object", that isn't even necessary: an index is never negative so just returning -1 is enough to say your object was not found.
  3. Disabling asserts in production: this breaks your logging logic, as people won't do logging + assert, they'll think the assert is enough. Again, you need logging in production and avoid crashes at all costs, so you can't rely on assertions.
  4. Return early is what the GLib does. Look at g_return_if_fail or g_return_val_if_fail. You want to have a trace of runtime errors: again use logging, with different levels (debug, info, error). And if that error is considered fatal and can't be recovered, then yes, stop.
  5. Be pragmatic. Sometimes the error code is enough, sometimes no and you'll need a location for a more specific error code and error message. Sometimes you use functions that return errors to errno and will have to cope with that internally but can wrap the errors before returning them to the layer above.

All in all, I just recommend you to give a look to the GLib and GTK+ libraries. I learned a lot looking at their source code.

2 added 648 characters in body
source | link

Never use asserts to check public API preconditionsNever use asserts to check public API preconditions, especially if you develop a library.

You don't control how other people call your library. Every crash in your library is a bug in that library. A library shouldn't crash just because it received bad input, it should return an error instead. Think about fuzz testing: it generates invalid input to check that your software can recover from it, which is the normal behavior. I once had a crash on Microsoft Word when opening a specific document. OpenOffice at that time could open it and helped me recover my data. Even if I had an assertion in Word telling the file was badly formed, which program do you think did a better job?

You think asserting helps getting to the place where the error happened? Use logging and you'll get the same effect, but without crashing forcedly. The assertion doesn't make a distinction beween recoverable and non-recoverable errors: you always stop. But logging allows you to know where and why it failed and lets you decide if you can continue or not.

Think of your customer that wants its app running, and each time a certain condition happens, it crashes. I think the customer may prefer to have some log or error showing up and the rest of the application resuming if the error is not a fatal one. You don't want intentionnal crashers in prodution code (and an assert is that an intentional crasher).

If you're developping your own application, you may use assert to check for your own bugs however, for your internal calls, but for a library it's a no-no.

As for your options:

  1. errno: I agree that errno doesn't fit current programming practices, especially with multithreading
  2. Return code, or return code + pointer to error is good. That is what GLib does. The pointer to error is optional but can be used to get a relevant message and return the error on layers above. In the cas of your "get_index_of_object", that isn't even necessary: an index is never negative so just returning -1 is enough to say your object was not found.
  3. Disabling asserts in production: this breaks your logging logic, as people won't do logging + assert, they'll think the assert is enough. Again, you need logging in production and avoid crashes at all costs, so you can't rely on assertions.
  4. Return early is what the GLib does. Look at g_return_if_fail or g_return_val_if_fail. You want to have a trace of runtime errors: again use logging, with different levels (debug, info, error). And if that error is considered fatal and can't be recovered, then yes, stop.
  5. Be pragmatic. Sometimes the error code is enough, sometimes no and you'll need a location for a more specific error code and error message. Sometimes you use functions that return errors to errno and will have to cope with that internally but can wrap the errors before returning them to the layer above.

All in all, I just recommend you to give a look to the GLib and GTK+ libraries where. I learned a looklot looking at thetheir source code.

Never use asserts to check public API preconditions, especially if you develop a library.

You don't control how other people call your library. Every crash in your library is a bug in that library. A library shouldn't crash just because it received bad input, it should return an error instead.

You think asserting helps getting to the place where the error happened? Use logging and you'll get the same effect, but without crashing forcedly.

Think of your customer that wants its app running, and each time a certain condition happens, it crashes. I think the customer may prefer to have some log or error showing up and the rest of the application resuming if the error is not a fatal one. You don't want intentionnal crashers in prodution code (and an assert is that an intentional crasher).

If you're developping your own application, you may use assert to check for your own bugs however, for your internal calls, but for a library it's a no-no.

As for your options:

  1. errno: I agree that errno doesn't fit current programming practices, especially with multithreading
  2. Return code, or return code + pointer to error is good. That is what GLib does. The pointer to error is optional but can be used to get a relevant message and return the error on layers above. In the cas of your "get_index_of_object", that isn't even necessary: an index is never negative so just returning -1 is enough to say your object was not found.
  3. Disabling asserts in production: this breaks your logging logic, as people won't do logging + assert, they'll think the assert is enough. Again, you need logging in production and avoid crashes at all costs, so you can't rely on assertions.
  4. Return early is what the GLib does. Look at g_return_if_fail or g_return_val_if_fail. You want to have a trace of runtime errors: again use logging, with different levels (debug, info, error). And if that error is considered fatal and can't be recovered, then yes, stop.
  5. Be pragmatic. Sometimes the error code is enough, sometimes no and you'll need a location for a more specific error code and error message. Sometimes you use functions that return errors to errno and will have to cope with that internally but can wrap the errors before returning them to the layer above.

All in all, I just recommend you to give a look to the GLib and GTK+ libraries where I learned a look looking at the source code.

Never use asserts to check public API preconditions, especially if you develop a library.

You don't control how other people call your library. Every crash in your library is a bug in that library. A library shouldn't crash just because it received bad input, it should return an error instead. Think about fuzz testing: it generates invalid input to check that your software can recover from it, which is the normal behavior. I once had a crash on Microsoft Word when opening a specific document. OpenOffice at that time could open it and helped me recover my data. Even if I had an assertion in Word telling the file was badly formed, which program do you think did a better job?

You think asserting helps getting to the place where the error happened? Use logging and you'll get the same effect, but without crashing forcedly. The assertion doesn't make a distinction beween recoverable and non-recoverable errors: you always stop. But logging allows you to know where and why it failed and lets you decide if you can continue or not.

Think of your customer that wants its app running, and each time a certain condition happens, it crashes. I think the customer may prefer to have some log or error showing up and the rest of the application resuming if the error is not a fatal one. You don't want intentionnal crashers in prodution code (and an assert is that an intentional crasher).

If you're developping your own application, you may use assert to check for your own bugs however, for your internal calls, but for a library it's a no-no.

As for your options:

  1. errno: I agree that errno doesn't fit current programming practices, especially with multithreading
  2. Return code, or return code + pointer to error is good. That is what GLib does. The pointer to error is optional but can be used to get a relevant message and return the error on layers above. In the cas of your "get_index_of_object", that isn't even necessary: an index is never negative so just returning -1 is enough to say your object was not found.
  3. Disabling asserts in production: this breaks your logging logic, as people won't do logging + assert, they'll think the assert is enough. Again, you need logging in production and avoid crashes at all costs, so you can't rely on assertions.
  4. Return early is what the GLib does. Look at g_return_if_fail or g_return_val_if_fail. You want to have a trace of runtime errors: again use logging, with different levels (debug, info, error). And if that error is considered fatal and can't be recovered, then yes, stop.
  5. Be pragmatic. Sometimes the error code is enough, sometimes no and you'll need a location for a more specific error code and error message. Sometimes you use functions that return errors to errno and will have to cope with that internally but can wrap the errors before returning them to the layer above.

All in all, I just recommend you to give a look to the GLib and GTK+ libraries. I learned a lot looking at their source code.

1
source | link