Live data from Hacker News

How I write HTTP services in Go after 13 years

grafana.com

111–120 of 259 posts

Re: How I write HTTP services in Go after 13 years

#111

Earlier quoted context omitted.

There is no such requirement. Common wisdom suggests that you should ensure zero values are useful, but that isn't about every random struct field – only the values you actually give others . Initialize your struct fields and you won't have to consider their zero state. They will never be zero. It's funny seeing this beside the DRY thread. Seems programmers taking things a bit too literally is a common theme.

> Initialize your struct fields and you won't have to consider their zero state. “Just do the right thing everywhere and you don’t have to worry!” You can’t stop consumers of your libraries from creating zero-valued instances.

Then the zero value is their problem, not yours. You have no reason to be worried about that any more than you are worried about them not getting enough sleep, or eating unhealthy food. What are you doing to stop them from doing that? Nothing, of course. Not your problem.

Coq exists if you really feel you need a complete type system. But there is probably good reason why almost nobody uses it.

Re: How I write HTTP services in Go after 13 years

#112
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

Crazy that actually using your type system leads to better code. Stop passing everything around as `string`. Parse them, and type them.

[dead]

Re: How I write HTTP services in Go after 13 years

#113
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

You can use new types with validation too. In fact the approaches seem to be duals.

Parse, don't validate:

                    string          ParsedString
  untrusted source -------> parse --------------> rest of system
Validate, don't parse:

                    UnvalidatedString            string
  untrusted source ------------------> validate -------> rest of system

Re: How I write HTTP services in Go after 13 years

#114
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

I always understood "parse don't validate" a bit differently. If you are doing the validation inside of a constructor, you are still doing validation instead of parsing. It is safer to do the validation in one place you know the execution will go through, of course, but not the idea I understand "parse don't validate" to mean. I understand it to mean: "write an actual parser, whatever passes the parser can be used in the rest of the program", where a parser is a set of grammar rules for example, or PEG.

Re: How I write HTTP services in Go after 13 years

#115
post #94
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

My Go is rusty, do you mean not exporting the type "Username" (ie username) to avoid default constructor usage?

In Go, capitalized identifiers are exported, whereas lowercase identifiers are not.

In the example I gave above, clients outside of the package can instantiate Username, but they can't access its "value" member, so the only way they could get a populated Username instance is by calling NewUsername.

Re: How I write HTTP services in Go after 13 years

#116
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

It's not guaranteed at all, that's where go's zero-values come in. E.g. nested structs, un/marshaljson magic methods etc. How do you deal with that?

C++ constructors actually make the guarantee, but it comes with other pains

Re: How I write HTTP services in Go after 13 years

#117
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

You can use new types with validation too. In fact the approaches seem to be duals. Parse, don't validate: string ParsedString untrusted source -------> parse --------------> rest of system Validate, don't parse: UnvalidatedString string untrusted source ------------------> validate -------> rest of system

The problem is that pattern "fails open." If anyone on the team forgets to define an untrusted string as UnvalidatedString, the data skips validation.

If you default to treating primitive types as untrusted, it's hard for someone to accidentally convert an untrusted type to a trusted type without using the correct parse method.

Re: How I write HTTP services in Go after 13 years

#118
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

But surely this is just another way of doing validation and not fundamentally "parsing"? If at the end you've just stored the input exactly as you got it, the only parsing you're potentially doing is in the validation step and then it gets thrown away.

Re: How I write HTTP services in Go after 13 years

#120
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

I always understood "parse don't validate" a bit differently. If you are doing the validation inside of a constructor, you are still doing validation instead of parsing. It is safer to do the validation in one place you know the execution will go through, of course, but not the idea I understand "parse don't validate" to mean. I understand it to mean: "write an actual parser, whatever passes the parser can be used in…

I'm not a Haskell developer, so it's possible that I misunderstood the original "Parse, Don't Validate" post.

>If you are doing the validation inside of a constructor, you are still doing validation instead of parsing.

Why that would be considered validation rather than parsing?

From the original post:

>Consider: what is a parser? Really, a parser is just a function that consumes less-structured input and produces more-structured output.

That's the key idea to me.

A parser enforces checks on an input and produces an output. And if you define an output type that's distinct from the input type, you allow the type system "preserve" the fact that the data passed a parser at some point in its life.

But again, I don't know Haskell, so I'm interested to know if I'm misunderstanding Lexi Lambda's post.

Post reply on HN