Live data from Hacker News

Stop writing CLI validation. Parse it right the first time

hackers.pub

91–100 of 169 posts

Re: Stop writing CLI validation. Parse it right the first time

#91
post #78
post #52

Earlier quoted context omitted.

Actually, I think argparse falls into the same trap that the author is talking about. You can define lots of invariants in the parser, and say that these two arguments can't be passed together, or that this argument, if specified, requires these arguments to also be specified, etc. But the end result is a namespace with a bunch of key-value pairs on it, and argparse doesn't play well with typing systems like mypy or…

In general case generating CLI options from app models leads to horrible CLI UX. Opposite is also true. Working with "nice" CLI options as direct app models is horrendous. You need a boundary to convert nice opts into nice types. Like pydantic models could take argparse namespace and convert it to something manageable.

I mean, that's much the same as working with web APIs or any other kind of interface. Your DTO will probably be different from your internal models. But that doesn't mean it can't contain invariants, or that you can't parse it into a meaningful type. A DTO that's just a grab-bag of optional values is a pain to work with.

Although in practice, I find clap's approach works pretty well: define an object that represents the parsed arguments as you want them, with annotations for details that can't be represented in the type system, and then derive a parser from that. Because Rust has ADTs and other tools for building meaningful types, and because the derive process can do so much. That creates an arguments object that you can quite easily pass to a function which runs the command.

Re: Stop writing CLI validation. Parse it right the first time

#92

Earlier quoted context omitted.

I will keep writing my CLI programs in the languages I want, thanks. Have it crossed your mind that these programs might be for yourself or for internal consumption? When you know runtime will be installed anyway?

You do you, obviously, but "now let npm work its wicked way" is an offputting step for some of us when narrowing down which tool to use. My most comfortable tool is Java, but I'm not going to persuade most of the HN crowd to install a JVM unless the software I'm offering is unbearably compelling. Internal to work? Yeah, Java's going to be an easy sell. I don't think OP necessarily meant it as a political statement.

There should be some way to define the CLI argument format and its constraints in some sort of DSL that can be compiled into the target language before the final compilation of the application. This way, it can be language agnostic (though I don't know why you would need this) without the need for another runtime. The same interface specification should be able to represent a customizable help/usage message with sane defaults, generate dynamic tab completions code for multiple shells, generate code for good quality customizable error messages in case of CLI argument errors and generate a neatly formatted man page with provisions for additional content, etc.

In fact, I think something like this already exists. I just can't recollect the project.

Re: Stop writing CLI validation. Parse it right the first time

#93
Not all of this validation belongs in the same layer. A lot of the problems people seem to have is due to people thinking it all has to be done in the I/O layer.

A CLI and an API should indeed occupy the same layer of a program architecture, namely they are entry points that live on the periphery. But really all you should be doing there is lifting the low byte stream you are getting from users to something higher level you can use to call your internals.

So "CLI validation" should be limited to just "I need an int here, one of these strings here, optionally" etc. Stuff like "is this port out of range" or "if you give me this I need this too" should be handled by your internals by e.g. throwing an exception. Your CLI can then display that as an error message in a nice way.

Re: Stop writing CLI validation. Parse it right the first time

#94

Rust with Clap solved this forever ago. Also - don't write CLI programs in languages that don't compile to native binaries. I don't want to have to drag around your runtime just to execute a command line tool.

Almost every command line tool has runtime dependencies that must be installed on your system.

    $ ldd /usr/bin/rg
    linux-vdso.so.1 (0x00007fff45dd7000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x000070764e7b1000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x000070764e6ca000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000070764de00000)
    /lib64/ld-linux-x86-64.so.2 (0x000070764e7e6000)
The worst is compiling a C program with a compiler that uses a more recent libc than is installed on the installation host.

Re: Stop writing CLI validation. Parse it right the first time

#96

Rust with Clap solved this forever ago. Also - don't write CLI programs in languages that don't compile to native binaries. I don't want to have to drag around your runtime just to execute a command line tool.

Apparently that ship has sailed. Claude Code and Gemini CLI requires Node.js installation, and Gemini README reads as if npm is a tool that everybody knows and has already installed.

https://www.anthropic.com/claude-code

https://github.com/google-gemini/gemini-cli

Re: Stop writing CLI validation. Parse it right the first time

#97

Earlier quoted context omitted.

Most validation libraries worth their salt give you options to deal with this sort of thing? They'll hand you an aggregate error with an 'errors' array, or they'll let you write an error message "prettify-er" to make a particular validation error easier to read.

Right, but that's validation, and this article is talking about parsing (not validating) into an already-correct structure by making invalid inputs unrepresentable. So maybe the reason why they were able to reduce the code is because they lost the ability to do good error reporting.

You parse into an applicative validation structure, combine those together, and then once you've brought everything together you handle that as either erroring out with all the errors or continuing with the correct config. It's easier to do that with a parsing approach than a validating approach, not harder.

Re: Stop writing CLI validation. Parse it right the first time

#98
post #50

Earlier quoted context omitted.

I think the key part, although the author doesn't quite make it explicit, is that (a) the parsing happens all up front, rather than weaving validation and logic together, and (b) the parsing creates a new structure that encodes the invariants of the application, so that the rest of the application no longer needs to check anything. Whether you do that with Zod or manually or whatever isn't important, the important th…

The base assumption is parsing upfront cost less than validating along. I thinks it's a common case, but not common enough to apply it as a generic principle. For instance if validating parameter values requires multiple trips to a DB or other external system, weaving the calls in the logic can spare duplicating these round trips. Light "surface" validation can still be applied, but that's not what we're talking abou…

> if validating parameter values requires multiple trips to a DB or other external system, weaving the calls in the logic can spare duplicating these round trips

Sure, but probably at the cost of leaving everything in a horribly inconsistent state when you error out partway through. Which is almost always not worth it.

Re: Stop writing CLI validation. Parse it right the first time

#99

Earlier quoted context omitted.

Most validation libraries worth their salt give you options to deal with this sort of thing? They'll hand you an aggregate error with an 'errors' array, or they'll let you write an error message "prettify-er" to make a particular validation error easier to read.

Right, but that's validation, and this article is talking about parsing (not validating) into an already-correct structure by making invalid inputs unrepresentable. So maybe the reason why they were able to reduce the code is because they lost the ability to do good error reporting.

Parsers can be made to not fail on first error. You return either a parsed structure or an array of found error.

Html5 parser is notoriously friendly to errors. See adoption agency algorithm.

Re: Stop writing CLI validation. Parse it right the first time

#100

I don't see anything in the post or the linked tutorial that gives a flavor of the user experience when you supply an invalid option. I tried running the example, but I've forgotten too much about Node and TypeScript to make it work. (It can't resolve the @optique references.) What happens when you pass --foo, --target bar, or --port 3.14?

I had a similar question: to me, the output format “or” statement looks like it might deterministically pick one winner instead of alerting the user that they erred. A good parser is terrific, but it needs to give useful feedback.

Absolutely; I think calling the function xor would be more appropriate.
Post reply on HN