A hands-on Go workspace for learning algorithms, data structures, design patterns, and idiomatic Go. Every public API is taught, not just shipped: documented in doc.go and demonstrated with Benchmark + Example + Test.
Created by Eric Garcia.
- About
- What's Inside
- Project Structure
- Getting Started
- Usage
- Documentation
- Development
- Testing Conventions
- Roadmap
- Contributing
- License
go-eng is a personal learning repository that doubles as a reusable library of small, well-tested Go packages. The root main.go is a demo only — the real value is in the subpackages under algo/, ds/, lib/, plus the isolated modules under design-patterns/ and examples/.
Full API docs live on pkg.go.dev.
| Package | Provides |
|---|---|
algo/anagrams |
Anagram detection (IsAnagram) |
algo/fibonacci |
Recursive, iterative, and memoized Fibonacci |
algo/search |
Binary search (loop + recursion), linear search |
algo/sorting |
Bubble sort, merge sort, std-lib merge helpers |
algo/vowels |
Vowel counting |
| Package | Provides |
|---|---|
ds/linkedlist |
Custom singly linked list + container/list wrapper |
ds/queue |
Slice-backed and linked-list-backed queues |
ds/stack |
Thread-safe slice-backed stack |
ds/hashtable |
Basic hash table (Set, Get, Keys, Values) |
ds/tree |
Binary search tree (Insert, Search, Delete) |
| Area | Package | Notes |
|---|---|---|
| Pattern | design-patterns/circuit-breaker/breaker |
Closed / Open / Half-Open states, thread-safe |
| Pattern | design-patterns/master-slave/masterslave |
Concurrent task distribution, health checks, metrics |
| Lib | lib/file |
ToFile file-writing helper |
| Example | examples/contexts |
Context timeout pattern |
| Example | examples/generics |
Generics tutorial code |
| Example | examples/web-service-gin |
Gin albums REST API tutorial |
See docs/project/inventory.md for the authoritative implemented-vs-planned list.
Go workspace (go.work) with one root module plus five independent modules:
.
├── algo/ # sorting, searching, fibonacci, anagrams, vowels
├── ds/ # linkedlist, queue, stack, hashtable, tree
├── lib/ # small helpers (file)
├── main.go # demo entrypoint (not a library)
├── docs/ # tutorials, how-to, reference, explanation, project
├── design-patterns/
│ ├── circuit-breaker/ # separate module
│ └── master-slave/ # separate module
└── examples/
├── contexts/ # separate module
├── generics/ # separate module
└── web-service-gin/ # separate module
| Module | Path |
|---|---|
| Root | github.com/eng618/go-eng |
| Circuit breaker | design-patterns/circuit-breaker |
| Master-slave | design-patterns/master-slave |
| Contexts | examples/contexts |
| Generics | examples/generics |
| Web service | examples/web-service-gin |
go commands for a submodule must run in that directory. The cross-module equivalent is task <module>-<action>, e.g. task circuit-breaker-test.
- Go 1.27 (see
.tool-versions;mise/asdfrecommended) - Task 3.x
- golangci-lint 2.x (invoked via
task lint)
git clone https://github.com/eng618/go-eng.git
cd go-eng
go work syncgo run main.goRun an isolated module:
task generics # cd examples/generics && go run main.go
task circuit-breaker # cd design-patterns/circuit-breaker && go run main.goImport any root-module package by its full path:
import (
"fmt"
"github.com/eng618/go-eng/algo/search"
"github.com/eng618/go-eng/algo/sorting"
"github.com/eng618/go-eng/ds/stack"
)
func main() {
fmt.Println(sorting.MergeSort([]int{5, 4, 3, 2, 1}))
idx, ok := search.BinaryLoop([]int{1, 2, 3, 4, 5}, 4)
fmt.Println(idx, ok)
s := stack.New()
s.Push(1)
v, _ := s.Pop()
fmt.Println(v)
}Circuit breaker (separate module — see its go.mod):
cb := breaker.NewCircuitBreaker(5, 10*time.Second)
err := cb.Execute(func() error {
return someRiskyOperation()
})- Start with the documentation index — tutorials, how-to guides, reference, and explanation.
- API reference: pkg.go.dev
- Big-O cheatsheet — complexity rules used across the labs.
- Implementation inventory — what is implemented vs. planned.
- Each package documents itself in
doc.gowith runnable examples
Taskfile.yml is the source of truth for all workflows. CI runs task lint, then task test, then task build.
task validate # lint -> test -> build (mirrors CI)
task lint # all modules; fix with task lint-fix
task test # all modules, with -race and coverage
task build # all modules
task bench # benchmarks, all modulesTargeted runs (from the module directory):
task root-test
go test ./algo/sorting/... -run TestBubbleSort
go test ./algo/sorting/... -bench=BenchmarkBubbleSortNotes:
- Do not run bare
golangci-lint run ./...;Taskfilewraps it asenv -u GOROOT -u GOTOOLDIR golangci-lint run ./.... TaskfilesetsGOTOOLCHAIN=local.- Generated, gitignored artifacts:
coverage.out,linter-output.json— do not commit.
Every public API follows the BET method:
- Benchmark — a
Benchmark*function, even when perf is not the point. - Example — an
Example*function with// Output:that teaches usage. - Test — table-driven, external
package foo_test, usingt.Run(tt.name, ...).
White-box tests live in *_internal_test.go (the only testpackage exemption). New packages must add a doc.go.
Import grouping (gci): stdlib, blank line, third-party, blank line, github.com/eng618/go-eng. Line length is 120 (lll, report-only).
Planned work (insertion sort, quick sort, BFS/DFS, graph, container/heap, container/ring, circular queue, doubly linked list) is tracked in docs/project/inventory.md, sourced from open issues and the former "Still to come" list. Work items are intentionally small so they can be done one at a time.
Conventional commits (feat:, fix:, chore:, …) are required — release-please owns CHANGELOG.md, so never edit it by hand. Run task validate before pushing.
See LICENSE.