basic statement of intent
This commit is contained in:
		
							
								
								
									
										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/)
 | 
				
			||||||
		Reference in New Issue
	
	Block a user