All means are fair except solving the problem

(yosefk.com)

62 points | by akkartik 2 days ago

10 comments

  • anyfoo 12 hours ago

    Does no one know what exit codes and stderr vs. stdout is anymore?

    I work with old and new code bases used by many clients in complicated setups, but adding a warning to stderr while stdout was left untouched, and proper exit codes maintained, was hardly, if ever, a problem so far.

    Of course, there's always some unpleasant exception, but it's rare.

    And of course, I also understand that the author might have found themselves not only in one of those rare-ish instances, but also one where reasoning with the other side was fruitless.

    • dylan604 11 hours ago

      > Does no one know what exit codes and stderr vs. stdout is anymore?

      Sounds like you don't use ffmpeg very often. Because ffmpeg is able to send its output to stdout to be piped to other apps, verbose text output can't use stdout as one would expect. Non-error text is sent to stderr instead. So when you want to trap the text output you have to route stderr to text file. It takes some getting used to, but it's now normal for me.

      So, yeah, I know stderr vs stdout still, but it's not what you want it to simply be. In the real world, things are not as clean as they are in school books.

      • anyfoo 6 hours ago

        That is exactly what I expect, or did I misread you? I expect its text output on stderr, and stdout being reserved for its video (or whatever) output.

        Maybe the name “stderr” is a bit misleading. It’s totally common for non-error output to be in stderr as well, like verbose/debug logging.

        • skydhash 9 hours ago

          I've just checked the man page for ffmpeg and they have a `-report` flag to capture the log. There should be no need to redirect stderr.

        • adrian_b 12 hours ago

          Yes, this was also exactly what I have thought while reading TFA.

          • AnimalMuppet 11 hours ago

            I worked on a code base that ran on a variety of Unixes. One customer complained about file corruption from our software. Turns out that their Unix setup was... rather unique. Spawned programs were not given a stderr file handle! If you wrote to stderr, it scribbled on whatever file was open on file handle 2.

            We, uh, reasoned with the other side - we told them to fix their stupid broken setup.

            • anyfoo 11 hours ago

              Glad you were able to sort it out properly. I guess maybe I'm also lucky to much less rarely work with, shall we say, consultation-resistant engineers than discussion forums sometimes make you believe.

          • linkregister 13 hours ago

            It's POSIX convention to write to stderr for anything that's not strict program output. I have seen 2>&1 far too often in scripts. I don't worry about it and happily write error messages to stderr whenever my scripts exit without a 0 status code.

            • ryandrake 13 hours ago

              Another thing that gets screwed up a lot is: Comand line usage help/information should be printed to stderr if it was invoked because the user passed an invalid option to the command line (in other words, the usage text counts as diagnostic[1] info), but it should be printed to stdout if the user invoked the application with -h, --help or similar. Reasons:

              1. If you mess up the command line to the program in a script or pipe, and get a bunch of usage output in stdout, a downstream consumer of that stdout might think its legit program output and try to parse it.

              2. If your user actually calls the program with -h or --help, they might want to |less through it to read it on a small terminal screen. Output that to stdout.

              3. Generally, you can always tell if something is going wrong by grepping for errors or warnings a single stream (stderr), or by looking for a nonzero exit code.

              But your general principle applies: Output expected by the user -> stdout. Diagnostic output or output incidental to the program's operation or errors -> stderr.

              1: https://pubs.opengroup.org/onlinepubs/9799919799/functions/s...

              • dylan604 10 hours ago

                > 3. Generally, you can always tell if something is going wrong by grepping for errors or warnings a single stream (stderr), or by looking for a nonzero exit code.

                I'll use ffmpeg as an example of being an edge case. It's hard to get ffmpeg to give a nonzero exit code. What might be a problem for the user wasn't necessarily a problem for the app, so the app thinks it is completed and does its thing exiting with zero. For example, if a file is being read as input that is corrupted causing ffmpeg to no longer be able to read from the source, it will happily close your file cleanly so it is usable (just shorter than expected) and report it completed successfully. If all you do is check the exit code, you'll think your file is completed. Much more due diligence is necessary to be sure.

                • IsTom 3 hours ago

                  Last time I had that problem -xerror helped.

                • anyfoo 12 hours ago

                  Disagree. stdout is only reserved for actual processed command output. It may be empty, it may be invalid because the input was invalid (shit in, shit out), but it may never be things intended for a human to read.

                  If one wants to use a pager (like I sometimes do, though most of the time I just scroll up), they'll just use `foo 2>&1 | less`.

                  • archargelod 22 minutes ago

                    > stdout is only reserved for actual processed command output

                    If user asks a program to print help message, the help text is the processed command output!

                    • ryandrake 12 hours ago

                      GNU offers guidance[1] to output --help to stdout, but it's not against the law to do it your way.

                      1: https://www.gnu.org/prep/standards/html_node/_002d_002dhelp....

                      • anyfoo 12 hours ago

                        I guess this is a point where I disagree with GNU. Then again, the reasons why I disagree are subtle enough that I don't care too much... I think this particular thing doesn't matter very much in practice, so go do your thing GNU...

                        • dylan604 10 hours ago

                          I can see both sides. As someone automating, I could see getting the malformed command -h result to stderr. I can also see that sending -h to stdout would be expected as that is the legit out as requested by the user. At the least, if -h is sent to stdout for a malformed command then by gawd it better be a nonzero exit. With that, I think (and boy did it hurt) that it's an okay rule to break

                          • ryandrake 11 hours ago

                            Out of the problems we all agonize over, this is probably a 1 out of 10!

                        • ramses0 9 hours ago

                          In the case of `git log -100 | grep FOO`, the log output should go to stdout.

                          In the case of `git diff | grep FOO`, the diff output should go to stdout.

                          In the case of `git --help | grep FOO` the help output should go to stdout.

                          In the case of `git --omg-wtf | grep FOO`, it's fine if there is only output on stderr.

                          • tardedmeme 11 hours ago

                            I see you've never tried to run command --help | less

                            • anyfoo 11 hours ago

                              I just said that I always do `command --help 2>&1 | less`?

                              • tardedmeme 10 hours ago

                                Pretty annoying. Wouldn't it be good if command --help would just display the help?

                      • PaulHoule 2 days ago

                        Aren't you supposed to return a 0 status code when "yea done!" and some other status code when it wasn't done?

                        • hiAndrewQuinn 5 hours ago

                          There is a parallel universe where the convention is that 0 is used for when something went wrong, and 1-127 are reserved for all the myriad and beautiful ways in which things went right.

                          • yosefk 2 days ago

                            Indeed you're supposed to, but that way if someone calls exit(0), it looks like the program worked fine, when in fact they committed some debug code and made the program no longer run to completion. "Yay, done" was put in for the scripts to flag this sort of thing, presumably based on experience.

                            • atmavatar 12 hours ago

                              Next thing you know, you'll have to skip a major version number in your product because a significant fraction of your user base string parse its name to determine what version it is.

                              • kubb 13 hours ago

                                "People deliberately misuse the very mechanism that was designed to indicate successful completion, so we added another, flawed detection mechanism based on IO, because there's no way they'll do the thing that they should have learned in the first year of school, and just call exit with any other argument than 0 on irregular completion".

                                Gosh I thought the engineering culture was bad where I work.

                                • ryandrake 13 hours ago

                                  Yea, whatever you do, don't solve the actual problem! This reminds me of solving a buffer overflow by just blindly increasing the size of the buffer until it no longer crashes.

                                  • hackable_sand 11 hours ago

                                    The amount of problems I have handled with liberal void* is greater than I care to admit

                                  • roughly 13 hours ago

                                    Brother, have I got bad news for you about all the places outside your door.

                                  • PaulHoule 1 day ago

                                    I can say up until 2005 or so I was a real believer in printf() debugging but I deliberately switched to using a debugger as much as possible around that time. I found that no matter how hard people "try" if they modifying the code to do debugging there is some chance these get checked in -- whereas you can investigate many things with the debugger without checking anything it.

                                    Some applications have more trouble with setup and teardown than others. Like I knew a professor who kept sending me C programs that would crash before main() and some systems have a lot of trouble with "crash on shutdown" which might be a problem (corrupted files) or a non-problem.

                                    • anyfoo 12 hours ago

                                      Just make it fprintf(stderr, ...) debugging instead.

                                      • quietbritishjim 13 hours ago

                                        > I was a real believer in printf() debugging but I deliberately switched to using a debugger

                                        This really does not need to be an either/or. They have different uses. You can stick in 20 printfs and get a quick feel for where the bug is far quicker than stepping through the code - especially if you set a breakpoint and hit run, only to realise that you've overshot. You can run the program 10 times with different parameters and compare the results with printf much more easily than you could with a debugger. But, once you've found the rough area, a debugger is much better for fine grained inspection, and especially interrogating state with carefully written watches.

                                        I do get your point about the risk of leaving in some trace by accident. But it feels like overkill to throw away such a valuable tool just because of that.

                                        • XorNot 13 hours ago

                                          We still seem to have fairly bad tooling for advanced debugging use cases.

                                          There's no good reason you shouldn't be able to have an IDE maintain a text overlay of debugging points which is solely supplied as breakpoint scripts to the debugger instead.

                                          IDEs seem to conk out at click to set breakpoint.

                                          • bitwize 3 hours ago

                                            That has literally been table stakes for Windows development since the 90s.

                                            Not having the debugger fully integrated into your integrated development environment is strictly a problem of the commercial Unix and open source crowd and their "Real Programmers are fine with stone knives and bearskins" machismo.

                                        • anyfoo 12 hours ago

                                          Then that's utterly and horribly wrong? And in my decades of experience, I've fortunately only relatively rarely had to deal with that particular kind of atrocity.

                                      • johnfn 13 hours ago

                                        But the whole idea is that a warning is a warning. Solving a warning can be deferred, and a warning doesn't cause execution to fail. Your warning was transmuting itself into an error. I feel like "All means are fair except solving the problem" is the wrong conclusion to draw here. If it should have been solved immediately, it should have been an error in the first place. (And then you should have politely bumped the version so that you don't immediately break the code of all your dependents.) If there is no need to solve it immediately, then "all means are fair" to convert it back to a warning as was originally intended.

                                        • asdfasgasdgasdg 12 hours ago

                                          The warning was only "transmuting" itself into an error because another team took a dependency in their test on the exact ordering of writes of certain data to a globally shared resource.

                                        • michaelt 12 hours ago

                                          > Instead, they were quick to point out that it’s hard to know where these warnings could come from, and we cannot risk all those critical workflows failing when some case of misuse surfaces in a new context.

                                          Ah yes, Schroedinger's workflow. So important any disruption is a disaster, and simultaneously so unimportant they couldn't possibly spend a single dime on the tools critical to the workflow.

                                          • JanneVee 3 hours ago

                                            We even have the options around in our compilers to treat warnings as errors. As continuation on that idea I for one was lucky earlier in my career to work with the brilliant idea of just asserting in production. Straight up crash the software when something was wrong. Wrong preconditions that could mess something in the future. "empty array where it isn't supposed to be empty, sorry crash - fix your bug". even when it kind of worked, which is the real issue... it kind of works until it doesn't. I've silently introduced this mindset into my work ever since and the quality of the result is so much better. Warnings are something that will be deferred when given the option so don't warn it is an error.

                                            • m463 11 hours ago

                                              I have seen this kind of thing go so many ways.

                                              - sometimes you can get the status code, sometimes you can't.

                                              - sometimes you can separate out stdout from stderr, sometimes you can't

                                              - sometimes the program generating the error message identifies itself, sometimes it doesn't

                                              - sometimes you don't know if you have a "good error" (ok to ignore) or a "bad error" (cannot ignore)

                                              I am a fan of the HARD FAIL.

                                              I think internal unit tests or things like that should hard fail, then get a human to either fix it, or put in a hard exception.

                                              if it is user-facing... sigh

                                              • shoo 5 hours ago

                                                > I am a fan of the HARD FAIL.

                                                It reads as if the change was made to some library code that was depended upon by someone else's program that would "yay, done", which was in turn depended on by some workflow.

                                                It's probably a non-starter to change library code so it hard fails if it detects its being used incorrectly, in situations where it previously ran and did something. That's a severe breaking change in behaviour.

                                                Easing it in by printing a warning message sounds like a reasonable step toward hard failing. But then we get the situation yosefk relates.

                                              • potbelly83 12 hours ago

                                                Why not have the program touch a file on success?

                                                • anyfoo 12 hours ago

                                                  Why not have the program exit with exit code 0 on success, and non-0 on failure, like almost every program in a POSIX environment ever?

                                                  • potbelly83 12 hours ago

                                                    see yosefk reply above

                                                    • anyfoo 12 hours ago

                                                      I'm sorry, but "they committed some debug code that made the program exit(0)" for me is pretty much equivalent to "they committed some debug code that made the program not work correctly".

                                                • chr15m 11 hours ago

                                                  Backwards compatibility is golden.

                                                  • chadgpt2 12 hours ago

                                                    Was this FOSS or commercial?

                                                    If it's commercial software, you're paid to make it work, no matter how stupid that may be, and forced stupidity isn't your problem.

                                                    If it's FOSS, you can tell the user to deal with it and close the ticket.