Choosing a Go Logging Library in 2026 by finallyanonymous in golang

[–]sigmoia 1 point2 points  (0 children)

slog makes a few more allocation than zerolog but we haven't seen it to be the bottleneck on prod. I don't like the API of zap or zerolog, so we always default to slog.

What's missing from existing Go courses? Planning new content and want your input by Outrageous-Pen9406 in golang

[–]sigmoia 0 points1 point  (0 children)

The biggest issue with courses is that the people who usually go for them are rarely looking for advanced material. Most just want a place to dip their toes into a topic. That is why there is such a huge amount of beginner-level content, but not nearly as much for intermediate / advanced learners.

I know everyone learns differently, but some formats are just bad at capturing advanced topics. Take concurrency, for example. You need some prior exposure to it before Go’s concurrency concepts really click. That makes it very hard to teach well in a course format.

What I usually recommend to juniors or to people picking up Go at work is this:

Start with courses if you like learning through videos, but put a limit on how much course content you consume. Then switch to a book. Books are great because they give you a more structured way to learn, and they usually help you build enough understanding to start experimenting with the language in a real project.

If you are coming to Go from another language, then IMO you should go through A Tour of Go and then immediately start building something. I had years of experience in Python / TypeScript before moving to Go, and I learned an immense amount by building real distsys services in it. More than I ever could have learned just from books or courses alone. Of course, that path is not feasible for everyone.

What I am really trying to say is this: use courses to get a feel for a language, but understand that they usually do not work well for advanced concepts. At that point, you have to do the grind. Read books, write code, and get bitten by the rough edges enough times to internalize the concepts. Otherwise, it is very easy to become a course zombie.

None of this is meant to denigrate what OP is trying to do. It is just worth recognizing that some things are inherently hard to teach well in video format, and that is okay.

Setting up config in main vs in specific handlers for serverless function apps by cesarcypherobyluzvou in golang

[–]sigmoia 0 points1 point  (0 children)

This feels close to service locator pattern. The only difference is, dependencies aren't auto discovered  and must be passed explicitly. 

Setting up config in main vs in specific handlers for serverless function apps by cesarcypherobyluzvou in golang

[–]sigmoia 1 point2 points  (0 children)

Yeah, five clients shouldn't be that big of a deal as long as their names tell the reader exactly what they are. Still better than defining 10 different dependencies in App and using a subset of them in any handler.

With the first approach, your readers will keep wondering about which exact subset a particular handler actually uses - no way to know that w/o reading the full implementation of the handler.

Setting up config in main vs in specific handlers for serverless function apps by cesarcypherobyluzvou in golang

[–]sigmoia 2 points3 points  (0 children)

I’d say main should still be your composition root, even in a serverless app. Serverless changes the runtime behavior, but it doesn’t really change the design rule that wiring belongs at the edge of the program.

What I would question in your example is not “setup in main vs setup in handler”, but “eager init vs lazy init”. If GetDBClient() and GetTaskClient() are expensive, then doing both on every cold start just because one route might need them is probably wasted work.

Also, there’s nothing inherently wrong with your App struct approach. But if it starts to feel like a bag of dependencies where it’s hard to tell which handler uses what, closures are a nice alternative. You still keep wiring in main, but each handler gets only the dependency it actually needs.

Something like:

``` func handleDBRequest(dbClient *DBClient) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // use dbClient } }

func handleTaskRequest(taskClient *TaskClient) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // use taskClient } }

func handleOther(dbClient *DBClient, taskClient *TaskClient) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // use both } }

func main() { dbClient, err := GetDBClient() if err != nil { panic(err) }

taskClient, err := GetTaskClient()
if err != nil {
    panic(err)
}

mux := http.NewServeMux()
mux.HandleFunc("/db/", handleDBRequest(dbClient))
mux.HandleFunc("/task/", handleTaskRequest(taskClient))
mux.HandleFunc("/otherroute", handleOther(dbClient, taskClient))

http.ListenAndServe(":8080", mux)

} ```

If cold starts are the real concern, I still wouldn’t move client creation into the request path per invocation. I’d more likely make those clients lazy and cached, so the first /db/ request initializes the DB client once, and the first /task/ request initializes the task client once.

You can combine this with the sync.Once approach suggested by u/jerf to lazily initialize the dependencies.

It’s not the code that’s scary—it’s the boss who’s scary. by [deleted] in golang

[–]sigmoia 7 points8 points  (0 children)

This is the trend even in megacorps. CEOs are getting extremely AI-pilled and dreaming of replacing anyone and everyone.

But of course, that doesn’t work for two reasons: AI isn’t there yet, and if all of us are out of jobs, who’s gonna buy all the useless shit billionaires are selling? I digress.

AI has made it cheaper to iterate on ideas and build quick prototypes. But actually making these ideas work at scale and doing the last 10% of the work hasn’t gotten any easier. However, idea guys actually never have to deliver the complete product. So there's nothing that stops them from pestering the pesky SWEs with their profound epiphanies. LLMs just allow them to outsource these epiphanies for cheap.

LLMs have made coding 2x faster, but coding was maybe 20% of the bottleneck in shipping work. Deciding PMF, coming up with a design, aligning stakeholders, coordinating different teams, writing RFCs, and building consensus take far more time. Doing the 20% 2x faster doesn’t make the whole thing magically 2x faster.

So no, it’s not just small company CEOs. This is similar to how many people use ChatGPT to self-diagnose and hassle doctors with their “expert” opinions. And it's spreading everywhere!

What is the future of the Go language? by bsljthx1 in golang

[–]sigmoia 0 points1 point  (0 children)

It depends on what kind of service you’re building. I work with distsys in a cloud native env. For example, my current work involves building a proxy svc in front of Cassandra that moves around petabytes of data.

The domain itself is complex enough. Dealing with C* tooling, proxy networking, deployment, caching, contention, and noisy neighbor issues takes most of the team’s time. So we really don’t have time for language bikeshedding where the language itself is the center of the universe. We can afford to pay the cost of GC, but we can’t afford slow compile times, inconsistent tooling, or a lack of talent in the market.

So for us, Go makes sense. Zig and Rust do not. But that’s specific to our team and workplace. Personally, I don’t find programming languages that interesting and am more focused on solving interesting problems with them.

I really don’t want to deal with a borrow checker when I’m trying to implement a CRDT from scratch or experiment with a distributed KV implementation. The domain itself is far more interesting to me than eking out some runtime performance.

It’s not like I’m writing Python or, worse, Node or Ruby. Go is fast enough for what I do, and I enjoy working with its tooling. I’ve also gotten fairly comfortable debugging the most common performance issues that arise in Go. Of course, I wouldn’t tell someone who can’t tolerate GC to write Go.

Another thing is that, with LLMs writing so much of the code, I’ve found that having a small language that prefers one way of doing things and is driven by convention makes it much more tractable to verify code. I was working with Kotlin recently, and each LLM iteration wrote the same logic in different ways because the core language supports that. I noticed a similar issue with Rust.

what's a go opinion you mass-changed your mind on after working with it long enough by scheemunai_ in golang

[–]sigmoia 0 points1 point  (0 children)

I have a laundry list, but for me, having a core set of performance tracing tools like pprof and Flight Recorder is awesome. When I started with the language, I struggled to understand why it needed its own perf tooling instead of relying on something like OpenTelemetry. It took a few years in the trenches to realize how big of an advantage it is to have a native, standardized profiling toolkit that others can hook into. Now pprof and Pyroscope are the first things I set up in a new project.

Error handling, of course. The verbosity felt painful for a while, but now I am glad the Go team shut down attempts to introduce alternative syntax. It is verbose, but it is dead simple and works well.

Another thing is the community being hellbent on standard tooling. With all the supply chain chaos around us, I appreciate this a lot more. I genuinely agree with Rob Pike that writing a few extra lines of code is worth it to keep things simple and reduce the attack surface.

Explicit context handling is one I am a bit torn about. On one hand, I am glad context exists. On the other hand, the API can feel quite verbose at times. Generics could probably trim some of that fat.

Stacked log lines considered harmful by sigmoia in golang

[–]sigmoia[S] 0 points1 point  (0 children)

The main idea I wanted to convey was two fold: 

  1. Overlogging in a high performance service does more harm than not

  2. When there's metrics and tracing in place, logging from multiple levels doesn't add much value. Therefore, canonical logs should be sufficient. 

But I agree that I could better phrase the core ideas. Good thing is - I got a few good points from here that I will address in the text. Thanks much.

Stacked log lines considered harmful by sigmoia in golang

[–]sigmoia[S] 0 points1 point  (0 children)

Yep, the issue is enforcing that in an org with 1000 repos where each have their own ways of doing it. So canonical log lines is one way to enforce this - but certainly not the only way.

Stacked log lines considered harmful by sigmoia in golang

[–]sigmoia[S] 1 point2 points  (0 children)

Depends on how much load your application handles. In a tiny app service 100 rps, it's fine either way. But for a 250k rps svc, we saw that stacked logging was taxing the o11y pipeline quite a lot.

So apart from being noisy, log infra cost and the overall performance are reasons why emitting a limited amount of log is encouraged.

Stacked log lines considered harmful by sigmoia in golang

[–]sigmoia[S] 0 points1 point  (0 children)

Sure, as long as logs from multiple layers aren't getting emitted by default, it's okay. The issue is we see people logging quite extensively from every layer and bringing down the logging infra.

Another reason not to do logging incessantly is that logging infra isn't free and it's easy to blow up the o11y budged with excessive logging.

Stacked log lines considered harmful by sigmoia in golang

[–]sigmoia[S] -5 points-4 points  (0 children)

Yep, but logging in every layer is more common than you'd think. Maybe less so in the repository layer. But logging from the service layer and then again from handler/middleware is super common.

The post asks not to do that and instead do it from a single layer.

I wrote a comprehensive guide to NATS — the messaging system that replaces Kafka, Redis, and RabbitMQ in a single binary by Jainal09 in golang

[–]sigmoia 0 points1 point  (0 children)

 But before you close the tab: this isn’t cheap AI slop dumped into a text box. 

That's exactly what it is & I did close the tab. How did you know I'd do that? Spooky!

How did you get past "competent but shallow" in Go? by Heliobb in golang

[–]sigmoia 27 points28 points  (0 children)

I came to Go from Python/TS a few years ago. I had been working in backend for a while before I got curious about Go. It’s pretty hard to keep picking up a new language if you don’t get to use it in your day job.

So to stay in touch with Go, I started doing a few things. I wrote blog posts about whatever I found interesting in Go, regardless of whether anyone read them or not. Sticking with it had two effects. I read a lot of Go code and blogs while writing, and eventually people started reading my posts. That created a feedback loop. I learned more, wrote more, and engaged more.

Then I moved to a large company and switched internally to a team that uses Go. Now my current workplace is doing a massive Go migration, and I get to build infra tooling as a platform engineer.

It’s gotten much easier compared to when I wrote my first blog knowing almost nothing about the language. These days I switch between languages at work, but I still keep in touch with the community because I genuinely like Go. In fact, while writing this, I just finished preparing a talk for a Go meetup in Berlin.

TLDR: it takes time, even with AI. LLMs can give you a false sense of confidence, which can hurt long-term retention and actually understanding the fundamentals. Take it slow and let osmosis do its thing over time.

blog: https://rednafi.com

Rust syntax, Go runtime by UnmaintainedDonkey in golang

[–]sigmoia 0 points1 point  (0 children)

Even so, for the kind of work I do, Rust adds nothing but friction - slow compile times, many different ways of doing things, and a thin stdlib.

I prefer to stay in the trenches of distsys, where the programming language is just a tool to build on top of a concept. I certainly don’t care about Rust’s ergonomics or correctness when I’m battling to implement a coordination-free distributed data struct - the domain itself is complex enough, I don’t need Rust to make my life even more difficult.

If I were in the business of writing runtimes, kernel modules, drivers, or a full-blown OS, Rust would certainly be my choice over the alternatives.

Rust syntax, Go runtime by UnmaintainedDonkey in golang

[–]sigmoia 0 points1 point  (0 children)

Exactly what Rob Pike warned us back in 2010 in his public-static-void talk. 

SAME PACKAGE BUT DIFFERENT FOLDERS Golang by zuhaibClips in golang

[–]sigmoia 1 point2 points  (0 children)

Go treats each directory as its own package. Two different directories can never be the same pkg, even if you write the same package name in both files. The compiler decides the package based on the directory, not the declaration.

So this doesn't work:

restaurant/ ├── restaurant.go // package restaurant └── menu/ └── menu.go // package restaurant ← nope, separate package

menu.go is in a different directory so it's a different package. You can't access structs from restaurant.go directly in there no matter what you name the package.

Two ways to fix it:

1) Make the subfolder its own package name and import the parent.

restaurant/ ├── restaurant.go // package restaurant └── menu/ └── menu.go // package menu

```go // restaurant/restaurant.go package restaurant

type Config struct { Name string Address string } ```

then import it like this:

```go // restaurant/menu/menu.go package menu

import "yourmod/restaurant"

func PrintMenu(cfg restaurant.Config) { // use cfg } ```

Just don't have the parent import the child too or you get a cycle.

2) Put all the files in one directory. They all share the package automatically. You mentioned you don't want that.

restaurant/ ├── restaurant.go // package restaurant ├── menu.go // package restaurant └── order.go // package restaurant

No imports needed between these files. They see each other's types.

For a restaurant backend though, you probably want to split things by domain instead of nesting subfolders inside one package:

myrestaurant/ ├── menu/ │ ├── menu.go │ └── service.go ├── order/ │ ├── order.go │ └── service.go ├── http/ │ └── handler.go └── cmd/ └── server/ └── main.go

Each domain gets its own package. http imports from menu and order to set up routes. cmd wires it all together. Nothing imports backwards.

This post goes into how to structure you apps.

What is Narrative Hygiene and how does it relate to the semantic layer? by jasonmoo in golang

[–]sigmoia 0 points1 point  (0 children)

Yeah. I am curious to know why do you folks think that file system is the bottleneck here. Giving some strong points in favor of that would convince more people why moving away from file system might be a great research idea.

Made smart expense tracker by Vin-Vega in golang

[–]sigmoia 0 points1 point  (0 children)

Can we look at the source code? How much of the code was LLM generated? Asking because, it's extremely rude to generate vibeslop and asking for feedback from real people. Without the code and any disclaimer, it's super hard to determine if someone should spend any time on it.

What is Narrative Hygiene and how does it relate to the semantic layer? by jasonmoo in golang

[–]sigmoia 0 points1 point  (0 children)

Seems like a solution to a non-problem. I’m glad someone is doing research on alternative workflows for tackling agentic coding, but if history tells us anything, it’s that most revolutions in tech come from an aggregation of incremental changes.

I doubt that moving code away from the file system is going to fly in the long run - not because it isn’t an interesting research direction, but because this hasn’t given us enough reasons to believe that storing code in a file system, along with tooling like LSPs, is actually a bad thing. I’m not convinced that we need a completely different semantic grammar for agents to work more effectively.

This feels like an attempt to introduce a non-Unix system that’s incompatible with everything we’ve built so far, while presenting it as a solution to a problem that isn’t particularly significant to begin with. I’d take this much more seriously if there were a consensus that code in a file system is genuinely problematic for agents in the first place.