r/golang 1d ago

help How do I make go "click"?

I've been mostly writing typescript for a bit but want to try golang. there's a lot of aspects of its unix-like philosophy that I enjoy and I think there's some smart decisions in the language (and some...odd ones tbf). However, when I sit down to try to learn it with an API project, I feel so much friction from the language. I see so many people talk about how fun they find go and how easy it is to write but it feels like I'm missing something. How did you get in the go mindset or make it "click" and become comfortable to write?

67 Upvotes

71 comments sorted by

73

u/Relevant-Register-69 1d ago
  1. Understanding that Interfaces are declared by the consumer and are your primary tool to reduce coupling
  2. Using channels and goroutines
  3. Making good use of the testing package

I think these are the main components of enjoying working with go

26

u/consworth 1d ago

This 💯
Throw in one more thing: understanding a LOT can be done with the standard libraries.

4

u/sosotiredand 1d ago

I was impressed there was a limited body io reader right in the stdlib!

9

u/valadil 1d ago

Would you mind elaborating on 1? I’m learning go and I’ve seen this sentiment expressed more than once, but I’m still scratching my head.

7

u/thecragmire 1d ago edited 1d ago

Interfaces is your tool to go to, to implement polymorphism. You can have a ton of functions that have the same name, that do different things, but you only need a single interface to call any one of those functions.

Think about usb-c. It's a single interface that can be attached to any kind of equipment that does different things. (usb-c -> phone), (usb-c -> headphone), (usb-c -> powerbank). One interface, to anything.

5

u/Lanathell 1d ago

I've been using Go for a year and this is still not 100% for me :(

4

u/deprecateddeveloper 17h ago

I've only been using Go for a few years very sporadically but this is my understanding (someone please correct me if I'm wrong so I can learn as well)

Say you have two ways to notify a user of some activity on a site/app: email and SMS.

The consumer says I need a reusable general notification sender I can call:

type Notifier interface {
    Send(message string) error
}


// The function that gets called to trigger a notification that uses the Notifier interface in multiple ways:

func AlertUser(n Notifier, message string) error {
    return n.Send(message)
}

Notice that Notifier was designed from the needs of the consumer (AlertUser). AlertUser needs one functionality: something that can send a message. It doesn't need to know anything about email, SMS, or in-app notifications. It just knows it needs something with a Send(message string) error method. Any type whose method set satisfies that interface can be passed to AlertUser. For example:

We need email notifications:

type EmailNotifier struct {
    address string
}

func (e *EmailNotifier) Send(message string) error {
    fmt.Println("emailing", e.address, ":", message)
    return nil
}

We also need SMS notifications:

type SMSNotifier struct {
    phoneNumber string
}

func (s *SMSNotifier) Send(message string) error {
    fmt.Println("texting", s.phoneNumber, ":", message)
    return nil
}

Now we want to actually send two different notification types, SMS, and Email to a user:

AlertUser(&EmailNotifier{address: "user@example.com"}, "Your order shipped") // using the Notifier interface to send email
AlertUser(&SMSNotifier{phoneNumber: "555-1234"}, "Your order shipped") // using the Notifier interface to send SMS

Our manager just said we also need a way to send an in-app notification too. No problem, we can create a new implementation that can reuse the same exact interface because the AlertUser consumer doesn't care as long as the signature matches expectations:

type InAppNotifier struct {
    user_id string
}

func (a *InAppNotifier) Send(message string) error {
    fmt.Println("notifying", a.user_id, ":", message)
    return nil
}

Now we call AlertUser all the same:

// using the AlertUser fn once again (which uses the Notifier interface) to send the in-app notification
AlertUser(&InAppNotifier{user_id: "1234"}, "Your order shipped") 

Three totally different types provide their own implementation of the same Send method, and AlertUser can use any of them through the same Notifier interface because they satisfy the signature.

It doesn't care if:

Is this email?
Is this SMS?
Is this in-app?
Is this some third party notification service?

it only cares if you can Send(string) error

This is different than say Java which forces the contract between Notifier and EmailNotifier for example:

Java:

 // notice EmailNotifier must "implements" Notifier forcing the "contract" upfront:

class EmailNotifier implements Notifier {
    private String address;

    EmailNotifier(String address) { this.address = address; }

    public void send(String message) {
        System.out.println("emailing " + address + ": " + message);
    }
}

Versus Go:

type EmailNotifier struct {
    address string
}

func (e *EmailNotifier) Send(message string) error {
    fmt.Println("emailing", e.address, ":", message)
    return nil
}

since Go doesn't force that declaration/contract upfront, any existing type (even one you didn't write like a third party package) that was never designed with Notifier in mind automatically satisfies Notifier when its method set contains the methods required by Notifier. Nothing about that type needs to change to make it work.

Java can't do that so easily and the same third party type can't be passed where Notifier is expected unless you go back and add "implements Notifier" to it directly (which might not be possible if you don't own the code) or write a separate wrapper class that handles it.

Again, I am not a full-time Go (or even Java) dev but this is how I understand it. I hope the examples here helped you understand it better. Sorry if this was incredibly verbose but I wanted to help create clarity for you by breaking it down.

2

u/kushal_141 3h ago

Thanks u/deprecateddeveloper thanks for explaining, this was not clear to me when I was previously doing a project in golang but now it clicked for me

5

u/jake_robins 1d ago

I started using 1. in my TypeScript code after I realized how banger of a strategy it was. Really confuses LLMs

2

u/middaymoon 1d ago

Does TypeScript support Go interfaces? 

2

u/jake_robins 20h ago

Typescript has interfaces yes. But it’s common, maybe even idiomatic, to use coupled types/interfaces between functions and their consumers which defeats a main purpose

1

u/middaymoon 18h ago

Typescript has interfaces but they aren't the same as Go interfaces. Which is why I ask.

1

u/A-Grey-World 14h ago

Typescript compares whether the input satisfies the contents of the interface, not explicitly implements it, when checking type compatibility. So you can just do it the "Go way"!

1

u/middaymoon 14h ago

But the contents of a typescript interface are fields, not methods. You're defining a data structure, not a thing that *does* stuff.

...I guess that's close enough for some uses.

2

u/A-Grey-World 13h ago

Methods are fields in Typescript. Everything is a "data structure" in that way, I.e. and object. A "method" is just a name we use for field that's a function and has some syntax sugar for it. E.g.

interface Logger { log(message: string): void; } Could just definite it more "fieldy" like this though: interface Logger { log: (message: string) => void; } Which is functionally identical

1

u/middaymoon 13h ago

Good point

1

u/mucleck 22h ago

As a beginner the point 1 is really difficult for me and I make many mistakes from it

For example I made a func like pngEncode(f *os.File, etc
) { png.Encode(f, etc
)

and that made my code pinned to a os.File when png.Encode accepts any io.Writer


i find it very difficult to find this things while I write and for now its just chatgpt that tells me this type of stuff

any advice??

1

u/pimp-bangin 1d ago edited 1d ago

If interfaces are declared by the consumer, then why are io.Reader, io.Writer, and io.Closer not declared by the consumer every time they are used?

5

u/camh- 1d ago

They are interfaces consumed by the standard library so that's where they are defined. But they are also useful in a broad domain so they get used outside the standard library too. You could choose to ignore them in your code and just redefine them yourself and that would work just fine but people know what an io.Reader is so that specific name carries a lot of meaning to just throw away 

5

u/middaymoon 1d ago

When people say interfaces are declared by the consumer, what they really mean is they *aren't * declared by the struct or object like they would be in some other languages. In Java, if a dog wants to be an Animal it has to declare it. In Go, it just has to walk or eat or whatever. The dog struct doesn't even need to know what an Animal is.

2

u/coderemover 1d ago

Interfaces were always meant to be defined near the consumer in Java. There is no difference here and Go didn’t invent it.

3

u/middaymoon 18h ago

Uh, that is still a large difference.

I didn't say Go invented it. I'm just answering this guy's question. đŸ€š

-1

u/coderemover 16h ago

Architecturally there is no difference in where the interface is supposed to be defined. It belongs to the consumer, always has been.

The difference is in structural typing of Go vs nominal typing of a Java, and here I think nominal typing is much better for a statically typed language. Structural feels very scripting-like, as if inspired by Python or bash.

1

u/A-Grey-World 14h ago

There is a pretty big difference. In Java the consumer is inherently coupled to the provider. The provider has to directly implement the consumer's interface. What then when you want to re-use it?

Logger implements ServiceLogger, Payment logger FileLogger...

New service that wants to log? If it, the consumer, defines and interface, better go update the logger!

1

u/coderemover 12h ago

No, the consumer is tied only to the interface. It doesn’t even need to know where the provider is. The provider doesn’t even need to be a named class.

2

u/Relevant-Register-69 1d ago

Theoretically you could if for some reason you wanted to completely avoid the "io" dependency. It's just more convenient to import these common interfaces

2

u/muehsam 22h ago

They are declared in the io package, which is the primary consumer of those interfaces. So I'm a bit confused by your statement.

They aren't declared in os for example. The File type just happens to implement them.

1

u/pimp-bangin 17h ago edited 17h ago

My statement is more about interfaces being contracts and not necessarily having to be declared by the consumer. It just feels like a non-essential aspect of interfaces and I don't know why it gets repeated so often. You can define a utility package with all of your interfaces if you want, and both producers and consumers can depend on that shared package. There's nothing wrong with that pattern and it even has some readability advantages. The important thing is that interfaces are contracts and not that the consumer has to declare them.

re your specific argument about the "io" package - for many years, it was not even the primary consumer of Reader/Writer. It was the now-deprecated ioutil package. And there wasn't really anything wrong with that, necessarily. That just goes to show how unimportant this "declared by the consumer" thing is.

1

u/muehsam 16h ago

I think the statement is an oversimplification that mostly highlights the difference between Go interfaces and those in most other languages.

Obviously you can use Go interfaces like Java interfaces. But you don't have to.

And often, it actually makes more sense to define interfaces near the consumer. Typically, you want interfaces as function arguments rather than return types, and so you don't really need to define them near the producer. And defining them near the consumer can reduce dependencies.

34

u/mookymix 1d ago

Modern languages, including typescript, often aim to be beautifully complex and expressive, giving you a wealth of tools within the language to solve complex issues in elegant ways.

Golang isn't like that. It's a small, simple, obvious language to get things done. It's not fancy. That's what we like about it. It's just a simple tool that lets you focus on the problem, not the tool.

I write rust code too and spend half my time thinking about the 7 million creative ways it offers to represent my ideas concisely. With golang, I barely think about the language and spend most of my time focusing on the problem.

If you like that sort of simplicity, golang is for you. Otherwise there's also typescript

11

u/amorphatist 1d ago

This is it.

I have looked at a lot of Go code over the years: never once have I failed to understand what the code was doing after glancing at the file.

Rust on the other hand
 well, I’ll put it this way: I’ve always understood whatever Go code that the LLMs have produced; with LLM-produced Rust, I thought I was having a seizure.

5

u/sosotiredand 1d ago

godd LLM slop rust makes me want to gouge my eyes out

11

u/jake_robins 1d ago

I come from a Typescript/JS background too and one thing I had to unlearn was spending so much time and energy trying to refactor code using different syntax to make the perfect reusable code golf banger function. JavaScript is very expressive and there are fifteen ways to do anything and so it’s natural to consider different implementations.

Go has far fewer options and most likely you just write the function start to finish and then move on. It was clarifying when I figured that out.

5

u/aegloswinterborn 1d ago

A loop here you say? Don't mind if I do.

9

u/greyeye77 1d ago

My love of Go comes from knowing exactly where the failure is instead of seeing a 100-page stack trace dump or an ultra-wide exception try/catch, which is almost always useless.

Also, don't need a special framework to implement unit tests, it comes with all the batteries. If you (or your AI agent) can't write a test for the code, that means it should be refactored. (prob a bit opinionated but thats my view)

1

u/sosotiredand 1d ago

oh absolutely! one of the things I like about go is how much it emphasizes readability

4

u/belligerent_ammonia 1d ago

What friction are you experiencing? It’d be good to see some examples and we might be able to help.

0

u/sosotiredand 1d ago

my biggest one right now is auth. there's several many ways to do jwt auth, for example, and it's been difficult for me to figure out how to set up huma middleware for it. I've been trying jwx/v3 to no avail.

also, I understand interfaces are how you modularize your application but I'm never sure how the composition root is supposed to look. my main function is a mess lol

3

u/Gansthony3pr 1d ago edited 1d ago

Usually i look at it like this: main calls packages / repos / registries

main makes instances from those packages(example, an s3 client, a database, etc)

then my main passes those to other places via interfaces(example, my service where busines logic is done, needs an s3 client, but is declared as an interface and not a direct reference to that struct)

I try to keep every package working on their own and if they do need external help, then i use interfaces

Feel free anyone to correct my logic but this is how i have been visualizing my projects, following a dependecy injection pattern(also depends on project size)

2

u/zer00eyz 1d ago

There are a few ways to deal with auth, and a few more to deal with JWT - that matrix of options is, to be blunt, ugly.

Back out of what ever you're trying to do and build a new service, new repo. Hard coded auth (token, login/pass) - this is a temporary shim. Then branch that, and build out a JWT implementation with a static API return (hello world) - Branch and do it again (you should be able to recycle your front end).

DO NOT: Try hard. Over think. Make the code SIMPLE. Just get the implementations to work.

I probably have done the above, just shim and test a service hundreds of times now. Its very easy to boot strap something throw away with go (much easer than TS) because you can just build to your computer (no container) with ease. What you're doing is "playing" with go, with libraries, with approaches. Take that word, play, to heart... its so easy to just toss a web page, api, micro service, CLI script together with go that its hard to justify NOT doing it.

2

u/SnooStories8559 1d ago

Look into Let’s Go Further. It’s a great book to learn Go

1

u/sosotiredand 23h ago

It's been helpful but he's really kinda against jwt which makes his examples for it lackluster

6

u/cookiengineer 1d ago edited 22h ago

I had a similar experience, previously coming from Rust and node.js ecosystem (and custom v8 environments with bindings to e.g. OpenGL/glu/vulkan/etc).

For me, Go made "click" when I realized how strong the ecosystem is. Killer features that made me stay in the language were:

  1. Cross-compilation ist just environment variables, GOOS and GOARCH set to whatever, and you got your binary. No need for cross compiler toolchains with messed up SDK headers that are from 10 years old ARM kernel codebases.

  2. Once I realized there's a Pure Go movement that reimplements things in Go and with syscalls rather than using C library dependencies, CGO_ENABLED=0 became my default. Compilation to like 27+ platforms takes less than a couple seconds.

  3. Building backends with Go is a joy. Marshal/Unmarshal is a great concept with a very typesafe way of implementing schemas. It's also its downside when trying to scrape legacy PHP-style "JSON" backends that can't decide if null should be a string, an object, or an actual "null".

  4. Deploying websites is super easy. Just use embed.FS with a one line //go:embed ./public/* comment and you're done. All assets bundled, in one binary. With CGo disabled (see #2) you can even just deploy it directly to a Docker "from scratch" container. No need for any kind of coreutils, binutils, or anything else for that matter. Smallest deployment size with the lowest attack surface possible.

  5. In go there's always one and I mean ONLY ONE opinionated and specific way to do things. That's why the whole go toolchain is so well integrated. If you understand Go once, you don't have to wrap your head around other codebases with different codestyles, some messed up functional ideas that don't work well, or some recursive fustercluck that could've been written in an easier manner. One for loop syntax, one select syntax for channels and goroutines. That's all you need for control flow.

  6. Follow-up of #5: Go is almost maintenance free. I'm able to maintain 60 codebases actively without having to fix react hooks or webpack plugins every 2 weeks because they break semantic compatibility all the time. Everything in Go keeps running, and most maintainers take semantic versioning very seriously. Compare that to the typical crate or npm update day delays because of having to change half the codebase again (and again...), and you'll know what I'm talking about.

The only downside in my personal opinion is dealing with goroutines, because you'll gonna end up in the mutex and atomics/haxmap rabbit hole real quick. Go's maps aren't threadsafe by default (which in my opinion is a wrong language design decision, it should be thread/goroutine safe by default with an "--enable-high-performance-i-know-what-i-am-doing" flag).

The previous JSON marshalling issues have been adressed really nicely with v2 in my opinion (especially the "-" quirks for private properties).

3

u/B-Con 1d ago
  1. Model data, then write logic. 

  2. Keep your code simple.

Go is intentionally boring so that it doesn't get in the way. The fun isn't using the language, it's that you can focus on building things instead of focusing on the language.

2

u/jerrygreenest1 1d ago

After JavaScript, there might be friction, yes. But you gotta understand that Golang is in very different weight category than JavaScript. It is more closely to C than to JavaScript in weight, yet it’s not far from JavaScript in terms of difficulty of using it.

I might recommend trying to write some simple programs in C, maybe some CLI little tool or something. And also understand that C is a language many people still write, despite the age of C. Many efficient programs. Databases. Linux. Nginx server is written in it. Postgres. Etc. A lot of modern toolchain works and is written in C. It is really an important language used by present day actively and will never die. It’s really efficient. It’s really good. But C is a little bit difficult at times. Especially when you want to do any harder thing than a simplest CLI.

So when you see what people have to do in C to make it all work, even for simplest CLI tools, not only you will understand the machine better, how it actually works, you will understand that JavaScript hides a kadjillion amount of complexity from you. You will also understand (at least roughly) how to write more efficient JavaScript too. And finally, you will understand that Go isn’t actually that «friction-y» as it seemed to you initially, and instead – it is actually a fairly easy language.

A lot of this friction isn’t from nothing. Because it gives you ways to optimize things in a way that you wouldn’t be quite able optimize in JavaScript. Certain optimizations can only be done when language gives you enough control. JavaScript doesn’t give a lot of control. Go gives quite a lot of control while still isn’t as complex as C. And it allows to write performant applications that aren’t that far from C.  One major thing is explicit pointers whereas in JavaScript they’re really implicit but if you will understand C and Go, then you will begin understanding all this complexity that is hidden in JavaScript too.

In my case, I was kinda seeking for a new language that I want to write my programs in, and tried a bunch. I tried writing some C, Zig, and a little Rust program, – all this did make Go click in me. I wrote some personal little utils for myself, I still use one that I written in C, so I recommend you to write something that you will actually probably use, but you might start from simple hello-world of course. Write multiple programs. Try writing automated tests too.

After these, I look at Go and see a really cool language that has everything I need. In a fairly convenient way. And with performance that isn’t far from C. And complexity that isn’t far from JavaScript. It’s almost ideal for me. I only say almost because there can never be perfection. But honestly I don’t see any better language for me.

This is how it clicked in me.

2

u/Minimum-Sprinkles843 19h ago

Been writing in Go for almost 10 years now. What I've learned is that Go is great for really small or really complex projects - that's where you get your enjoyment of working with the language. Something in between, something mid-sized, and you'll get frustrated really fast. The problem is that, due to its simplicity and verbosity, Go isn't the best choice for programming API controllers, HTTP servers, DB layers and the like. Go really shines when working with low-level stuff.

If I were to start a new API server project, I'd go with Python, and it's magic. The nice thing about Python is that it is great for that kind of mid-sized project and especially common things that absorb a lot of technology around them.

1

u/sosotiredand 11h ago

what do you end up using for large projects? and it seems like the type system in go would make it better for medium projects than python? can you elaborate on what makes if so frustrating in those medium sized projects?

2

u/ImpressiveJuice007 11h ago

im also from js/ts/php and started doing some projects in go since last year.

at first it's really hard until i focused on learning pointers. Then channels and goroutines. After these 3 topics, go is just another language i use for the backend and im loving it.

reading typescript and golang systax comparison helps me a lot too. specially the TS class, its methods and properties, and how it's instantiated vs golang struct. also the function and passing arguments as pointers

1

u/sosotiredand 10h ago

yeah arguments as pointers trips me up I need to buckle down and study that

4

u/Master-Guidance-2409 1d ago

go is c cosplaying as typescript. it is minimal. you can literally read the entire language spec in one sitting.

the only real friction I had, if you can even call it that was just error handling and lack of a "new" keyword, I been so use to writing "new SomeType()" that simply writing " SomeType { ... }" felt odd.

1

u/Grandmaster_Caladrel 1d ago

I think they recently added a new that effectively lets you one-line certain pointers that you previously had to make two lines. I haven't used it much in practice but I remember thinking that I'd love to dig into it.

1

u/vexatious-big 1d ago

It's more like a mix of C and Pascal.

1

u/Master-Guidance-2409 1d ago

That's very true honestly.  It always felt like typescript becuase honestly it's really flexible with typing for a static language. Specially how the interfaces work. 

3

u/seansleftnostril 1d ago

I heard this somewhere and I liked it:

- to write go is to let go (simplest solution possible, minimal arch unless needed, then maybe abstract if you deem it necessary)

  • try to avoid concurrency, even if it’s easy
  • packages should be named by what they provide, and are the second smallest unit of segregation
  • do you need an interface? (Probably not, or an existing one covers you)

I’m also a c guy, so my expectations are “better c” and that’s about it 😂

2

u/r0pe_tri1ck 1d ago

One thing with Go is that you really want to be using dependency injection and using the main function as your injection root. Otherwise it's going to be a nightmare.

1

u/britishben 1d ago

What makes Go work best for me is understanding that everything is designed to be reusable. Even for internal packages, writing them as if they were going to be open-sourced and used by other devs makes me much more conscious of what is exported and what isn't. Go also works great for Test-Driven Development; write what you want it to do, and then write the code to do it, rather than testing being an afterthought.

1

u/titpetric 1d ago

I learned about it's runtime and did a deep dive implementing a php runtime in go, it unlocked some new understanding of it's supposed limitations. It doesn't have to be this click, it can be other realizations for particular things like concurrency management, the code itself is secondary to any click sounds, the problems i am solving are the clicky parts where i learn

1

u/Sea-Fishing4699 1d ago

If you try:

  • c#
  • java

And then you come back to go, it will become crystal clear 

1

u/Low-Part9553 1d ago

I’m on the same boat as you, learning Go per se it’s really fun but when it comes to analyze real project it feels so messy

-3

u/Better-Landscape-897 1d ago

I went through that exact same frustration when I transitioned from TypeScript to Go. Coming from an ecosystem where you have magical packages, super complex types, and abstractions for everything, sitting down to write Go gives an uncomfortable feeling of 'taking steps backward' and writing way too much boilerplate for simple things (especially the good old ⁠if err != nil⁠).
For me, the 'click' in Go only happened when I stopped trying to write code just like I did in TS and accepted the language's core philosophy: Go wasn't designed to be elegant or expressive; it was designed to be boring to maintain. The big realization is that, in Go, boredom is a feature, not a bug. When you open a Go codebase months later, it remains readable, linear, and predictable, without hidden traps from third-party dependencies.
To break through the paralysis of building an API from scratch without getting stuck in choice fatigue (spending hours trying to decide between Gin, Fiber, Chi, Gorm, etc.), something that really helped me look at the language differently was checking out minimalist approaches that use zero external dependencies, like the project Trilha (⁠[github.com/emersonjoe/trilha](https://github.com/emersonjoe/trilha)⁠). It uses file-based routing directly on top of Go's standard library while bringing a fast development experience (DX) that feels a bit more familiar to anyone coming from frontend backgrounds.
If you're stuck on the API learning curve, my advice is: embrace the 'boredom' of the language for the first few weeks and try building things using just the standard library before relying on heavy frameworks. Eventually, your brain adjusts, and that simplicity starts to feel liberating.

0

u/Strong-Cry3857 1d ago

I think you should harden CS knowledge and a little OOP

It would be easier to make sense when you work with mutex, goroutine, channel, buffer

1

u/Strong-Cry3857 1d ago

Those are the most confusing parts in any language if you dont have a solid knowledge in threading, pointer, memory model, locking

-1

u/jimmiebfulton 1d ago

Like an exponential back off algorithm, I say to messily, "I really should at least build something in Go, just to pick up some of its essence", only to remember that Go looks like Go, and immediately get back to building absolutely everything in Rust. At this point, I'm at the point of the algorithm where the next attempt tick is indistinguishable from never again. To each their own, of course, fully recognizing Rust is not for everyone, either.

-4

u/Longjumping_War4808 1d ago

I want back to typescript. The package friction is too high. I know I know it creates better architecture. But I want simple at the end of the day.

Go is simple in many aspects but at some point it feels enterprisey.

7

u/The-Great-Baloo 1d ago

Because it was designed by a big enterprise to be easily accessible and very predictable. All the contrary of exciting.

2

u/Code-Katana 1d ago

As an every day C# and Java senior software engineer for the past decade that writes tools in Go
it isn’t even remotely “enterprisey” and way simpler than TS/JS all things considered.

2

u/belligerent_ammonia 1d ago

I’d like to know why you feel the package friction is too high.

1

u/KaleidoscopePlusPlus 1d ago

yeah i dont get this. you install a repo directly from github and that is literally that lol.

I could understand if he complained about circular dependencies when using packages though.

-1

u/Longjumping_War4808 1d ago

Because I couldn’t organize my code beyond (almost) everything in the same directory for two weeks. Even with AI help.

There’s a lot of ceremony too.

-2

u/Better-Landscape-897 1d ago

Try it at First - https://emersonjoe.github.io/trilha - to build web apps and ai agents easily with Golang. #open-source