mfbmina.dev

by Matheus Mina

Breaking down Go's sync package

In my opinion, Go provides excellent support for concurrent work, not only due to goroutines but also because of the language’s ecosystem. A great example of this is the sync package, which helps synchronize concurrent routines. In this post, we’ll dive into everything this package has to offer.

Waitgroups

Waitgroups are used to coordinate the execution of multiple routines. They make it easy to create and ensure that all sub-routines will finish before the main routine ends. In the post about waitgroups I explain better how they work and what changed with Go version 1.25.

Waitgroups: what they are, how to use them and what changed with Go 1.25

Imagine the following problem: you need to process hundreds of records and generate a single output. One way to solve this is to process each record sequentially and unify the output only at the end. However, this can be extremely slow, depending on the time spent processing each record. Another way is to process them concurrently, speeding up the overall time. In my post about introduction to concurrency, I talked a bit about goroutines and channels. Now, I’ve decided to talk about waitgroups, a way to simplify the management of multiple goroutines.

testcontainers: improving E2E tests

In a previous post I showed some ways to improve tests by creating API mocks that we call. However, that’s not always enough, and we might need E2E tests (or acceptance tests), for example, to test integrations with databases, messaging services, or anything else. For these cases, I’m here to introduce the Testcontainers tool.

The Testcontainers library is an open-source tool that lets you create containers during test execution. The idea is for your application’s test dependencies to be part of the code, avoiding the need for mocks and even local dependency installation. Another big advantage is that it makes it easier to achieve test isolation and replicability among developers. The tool supports various programming languages like Go, Ruby, Elixir, Java, etc.

Eliminating dead code in Go projects

As the software we work on grows, the code tends to undergo various changes and refactorings. During this process, we might simply forget pieces of code that were once used but no longer make sense in the project, the infamous dead code. A very common example is when an API is deactivated, and only the handler is removed, but all the business logic remains, unused.

What is deadcode?

Dead code can be defined as a function that exists within your codebase, is syntactically valid, but is not used by any other part of your code. In other words, it’s an unreachable function. Dead code brings indirect problems to a project, such as outdated libraries, legacy code, code bloat, security vulnerabilities, and so on. If it’s still not clear what dead code is, see the example below:

Exploring the Rate package and the Token Bucket algorithm

At my Circuit Breaker post, I mentioned that nowadays it is common that the application has to communicate with other ones, and with that, traffic control strategies become essential. Recently I’ve discovered the Token Bucket, a strategy based on tokens used to control the traffic.

Imagine that you have 5 tickets to a ride, and every new hour you get a new ticket, but you can never exceed the limit of 5. Every time you ride, a ticket is used. So, if you use all your tickets, you can’t ride anymore until you get a new one. It is a very interesting algorithm, used by the PIX (a Brazilian instant payment method), for not allowing an attacker to scrape all users’ data.