summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-04 20:55:17 +0200
committerPaul Buetow <paul@buetow.org>2026-03-04 20:55:17 +0200
commitdba288dcfdccd41ec02cb02544d452769dd0a857 (patch)
tree3fd5f11ec279320776213690b85c81b47c62f7d2
parent96cd2dc9dbc7e1fffe65cc8d012073355241bb45 (diff)
fix: populate stub reference files, remove redundant TL;DR, fix HTML entities
- Populate 19 stub files with actual content from 100go.co - Remove redundant bare 'TL;DR' line after '#### TL;DR' header in 76 files - Convert 3 mid-file '#### TL;DR / Note' sections to '#### Note' - Fix HTML entities (&lt; &gt; &amp;) to proper characters in 9 files Amp-Thread-ID: https://ampcode.com/threads/T-019cba2c-0536-70d9-956b-8ff115f07646 Co-authored-by: Amp <amp@ampcode.com>
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-01-unintended-variable-shadowing.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-02-unnecessary-nested-code.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-03-misusing-init-functions.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-04-overusing-getters-and-setters.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-05-interface-pollution.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-06-interface-on-the-producer-side.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-07-returning-interfaces.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-08-any-says-nothing.md6
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-09-being-confused-about-when-to-use-generics.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-10-not-being-aware-of-the-possible-problems-with-type-embedding.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-100-not-understanding-the-impacts-of-running-go-in-docker-and-kubernetes.md12
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-11-not-using-the-functional-options-pattern.md7
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-13-creating-utility-packages.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-14-ignoring-package-name-collisions.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-15-missing-code-documentation.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-16-not-using-linters.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-17-creating-confusion-with-octal-literals.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-18-neglecting-integer-overflows.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-19-not-understanding-floating-points.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-20-not-understanding-slice-length-and-capacity.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-21-inefficient-slice-initialization.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-22-being-confused-about-nil-vs-empty-slice.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-23-not-properly-checking-if-a-slice-is-empty.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-24-not-making-slice-copies-correctly.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-25-unexpected-side-effects-using-slice-append.md4
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-26-slices-and-memory-leaks.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-27-inefficient-map-initialization.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-28-maps-and-memory-leaks.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-29-comparing-values-incorrectly.md6
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-30-ignoring-that-elements-are-copied-in-range-loops.md12
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-31-ignoring-how-arguments-are-evaluated-in-range-loops-channels-and-arrays.md18
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-32-ignoring-the-impacts-of-using-pointer-elements-in-range-loops.md15
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-33-making-wrong-assumptions-during-map-iterations-ordering-and-map-insert-during-iteration.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-34-ignoring-how-the-break-statement-works.md35
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-35-using-defer-inside-a-loop.md45
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-36-not-understanding-the-concept-of-rune.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-37-inaccurate-string-iteration.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-38-misusing-trim-functions.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-39-under-optimized-strings-concatenation.md6
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-40-useless-string-conversions.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-41-substring-and-memory-leaks.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-42-not-knowing-which-type-of-receiver-to-use.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-43-never-using-named-result-parameters.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-44-unintended-side-effects-with-named-result-parameters.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-45-returning-a-nil-receiver.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-46-using-a-filename-as-a-function-input.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-47-ignoring-how-defer-arguments-and-receivers-are-evaluated.md59
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-48-panicking.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-49-ignoring-when-to-wrap-an-error.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-50-comparing-an-error-type-inaccurately.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-51-comparing-an-error-value-inaccurately.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-52-handling-an-error-twice.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-53-not-handling-an-error.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-54-not-handling-defer-errors.md29
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-55-mixing-up-concurrency-and-parallelism.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-56-thinking-concurrency-is-always-faster.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-57-being-puzzled-about-when-to-use-channels-or-mutexes.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-58-not-understanding-race-problems-data-races-vs-race-conditions.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-59-not-understanding-the-concurrency-impacts-of-a-workload-type.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-60-misunderstanding-go-contexts.md3
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-61-propagating-an-inappropriate-context.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-62-starting-a-goroutine-without-knowing-when-to-stop-it.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-63-not-being-careful-with-goroutines-and-loop-variables.md31
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-64-expecting-a-deterministic-behavior-using-select-and-channels.md11
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-65-not-using-notification-channels.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-66-not-using-nil-channels.md15
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-67-being-puzzled-about-channel-size.md5
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-68-forgetting-about-possible-side-effects-with-string-formatting.md7
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-69-creating-data-races-with-append.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-70-using-mutexes-inaccurately-with-slices-and-maps.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-71-misusing-syncwaitgroup.md36
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-72-forgetting-about-synccond.md13
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-73-not-using-errgroup.md12
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-74-copying-a-sync-type.md14
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-75-providing-a-wrong-time-duration.md3
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-76-timeafter-and-memory-leaks.md22
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-79-not-closing-transient-resources-http-body-sqlrows-and-osfile.md20
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-80-forgetting-the-return-statement-after-replying-to-an-http-request.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-81-using-the-default-http-client-and-server.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-82-not-categorizing-tests-build-tags-environment-variables-and-short-mode.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-83-not-enabling-the-race-flag.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-84-not-using-test-execution-modes-parallel-and-shuffle.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-85-not-using-table-driven-tests.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-86-sleeping-in-unit-tests.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-87-not-dealing-with-the-time-api-efficiently.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-88-not-using-testing-utility-packages-httptest-and-iotest.md20
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-89-writing-inaccurate-benchmarks.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-92-writing-concurrent-code-that-leads-to-false-sharing.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-93-not-taking-into-account-instruction-level-parallelism.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-94-not-being-aware-of-data-alignment.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-95-not-understanding-stack-vs-heap.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-96-not-knowing-how-to-reduce-allocations.md22
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-97-not-relying-on-inlining.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-98-not-using-go-diagnostics-tooling.md1
-rw-r--r--prompts/skills/100-go-mistakes/references/mistake-99-not-understanding-how-the-gc-works.md20
95 files changed, 449 insertions, 125 deletions
diff --git a/prompts/skills/100-go-mistakes/references/mistake-01-unintended-variable-shadowing.md b/prompts/skills/100-go-mistakes/references/mistake-01-unintended-variable-shadowing.md
index 076039e..54d5f69 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-01-unintended-variable-shadowing.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-01-unintended-variable-shadowing.md
@@ -1,7 +1,6 @@
# Mistake #1: Unintended variable shadowing
#### TL;DR
-TL;DR
Avoiding shadowed variables can help prevent mistakes like referencing the wrong variable or confusing readers.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-02-unnecessary-nested-code.md b/prompts/skills/100-go-mistakes/references/mistake-02-unnecessary-nested-code.md
index dfd04f3..e8cf6c4 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-02-unnecessary-nested-code.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-02-unnecessary-nested-code.md
@@ -1,7 +1,6 @@
# Mistake #2: Unnecessary nested code
#### TL;DR
-TL;DR
Avoiding nested levels and keeping the happy path aligned on the left makes building a mental code model easier.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-03-misusing-init-functions.md b/prompts/skills/100-go-mistakes/references/mistake-03-misusing-init-functions.md
index 805677e..8695301 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-03-misusing-init-functions.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-03-misusing-init-functions.md
@@ -1,7 +1,6 @@
# Mistake #3: Misusing init functions
#### TL;DR
-TL;DR
When initializing variables, remember that init functions have limited error handling and make state handling and testing more complex. In most cases, initializations should be handled as specific functions.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-04-overusing-getters-and-setters.md b/prompts/skills/100-go-mistakes/references/mistake-04-overusing-getters-and-setters.md
index a93dffc..d7730ef 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-04-overusing-getters-and-setters.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-04-overusing-getters-and-setters.md
@@ -1,7 +1,6 @@
# Mistake #4: Overusing getters and setters
#### TL;DR
-TL;DR
Forcing the use of getters and setters isn’t idiomatic in Go. Being pragmatic and finding the right balance between efficiency and blindly following certain idioms should be the way to go.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-05-interface-pollution.md b/prompts/skills/100-go-mistakes/references/mistake-05-interface-pollution.md
index 00c9738..203be64 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-05-interface-pollution.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-05-interface-pollution.md
@@ -1,7 +1,6 @@
# Mistake #5: Interface pollution
#### TL;DR
-TL;DR
Abstractions should be discovered, not created. To prevent unnecessary complexity, create an interface when you need it and not when you foresee needing it, or if you can at least prove the abstraction to be a valid one.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-06-interface-on-the-producer-side.md b/prompts/skills/100-go-mistakes/references/mistake-06-interface-on-the-producer-side.md
index d77acb7..ca7e752 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-06-interface-on-the-producer-side.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-06-interface-on-the-producer-side.md
@@ -1,7 +1,6 @@
# Mistake #6: Interface on the producer side
#### TL;DR
-TL;DR
Keeping interfaces on the client side avoids unnecessary abstractions.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-07-returning-interfaces.md b/prompts/skills/100-go-mistakes/references/mistake-07-returning-interfaces.md
index f7c4fca..db52c2e 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-07-returning-interfaces.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-07-returning-interfaces.md
@@ -1,7 +1,6 @@
# Mistake #7: Returning interfaces
#### TL;DR
-TL;DR
To prevent being restricted in terms of flexibility, a function shouldn’t return interfaces but concrete implementations in most cases. Conversely, a function should accept interfaces whenever possible.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-08-any-says-nothing.md b/prompts/skills/100-go-mistakes/references/mistake-08-any-says-nothing.md
index af8a478..f7c8931 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-08-any-says-nothing.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-08-any-says-nothing.md
@@ -1,3 +1,7 @@
# Mistake #8: any says nothing
-[Documentation for mistake #8 from 100go.co]
+#### TL;DR
+
+The `any` type can be helpful if there is a genuine need for accepting or returning any possible type (for instance, when it comes to marshaling or formatting). In general, we should avoid overgeneralizing the code we write at all costs. Perhaps a little bit of duplicated code might occasionally be better if it improves other aspects such as code expressiveness.
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/02-code-project-organization/8-any/main.go)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-09-being-confused-about-when-to-use-generics.md b/prompts/skills/100-go-mistakes/references/mistake-09-being-confused-about-when-to-use-generics.md
index 64e10ce..120881f 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-09-being-confused-about-when-to-use-generics.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-09-being-confused-about-when-to-use-generics.md
@@ -1,7 +1,6 @@
# Mistake #9: Being confused about when to use generics
#### TL;DR
-TL;DR
Relying on generics and type parameters can prevent writing boilerplate code to factor out elements or behaviors. However, do not use type parameters prematurely, but only when you see a concrete need for them. Otherwise, they introduce unnecessary abstractions and complexity.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-10-not-being-aware-of-the-possible-problems-with-type-embedding.md b/prompts/skills/100-go-mistakes/references/mistake-10-not-being-aware-of-the-possible-problems-with-type-embedding.md
index 28f1864..0d6912c 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-10-not-being-aware-of-the-possible-problems-with-type-embedding.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-10-not-being-aware-of-the-possible-problems-with-type-embedding.md
@@ -1,7 +1,6 @@
# Mistake #10: Not being aware of the possible problems with type embedding
#### TL;DR
-TL;DR
Using type embedding can also help avoid boilerplate code; however, ensure that doing so doesn’t lead to visibility issues where some fields should have remained hidden.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-100-not-understanding-the-impacts-of-running-go-in-docker-and-kubernetes.md b/prompts/skills/100-go-mistakes/references/mistake-100-not-understanding-the-impacts-of-running-go-in-docker-and-kubernetes.md
index a31b72a..67c197c 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-100-not-understanding-the-impacts-of-running-go-in-docker-and-kubernetes.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-100-not-understanding-the-impacts-of-running-go-in-docker-and-kubernetes.md
@@ -1,3 +1,13 @@
# Mistake #100: Not understanding the impacts of running Go in Docker and Kubernetes
-[Documentation for mistake #100 from 100go.co]
+#### TL;DR
+
+Be aware that `GOMAXPROCS` defaults to the number of OS-visible CPUs, not the container's CPU limit. Use libraries like `automaxprocs` to set it correctly based on cgroup limits.
+
+When running Go applications in Docker or Kubernetes, several runtime behaviors can lead to performance issues:
+
+* **GOMAXPROCS**: By default, `runtime.GOMAXPROCS` is set to the number of CPUs visible to the OS, not the container's CPU limit. For example, on a 64-core host with a container limited to 2 CPUs, Go will create 64 OS threads for scheduling. This leads to excessive context switching and reduced performance. Use `go.uber.org/automaxprocs` to automatically set `GOMAXPROCS` based on the cgroup CPU quota.
+
+* **Memory limits**: Similarly, Go's GC doesn't natively know about container memory limits (prior to `GOMEMLIMIT` in Go 1.19). Without `GOMEMLIMIT`, the GC may allow heap growth beyond the container's memory limit, causing OOM kills.
+
+* **Minimal Docker images**: Use multi-stage builds with `scratch` or `distroless` base images to reduce image size and attack surface. Remember to include CA certificates if making HTTPS calls.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-11-not-using-the-functional-options-pattern.md b/prompts/skills/100-go-mistakes/references/mistake-11-not-using-the-functional-options-pattern.md
index 56f7cae..8179281 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-11-not-using-the-functional-options-pattern.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-11-not-using-the-functional-options-pattern.md
@@ -1,7 +1,6 @@
# Mistake #11: Not using the functional options pattern
#### TL;DR
-TL;DR
To handle options conveniently and in an API-friendly manner, use the functional options pattern.
@@ -18,10 +17,10 @@ type Option func(options *options) error
func WithPort(port int) Option {
return func(options *options) error {
- if port &lt; 0 {
+ if port < 0 {
return errors.New("port should be positive")
}
- options.port = &amp;port
+ options.port = &port
return nil
}
}
@@ -29,7 +28,7 @@ func WithPort(port int) Option {
func NewServer(addr string, opts ...Option) ( *http.Server, error) {
var options options
for _, opt := range opts {
- err := opt(&amp;options)
+ err := opt(&options)
if err != nil {
return nil, err
}
diff --git a/prompts/skills/100-go-mistakes/references/mistake-13-creating-utility-packages.md b/prompts/skills/100-go-mistakes/references/mistake-13-creating-utility-packages.md
index 5b45254..0e6c4f6 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-13-creating-utility-packages.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-13-creating-utility-packages.md
@@ -1,7 +1,6 @@
# Mistake #13: Creating utility packages
#### TL;DR
-TL;DR
Naming is a critical piece of application design. Creating packages such as `common`, `util`, and `shared` doesn’t bring much value for the reader. Refactor such packages into meaningful and specific package names.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-14-ignoring-package-name-collisions.md b/prompts/skills/100-go-mistakes/references/mistake-14-ignoring-package-name-collisions.md
index 98a050c..eee965c 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-14-ignoring-package-name-collisions.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-14-ignoring-package-name-collisions.md
@@ -1,7 +1,6 @@
# Mistake #14: Ignoring package name collisions
#### TL;DR
-TL;DR
To avoid naming collisions between variables and packages, leading to confusion or perhaps even bugs, use unique names for each one. If this isn’t feasible, use an import alias to change the qualifier to differentiate the package name from the variable name, or think of a better name.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-15-missing-code-documentation.md b/prompts/skills/100-go-mistakes/references/mistake-15-missing-code-documentation.md
index 2151605..f9fdc8e 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-15-missing-code-documentation.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-15-missing-code-documentation.md
@@ -1,7 +1,6 @@
# Mistake #15: Missing code documentation
#### TL;DR
-TL;DR
To help clients and maintainers understand your code’s purpose, document exported elements.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-16-not-using-linters.md b/prompts/skills/100-go-mistakes/references/mistake-16-not-using-linters.md
index 440e0c5..1106f75 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-16-not-using-linters.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-16-not-using-linters.md
@@ -1,7 +1,6 @@
# Mistake #16: Not using linters
#### TL;DR
-TL;DR
To improve code quality and consistency, use linters and formatters.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-17-creating-confusion-with-octal-literals.md b/prompts/skills/100-go-mistakes/references/mistake-17-creating-confusion-with-octal-literals.md
index 7c89902..010f574 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-17-creating-confusion-with-octal-literals.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-17-creating-confusion-with-octal-literals.md
@@ -1,7 +1,6 @@
# Mistake #17: Creating confusion with octal literals
#### TL;DR
-TL;DR
When reading existing code, bear in mind that integer literals starting with `0` are octal numbers. Also, to improve readability, make octal integers explicit by prefixing them with `0o`.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-18-neglecting-integer-overflows.md b/prompts/skills/100-go-mistakes/references/mistake-18-neglecting-integer-overflows.md
index 8ab3127..f0e35ee 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-18-neglecting-integer-overflows.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-18-neglecting-integer-overflows.md
@@ -1,7 +1,6 @@
# Mistake #18: Neglecting integer overflows
#### TL;DR
-TL;DR
Because integer overflows and underflows are handled silently in Go, you can implement your own functions to catch them.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-19-not-understanding-floating-points.md b/prompts/skills/100-go-mistakes/references/mistake-19-not-understanding-floating-points.md
index e95be48..85867e6 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-19-not-understanding-floating-points.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-19-not-understanding-floating-points.md
@@ -1,7 +1,6 @@
# Mistake #19: Not understanding floating-points
#### TL;DR
-TL;DR
Making floating-point comparisons within a given delta can ensure that your code is portable. When performing addition or subtraction, group the operations with a similar order of magnitude to favor accuracy. Also, perform multiplication and division before addition and subtraction.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-20-not-understanding-slice-length-and-capacity.md b/prompts/skills/100-go-mistakes/references/mistake-20-not-understanding-slice-length-and-capacity.md
index 473d0e2..7fb89cb 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-20-not-understanding-slice-length-and-capacity.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-20-not-understanding-slice-length-and-capacity.md
@@ -1,7 +1,6 @@
# Mistake #20: Not understanding slice length and capacity
#### TL;DR
-TL;DR
Understanding the difference between slice length and capacity should be part of a Go developer’s core knowledge. The slice length is the number of available elements in the slice, whereas the slice capacity is the number of elements in the backing array.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-21-inefficient-slice-initialization.md b/prompts/skills/100-go-mistakes/references/mistake-21-inefficient-slice-initialization.md
index 49f3a4e..024a2c1 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-21-inefficient-slice-initialization.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-21-inefficient-slice-initialization.md
@@ -1,7 +1,6 @@
# Mistake #21: Inefficient slice initialization
#### TL;DR
-TL;DR
When creating a slice, initialize it with a given length or capacity if its length is already known. This reduces the number of allocations and improves performance.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-22-being-confused-about-nil-vs-empty-slice.md b/prompts/skills/100-go-mistakes/references/mistake-22-being-confused-about-nil-vs-empty-slice.md
index f850dbc..528508e 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-22-being-confused-about-nil-vs-empty-slice.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-22-being-confused-about-nil-vs-empty-slice.md
@@ -1,7 +1,6 @@
# Mistake #22: Being confused about nil vs. empty slice
#### TL;DR
-TL;DR
To prevent common confusions such as when using the `encoding/json` or the `reflect` package, you need to understand the difference between nil and empty slices. Both are zero-length, zero-capacity slices, but only a nil slice doesn’t require allocation.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-23-not-properly-checking-if-a-slice-is-empty.md b/prompts/skills/100-go-mistakes/references/mistake-23-not-properly-checking-if-a-slice-is-empty.md
index 25c6f29..9b734e8 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-23-not-properly-checking-if-a-slice-is-empty.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-23-not-properly-checking-if-a-slice-is-empty.md
@@ -1,7 +1,6 @@
# Mistake #23: Not properly checking if a slice is empty
#### TL;DR
-TL;DR
To check if a slice doesn’t contain any element, check its length. This check works regardless of whether the slice is `nil` or empty. The same goes for maps. To design unambiguous APIs, you shouldn’t distinguish between nil and empty slices.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-24-not-making-slice-copies-correctly.md b/prompts/skills/100-go-mistakes/references/mistake-24-not-making-slice-copies-correctly.md
index a16b53f..0fa368a 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-24-not-making-slice-copies-correctly.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-24-not-making-slice-copies-correctly.md
@@ -1,7 +1,6 @@
# Mistake #24: Not making slice copies correctly
#### TL;DR
-TL;DR
To copy one slice to another using the `copy` built-in function, remember that the number of copied elements corresponds to the minimum between the two slice’s lengths.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-25-unexpected-side-effects-using-slice-append.md b/prompts/skills/100-go-mistakes/references/mistake-25-unexpected-side-effects-using-slice-append.md
index e1b513d..b38083f 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-25-unexpected-side-effects-using-slice-append.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-25-unexpected-side-effects-using-slice-append.md
@@ -1,14 +1,12 @@
# Mistake #25: Unexpected side effects using slice append
#### TL;DR
-TL;DR
Using copy or the full slice expression is a way to prevent `append` from creating conflicts if two different functions use slices backed by the same array. However, only a slice copy prevents memory leaks if you want to shrink a large slice.
When using slicing, we must remember that we can face a situation leading to unintended side effects. If the resulting slice has a length smaller than its capacity, append can mutate the original slice. If we want to restrict the range of possible side effects, we can use either a slice copy or the full slice expression, which prevents us from doing a copy.
-#### TL;DR
-Note
+#### Note
`s[low:high:max]` (full slice expression): This statement creates a slice similar to the one created with `s[low:high]`, except that the resulting slice’s capacity is equal to `max - low`.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-26-slices-and-memory-leaks.md b/prompts/skills/100-go-mistakes/references/mistake-26-slices-and-memory-leaks.md
index a5cd33e..78474a3 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-26-slices-and-memory-leaks.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-26-slices-and-memory-leaks.md
@@ -1,7 +1,6 @@
# Mistake #26: Slices and memory leaks
#### TL;DR
-TL;DR
Working with a slice of pointers or structs with pointer fields, you can avoid memory leaks by marking as nil the elements excluded by a slicing operation.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-27-inefficient-map-initialization.md b/prompts/skills/100-go-mistakes/references/mistake-27-inefficient-map-initialization.md
index bff64ac..3328921 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-27-inefficient-map-initialization.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-27-inefficient-map-initialization.md
@@ -1,7 +1,6 @@
# Mistake #27: Inefficient map initialization
#### TL;DR
-TL;DR
When creating a map, initialize it with a given length if its length is already known. This reduces the number of allocations and improves performance.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-28-maps-and-memory-leaks.md b/prompts/skills/100-go-mistakes/references/mistake-28-maps-and-memory-leaks.md
index b281d21..7fb8f7e 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-28-maps-and-memory-leaks.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-28-maps-and-memory-leaks.md
@@ -1,7 +1,6 @@
# Mistake #28: Maps and memory leaks
#### TL;DR
-TL;DR
A map can always grow in memory, but it never shrinks. Hence, if it leads to some memory issues, you can try different options, such as forcing Go to recreate the map or using pointers.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-29-comparing-values-incorrectly.md b/prompts/skills/100-go-mistakes/references/mistake-29-comparing-values-incorrectly.md
index 2d99d7e..daef02a 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-29-comparing-values-incorrectly.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-29-comparing-values-incorrectly.md
@@ -1,7 +1,6 @@
# Mistake #29: Comparing values incorrectly
#### TL;DR
-TL;DR
To compare types in Go, you can use the == and != operators if two types are comparable: Booleans, numerals, strings, pointers, channels, and structs are composed entirely of comparable types. Otherwise, you can either use `reflect.DeepEqual` and pay the price of reflection or use custom implementations and libraries.
@@ -15,10 +14,9 @@ It’s essential to understand how to use `==` and `!=` to make comparisons effe
* Pointers—Compare whether two pointers point to the same value in memory or if both are nil.
* Structs and arrays—Compare whether they are composed of similar types.
-#### TL;DR
-Note
+#### Note
-We can also use the `?`, `&gt;=`, `&lt;`, and `&gt;` operators with numeric types to compare values and with strings to compare their lexical order.
+We can also use the `<=`, `>=`, `<`, and `>` operators with numeric types to compare values and with strings to compare their lexical order.
If operands are not comparable (e.g., slices and maps), we have to use other options such as reflection. Reflection is a form of metaprogramming, and it refers to the ability of an application to introspect and modify its structure and behavior. For example, in Go, we can use `reflect.DeepEqual`. This function reports whether two elements are deeply equal by recursively traversing two values. The elements it accepts are basic types plus arrays, structs, slices, maps, pointers, interfaces, and functions. Yet, the main catch is the performance penalty.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-30-ignoring-that-elements-are-copied-in-range-loops.md b/prompts/skills/100-go-mistakes/references/mistake-30-ignoring-that-elements-are-copied-in-range-loops.md
index 32d79c5..83a9c1a 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-30-ignoring-that-elements-are-copied-in-range-loops.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-30-ignoring-that-elements-are-copied-in-range-loops.md
@@ -1,3 +1,13 @@
# Mistake #30: Ignoring that elements are copied in range loops
-[Documentation for mistake #30 from 100go.co]
+#### TL;DR
+
+The value element in a range loop is a copy. Therefore, to mutate a struct, use the index to access it directly or use a classic for loop with pointers.
+
+A range loop allows iterating over different data structures: String, Array, Pointer to an array, Slice, Map, Receiving channel.
+
+Compared to a classic for loop, a range loop is a convenient way to iterate over all the elements of one of these data structures, thanks to its concise syntax.
+
+Yet, we should remember that the value element in a range loop is a copy. Therefore, if the value is a struct we need to mutate, we will only update the copy, not the element itself, unless the value or field we modify is a pointer. The favored options are to access the element via the index using a range loop or a classic for loop.
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/04-control-structures/30-range-loop-element-copied/)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-31-ignoring-how-arguments-are-evaluated-in-range-loops-channels-and-arrays.md b/prompts/skills/100-go-mistakes/references/mistake-31-ignoring-how-arguments-are-evaluated-in-range-loops-channels-and-arrays.md
index 9775d58..7a16c53 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-31-ignoring-how-arguments-are-evaluated-in-range-loops-channels-and-arrays.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-31-ignoring-how-arguments-are-evaluated-in-range-loops-channels-and-arrays.md
@@ -1,3 +1,19 @@
# Mistake #31: Ignoring how arguments are evaluated in range loops (channels and arrays)
-[Documentation for mistake #31 from 100go.co]
+#### TL;DR
+
+The range loop expression is evaluated only once, before the beginning of the loop, by doing a copy. Be aware of this to avoid common mistakes.
+
+The range loop evaluates the provided expression only once, before the beginning of the loop, by doing a copy (regardless of the type). We should remember this behavior to avoid common mistakes that might, for example, lead us to access the wrong element. For example:
+
+ a := [3]int{0, 1, 2}
+ for i, v := range a {
+ a[2] = 10
+ if i == 2 {
+ fmt.Println(v)
+ }
+ }
+
+This code updates the last index to 10. However, if we run this code, it does not print 10; it prints 2, because the range expression `a` was copied before the loop started.
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/04-control-structures/31-range-loop-arg-evaluation/)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-32-ignoring-the-impacts-of-using-pointer-elements-in-range-loops.md b/prompts/skills/100-go-mistakes/references/mistake-32-ignoring-the-impacts-of-using-pointer-elements-in-range-loops.md
index bad6234..c6e02c3 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-32-ignoring-the-impacts-of-using-pointer-elements-in-range-loops.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-32-ignoring-the-impacts-of-using-pointer-elements-in-range-loops.md
@@ -1,3 +1,16 @@
# Mistake #32: Ignoring the impacts of using pointer elements in range loops
-[Documentation for mistake #32 from 100go.co]
+#### TL;DR
+
+When iterating over a data structure using a range loop and storing the pointer of each element, be aware that all pointers will point to the same element: the last one. Use a local variable or index access instead.
+
+When using a range loop with pointer elements, a common mistake is to store pointers to the loop variable. Since the loop variable is reused across iterations, all stored pointers end up referencing the same (last) element. To fix this, create a local copy within the loop or access elements by index.
+
+ s := []int{1, 2, 3}
+ var ptrs []*int
+ for _, v := range s {
+ v := v // Create a local copy
+ ptrs = append(ptrs, &v)
+ }
+
+Note: As of Go 1.22, the loop variable is redefined per iteration, which eliminates this issue in newer Go versions.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-33-making-wrong-assumptions-during-map-iterations-ordering-and-map-insert-during-iteration.md b/prompts/skills/100-go-mistakes/references/mistake-33-making-wrong-assumptions-during-map-iterations-ordering-and-map-insert-during-iteration.md
index b5eafb8..10c3f19 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-33-making-wrong-assumptions-during-map-iterations-ordering-and-map-insert-during-iteration.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-33-making-wrong-assumptions-during-map-iterations-ordering-and-map-insert-during-iteration.md
@@ -1,7 +1,6 @@
# Mistake #33: Making wrong assumptions during map iterations (ordering and map insert during iteration)
#### TL;DR
-TL;DR
To ensure predictable outputs when using maps, remember that a map data structure:
diff --git a/prompts/skills/100-go-mistakes/references/mistake-34-ignoring-how-the-break-statement-works.md b/prompts/skills/100-go-mistakes/references/mistake-34-ignoring-how-the-break-statement-works.md
index 9bdb601..594de48 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-34-ignoring-how-the-break-statement-works.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-34-ignoring-how-the-break-statement-works.md
@@ -1,3 +1,36 @@
# Mistake #34: Ignoring how the break statement works
-[Documentation for mistake #34 from 100go.co]
+#### TL;DR
+
+A `break` statement terminates the execution of the innermost `for`, `switch`, or `select` statement. Use labels to break out of an outer loop from within a `switch` or `select`.
+
+A break statement is commonly used to terminate the execution of a loop. When loops are used in conjunction with switch or select, developers frequently make the mistake of breaking the wrong statement. For example:
+
+ for i := 0; i < 5; i++ {
+ fmt.Printf("%d ", i)
+ switch i {
+ default:
+ case 2:
+ break
+ }
+ }
+
+The break statement doesn't terminate the `for` loop: it terminates the `switch` statement, instead. Hence, instead of iterating from 0 to 2, this code iterates from 0 to 4: `0 1 2 3 4`.
+
+One essential rule to keep in mind is that a `break` statement terminates the execution of the innermost `for`, `switch`, or `select` statement.
+
+To break the loop instead of the `switch` statement, the most idiomatic way is to use a label:
+
+ loop:
+ for i := 0; i < 5; i++ {
+ fmt.Printf("%d ", i)
+ switch i {
+ default:
+ case 2:
+ break loop
+ }
+ }
+
+Here, we associate the `loop` label with the `for` loop. Then, because we provide the `loop` label to the `break` statement, it breaks the loop, not the switch. Therefore, this new version will print `0 1 2`, as we expected.
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/04-control-structures/34-break/main.go)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-35-using-defer-inside-a-loop.md b/prompts/skills/100-go-mistakes/references/mistake-35-using-defer-inside-a-loop.md
index 54b3a20..f0dff21 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-35-using-defer-inside-a-loop.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-35-using-defer-inside-a-loop.md
@@ -1,3 +1,46 @@
# Mistake #35: Using defer inside a loop
-[Documentation for mistake #35 from 100go.co]
+#### TL;DR
+
+A `defer` call is executed not during each loop iteration but when the surrounding function returns. Be cautious about using `defer` inside loops; extract the loop body into a function to ensure `defer` executes per iteration.
+
+The `defer` statement delays a call's execution until the surrounding function returns. One common mistake with `defer` is to forget that it schedules a function call when the surrounding function returns, not when the current block or iteration completes. For example:
+
+ func readFiles(ch <-chan string) error {
+ for path := range ch {
+ file, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+ // Do something with file
+ }
+ return nil
+ }
+
+The `defer` calls are executed not during each loop iteration but when the `readFiles` function returns. If `readFiles` doesn't return, the file descriptors will be kept open forever, causing leaks.
+
+One common option to fix this problem is to create a surrounding function after `defer`, called during each iteration:
+
+ func readFiles(ch <-chan string) error {
+ for path := range ch {
+ if err := readFile(path); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
+ func readFile(path string) error {
+ file, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+ // Do something with file
+ return nil
+ }
+
+Another solution is to make the `readFile` function a closure but intrinsically, this remains the same solution: adding another surrounding function to execute the `defer` calls during each iteration.
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/04-control-structures/35-defer-loop/main.go)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-36-not-understanding-the-concept-of-rune.md b/prompts/skills/100-go-mistakes/references/mistake-36-not-understanding-the-concept-of-rune.md
index d3f174f..c4c97e7 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-36-not-understanding-the-concept-of-rune.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-36-not-understanding-the-concept-of-rune.md
@@ -1,7 +1,6 @@
# Mistake #36: Not understanding the concept of rune
#### TL;DR
-TL;DR
Understanding that a rune corresponds to the concept of a Unicode code point and that it can be composed of multiple bytes should be part of the Go developer’s core knowledge to work accurately with strings.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-37-inaccurate-string-iteration.md b/prompts/skills/100-go-mistakes/references/mistake-37-inaccurate-string-iteration.md
index 9693598..b3e83bd 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-37-inaccurate-string-iteration.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-37-inaccurate-string-iteration.md
@@ -1,7 +1,6 @@
# Mistake #37: Inaccurate string iteration
#### TL;DR
-TL;DR
Iterating on a string with the `range` operator iterates on the runes with the index corresponding to the starting index of the rune’s byte sequence. To access a specific rune index (such as the third rune), convert the string into a `[]rune`.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-38-misusing-trim-functions.md b/prompts/skills/100-go-mistakes/references/mistake-38-misusing-trim-functions.md
index 5faf065..177c373 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-38-misusing-trim-functions.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-38-misusing-trim-functions.md
@@ -1,7 +1,6 @@
# Mistake #38: Misusing trim functions
#### TL;DR
-TL;DR
`strings.TrimRight`/`strings.TrimLeft` removes all the trailing/leading runes contained in a given set, whereas `strings.TrimSuffix`/`strings.TrimPrefix` returns a string without a provided suffix/prefix.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-39-under-optimized-strings-concatenation.md b/prompts/skills/100-go-mistakes/references/mistake-39-under-optimized-strings-concatenation.md
index 5949474..862225c 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-39-under-optimized-strings-concatenation.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-39-under-optimized-strings-concatenation.md
@@ -1,7 +1,6 @@
# Mistake #39: Under-optimized strings concatenation
#### TL;DR
-TL;DR
Concatenating a list of strings should be done with `strings.Builder` to prevent allocating a new string during each iteration.
@@ -29,8 +28,7 @@ func concat(values []string) string {
During each iteration, we constructed the resulting string by calling the `WriteString` method that appends the content of value to its internal buffer, hence minimizing memory copying.
-#### TL;DR
-Note
+#### Note
`WriteString` returns an error as the second output, but we purposely ignore it. Indeed, this method will never return a non-nil error. So what’s the purpose of this method returning an error as part of its signature? `strings.Builder` implements the `io.StringWriter` interface, which contains a single method: `WriteString(s string) (n int, err error)`. Hence, to comply with this interface, `WriteString` must return an error.
@@ -38,7 +36,7 @@ Internally, `strings.Builder` holds a byte slice. Each call to `WriteString` res
func concat(values []string) string {
total := 0
- for i := 0; i &lt; len(values); i++ {
+ for i := 0; i < len(values); i++ {
total += len(values[i])
}
diff --git a/prompts/skills/100-go-mistakes/references/mistake-40-useless-string-conversions.md b/prompts/skills/100-go-mistakes/references/mistake-40-useless-string-conversions.md
index 3a46cc7..5301d23 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-40-useless-string-conversions.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-40-useless-string-conversions.md
@@ -1,7 +1,6 @@
# Mistake #40: Useless string conversions
#### TL;DR
-TL;DR
Remembering that the `bytes` package offers the same operations as the `strings` package can help avoid extra byte/string conversions.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-41-substring-and-memory-leaks.md b/prompts/skills/100-go-mistakes/references/mistake-41-substring-and-memory-leaks.md
index 9042bb6..5b5d0e6 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-41-substring-and-memory-leaks.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-41-substring-and-memory-leaks.md
@@ -1,7 +1,6 @@
# Mistake #41: Substring and memory leaks
#### TL;DR
-TL;DR
Using copies instead of substrings can prevent memory leaks, as the string returned by a substring operation will be backed by the same byte array.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-42-not-knowing-which-type-of-receiver-to-use.md b/prompts/skills/100-go-mistakes/references/mistake-42-not-knowing-which-type-of-receiver-to-use.md
index aa51515..1d7bd35 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-42-not-knowing-which-type-of-receiver-to-use.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-42-not-knowing-which-type-of-receiver-to-use.md
@@ -1,7 +1,6 @@
# Mistake #42: Not knowing which type of receiver to use
#### TL;DR
-TL;DR
The decision whether to use a value or a pointer receiver should be made based on factors such as the type, whether it has to be mutated, whether it contains a field that can’t be copied, and how large the object is. When in doubt, use a pointer receiver.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-43-never-using-named-result-parameters.md b/prompts/skills/100-go-mistakes/references/mistake-43-never-using-named-result-parameters.md
index d8a9857..3bc2ac4 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-43-never-using-named-result-parameters.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-43-never-using-named-result-parameters.md
@@ -1,7 +1,6 @@
# Mistake #43: Never using named result parameters
#### TL;DR
-TL;DR
Using named result parameters can be an efficient way to improve the readability of a function/method, especially if multiple result parameters have the same type. In some cases, this approach can also be convenient because named result parameters are initialized to their zero value. But be cautious about potential side effects.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-44-unintended-side-effects-with-named-result-parameters.md b/prompts/skills/100-go-mistakes/references/mistake-44-unintended-side-effects-with-named-result-parameters.md
index 9cea481..2230494 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-44-unintended-side-effects-with-named-result-parameters.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-44-unintended-side-effects-with-named-result-parameters.md
@@ -1,7 +1,6 @@
# Mistake #44: Unintended side effects with named result parameters
#### TL;DR
-TL;DR
See #43.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-45-returning-a-nil-receiver.md b/prompts/skills/100-go-mistakes/references/mistake-45-returning-a-nil-receiver.md
index d0463ff..a2f869b 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-45-returning-a-nil-receiver.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-45-returning-a-nil-receiver.md
@@ -1,7 +1,6 @@
# Mistake #45: Returning a nil receiver
#### TL;DR
-TL;DR
When returning an interface, be cautious about not returning a nil pointer but an explicit nil value. Otherwise, unintended consequences may occur and the caller will receive a non-nil value.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-46-using-a-filename-as-a-function-input.md b/prompts/skills/100-go-mistakes/references/mistake-46-using-a-filename-as-a-function-input.md
index d26e4b8..860f9ef 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-46-using-a-filename-as-a-function-input.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-46-using-a-filename-as-a-function-input.md
@@ -1,7 +1,6 @@
# Mistake #46: Using a filename as a function input
#### TL;DR
-TL;DR
Designing functions to receive `io.Reader` types instead of filenames improves the reusability of a function and makes testing easier.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-47-ignoring-how-defer-arguments-and-receivers-are-evaluated.md b/prompts/skills/100-go-mistakes/references/mistake-47-ignoring-how-defer-arguments-and-receivers-are-evaluated.md
index 167877f..3e6818f 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-47-ignoring-how-defer-arguments-and-receivers-are-evaluated.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-47-ignoring-how-defer-arguments-and-receivers-are-evaluated.md
@@ -1,3 +1,60 @@
# Mistake #47: Ignoring how defer arguments and receivers are evaluated
-[Documentation for mistake #47 from 100go.co]
+#### TL;DR
+
+In a `defer` function, arguments are evaluated right away, not once the surrounding function returns. To defer a call with an updated value, use pointers or closures.
+
+In a `defer` function the arguments are evaluated right away, not once the surrounding function returns. For example, in this code, we always call `notify` and `incrementCounter` with the same status: an empty string.
+
+ const (
+ StatusSuccess = "success"
+ StatusErrorFoo = "error_foo"
+ StatusErrorBar = "error_bar"
+ )
+
+ func f() error {
+ var status string
+ defer notify(status)
+ defer incrementCounter(status)
+
+ if err := foo(); err != nil {
+ status = StatusErrorFoo
+ return err
+ }
+
+ if err := bar(); err != nil {
+ status = StatusErrorBar
+ return err
+ }
+
+ status = StatusSuccess
+ return nil
+ }
+
+Two leading options if we want to keep using `defer`:
+
+The first solution is to pass a string pointer:
+
+ func f() error {
+ var status string
+ defer notify(&status)
+ defer incrementCounter(&status)
+ // The rest of the function unchanged
+ }
+
+There's another solution: calling a closure as a `defer` statement:
+
+ func f() error {
+ var status string
+ defer func() {
+ notify(status)
+ incrementCounter(status)
+ }()
+ // The rest of the function unchanged
+ }
+
+Here, we wrap the calls within a closure. This closure references the status variable from outside its body. Therefore, `status` is evaluated once the closure is executed, not when we call `defer`.
+
+Let's also note this behavior applies with method receivers: the receiver is evaluated immediately.
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/06-functions-methods/47-defer-evaluation/)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-48-panicking.md b/prompts/skills/100-go-mistakes/references/mistake-48-panicking.md
index e2e650d..e2ac88e 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-48-panicking.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-48-panicking.md
@@ -1,7 +1,6 @@
# Mistake #48: Panicking
#### TL;DR
-TL;DR
Using `panic` is an option to deal with errors in Go. However, it should only be used sparingly in unrecoverable conditions: for example, to signal a programmer error or when you fail to load a mandatory dependency.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-49-ignoring-when-to-wrap-an-error.md b/prompts/skills/100-go-mistakes/references/mistake-49-ignoring-when-to-wrap-an-error.md
index 5284e0b..dffec32 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-49-ignoring-when-to-wrap-an-error.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-49-ignoring-when-to-wrap-an-error.md
@@ -1,7 +1,6 @@
# Mistake #49: Ignoring when to wrap an error
#### TL;DR
-TL;DR
Wrapping an error allows you to mark an error and/or provide additional context. However, error wrapping creates potential coupling as it makes the source error available for the caller. If you want to prevent that, don’t use error wrapping.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-50-comparing-an-error-type-inaccurately.md b/prompts/skills/100-go-mistakes/references/mistake-50-comparing-an-error-type-inaccurately.md
index 9d9a78d..4a0f122 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-50-comparing-an-error-type-inaccurately.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-50-comparing-an-error-type-inaccurately.md
@@ -1,7 +1,6 @@
# Mistake #50: Comparing an error type inaccurately
#### TL;DR
-TL;DR
If you use Go 1.13 error wrapping with the `%w` directive and `fmt.Errorf`, comparing an error against a type has to be done using `errors.As`. Otherwise, if the returned error you want to check is wrapped, it will fail the checks.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-51-comparing-an-error-value-inaccurately.md b/prompts/skills/100-go-mistakes/references/mistake-51-comparing-an-error-value-inaccurately.md
index 23dce0e..6ad5963 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-51-comparing-an-error-value-inaccurately.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-51-comparing-an-error-value-inaccurately.md
@@ -1,7 +1,6 @@
# Mistake #51: Comparing an error value inaccurately
#### TL;DR
-TL;DR
If you use Go 1.13 error wrapping with the `%w` directive and `fmt.Errorf`, comparing an error against or a value has to be done using `errors.As`. Otherwise, if the returned error you want to check is wrapped, it will fail the checks.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-52-handling-an-error-twice.md b/prompts/skills/100-go-mistakes/references/mistake-52-handling-an-error-twice.md
index 812d3f0..2e2869a 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-52-handling-an-error-twice.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-52-handling-an-error-twice.md
@@ -1,7 +1,6 @@
# Mistake #52: Handling an error twice
#### TL;DR
-TL;DR
In most situations, an error should be handled only once. Logging an error is handling an error. Therefore, you have to choose between logging or returning an error. In many cases, error wrapping is the solution as it allows you to provide additional context to an error and return the source error.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-53-not-handling-an-error.md b/prompts/skills/100-go-mistakes/references/mistake-53-not-handling-an-error.md
index fe98f60..f7bc7c7 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-53-not-handling-an-error.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-53-not-handling-an-error.md
@@ -1,7 +1,6 @@
# Mistake #53: Not handling an error
#### TL;DR
-TL;DR
Ignoring an error, whether during a function call or in a `defer` function, should be done explicitly using the blank identifier. Otherwise, future readers may be confused about whether it was intentional or a miss.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-54-not-handling-defer-errors.md b/prompts/skills/100-go-mistakes/references/mistake-54-not-handling-defer-errors.md
index 80dc62a..111ead8 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-54-not-handling-defer-errors.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-54-not-handling-defer-errors.md
@@ -1,3 +1,30 @@
# Mistake #54: Not handling defer errors
-[Documentation for mistake #54 from 100go.co]
+#### TL;DR
+
+When we want to ignore an error in a `defer` call, use the blank identifier (`_`) to make it explicit and add a comment explaining why.
+
+Consider the following code:
+
+ func f() {
+ // ...
+ notify() // Error handling is omitted
+ }
+
+ func notify() error {
+ // ...
+ }
+
+From a maintainability perspective, the code can lead to some issues. A reader looking at it cannot tell whether the error was intentionally ignored or accidentally forgotten.
+
+For these reasons, when we want to ignore an error, there's only one way to do it, using the blank identifier (`_`):
+
+ _ = notify()
+
+In terms of compilation and run time, this approach doesn't change anything compared to the first piece of code. But this new version makes explicit that we aren't interested in the error. Also, we can add a comment that indicates the rationale for why an error is ignored:
+
+ // At-most once delivery.
+ // Hence, it's accepted to miss some of them in case of errors.
+ _ = notify()
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/07-error-management/54-defer-errors/main.go)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-55-mixing-up-concurrency-and-parallelism.md b/prompts/skills/100-go-mistakes/references/mistake-55-mixing-up-concurrency-and-parallelism.md
index a63149b..f619e0b 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-55-mixing-up-concurrency-and-parallelism.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-55-mixing-up-concurrency-and-parallelism.md
@@ -1,7 +1,6 @@
# Mistake #55: Mixing up concurrency and parallelism
#### TL;DR
-TL;DR
Understanding the fundamental differences between concurrency and parallelism is a cornerstone of the Go developer’s knowledge. Concurrency is about structure, whereas parallelism is about execution.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-56-thinking-concurrency-is-always-faster.md b/prompts/skills/100-go-mistakes/references/mistake-56-thinking-concurrency-is-always-faster.md
index 203520f..53e09f6 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-56-thinking-concurrency-is-always-faster.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-56-thinking-concurrency-is-always-faster.md
@@ -1,7 +1,6 @@
# Mistake #56: Thinking concurrency is always faster
#### TL;DR
-TL;DR
To be a proficient developer, you must acknowledge that concurrency isn’t always faster. Solutions involving parallelization of minimal workloads may not necessarily be faster than a sequential implementation. Benchmarking sequential versus concurrent solutions should be the way to validate assumptions.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-57-being-puzzled-about-when-to-use-channels-or-mutexes.md b/prompts/skills/100-go-mistakes/references/mistake-57-being-puzzled-about-when-to-use-channels-or-mutexes.md
index 7bc9e23..29310ad 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-57-being-puzzled-about-when-to-use-channels-or-mutexes.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-57-being-puzzled-about-when-to-use-channels-or-mutexes.md
@@ -1,7 +1,6 @@
# Mistake #57: Being puzzled about when to use channels or mutexes
#### TL;DR
-TL;DR
Being aware of goroutine interactions can also be helpful when deciding between channels and mutexes. In general, parallel goroutines require synchronization and hence mutexes. Conversely, concurrent goroutines generally require coordination and orchestration and hence channels.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-58-not-understanding-race-problems-data-races-vs-race-conditions.md b/prompts/skills/100-go-mistakes/references/mistake-58-not-understanding-race-problems-data-races-vs-race-conditions.md
index 00d536d..418b909 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-58-not-understanding-race-problems-data-races-vs-race-conditions.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-58-not-understanding-race-problems-data-races-vs-race-conditions.md
@@ -1,7 +1,6 @@
# Mistake #58: Not understanding race problems (data races vs. race conditions and the Go memory model)
#### TL;DR
-TL;DR
Being proficient in concurrency also means understanding that data races and race conditions are different concepts. Data races occur when multiple goroutines simultaneously access the same memory location and at least one of them is writing. Meanwhile, being data-race-free doesn’t necessarily mean deterministic execution. When a behavior depends on the sequence or the timing of events that can’t be controlled, this is a race condition.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-59-not-understanding-the-concurrency-impacts-of-a-workload-type.md b/prompts/skills/100-go-mistakes/references/mistake-59-not-understanding-the-concurrency-impacts-of-a-workload-type.md
index a3476be..0a60da5 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-59-not-understanding-the-concurrency-impacts-of-a-workload-type.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-59-not-understanding-the-concurrency-impacts-of-a-workload-type.md
@@ -1,7 +1,6 @@
# Mistake #59: Not understanding the concurrency impacts of a workload type
#### TL;DR
-TL;DR
When creating a certain number of goroutines, consider the workload type. Creating CPU-bound goroutines means bounding this number close to the GOMAXPROCS variable (based by default on the number of CPU cores on the host). Creating I/O-bound goroutines depends on other factors, such as the external system.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-60-misunderstanding-go-contexts.md b/prompts/skills/100-go-mistakes/references/mistake-60-misunderstanding-go-contexts.md
index 71be7c5..fe44998 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-60-misunderstanding-go-contexts.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-60-misunderstanding-go-contexts.md
@@ -1,7 +1,6 @@
# Mistake #60: Misunderstanding Go contexts
#### TL;DR
-TL;DR
Go contexts are also one of the cornerstones of concurrency in Go. A context allows you to carry a deadline, a cancellation signal, and/or a list of keys-values.
@@ -30,7 +29,7 @@ For example, if we use tracing, we may want different subfunctions to share the
Catching a context cancellation
-The `context.Context` type exports a `Done` method that returns a receive-only notification channel: `&lt;-chan struct{}`. This channel is closed when the work associated with the context should be canceled. For example,
+The `context.Context` type exports a `Done` method that returns a receive-only notification channel: `<-chan struct{}`. This channel is closed when the work associated with the context should be canceled. For example,
* The Done channel related to a context created with `context.WithCancel` is closed when the cancel function is called.
* The Done channel related to a context created with `context.WithDeadline` is closed when the deadline has expired.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-61-propagating-an-inappropriate-context.md b/prompts/skills/100-go-mistakes/references/mistake-61-propagating-an-inappropriate-context.md
index a0f3e5a..8fa7b09 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-61-propagating-an-inappropriate-context.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-61-propagating-an-inappropriate-context.md
@@ -1,7 +1,6 @@
# Mistake #61: Propagating an inappropriate context
#### TL;DR
-TL;DR
Understanding the conditions when a context can be canceled should matter when propagating it: for example, an HTTP handler canceling the context when the response has been sent.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-62-starting-a-goroutine-without-knowing-when-to-stop-it.md b/prompts/skills/100-go-mistakes/references/mistake-62-starting-a-goroutine-without-knowing-when-to-stop-it.md
index b9dcbf4..6438377 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-62-starting-a-goroutine-without-knowing-when-to-stop-it.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-62-starting-a-goroutine-without-knowing-when-to-stop-it.md
@@ -1,7 +1,6 @@
# Mistake #62: Starting a goroutine without knowing when to stop it
#### TL;DR
-TL;DR
Avoiding leaks means being mindful that whenever a goroutine is started, you should have a plan to stop it eventually.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-63-not-being-careful-with-goroutines-and-loop-variables.md b/prompts/skills/100-go-mistakes/references/mistake-63-not-being-careful-with-goroutines-and-loop-variables.md
index 47cc181..ed7d1c3 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-63-not-being-careful-with-goroutines-and-loop-variables.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-63-not-being-careful-with-goroutines-and-loop-variables.md
@@ -1,3 +1,32 @@
# Mistake #63: Not being careful with goroutines and loop variables
-[Documentation for mistake #63 from 100go.co]
+#### TL;DR
+
+When launching goroutines from within a loop, be aware that the loop variable is shared across all iterations (prior to Go 1.22). Pass it as a parameter or create a local copy to avoid all goroutines referencing the last value.
+
+A common mistake when using goroutines with loop variables is that all goroutines end up referencing the same variable, which holds the last iteration's value by the time goroutines execute. For example:
+
+ for _, v := range s {
+ go func() {
+ fmt.Println(v) // All goroutines may print the last element
+ }()
+ }
+
+The fix is to either pass the variable as a function argument or create a local copy:
+
+ for _, v := range s {
+ v := v // Create a local copy
+ go func() {
+ fmt.Println(v)
+ }()
+ }
+
+Or pass it as a parameter:
+
+ for _, v := range s {
+ go func(val int) {
+ fmt.Println(val)
+ }(v)
+ }
+
+Note: As of Go 1.22, the loop variable semantics changed so each iteration gets its own variable, eliminating this class of bugs in newer Go versions.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-64-expecting-a-deterministic-behavior-using-select-and-channels.md b/prompts/skills/100-go-mistakes/references/mistake-64-expecting-a-deterministic-behavior-using-select-and-channels.md
index a9a3781..fdbba40 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-64-expecting-a-deterministic-behavior-using-select-and-channels.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-64-expecting-a-deterministic-behavior-using-select-and-channels.md
@@ -1,7 +1,6 @@
# Mistake #64: Expecting a deterministic behavior using select and channels
#### TL;DR
-TL;DR
Understanding that `select` with multiple channels chooses the case randomly if multiple options are possible prevents making wrong assumptions that can lead to subtle concurrency bugs.
@@ -10,17 +9,17 @@ One common mistake made by Go developers while working with channels is to make
For example, let's consider the following case (`disconnectCh` is a unbuffered channel):
go func() {
- for i := 0; i &lt; 10; i++ {
- messageCh &lt;- i
+ for i := 0; i < 10; i++ {
+ messageCh <- i
}
- disconnectCh &lt;- struct{}{}
+ disconnectCh <- struct{}{}
}()
for {
select {
- case v := &lt;-messageCh:
+ case v := <-messageCh:
fmt.Println(v)
- case &lt;-disconnectCh:
+ case <-disconnectCh:
fmt.Println("disconnection, return")
return
}
diff --git a/prompts/skills/100-go-mistakes/references/mistake-65-not-using-notification-channels.md b/prompts/skills/100-go-mistakes/references/mistake-65-not-using-notification-channels.md
index 78d748f..db66f67 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-65-not-using-notification-channels.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-65-not-using-notification-channels.md
@@ -1,7 +1,6 @@
# Mistake #65: Not using notification channels
#### TL;DR
-TL;DR
Send notifications using a `chan struct{}` type.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-66-not-using-nil-channels.md b/prompts/skills/100-go-mistakes/references/mistake-66-not-using-nil-channels.md
index 08ea379..91e298b 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-66-not-using-nil-channels.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-66-not-using-nil-channels.md
@@ -1,42 +1,41 @@
# Mistake #66: Not using nil channels
#### TL;DR
-TL;DR
Using nil channels should be part of your concurrency toolset because it allows you to remove cases from `select` statements, for example.
What should this code do?
var ch chan int
-&lt;-ch
+<-ch
`ch` is a `chan int` type. The zero value of a channel being nil, `ch` is `nil`. The goroutine won’t panic; however, it will block forever.
The principle is the same if we send a message to a nil channel. This goroutine blocks forever:
var ch chan int
-ch &lt;- 0
+ch <- 0
Then what’s the purpose of Go allowing messages to be received from or sent to a nil channel? For example, we can use nil channels to implement an idiomatic way to merge two channels:
-func merge(ch1, ch2 &lt;-chan int) &lt;-chan int {
+func merge(ch1, ch2 <-chan int) <-chan int {
ch := make(chan int, 1)
go func() {
for ch1 != nil || ch2 != nil { // Continue if at least one channel isn’t nil
select {
- case v, open := &lt;-ch1:
+ case v, open := <-ch1:
if !open {
ch1 = nil // Assign ch1 to a nil channel once closed
break
}
- ch &lt;- v
- case v, open := &lt;-ch2:
+ ch <- v
+ case v, open := <-ch2:
if !open {
ch2 = nil // Assigns ch2 to a nil channel once closed
break
}
- ch &lt;- v
+ ch <- v
}
}
close(ch)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-67-being-puzzled-about-channel-size.md b/prompts/skills/100-go-mistakes/references/mistake-67-being-puzzled-about-channel-size.md
index 86ed2d3..8b3d867 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-67-being-puzzled-about-channel-size.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-67-being-puzzled-about-channel-size.md
@@ -1,7 +1,6 @@
# Mistake #67: Being puzzled about channel size
#### TL;DR
-TL;DR
Carefully decide on the right channel type to use, given a problem. Only unbuffered channels provide strong synchronization guarantees. For buffered channels, you should have a good reason to specify a channel size other than one.
@@ -19,8 +18,8 @@ ch3 := make(chan int, 1)
With a buffered channel, a sender can send messages while the channel isn’t full. Once the channel is full, it will block until a receiver goroutine receives a message:
ch3 := make(chan int, 1)
-ch3 &lt;-1 // Non-blocking
-ch3 &lt;-2 // Blocking
+ch3 <-1 // Non-blocking
+ch3 <-2 // Blocking
The first send isn’t blocking, whereas the second one is, as the channel is full at this stage.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-68-forgetting-about-possible-side-effects-with-string-formatting.md b/prompts/skills/100-go-mistakes/references/mistake-68-forgetting-about-possible-side-effects-with-string-formatting.md
index 7612443..3f09eef 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-68-forgetting-about-possible-side-effects-with-string-formatting.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-68-forgetting-about-possible-side-effects-with-string-formatting.md
@@ -1,7 +1,6 @@
# Mistake #68: Forgetting about possible side effects with string formatting
#### TL;DR
-TL;DR
Being aware that string formatting may lead to calling existing functions means watching out for possible deadlocks and other data races.
@@ -25,7 +24,7 @@ func (c *Customer) UpdateAge(age int) error {
c.mutex.Lock() // Locks and defers unlock as we update Customer
defer c.mutex.Unlock()
- if age &lt; 0 { // Returns an error if age is negative
+ if age < 0 { // Returns an error if age is negative
return fmt.Errorf("age should be positive for customer %v", c)
}
@@ -44,7 +43,7 @@ The problem here may not be straightforward. If the provided age is negative, we
One possible solution is to restrict the scope of the mutex lock:
func (c *Customer) UpdateAge(age int) error {
- if age &lt; 0 {
+ if age < 0 {
return fmt.Errorf("age should be positive for customer %v", c)
}
@@ -63,7 +62,7 @@ func (c *Customer) UpdateAge(age int) error {
c.mutex.Lock()
defer c.mutex.Unlock()
- if age &lt; 0 {
+ if age < 0 {
return fmt.Errorf("age should be positive for customer id %s", c.id)
}
diff --git a/prompts/skills/100-go-mistakes/references/mistake-69-creating-data-races-with-append.md b/prompts/skills/100-go-mistakes/references/mistake-69-creating-data-races-with-append.md
index 3888d2a..f1d411b 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-69-creating-data-races-with-append.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-69-creating-data-races-with-append.md
@@ -1,7 +1,6 @@
# Mistake #69: Creating data races with append
#### TL;DR
-TL;DR
Calling `append` isn’t always data-race-free; hence, it shouldn’t be used concurrently on a shared slice.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-70-using-mutexes-inaccurately-with-slices-and-maps.md b/prompts/skills/100-go-mistakes/references/mistake-70-using-mutexes-inaccurately-with-slices-and-maps.md
index 47b9f69..f764b59 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-70-using-mutexes-inaccurately-with-slices-and-maps.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-70-using-mutexes-inaccurately-with-slices-and-maps.md
@@ -1,7 +1,6 @@
# Mistake #70: Using mutexes inaccurately with slices and maps
#### TL;DR
-TL;DR
Remembering that slices and maps are pointers can prevent common data races.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-71-misusing-syncwaitgroup.md b/prompts/skills/100-go-mistakes/references/mistake-71-misusing-syncwaitgroup.md
index e40513e..b9f897c 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-71-misusing-syncwaitgroup.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-71-misusing-syncwaitgroup.md
@@ -1,3 +1,37 @@
# Mistake #71: Misusing sync.WaitGroup
-[Documentation for mistake #71 from 100go.co]
+#### TL;DR
+
+Call `wg.Add` before spinning up goroutines, not inside them. Calling `Add` inside a goroutine introduces a race with `Wait`.
+
+In the following example, `wg.Add(1)` is called within the newly created goroutine, not in the parent goroutine:
+
+ wg := sync.WaitGroup{}
+ var v uint64
+ for i := 0; i < 3; i++ {
+ go func() {
+ wg.Add(1)
+ atomic.AddUint64(&v, 1)
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+ fmt.Println(v)
+
+If we run this example, we get a non-deterministic value (0 to 3) and a data race. The problem is that there is no guarantee that we have indicated to the wait group that we want to wait for three goroutines before calling `wg.Wait()`.
+
+To fix this, call `wg.Add` before the loop or inside the loop but not in the goroutine:
+
+ wg := sync.WaitGroup{}
+ var v uint64
+ wg.Add(3)
+ for i := 0; i < 3; i++ {
+ go func() {
+ atomic.AddUint64(&v, 1)
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+ fmt.Println(v)
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/71-wait-group/main.go)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-72-forgetting-about-synccond.md b/prompts/skills/100-go-mistakes/references/mistake-72-forgetting-about-synccond.md
index 549a47d..6920862 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-72-forgetting-about-synccond.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-72-forgetting-about-synccond.md
@@ -1,3 +1,14 @@
# Mistake #72: Forgetting about sync.Cond
-[Documentation for mistake #72 from 100go.co]
+#### TL;DR
+
+Use `sync.Cond` to send notifications to multiple goroutines. It provides `Signal` (wake one goroutine) and `Broadcast` (wake all waiting goroutines), which can be more efficient than channel-based alternatives when broadcasting.
+
+`sync.Cond` is a condition variable implementation that can be used to coordinate goroutines waiting for or announcing the occurrence of an event. It's useful in scenarios where multiple goroutines need to wait for some shared state to change. Instead of busy-waiting or using channels with limitations, `sync.Cond` provides an efficient mechanism.
+
+Key methods:
+* `Wait()` — Suspends the calling goroutine, releasing the lock, and resumes when signaled.
+* `Signal()` — Wakes one goroutine waiting on the condition.
+* `Broadcast()` — Wakes all goroutines waiting on the condition.
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/72-cond/main.go)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-73-not-using-errgroup.md b/prompts/skills/100-go-mistakes/references/mistake-73-not-using-errgroup.md
index 4c5486a..5b53c0f 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-73-not-using-errgroup.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-73-not-using-errgroup.md
@@ -1,3 +1,13 @@
# Mistake #73: Not using errgroup
-[Documentation for mistake #73 from 100go.co]
+#### TL;DR
+
+Use `errgroup` to synchronize a group of goroutines and handle errors, as well as shared context cancellation. It simplifies patterns involving multiple concurrent operations that can fail.
+
+The `golang.org/x/sync/errgroup` package provides a convenient way to synchronize a group of goroutines working on subtasks of a common task. Compared to using a plain `sync.WaitGroup`, `errgroup` adds:
+
+* Error propagation — the first non-nil error returned by any goroutine is captured and returned by `Wait()`.
+* Context cancellation — using `errgroup.WithContext`, a shared context is canceled when any goroutine returns an error, allowing other goroutines to stop early.
+* Concurrency limiting — `SetLimit` allows controlling the maximum number of goroutines running simultaneously.
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/73-errgroup/main.go)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-74-copying-a-sync-type.md b/prompts/skills/100-go-mistakes/references/mistake-74-copying-a-sync-type.md
index b92f8f8..6862867 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-74-copying-a-sync-type.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-74-copying-a-sync-type.md
@@ -1,3 +1,15 @@
# Mistake #74: Copying a sync type
-[Documentation for mistake #74 from 100go.co]
+#### TL;DR
+
+Types from the `sync` package should never be copied. This applies to `sync.Mutex`, `sync.WaitGroup`, `sync.Cond`, and the other types. Use pointers to share them.
+
+The `sync` package types (`Mutex`, `RWMutex`, `WaitGroup`, `Cond`, `Map`, `Pool`, `Once`) should never be copied after first use. Copying a mutex, for example, duplicates its internal state, which can lead to deadlocks or data races. This includes:
+
+* Passing a sync type by value to a function
+* Assigning a struct containing a sync type to another variable
+* Returning a struct containing a sync type by value
+
+Use the `go vet` tool to detect accidental copies of sync types. Always pass sync types by pointer when they need to be shared.
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/74-copying-sync/main.go)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-75-providing-a-wrong-time-duration.md b/prompts/skills/100-go-mistakes/references/mistake-75-providing-a-wrong-time-duration.md
index 6446af0..2755efc 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-75-providing-a-wrong-time-duration.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-75-providing-a-wrong-time-duration.md
@@ -1,7 +1,6 @@
# Mistake #75: Providing a wrong time duration
#### TL;DR
-TL;DR
Remain cautious with functions accepting a `time.Duration`. Even though passing an integer is allowed, strive to use the time API to prevent any possible confusion.
@@ -12,7 +11,7 @@ A developer with experience in other languages might assume that the following c
ticker := time.NewTicker(1000)
for {
select {
- case &lt;-ticker.C:
+ case <-ticker.C:
// Do something
}
}
diff --git a/prompts/skills/100-go-mistakes/references/mistake-76-timeafter-and-memory-leaks.md b/prompts/skills/100-go-mistakes/references/mistake-76-timeafter-and-memory-leaks.md
index ec6613e..6a0141f 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-76-timeafter-and-memory-leaks.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-76-timeafter-and-memory-leaks.md
@@ -1,3 +1,23 @@
# Mistake #76: time.After and memory leaks
-[Documentation for mistake #76 from 100go.co]
+#### TL;DR
+
+Avoid using `time.After` in loops or repeated calls; it creates a new channel each time that won't be GC'd until the timer fires. Use `time.NewTimer` instead and call `Stop` when done.
+
+`time.After(d)` is a convenience wrapper that returns a channel that will receive the current time after duration `d`. However, the resources created by `time.After` are not freed until the timer expires. If used inside a loop—for example, in a `select` statement—each iteration creates a new timer that won't be garbage collected until it fires. This can lead to significant memory leaks in long-running applications.
+
+The solution is to use `time.NewTimer` instead, which allows you to stop the timer proactively:
+
+ timer := time.NewTimer(d)
+ defer timer.Stop()
+
+ select {
+ case <-ch:
+ // Handle message
+ if !timer.Stop() {
+ <-timer.C
+ }
+ timer.Reset(d)
+ case <-timer.C:
+ // Handle timeout
+ }
diff --git a/prompts/skills/100-go-mistakes/references/mistake-79-not-closing-transient-resources-http-body-sqlrows-and-osfile.md b/prompts/skills/100-go-mistakes/references/mistake-79-not-closing-transient-resources-http-body-sqlrows-and-osfile.md
index 87208da..8ec7653 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-79-not-closing-transient-resources-http-body-sqlrows-and-osfile.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-79-not-closing-transient-resources-http-body-sqlrows-and-osfile.md
@@ -1,3 +1,21 @@
# Mistake #79: Not closing transient resources (HTTP body, sql.Rows, and os.File)
-[Documentation for mistake #79 from 100go.co]
+#### TL;DR
+
+Always close transient resources like HTTP response bodies, `sql.Rows`, and `os.File` to avoid leaks. Use `defer` after checking for errors.
+
+Transient resources such as HTTP response bodies, `sql.Rows`, and `os.File` must be closed after use. Failing to do so can cause resource leaks—leaked file descriptors, connections held open, or memory not being freed.
+
+* **HTTP body**: The response body must be closed even if you don't read it. Otherwise, the underlying TCP connection cannot be reused. Always defer `resp.Body.Close()` after the error check.
+* **sql.Rows**: `sql.Rows` holds a database connection. If not closed, the connection is not returned to the pool, potentially exhausting available connections.
+* **os.File**: Open file descriptors are a limited resource. Not closing them can lead to "too many open files" errors.
+
+The idiomatic pattern is:
+
+ resp, err := http.Get(url)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/79-closing-resources/)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-80-forgetting-the-return-statement-after-replying-to-an-http-request.md b/prompts/skills/100-go-mistakes/references/mistake-80-forgetting-the-return-statement-after-replying-to-an-http-request.md
index 729b968..30447f9 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-80-forgetting-the-return-statement-after-replying-to-an-http-request.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-80-forgetting-the-return-statement-after-replying-to-an-http-request.md
@@ -1,7 +1,6 @@
# Mistake #80: Forgetting the return statement after replying to an HTTP request
#### TL;DR
-TL;DR
To avoid unexpected behaviors in HTTP handler implementations, make sure you don’t miss the `return` statement if you want a handler to stop after `http.Error`.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-81-using-the-default-http-client-and-server.md b/prompts/skills/100-go-mistakes/references/mistake-81-using-the-default-http-client-and-server.md
index 8560717..b0ec2f7 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-81-using-the-default-http-client-and-server.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-81-using-the-default-http-client-and-server.md
@@ -1,7 +1,6 @@
# Mistake #81: Using the default HTTP client and server
#### TL;DR
-TL;DR
For production-grade applications, don’t use the default HTTP client and server implementations. These implementations are missing timeouts and behaviors that should be mandatory in production.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-82-not-categorizing-tests-build-tags-environment-variables-and-short-mode.md b/prompts/skills/100-go-mistakes/references/mistake-82-not-categorizing-tests-build-tags-environment-variables-and-short-mode.md
index de30dca..3ca678f 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-82-not-categorizing-tests-build-tags-environment-variables-and-short-mode.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-82-not-categorizing-tests-build-tags-environment-variables-and-short-mode.md
@@ -1,7 +1,6 @@
# Mistake #82: Not categorizing tests (build tags, environment variables, and short mode)
#### TL;DR
-TL;DR
Categorizing tests using build flags, environment variables, or short mode makes the testing process more efficient. You can create test categories using build flags or environment variables (for example, unit versus integration tests) and differentiate short from long-running tests to decide which kinds of tests to execute.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-83-not-enabling-the-race-flag.md b/prompts/skills/100-go-mistakes/references/mistake-83-not-enabling-the-race-flag.md
index 0c636ce..d3aa113 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-83-not-enabling-the-race-flag.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-83-not-enabling-the-race-flag.md
@@ -1,7 +1,6 @@
# Mistake #83: Not enabling the race flag
#### TL;DR
-TL;DR
Enabling the `-race` flag is highly recommended when writing concurrent applications. Doing so allows you to catch potential data races that can lead to software bugs.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-84-not-using-test-execution-modes-parallel-and-shuffle.md b/prompts/skills/100-go-mistakes/references/mistake-84-not-using-test-execution-modes-parallel-and-shuffle.md
index 9c7f9ed..31c968a 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-84-not-using-test-execution-modes-parallel-and-shuffle.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-84-not-using-test-execution-modes-parallel-and-shuffle.md
@@ -1,6 +1,5 @@
# Mistake #84: Not using test execution modes (parallel and shuffle)
#### TL;DR
-TL;DR
Using the `-parallel` flag is an efficient way to speed up tests, especially long-running ones. Use the `-shuffle` flag to help ensure that a test suite doesn’t rely on wrong assumptions that could hide bugs.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-85-not-using-table-driven-tests.md b/prompts/skills/100-go-mistakes/references/mistake-85-not-using-table-driven-tests.md
index 9624b8c..f2fdfd2 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-85-not-using-table-driven-tests.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-85-not-using-table-driven-tests.md
@@ -1,7 +1,6 @@
# Mistake #85: Not using table-driven tests
#### TL;DR
-TL;DR
Table-driven tests are an efficient way to group a set of similar tests to prevent code duplication and make future updates easier to handle.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-86-sleeping-in-unit-tests.md b/prompts/skills/100-go-mistakes/references/mistake-86-sleeping-in-unit-tests.md
index 3827501..879f7c3 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-86-sleeping-in-unit-tests.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-86-sleeping-in-unit-tests.md
@@ -1,7 +1,6 @@
# Mistake #86: Sleeping in unit tests
#### TL;DR
-TL;DR
Avoid sleeps using synchronization to make a test less flaky and more robust. If synchronization isn’t possible, consider a retry approach.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-87-not-dealing-with-the-time-api-efficiently.md b/prompts/skills/100-go-mistakes/references/mistake-87-not-dealing-with-the-time-api-efficiently.md
index c41d2b2..738e54e 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-87-not-dealing-with-the-time-api-efficiently.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-87-not-dealing-with-the-time-api-efficiently.md
@@ -1,7 +1,6 @@
# Mistake #87: Not dealing with the time API efficiently
#### TL;DR
-TL;DR
Understanding how to deal with functions using the time API is another way to make a test less flaky. You can use standard techniques such as handling the time as part of a hidden dependency or asking clients to provide it.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-88-not-using-testing-utility-packages-httptest-and-iotest.md b/prompts/skills/100-go-mistakes/references/mistake-88-not-using-testing-utility-packages-httptest-and-iotest.md
index 583646e..5c237b7 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-88-not-using-testing-utility-packages-httptest-and-iotest.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-88-not-using-testing-utility-packages-httptest-and-iotest.md
@@ -1,3 +1,21 @@
# Mistake #88: Not using testing utility packages (httptest and iotest)
-[Documentation for mistake #88 from 100go.co]
+#### TL;DR
+
+Use the `httptest` package for testing HTTP clients and servers, and the `iotest` package for testing `io.Reader` implementations and error tolerance.
+
+The `httptest` package provides utilities to test HTTP applications without starting a real server:
+
+* `httptest.NewServer` creates a local HTTP server for integration testing.
+* `httptest.NewRecorder` creates a `ResponseRecorder` to inspect HTTP responses in handler tests.
+
+The `iotest` package helps write `io.Reader` implementations and test that an application is tolerant to errors:
+
+* `iotest.ErrReader` returns a reader that always returns an error.
+* `iotest.HalfReader` returns a reader that reads half the requested bytes.
+* `iotest.OneByteReader` returns a reader that reads one byte at a time.
+* `iotest.TestReader` tests an `io.Reader` implementation for correctness.
+
+[Source code (httptest)](https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/88-utility-package/httptest/main_test.go)
+
+[Source code (iotest)](https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/88-utility-package/iotest/main_test.go)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-89-writing-inaccurate-benchmarks.md b/prompts/skills/100-go-mistakes/references/mistake-89-writing-inaccurate-benchmarks.md
index 5b79fc6..d711c92 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-89-writing-inaccurate-benchmarks.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-89-writing-inaccurate-benchmarks.md
@@ -1,7 +1,6 @@
# Mistake #89: Writing inaccurate benchmarks
#### TL;DR
-TL;DR
Regarding benchmarks:
diff --git a/prompts/skills/100-go-mistakes/references/mistake-92-writing-concurrent-code-that-leads-to-false-sharing.md b/prompts/skills/100-go-mistakes/references/mistake-92-writing-concurrent-code-that-leads-to-false-sharing.md
index 54e8816..38c1c89 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-92-writing-concurrent-code-that-leads-to-false-sharing.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-92-writing-concurrent-code-that-leads-to-false-sharing.md
@@ -1,7 +1,6 @@
# Mistake #92: Writing concurrent code that leads to false sharing
#### TL;DR
-TL;DR
Knowing that lower levels of CPU caches aren’t shared across all the cores helps avoid performance-degrading patterns such as false sharing while writing concurrency code. Sharing memory is an illusion.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-93-not-taking-into-account-instruction-level-parallelism.md b/prompts/skills/100-go-mistakes/references/mistake-93-not-taking-into-account-instruction-level-parallelism.md
index 13d2f50..ce4cafc 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-93-not-taking-into-account-instruction-level-parallelism.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-93-not-taking-into-account-instruction-level-parallelism.md
@@ -1,7 +1,6 @@
# Mistake #93: Not taking into account instruction-level parallelism
#### TL;DR
-TL;DR
Use ILP to optimize specific parts of your code to allow a CPU to execute as many parallel instructions as possible. Identifying data hazards is one of the main steps.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-94-not-being-aware-of-data-alignment.md b/prompts/skills/100-go-mistakes/references/mistake-94-not-being-aware-of-data-alignment.md
index 69f19eb..f2ff22c 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-94-not-being-aware-of-data-alignment.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-94-not-being-aware-of-data-alignment.md
@@ -1,7 +1,6 @@
# Mistake #94: Not being aware of data alignment
#### TL;DR
-TL;DR
You can avoid common mistakes by remembering that in Go, basic types are aligned with their own size. For example, keep in mind that reorganizing the fields of a struct by size in descending order can lead to more compact structs (less memory allocation and potentially a better spatial locality).
diff --git a/prompts/skills/100-go-mistakes/references/mistake-95-not-understanding-stack-vs-heap.md b/prompts/skills/100-go-mistakes/references/mistake-95-not-understanding-stack-vs-heap.md
index 69ed7ce..ad2d02d 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-95-not-understanding-stack-vs-heap.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-95-not-understanding-stack-vs-heap.md
@@ -1,7 +1,6 @@
# Mistake #95: Not understanding stack vs. heap
#### TL;DR
-TL;DR
Understanding the fundamental differences between heap and stack should also be part of your core knowledge when optimizing a Go application. Stack allocations are almost free, whereas heap allocations are slower and rely on the GC to clean the memory.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-96-not-knowing-how-to-reduce-allocations.md b/prompts/skills/100-go-mistakes/references/mistake-96-not-knowing-how-to-reduce-allocations.md
index 8872340..10a478e 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-96-not-knowing-how-to-reduce-allocations.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-96-not-knowing-how-to-reduce-allocations.md
@@ -1,3 +1,23 @@
# Mistake #96: Not knowing how to reduce allocations
-[Documentation for mistake #96 from 100go.co]
+#### TL;DR
+
+Reducing allocations improves performance by decreasing GC pressure. Techniques include API changes to accept pre-allocated buffers, leveraging compiler optimizations, and using `sync.Pool` for reusable objects.
+
+Reducing the number of heap allocations is one of the most effective ways to improve Go application performance. Each allocation adds pressure on the garbage collector.
+
+Key techniques:
+* **API changes**: Design functions to accept pre-allocated slices or buffers rather than always creating new ones. For example, `io.Reader.Read(p []byte)` lets the caller control the allocation.
+* **Compiler optimizations**: Be aware that the compiler can sometimes optimize away allocations (e.g., inlining small functions). Use `go build -gcflags="-m"` to see escape analysis decisions.
+* **sync.Pool**: Use `sync.Pool` for frequently allocated and deallocated objects. The pool maintains a set of temporary objects that can be reused, reducing allocation overhead. Note that pooled objects can be reclaimed by the GC at any time.
+
+ var pool = sync.Pool{
+ New: func() any {
+ return make([]byte, 1024)
+ },
+ }
+
+ buf := pool.Get().([]byte)
+ defer pool.Put(buf)
+
+[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/12-optimizations/96-reduce-allocations/)
diff --git a/prompts/skills/100-go-mistakes/references/mistake-97-not-relying-on-inlining.md b/prompts/skills/100-go-mistakes/references/mistake-97-not-relying-on-inlining.md
index 6825c82..fefcb97 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-97-not-relying-on-inlining.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-97-not-relying-on-inlining.md
@@ -1,6 +1,5 @@
# Mistake #97: Not relying on inlining
#### TL;DR
-TL;DR
Use the fast-path inlining technique to efficiently reduce the amortized time to call a function.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-98-not-using-go-diagnostics-tooling.md b/prompts/skills/100-go-mistakes/references/mistake-98-not-using-go-diagnostics-tooling.md
index 2a07e97..4002313 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-98-not-using-go-diagnostics-tooling.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-98-not-using-go-diagnostics-tooling.md
@@ -1,7 +1,6 @@
# Mistake #98: Not using Go diagnostics tooling
#### TL;DR
-TL;DR
Rely on profiling and the execution tracer to understand how an application performs and the parts to optimize.
diff --git a/prompts/skills/100-go-mistakes/references/mistake-99-not-understanding-how-the-gc-works.md b/prompts/skills/100-go-mistakes/references/mistake-99-not-understanding-how-the-gc-works.md
index fc6d7ba..af64289 100644
--- a/prompts/skills/100-go-mistakes/references/mistake-99-not-understanding-how-the-gc-works.md
+++ b/prompts/skills/100-go-mistakes/references/mistake-99-not-understanding-how-the-gc-works.md
@@ -1,3 +1,21 @@
# Mistake #99: Not understanding how the GC works
-[Documentation for mistake #99 from 100go.co]
+#### TL;DR
+
+Understanding the Go garbage collector helps write more efficient applications. The GC uses a concurrent, tri-color mark-and-sweep algorithm. Reducing heap allocations and understanding the `GOGC` tuning parameter are key.
+
+Go uses a concurrent garbage collector based on the tri-color mark-and-sweep algorithm. Understanding how it works helps write performance-sensitive applications:
+
+* **Mark phase**: The GC traverses the object graph starting from roots (stacks, globals) and marks all reachable objects.
+* **Sweep phase**: Unreachable objects are freed.
+* The GC runs concurrently with the application, minimizing stop-the-world pauses.
+
+Key tuning parameters:
+* `GOGC` (default 100): Controls the GC target percentage. A value of 100 means the GC triggers when heap size doubles since the last collection. Lower values trigger more frequent GC (less memory, more CPU); higher values trigger less frequent GC (more memory, less CPU).
+* `GOMEMLIMIT` (Go 1.19+): Sets a soft memory limit for the Go runtime, helping prevent OOM situations.
+
+To optimize GC performance:
+* Reduce heap allocations (see mistake #96).
+* Use value types instead of pointer types where possible.
+* Pre-allocate slices and maps when the size is known.
+* Consider `sync.Pool` for frequently allocated objects.