Bisecting FTW • The Applied Go Weekly Newsletetter 2024-07-21
Your weekly source of Go news, tips, and projects
Slowly, the newsletter gets out of summer break mode. The most surprising article of the week (for me) is Russ Cox's article about the new bisect
tool, right below in the Featured Articles section. And the most eye-opening article of the week (again, for me) is the very last one, in the Unrelated to Go section, which removes a blind spot about the reasons for decreasing work throughput.
When I look at my "work map", a directed graph of tasks that should lead to results and that I created back in May, I feel like I already crossed the border to High Work In Progress spectacularly:
Are you in High WIP mode right now?
Featured Articles
Hash-Based Bisect Debugging in Compilers and Runtimes
Git has a bisect
command to find which commit in a project history introduced a bug. But what if you find that commit but still cannot find the bug? Russ Cox simply continues the bisecting strategy on the code itself. And because this is tedious to do manually, the Go team created a bisect
tool that runs specifically prepared target commands with various changes individually enabled or disabled, until it finds a minimal number of changes triggers the bug.
Go 1.23: Interactive release notes
Try before you buy! Anton Zhiyanov built interactive release notes for the upcoming Go 1.23 release.
Go range iterators demystified
Go 1.23 offers a new way of creating range loops, by constructing custom iterator functions. The DoltHub team explains all three types of iterator functions, along with examples.
Go book, manga style.
"Don’t say you know Go if you haven’t read the manga"
Podcast corner
Cup o' Go: 🇰🇪 yield(RC2, 1st GopherCon in Africa, LLMs, Dreams of code, and more)
Jonathan Hall and Shay Nehmad about the upcoming Go 1.23 release, Copilot's effect on Go, the range-over-func feature, a more
/less
replacement, and more.
Go Time: Aha moments reading Go's source: Part 1
So you've finished reading all the books on your coffee table? Time to turn to some extra-deep literature: The Go Source Files.
Go tip of the week: Three flavors of synchronization
Synchronizing concurrent threads of execution is a difficult art. Here are three options for synchronizing the flow of code or data in a Go app.
An unbuffered channel
- How it works: A channel with no capacity cannot hold any elements. The sending goroutine must therefore wait until a receiving goroutine reads from the channel.
- Use cases:
- A goroutine started another goroutine and, after doing some work, has to wait for the (single) result from the other goroutine.
- A goroutine must ensure that antoher goroutine has received a value before continuing.
A mutex
- How it works: A mutex is a guard that allows a single goroutine to enter a code block. Goroutines that request to enter the code block after a goroutine already acquired the mutex have to wait until the first goroutine exits the code block and releases the mutex.
- Use cases: Mutexes are typically used to guard access to shared data. While in contradiction to the Go proverb that says, "Don't communicate by sharing memory, share memory by communicating", mutexes can help modeling certain data access patterns (but first try to use channels, which are easier to reason about, and proceed with care if deciding for mutexes. They are handy for simple cases but can become unwieldy if the synchronization scenario becomes complex.)
A WaitGroup
- How it works: A wait group is a construct where goroutines can "register" themselves (through an
Add()
call) and send aDone()
message when they are finished. The wait group'sWait()
method blocks until all registered goroutines have send theirDone()
message. - Use case: Use a wait group if the originating goroutine (most often, this is the main goroutine) spawns a number of goroutines simultaneously and has to wait for all of them to finish. A typical scenario: The elements of a (large) slice can be calculated independently of each other, and spawning multiple goroutines allows filling multiple sections of the slice concurrently.
What about buffered channels?
Buffered channels are not about synchronization. If a channel can hold one or more elements, it effectively decouples the sending goroutine from the receiving goroutine. Both can progress at their pace, until the buffer is either full (then the sender has to wait) or empty (then the receiver has to wait), but if the send and receive speeds are roughly balanced, both goroutines can move ahead quite undisturbed by the other goroutine's progress.
With a buffered channel, the sender can, for example, send a thousand elements at once and move on while the receiver can read these elements one by one. Or it can be the other way round. Or any other scenario where unpredictable progress velocity of one goroutine shall not block another goroutine.
Computer science came up with even more possible synchronization techniques, such as semaphores, monitors, condition variables, barriers, or spinlocks. However, unbuffered channels, mutexes, and wait groups are sufficient for covering a wide range of synchronization needs. Better have a few tools and know how to use them well than having a king-size toolbox where you know each tool only superficially.
Quote of the week: Clean, simple, and fun
I cannot stress enough how much I prefer working with Go compared to Java. It's clean, simple, and, it's fun! No more factory design pattern, no more hundred lines of getters and setters, and no more shitty annotations. It all just makes sense.
More articles, videos, talks
Mastering SOLID Principles with Go Examples | by Alex Pliutau | Jul, 2024 | Stackademic
Can you name each of the SOLID principles by hart? This article is a good refresher while also showcasing the implementation of each SOLID principle in Go.
Profiling in Go: A Practical Guide | nyadgar.com
Performance bottlenecks can be nasty to track down, especially in concurrent applications. Go helps address this challenge with the pprof
tool, but you need to know how to use it.
Introducing Quartz: A Deterministic Time Testing Library for Go - Coder
How do you test code that depends on times and timings? Coder.com decided to build their own time mocking library.
The value of API-First design on side-projects
API-first design with Open API in a nutshell, with server code in Go and client code in TypeScript.
Terminating Elegantly: A Guide to Graceful Shutdowns | by Alex Pliutau | Jul, 2024 | ITNEXT
A rolling update in Kubernetes (or in any other system, for that matter) can cause data loss if the services don't know how to shut down gracefully. Alex Pilutau wants you to run an experiment: See a service break during a rolling k8s update, then add code to handle a SIGTERM signal and finish all pending requests before exiting.
Better Go Playground—looking for beta testers
goplay.tools
, the alternative Go playground UI, moves towards a v2 release. The author asks for beta testers.
Safeguarding changes using the plan-execute pattern
If you make a change to an infrastructure description in Terraform, you can ask Terraform to show you its plan for applying the changes to the current system status. Tom Nick expands this "plan-execute" pattern to database updates.
First impressions of Go 1.23's range-over-func feature
Jonathan Hall now ranges over functions, thanks to Zach Musgrave's blog post (see Featured Articles)
Here-doc headache
Beware of setting an environment variable in a here-doc that's to be interpreted by a shell.
Are Pointers in Go Faster Than Values?
Think twice before reaching out for pointers to speed up parameter passing. Most of the time, pointers are not faster, and the main purpose of pointer is to share access to a value, says Lane Wagner.
Projects
GitHub - hoophq/hoop: The only access gateway with data masking
A gateway that manipulates the data that flows through it? The creators list some valid applications, " like data access policies (DLP), review of critical operations before they run (Change Management), automate repeat operations (Runbooks) and more."
GitHub - sonalys/gotestfast: A Golang test execution tool for prioritizing failing tests
Do you frequently re-run your CI pipeline to check a failing test? This tool prioritizes tests that previously failed, saving you precious time.
GitHub - alira008/SequelGo
A REPL that interprets Microsoft's T-SQL dialect and produces an AST. WIP.
GitHub - manosriram/lark: functional toy interpreter
The author of this project builds a functional interpreter (progress board here and asks for suggestions.
GitHub - felangga/chiko: The ultimate beauty gRPC Client on your Terminal!
Test gRPC services interactively in your terminal.
GitHub - Kapps/funcie: Funcie makes local development of serverless applications easier by transitioning between local and cloud execution seamlessly.
Funcie redirects calls to FaaS functions (currently AWS Lambda functions) to a local copy, allowing cloud function tests without the cloud.
GitHub - yeo/ec2.shop: fastest way to check and compare ec2 and other aws service pricing
Check up-to-date Amazon AWS pricings with this web service (it's actually up and running on ec2.shop.
GitHub - kurtosis-tech/kardinal: Kardinal is the lightest-weight way to spin up dev and test environments in Kubernetes. Deploy the absolute minimum resources necessary and implement dev, test, and QA all in one cluster.
Kubernetes clusters can become large and expensive. This tool helps you save costs by sharing one cluster between dev, test, and prod.
Completely unrelated to Go
Here-doc headache
Beware of setting an environment variable in a here-doc that's to be interpreted by a shell.
Your Company's Problem is Hiding in Plain Sight - High Work-In-Progress (WIP)
When a process randomly accesses more virtual memory pages than fit into physical memory, the system starts frantically swapping pages to and from the swap file (known as "thrashing"). As a result, the process radically slows down.
A similar problem occurs if humans are overloaded with tasks. But this problem is difficult to see, unless you know the signs.
Happy coding! ʕ◔ϖ◔ʔ
Questions or feedback? Drop me a line. I'd love to hear from you.
Best from Munich, Christoph
Not a subscriber yet?
If you read this newsletter issue online, or if someone forwarded the newsletter to you, subscribe for regular updates to get every new issue earlier than the online version, and more reliable than an occasional forwarding.
Find the subscription form at the end of this page.
How I can help
If you're looking for more useful content around Go, here are some ways I can help you become a better Gopher (or a Gopher at all):
On AppliedGo.net, I blog about Go projects, algorithms and data structures in Go, and other fun stuff.
Or visit the AppliedGo.com blog and learn about language specifics, Go updates, and programming-related stuff.
My AppliedGo YouTube channel hosts quick tip and crash course videos that help you get more productive and creative with Go.
Enroll in my Go course for developers that stands out for its intense use of animated graphics for explaining abstract concepts in an intuitive way. Numerous short and concise lectures allow you to schedule your learning flow as you like.
Christoph Berger IT Products and Services
Dachauer Straße 29
Bergkirchen
Germany