The Applied Go Weekly Newsletter logo

The Applied Go Weekly Newsletter

Subscribe
Archives
May 12, 2024

This Go code is bad • The Applied Go Weekly Newsletter 2024-05-12

AppliedGoNewsletterHeader640.png

Your weekly source of Go news, tips, and projects

This week, let's start with two actionable articles. Write a Web app with JetBrains and explore a coding problem that has no optimal solution (but at least, it has one).

Also worth noting: Encore goes open source! In the recent months, we have seen the opposite happening. First, Hashicorp changed the licenses for Terraform and other tools from FOSS to BSL (a mere "source code availabe" license) , then, Redis followed. It is relieving to see that there are companies that see the power of free and open source and build their business model around freedom instead of building moats.

Whatever you're hacking on this week, happy coding!

Web App with Go and React - Part 1 - JetBrains Guide

In this four-part tutorial, you'll learn to write a chat app using Go, SQLite, Gin, and React.

Web App with Go and React - Part 1 - JetBrains Guide

Constraining Go type parameter pointers | Mero's Blog

In which Axel "The Merovious" Wagner explains an unfortunate conflict between a type parameter and a method with a pointer receiver, describes a pattern that works, and then recommends to avoid that pattern by all means.

Spoiler: The article ends with a nice and readable solution, and this solution contains no type parameters.

Constraining Go type parameter pointers | Mero's Blog

Encore is now fully Open Source — Launch Week Day 2 – Encore Blog

Encore, the development platform for Go and TS, is approaching the masses! They open-sourced their core tools, making it easy for everyone to self-host their deployments. Even if you are a happy user of Encore's services, knowing that you have a fallback in case their business grinds to a halt (which hopefully never happens, fingers crossed) can give you some peace of mind. Moreover, Encore offers a new Pro plan that is much cheaper than the preceding Teams plan.

Encore is now fully Open Source — Launch Week Day 2 – Encore Blog

[security] Go 1.22.3 and Go 1.21.10 are released

New security patches for Go 1.22 and Go 1.21 have been released. The patches fix an issue where a Go module containing CGO can trigger arbitrary code execution at build time when using the Apple version of ld. Also, an issue is fixed in the net package where malformed DNS message in response to a query can cause the Lookup functions to get stuck in an infinite loop.

[security] Go 1.22.3 and Go 1.21.10 are released

Podcast corner

Cup o' Go

Jamie Tanna is the guest of this week's episode, and Jonathan, Shay, and Jamie talk about OpenAPI (NOT OpenAI) and Go, specifically about deepmap/oapi-codegen.

Cup o' Go | A quick tour of some proposals, and a long chat about OpenAPI with Jamie Tanna

Go Time

Tuesday, a few years from now. The unthinkable has happened: Google has laid off the entire Go team! Is this an earthshaking catastrophe, or would everybody just shrugh their shoulders and move on? Kris, Ian, and Johnny discuss an imaginative future of Go without Google.

What if Google lays off the Go team? (Go Time #315)

go podcast()

Should you choose Go for your startup? If looking at the langauge only: yes, absolutely. But there is more to picking a programming language than the language itself.

037: Is Go a good choice for your Startup?

Go tip of the week: 3 Go anti-patterns

One of the Go proberbs says:

Clear is better than clever.

Trying to write clever code always backfires when others have to maintain your code (where "others" include your future self four weeks from now). Yet, I continue to see "clever" coding being suggested as cool trick or advanced programming. Here are three "clever Go tricks" that are, in fact, anti-patterns.

Anti-pattern: Dot imports

How dot imports work

Dot imports let you import a package and use its exported identifiers without prefixing them with the package name.

So if you import fmt as dot import, you can call Println() and friends without the fmt. prefix.

import . "fmt" 

func main() {
    Println("Look ma! no prefix")
}

Why this is an anti-pattern

The identifiers exported from this package appear as if they are defined in the current package. This is bad in two ways:

  1. Readers get confused while searching through source files looking for a definition of the identifier in the current package.
  2. Some packages have drop-in replacements that export the same identifiers. If those drop-in packages are imported through a dot import, readers may, after falling victim to problem #1, start thinking that the identifiers belong to the original package where in fact they belong to the drop-in package.

So if you get asked in your next job interview about the advantages of dot imports, tell them there are none.

Anti-pattern: Chaining

How chaining works

If a method updates its receiver, and nothing can go wrong with this update, the method does not need to return anything. Multiple such methods are called one after the other:

type num int

func (n *num) Add(delta num) {
    *n = delta
}

func (n *num) Mult(m num) {
    *n *= m
}

func main() {
    var n num = 6
    n.Add(4)
    n.Mult(3)
    //...
}

Too boring for cl3vr c0drs! Let's chain the methods together! We only need to have each method return its receiver. Then we can dot-call a second method on the result of the first method:

type num int

func (n *num) Add(delta num) *num {
    *n = delta
    return n
}

func (n *num) Mult(m num) *num {
    *n *= m
    return n
}

func main() {
    var n num = 6
    n.Add(4).Mult(3)
    fmt.Println(n)
}

Whoa, we've saved a line!

Why this is an anti-pattern

Three reasons:

  1. We have not gained anything. Really, chaining does not give us anything we need and don't have already.
  2. Chained methods cannot return errors. So if you have errors, you need to fall back to the normal pattern. Now you have two different styles in your code: chaining and normal.
  3. Go code prefers to keep the reading focus to the left edge of the code. This means short lines, and few nesting levels (ideally only one). Method call chains can easiy travel across the whole screen and even cause a line break that looks ugly and makes the code even harder to read.

Method chaining is unidiomatic Go and should be avoided.

Anti-pattern: Defer as initialization

Pop quiz: What does the following code print?

func mysteriousDefer() func() {
    fmt.Println("f runs")
    return func() {
        fmt.Println("func returned by f runs")
    }
}

func main() {
    defer mysteriousDefer()()
    fmt.Println("main runs")
}

main calls mysteriousDefer() as a deferred function, so everything that mysteriousDefer() prints should be printed after main has done its prints.

However, if you run this code, you'll get the following output:

f runs
main runs
func returned by f runs

So one part of the deferred function runs before main!

Why this is an anti-pattern

This "clever trick" allows things like putting initialization and cleanup into one function.

Did you notice the double parentheses in the defer call?

    defer mysteriousDefer()()

You typically would call a deferred function like so:

    defer mysteriousDefer()

The second pair of parentheses calls mysteriousDefer() before it is evaluated by the defer directive. Then mysteriousDefer() prints its message and returns another function, which is the actual function to be deferred.

This convoluted mess of immediate function calling, function returning and deferring a function is hard to grok, and the double pair of parentheses is really easy to miss when glancing over the code.

What's wrong with writing out an initialization function and a cleanup function?

Conclusion

If you learn a new language, it is just too natural (and completely fine!) to be curious and explore every feature of the language, to see how it works. It is also natural to carry over the patterns that you learned in your previous language. But every language has its specific rules and idioms, for a reason. Patterns taken over from other languages may not work well in Go and only lead to convoluted code that is hard to understand and harder to maintain.

Remember the Go proverb cited above, and strive to deliver clear code. All the readers of your code, including your future self, will thank you.

Overheard on Reddit

Some praise for Go:

Go is an excellent choice if you've never worked with a compiled, statically typed language or pointers. The pointers are safe and as simple as they get. And the typing is excellent, very flexible.

– /u/PseudoCalamari

More articles, videos, talks

Golang Programming by Packt (pay what you want and help charity)

Packt offers a Humble Bundle of Go books. The complete bundle of 17 books costs $16,80 USD, with the option to pay more, and some of the revenue goes to the charity "Save the Children." (Expand the Adjust your Donation box on the bundle page for details.) The offer is valid until May 27th (if my "remaining days" calculation is correct).

notebox

The creator of notebox.cloud open-sources their works, parts of which are implemented in Go.

Creating a more sustainable model for oapi-codegen in the future · Jamie Tanna | Software Engineer

The oapi-codegen project shall receive one full day of dedicated work per week and is looking for sponsors.

using golang's crypto/aes and crypto/cipher packages · Aran Wilkinson

"Don't roll your own crypto" is a piece of cryptographer wisdom. Luckily, the standard library comes with pre-packaged cryptography. Here is an introduction to AES encryption and decryption.

Domenico Luciani - Create a DNS Resolver with Golang

Domenico Luciani implemented one of John Crickett's coding challenges with Go and test-driven development.

GitHub - ManitVig/GoTHAM-stack: A tech stack for creating modern web applications in the simplest way possible.

Remember the GoTH stack (Go, Templ, HTMX)? Here is the GoTHAM stack (Go, Tailwind, HTMX, AlpineJS and MySQL/MariaDB/MongoDB).

Devlog I: Foundations

Willem Schots builds a reference Web app. This blog post is an overview of the app's parts.

Projects

Libraries

GitHub - aminedakhlii/topGgraph: A Go-based graph management library for efficient handling and persistent storage of graph data using BadgerDB. Ideal for applications requiring complex data relationships and graph traversal operations.

In short: "create, persist, manage, search a graph in Go."

GitHub - anuragkumar19/binding: Go request binding for std lib

Echo's binding feature, extracted and made available for stdlib net/http and Chi.

GitHub - WangYihang/gojob: Go(od) Job is a simple job scheduler that supports task retries, logging, and task sharding.

A task scheduler with an intentionally simple UX: "All you need to do is just implement the Task interface, only one func Do() error function is enough, the gojob scheduler will do the rest tedious work (retry on failure, logging results, etc.) for you."

GitHub - pijng/moonject: Wrapper for simple golang preprocessors

moonject lets you do nastyinteresting things with your code at compile time, such as adding a Println() call to the beginning of each function, or implementing #ifdef-like macros.

Tools and applications

GitHub - unklnik/bitty_knight: Source code for the first game I made with Go on Steam

Bitty Knight is a fast, 2D, top-view, retro-style game. The author shares the source code upon request in an /r/golang thread.

GitHub - jankammerath/servertag: Proof-of-concept server-side JavaScript webserver supporting the -tag

If you ever wanted to add JavaScript to your HTML pages that gets executed at the server, this is your chance. (PoC)

GitHub - dkorunic/pktstat-bpf: TC and XDP eBPF based simple Ethernet interface traffic monitor and reporting tool

This tool was written as an eBPF-based alternative to the ncurses/libpcap-based https://github.com/dleonard0/pktstat, aiming for smooth operation even under high traffic.

GitHub - sdrshnv/tjern: A happy little journaling app

Quickly save your thoughts with this TUI app built with Bubbletea and utilizing a Turso database (basically a hosted version of libsqlite, a fork of SQLite)

GitHub - sgatu/chezz-back: Golang chess engine with api - used together with chezz-front

An API-based chess sever. The corresponding frontend is here.

GitHub - sharpvik/snapsound: Play sound from PNG images

"Everything is just bytes under the hood!" The author took this bit of wisdom by its word and wrote an app that interprets an image file as music. But it's just a trick: The PNG file to be played must be a repackaged MP3 file. Still, the claim holds: It's just bytes after all.

Ryan Wiley / texty: A demo for user authentication using wish and bubbletea · GitLab

The author felt that the Bubbletea/Wish combo lacks a good example of the Wish server sharing an ssh key with a Bubbletea client app, so he wrote one.

GitHub - nobotro/Go_emu: Go lang risc-v 5 stage pipeline emulator

What was your first Go project? I can definitely say that mine was not as RISC-V stage pipeline emulator.

GitHub - worlpaker/gitty: Download GitHub File & Directory

Do you frequently need to download a small subtree from a large GitHub repository? gitty is your new friend.

GitHub - f01c33/noter: notifies you after some time about what you want to remember when you want to remember

Forgetful? Noter will remind you of your errands.

GitHub - dunkbing/kana: Terminal app to practice typing Kana (Japanese characters) in Romaji

Romaji is a system for writing Japanese using roman characters.

GitHub - Sieep-Coding/todo-htmx-alpine-go: Todo app in HTMX, Alpine.js, Air, and Go

A super-simple Todo app, ideal for exploring how writing Web apps with HTMX works.

GitHub - distantmagic/structured: [WIP] structured data extractor with llama.cpp

(1) Describe the desired data structure as JSON. (2) Let lama.cpp extract relevant data from unstructured input, such as English sentences.

GitHub - oq-x/qusic: Free music app written in Go

With the only non-Go dependency being MPV, an open-source media player.

Completely unrelated to Go

Building a social network from scratch on a whiteboard

Why do even seemingly simple Web services evolve into an unmaintainable mess of microservices, proxies, databases, and storage layers? In this article, Xe Iaso dissects the process that leads from a simple idea to mind-boggling server bloat.

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.

Check it out.


Christoph Berger IT Products and Services
Dachauer Straße 29
Bergkirchen
Germany

Don't miss what's next. Subscribe to The Applied Go Weekly Newsletter:
LinkedIn
This email brought to you by Buttondown, the easiest way to start and grow your newsletter.