Go, also known as Golang, is a statically typed compiled programming language designed at Google by Robert Griesemer, Rob Pike, and Ken Thompson. It is syntactically similar to C, but also has memory safety, garbage collection, structural typing, and CSP-style concurrency. Docker, Kubernetes, Terraform, etcd, ist.io and many other tools are written in go.
Learning anything is a uniquely individual process. There are some hypotheses that state there are somewhere between 4 and 8 different ways people learn. Though it's often hard to understand how to best learn a new thing arming yourself with as many arrows in your quiver is the best way to get there. Thankfully there is a wealth of online tools to help with that. Here are some:
https://go.dev/doc/effective_go
Code Review Comments along with Effective Go (above) are the base guidelines for "idiomatic" go. The golint tool uses them for its warnings:
https://go.dev/wiki/CodeReviewComments
Go can be downloaded and installed from here: https://go.dev/dl/
VSCode is a popular free IDE that supports several languages including go.
-
Initialize a go.mod with the command "go mod init stl-go/go-learning-series"
$ go mod init stl-go/go-learning-series go: creating new go.mod: module stl-go/go-learning-series
-
Edit / create a main.go file:
package main import "fmt" func main() { fmt.Println("Hello world from the St. Louis Go learning Series") }
-
Run your program by executing "go run hello-world"
$ go run hello-world.go Hello world from the St. Louis Go learning Series
-
You could, if you so chose, to create an executable of your hello world program by executing "go build main.go" this will create a main (or main.exe if you're on windows) binary
go build main.go
-
You can now run your executable without the need to invoke go commands
$ main Hello world from the St. Louis Go learning Series
Congratulations you've now run your first Go program!
We have some examples and some documentation on how to go from "hello world" to a fully functional webservice that can handle both REST and WebSockets, we won't say in 45 minutes or less, but with some time and elbow grease it's doable.
- Primitive Types
- Structures
- Maps and Slices
- Logging
- Files
- JSON
- Go routines
- Channels
- Timed Tasks
- Logging
- Cryptography
- Configurations
- Database access
- Static web hosting
- Virtual hosting
- WebService clients
Sometimes seeing things in context helps. The next set of examples is included in the "Grow with stl-go" application example. It is a fully functioning webservice with a UI and REST / WebSocket apis
- Makefile
- Linting
More details about the Grow with stl-go can be found on the docs.
*For windows you can use cygwin, note that you'll need MinGW on the path prior to cygwin to compile the Sqlite module.
git clone https://github.com/stlgo/grow-with-stl-go.git
Execute a make inside the project directory
$ make
Executing frontend build steps...
npm WARN deprecated @fortawesome/fontawesome-free-solid@5.0.13: This package is deprecated. See https://git.io/fNCzJ for information about upgrading.
added 232 packages, and audited 233 packages in 29s
36 packages are looking for funding
run `npm fund` for details
2 moderate severity vulnerabilities
Some issues need review, and may require choosing
a different dependency.
Run `npm audit` for details.
Frontend build completed successfully
Executing backend build steps...
Backend build completed successfully
Start the application
$ bin/grow-with-stl-go --loglevel 6
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/configs/configs.go:118: [ERROR] open etc/grow-with-stl-go.json: The system cannot find the path specified.
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/configs/configs.go:119: [INFO] No configuration found building a default configuration
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/configs/configs.go:126: [ERROR] unexpected end of JSON input
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/configs/apiuser.go:54: [WARN] Password generated for user 'admin', password 5363839e28768ba89b5fef2c503c4885e21f7fe1bde18963351a965f3e3706b8 - DO NOT USE THIS FOR PRODUCTION
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/configs/apiuser.go:54: [WARN] Password generated for user 'user', password d5f2bf6124cc4a35294b831266a1cf126fc82fa03c778c68378461650c5d59c5 - DO NOT USE THIS FOR PRODUCTION
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/configs/webservice.go:35: [INFO] No webservice config found, generating ssl keys, host and port info
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/cryptography/ssl.go:40: [WARN] Generating private key C:\temp\grow-with-stl-go\etc\key.pem. DO NOT USE THIS FOR PRODUCTION
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/cryptography/ssl.go:47: [WARN] Generating public key C:\temp\grow-with-stl-go\etc\cert.pem. DO NOT USE THIS FOR PRODUCTION
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:57: [DEBUG] No embedded database found in the config file, generating a default configuration
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:88: [DEBUG] Using encrypted aud database in C:\temp\grow-with-stl-go\etc\grow-with-stl-go.db
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/configs/configs.go:282: [DEBUG] Rewriting etc/grow-with-stl-go.json to ensure data is enciphered on disk
[stl-go] 2024/02/28 13:17:25 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:132: [TRACE] Audit table WebSocket was created if it didn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:132: [TRACE] Audit table REST was created if it didn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:132: [TRACE] Audit table user was created if it didn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/webservice/websocket.go:74: [DEBUG] Regestering 'seeds' as a WebSocket Endpoint
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/webservice/webservice.go:53: [DEBUG] Regestering seeds as a REST Endpoint
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:132: [TRACE] Audit table seeds was created if it didn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default chive for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default bell pepper for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default serrano for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default galahad for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default plum regal for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default oreagno for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default ailsa craig for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default walla walla for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default carbon for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default basil for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default poblano for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default san marzano for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default dill for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default patterson for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default red wing for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/SQLite.go:156: [TRACE] Inserting default jalapeno for table seeds if it doesn't already exist
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/configs/configs.go:282: [DEBUG] Rewriting etc/grow-with-stl-go.json to ensure data is enciphered on disk
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/seeds/seeds.go:160: [DEBUG] 4 categories in inventory cache
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/webservice/websocket.go:74: [DEBUG] Regestering 'admin' as a WebSocket Endpoint
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/webservice/server.go:57: [DEBUG] Attempting to serve static content from web
[stl-go] 2024/02/28 13:17:26 stl-go/grow-with-stl-go/pkg/webservice/server.go:63: [INFO] Attempting to start webservice on localhost:10443
Login to the web page with the generated ids / passwords in the output above at localhost:10443 or flex the REST and WebSocket apis via the procedures in our documentation.
Programming is both an art and a science and that concept is sometimes lost in translation. If you've read Isaac Asimov's The Relativity of Wrong you'll understand that we may not always get everything 100% perfectly right every time but so long as we continue to move towards a more correct and better way to do things we'll improve. To that end Tim Peters wrote a small blurb called the Zen of Python, and while it does have the word python in the title, the concepts can be applied to this or any project you may be involved in and should be considered in how you approach problem solving:
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea – let's do more of those!