How I write HTTP services in Go after 13 years
51–60 of 259 posts
Re: How I write HTTP services in Go after 13 years
#52Re: How I write HTTP services in Go after 13 years
#53The validator should return map[string][]string so that a request can have multiple problems with one field.
Re: How I write HTTP services in Go after 13 years
#54is there a git repo with example code?
Not OP, but I design my Go projects with a very similar pattern that I learned from OP's 2018 post. I think this is a pretty good example of a real-world implementation: https://github.com/mtlynch/picoshare Particularly these files: https://github.com/mtlynch/picoshare/blob/2cd9979dab084ca781... https://github.com/mtlynch/picoshare/blob/2cd9979dab084ca781...
Re: How I write HTTP services in Go after 13 years
#55I really like Mat Ryer's work, and I've applied most of the ideas in the 2018 version of this article to all of my Go projects since then. The one weak spot for me is this aspect: > NewServer is a big constructor that takes in all dependencies as arguments... In test cases that don’t need all of the dependencies, I pass in nil as a signal that it won’t be used. This has always felt wrong to me, but I've never been ab…
It means the object created by NewServer is dealing with too much. Probably has too many data types coupled to it and too much behavior. Simple example is adding a logger. If you add it as a dependency to the constructor, the object starts doing a bit more than initial simple implementation. It's fine to do it, but shame to not figure out how to log without editing the implementation of a simple thing. Higher order f…
But if I really feel I can't avoid the need to pass a good amount of external context, I create a dedicated "options" struct and pass that into the constructor as a pointer. The purpose of the pointer (rather than pass by value) is if I want default arguments, I can pass nil.
type ServerOptions struct {
logger *magic.Logger
secretKey string
}
func NewServer(options *ServerOptions) (*Server, error) {
...
}Re: How I write HTTP services in Go after 13 years
#56Earlier quoted context omitted.
Except Username is not exactly the same as string, and that's important. Username is a subset of string. If they were equivalent, we wouldn't need to parse/validate. The often misinterpreted part of DRY is conflating "these are the same words, so they are the same", with "these are the same concept, so they are the same". A Username and a String are conceptually different.
DRY is just "Do not repeat yourself". And a LOT of devs take that literally. It's not "Do not repeat concepts" (which is what it SHOULD be but DRC isn't a fun acronym). Unfortunately "This is the same character string" is all a DRY purist needs to start messing up the code base. I honestly believe that "DRY" is an anti-pattern because of how often I see this exact behavior trotted out or espoused. It's a cargo cult t…
When you add complexity to DRY out your code, you're adding a readability regression. DRY matters in very few context beyond readability, and simplicity and low cognitive load need to be in charge. Everything else you do code-style wise should be in service of those two things.
Re: How I write HTTP services in Go after 13 years
#57> 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.
Re: How I write HTTP services in Go after 13 years
#58Earlier quoted context omitted.
Not OP, but I design my Go projects with a very similar pattern that I learned from OP's 2018 post. I think this is a pretty good example of a real-world implementation: https://github.com/mtlynch/picoshare Particularly these files: https://github.com/mtlynch/picoshare/blob/2cd9979dab084ca781... https://github.com/mtlynch/picoshare/blob/2cd9979dab084ca781...
out of curiosity, why no sort-of-established pkg and internal dirs? What do you think of https://github.com/photoprism/photoprism structure?
Re: How I write HTTP services in Go after 13 years
#59Earlier quoted context omitted.
Except Username is not exactly the same as string, and that's important. Username is a subset of string. If they were equivalent, we wouldn't need to parse/validate. The often misinterpreted part of DRY is conflating "these are the same words, so they are the same", with "these are the same concept, so they are the same". A Username and a String are conceptually different.
DRY is just "Do not repeat yourself". And a LOT of devs take that literally. It's not "Do not repeat concepts" (which is what it SHOULD be but DRC isn't a fun acronym). Unfortunately "This is the same character string" is all a DRY purist needs to start messing up the code base. I honestly believe that "DRY" is an anti-pattern because of how often I see this exact behavior trotted out or espoused. It's a cargo cult t…
Re: How I write HTTP services in Go after 13 years
#60The second issue involves passing an unused *http.Request, which will likely cause the linter to flag it.