basic statement of intent
This commit is contained in:
commit
6e5af42d93
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/furthur
|
3
cmd/furthur/main.go
Normal file
3
cmd/furthur/main.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
func main() {}
|
3
go.mod
Normal file
3
go.mod
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module git.yetaga.in/alazyreader/going-further
|
||||||
|
|
||||||
|
go 1.22.2
|
108
readme.md
Normal file
108
readme.md
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
# Going Further
|
||||||
|
|
||||||
|
This project aims to showcase "intermediate" go programming --
|
||||||
|
once you've learned the language itself, what are the idioms that
|
||||||
|
make for a proficient go programmer?
|
||||||
|
|
||||||
|
This is an implementation of a [golinks](https://golinks.github.io/golinks/)
|
||||||
|
service using only the standard library.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
The go toolchain is very unopinionated about how a project is laid
|
||||||
|
out, except for a few specific folder names and rules:
|
||||||
|
|
||||||
|
* packages with `internal/` in the path can only be imported by other
|
||||||
|
packages that they share a "root" with. In go, any package that can
|
||||||
|
be loaded by the compiler can be pulled into another project, even
|
||||||
|
packages that weren't designed to be "libraries" in a traditional
|
||||||
|
sense. The `internal` convention was introduced as a way to allow
|
||||||
|
the authors of public (or even closed-source) code to truly keep
|
||||||
|
a package internal to its parent module.
|
||||||
|
* folders named `testdata` are ignored by the toolchain, and are used
|
||||||
|
to store exactly that -- files and data that tests are to use as
|
||||||
|
either input or validation.
|
||||||
|
|
||||||
|
Outside of that, there are a few conventions that have become _relatively_
|
||||||
|
common:
|
||||||
|
|
||||||
|
* For modules that generate a command-line binary -- that is, those that
|
||||||
|
have a `main` package -- it's common to place that entrypoint file in a
|
||||||
|
subfolder of `cmd` named the same as the expected binary's name. In this
|
||||||
|
repo, that's `/cmd/furthur`. Running `go build ./cmd/furthur` in this module
|
||||||
|
results in a binary named `furthur`.
|
||||||
|
* Packages should be named after what they provide, and packages that collect
|
||||||
|
together a lot of related functionality aren't a negative thing. Package
|
||||||
|
names like `util` or `etc` are signs that your code is poorly laid-out.
|
||||||
|
If you find yourself needing to put a bunch of shared functionality into
|
||||||
|
one utility class, it might be a sign that all of the packages that use
|
||||||
|
that utility might actually be more coherent as one larger package.
|
||||||
|
* See the experience of the stdlib itself with [`io/ioutil`](https://pkg.go.dev/io/ioutil),
|
||||||
|
which ended up being entirely deprecated and moved into `io` and `os`.
|
||||||
|
* One pattern that used to be recommended before the advent of `internal` was
|
||||||
|
to explicitly place packages that were "intended" to be public in a folder
|
||||||
|
called `pkg`, but the community was never uniform in that approach, and
|
||||||
|
it is now generally discouraged.
|
||||||
|
|
||||||
|
## HTTP Services
|
||||||
|
|
||||||
|
## Generics
|
||||||
|
|
||||||
|
Go has generics now, and they're useful... but mostly for authors of _libraries_,
|
||||||
|
not for application developers. They have allowed for the standard library
|
||||||
|
to finally ship a bunch of generic functions in the [`slices`](https://pkg.go.dev/slices)
|
||||||
|
package that developers used to have to write themselves.
|
||||||
|
|
||||||
|
## //go:embed
|
||||||
|
|
||||||
|
<https://pkg.go.dev/embed>
|
||||||
|
|
||||||
|
## Testing and Benchmarking
|
||||||
|
|
||||||
|
## Concurrency
|
||||||
|
|
||||||
|
It turns out channels are hard to reason about, but that's because _concurrency_ is
|
||||||
|
hard to reason about.
|
||||||
|
|
||||||
|
Always remember that read/write access to a shared map _must_ be gated with a mutex.
|
||||||
|
|
||||||
|
## Go Generate
|
||||||
|
|
||||||
|
## Build tags
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
`slog` package
|
||||||
|
|
||||||
|
## init functions and globals
|
||||||
|
|
||||||
|
Don't use them! They're hard to reason about and until recent versions of go
|
||||||
|
the order they ran in was undefined, leading to subtle bugs.
|
||||||
|
|
||||||
|
## Common tools
|
||||||
|
|
||||||
|
* `go vet`
|
||||||
|
* [`staticcheck`](https://staticcheck.dev/)
|
||||||
|
|
||||||
|
## Other common idioms and stumbling blocks
|
||||||
|
|
||||||
|
`./...` is a common shorthand to pass to parts of the go toolchain that means
|
||||||
|
"this directory and all directories underneath it". You'll often come across
|
||||||
|
it when running tests (`go test ./...`) or linters (`staticcheck ./...`).
|
||||||
|
|
||||||
|
When working with closed-source code that is not cached in the public
|
||||||
|
[`GOPROXY`](https://proxy.golang.org/), you need to set `GOPRIVATE` to match
|
||||||
|
the name of the module or else you'll get cryptic errors when go tries to build.
|
||||||
|
This can be set globally for the entire toolchain using `go env`:
|
||||||
|
`go env -w GOPRIVATE="https://git.yetaga.in/*"`. See
|
||||||
|
<https://pkg.go.dev/cmd/go#hdr-Configuration_for_downloading_non_public_code>
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
## Related Resources
|
||||||
|
|
||||||
|
* Rob Pike's [Go Proverbs](https://go-proverbs.github.io/). Of particular value:
|
||||||
|
* _The bigger the interface, the weaker the abstraction._
|
||||||
|
* _A little copying is better than a little dependency._
|
||||||
|
* _Clear is better than clever._
|
||||||
|
* _Don't just check errors, handle them gracefully._
|
||||||
|
* Mat Ryer's [How I write HTTP services in Go after 13 years](https://grafana.com/blog/2024/02/09/how-i-write-http-services-in-go-after-13-years/)
|
Loading…
Reference in New Issue
Block a user