u/sigmoia

▲ 48 r/golang

pkg & internal directories are way overused

TLDR; Opting for a flatter structure typically guides you organically away from pkg and overly nested internal.

pkg is now used considerably less than it used to be. But it's still fairly common. Mostly because lots of folks coming to Go encounter the standard package layout repo and copy the structure.

pkg is an old vestige from the GOPATH era. Then other large projects like k8s went w/ the structure & never changed it because of the size of the projects and their backward compat promises.

But that doesn't mean we should copy that w/o asking why. The extra layer of nesting makes imports ugly and code discovery harder. pkg pretty much has no place in today's greenfield projects. But I also don't go around rooting it out of existing projects.

Another common one is abusing the /internal directory in svcs. I review a ton of candidate assignment submissions at work, and it's pretty common to see the entire app code shoved into the internal directory. The common rationale is abstraction.

But if it's application code, then no one is importing it. So shoving everything into the internal package is lazy design instead of properly structuring the core subpackages.

In libraries, internal makes sense to keep implementation details away from users of the API. Even there, creating three layers of nesting is a code smell.

Code organization is subjective & contexual. Giving general advice is extremely hard. But one thing I have found teachable is this:

  • Go already doesn't allow import cycles
  • On top of that, you should design your packages so that dependencies flow inwards. This means outer/adaptor packages can depend on core packages, but core packages should not depend on the outer ones.
myapp/
  order/
    order.go              // package order: Order, LineItem, Status
    repository.go         // package order: Repository interface

  postgres/
    order_repository.go   // package postgres, imports "myapp/order"

  http/
    order_handler.go      // package http, imports "myapp/order"

Here, postgres and http can import order, but order doesn't import either of them. The core package doesn't know / care whether it is being used by HTTP, Postgres, Kafka, or anything else.

This is the only generalized rule that goes a long way for most applications and libraries. Otherwise, eschewing unnecessary nesting and gauging the smell from import paths is the way to go.

Another thing I've found quite helpful is running go doc continuously while developing something. This way, I can assess whether the public API looks ugly and overwhelming from a user's perspective.

reddit.com
u/sigmoia — 3 days ago
▲ 0 r/golang

eon: I wrote a tiny job scheduler

At work, I've been doing some agent automation, like pulling in a Slack digest every morning / checking my calendar & posting a summary before I start the day.

I mostly use claude code, and it already has an in-process ticker for scheduling tasks. The issue is that you need to keep the cc process alive or schedule an actual cron job.

Also, for one-shot jobs, you could use at. But on macOS, the atd daemon isn't turned on by default.

So I wrote a tiny tool that works the same way on macOS and Linux. It allows you to schedule:

  • cron jobs
  • one-shot jobs at a certain wall time

It has its own daemon and lifecycle, which makes sure it works the same way on both platforms. To keep the daemon alive, it uses OS-specific launchd or systemd, so the hard work is offloaded to the OS.

I now just ask the clankers to schedule job using this tool. This allows me to keep track of the jobs, completion state, logs, etc. I’ve been running it for two days, and so far it's working well. You might find it useful.

side note: I wanted to make it a tui but then I realized that the world could probably use one less tui. Also, testing tuis are still hard.

https://github.com/rednafi/eon

reddit.com
u/sigmoia — 4 days ago
▲ 168 r/golang

Just use slog for structured logging in Go. This zerlog/zap APIs are a pain to deal w/. In 99% of cases, the few extra allocations made by slog simply doesn’t matter.

But the cost of wrangling externel API is there forever. Also, at a fairly large scale,(1000+ k8s pods) we have rarely experienced slog to be reason of tail latency spike. So it makes little sense to default to an idiosyncratic library now that slog is here.

It's better to go with the default and only switch if you have measured slog to be the bottleneck (which it rarely is)

W/ LLMs, now I'm seeing clankers pulling in all three libs in the same codebase & making a mess out of it. Add that with other OTEL circus, half of your codebase turns into this unmaintainable plumbing mess.

reddit.com
u/sigmoia — 17 days ago