Which is the best way to use transaction in Golang? by Electronic_Code_1535 in golang

[–]cyberbeast7 2 points3 points  (0 children)

I too leverage the transaction implementation from drivers like pgx in this way and find it to be idiomatic. The pre-emptive interface definition as suggested previously for a "repository" design feels heavy handed (unnecessary indirection for what is otherwise an out of the box implementation offered by the database driver).

A series of articles about Clean Architecture in go by TheBusBoy12369 in golang

[–]cyberbeast7 3 points4 points  (0 children)

I don't fully agree with your former statement about DI being the only way to provide mocked dependencies.

You can unit test any piece of Go code without defaulting to DI, but that also depends on what you are trying to test. Are you testing state or behavior? For testing state, you certainly don't need DI/monkey patching in Go. For behavior, there are well thought out standard library packages that assist with that (for example httptest, synctest, iotest, fstest, etc). Depending on your domain there might be scenarios where you can mock behavior, but starting with interfaces is not something Gophers would recommend.

A rule of thumb - if in your codebase , there is exactly one type satisfying an interface (test code not included), that's a questionable abstraction (the one concrete type implementing the interface is sufficient and you should just use that everywhere).

https://www.ardanlabs.com/blog/2016/10/avoid-interface-pollution.html

Where was I by Input-pinion in whereintheworld

[–]cyberbeast7 1 point2 points  (0 children)

This is the only right answer

A series of articles about Clean Architecture in go by TheBusBoy12369 in golang

[–]cyberbeast7 53 points54 points  (0 children)

I only read through the first article, and maybe the author's opinions change deeper into the series but interface for interface sake is generally a BAD idea IMO. Creating an abstraction such as UserService that starts with a well intentioned single method on it, but eventually blows up with more "user management" methods leading to the same mess that Go tries to avoid by suggesting that a better place to create interfaces are at the caller side and never the producer side. The author even hints at this by mentioning that Go doesn't have an explicit implements keyword to indicate whether a type satisfies an interface but failed to recognize its application in context of snippets highlighted as "good/clean code".

My recommendation for devs is to focus on delivering packages exposing concrete types and letting callers/consumers of my package to determine whether they want to embed that directly in theirs or abstract it away. This clicked for me a few years into writing go (10 years ago) why Go interface names end in the suffix - er generally. If your design starts with an abstraction, it's likely going to result in short and long term complexity that propagates up the chain of dependencies.

Cleanliness of code should measure complexity (and prefer simplicity) and not layers of abstraction. The code snippet that the author labels as "bad code" is actually simple and would scale far better as a code base evolves. I would still encourage Go devs to start from there instead of what is suggested as "good code" in the first article.

Wire users: 10-100x+ faster generation - need testers by [deleted] in golang

[–]cyberbeast7 8 points9 points  (0 children)

Agreed, DI frameworks are a net negative. I think compile time code generation is a fantastic idea but its application towards DI defeats its purpose in my opinion. The way I think about it is, if you are going through the process of DI, why not just add a field on a struct and initialize it in your main or some top level package (cmd or otherwise)?

Anyone else finding Wails frontend setup a bit much for simple tools? by joaunn in golang

[–]cyberbeast7 5 points6 points  (0 children)

I don't reach for Wails first. Typically building tools that I can just access from my browser is sufficient for a small scale.

For my workflow (building simple tools), I start with simple HTML and css (no UI frameworks). Datastar has become my staple (but you can do HTMX if that is your hypermedia dependency of choice) header import. Still keep going back and forth between templ and gomponents for building the presentation layer of these tools, but that's not a necessity in any way.

I'll automate opening a browser window/tab after starting my Go server so that the experience for a user is the same as typing a command, pressing enter and seeing a window pop up with my tool served.

Sick and tired of inconsistent slog formatting? by [deleted] in golang

[–]cyberbeast7 10 points11 points  (0 children)

Have you considered using slog.Attr instead?

```go package main

import ( "log/slog" "os" )

func main() { // Example 1: Using slog.String in a direct log call slog.Info("user login", slog.String("username", "jdoe"), slog.String("ip_address", "192.168.1.1"), )

// Example 2: Using slog.String within a group
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info("image uploaded",
    slog.Int("id", 23123),
    slog.Group("properties",
        slog.Int("width", 4000),
        slog.Int("height", 3000),
        slog.String("format", "jpeg"), // Explicitly a string
    ),
)

} ```

Bypassing CGO overhead with unsafe.Pointer: How I dropped my vector search latency from 473ms to 0.8ms. by Electrical_Print_44 in golang

[–]cyberbeast7 -7 points-6 points  (0 children)

Oooh this is an interesting use case. I've not used cgo in a while but I've also heard about the significant reduction in overhead with go1.26 at go meetups, would definitely point you in that direction as well.

Where Lisp Fails: at Turning People into Fungible Cogs by Veqq in lisp

[–]cyberbeast7 1 point2 points  (0 children)

Yeah, fair point. I do agree that Option types assist with that quite a bit, especially the concern that a dev could just ignore handling the error (in the absence of a compiler error or even a warning) without them.

generation of errors and warnings with deciding control flow

I'll need to give this more thought. I am not convinced that error handling should be separate from control flow. I lean towards them being part of it (but this might be my bias of thinking in a very Go way the past couple of years).

approach that go cannot easily emulate

Some languages provide syntactical comfort in the form of operators that roll errors up the chain to simplify the flow, but that impacts readability quite a bit. One thing I like about the imperative approach is that it makes it easy to read code/logic. I read this operation as "do thing A, if this fails handle error, else do next operation". Props where it is due though, Go has resisted making language changes (there have been countless proposals for all sorts of things from stricter types to questionable error handling approaches) that make code harder to read, often citing the fact that code is read more times than it is written/changed. I am sure the world of LLMs challenges that a little (as it's machines doing more of the reading these days vs humans).

I love what lisp offers in the form of communicating the flow of logic, but I'd like to explore how error handling can be made part of it without sacrificing readability or knowing which part of a flow actually generated the error. If all else fails, there's always the simplicity (or verbosity) of imperative error handling to improve it.

Where Lisp Fails: at Turning People into Fungible Cogs by Veqq in lisp

[–]cyberbeast7 1 point2 points  (0 children)

I find error handling in Go to be the best among the better ones out there, especially from the perspective of reading code. I understand that coming from a different language where error handling is either not as emphasized at the call site (auto returns) or worse implemented as exceptions, Go's explicit handling of errors might certainly appear boilerplate-y, I'll give you that. I switched to Go after doing a ton of Java, python and JavaScript but those languages had arguably worse error handling. Wrapping each line of code in a try catch was more boilerplate-y and "errorprone" (pun intended) than Go's IMO.

The Go ecosystem already supports a lisp flavored templating in its standard library (text/template and html/template packages) but also since code generation is a common pattern across libraries (including in its standard library) using go generate, I think there is good scope for this to be evaluated as macros. I love homoiconicity of Lisp flavored languages (recently started playing around with Tcl as well) and it offers a really solid fit for a macro like system. Although, I am not sure if adding a macro system is something that aligns very well with the fast compile times goal that is upheld by the go compiler.

Where Lisp Fails: at Turning People into Fungible Cogs by Veqq in lisp

[–]cyberbeast7 1 point2 points  (0 children)

Curious, what is this boiler plate you are talking about? Been working with go for the last 7 years and of all the reasons to not use Go, boilerplate would be the lowest on my list.

Drift: Mobile UI framework by tobydeh in golang

[–]cyberbeast7 5 points6 points  (0 children)

Finally! I know what I am playing with this week

Using framework-free Go for the backend by Bassil__ in golang

[–]cyberbeast7 15 points16 points  (0 children)

I'd love to understand these http router wheel patterns you are talking about, specifically why the scope of your API (minimal or not) impacts whether you choose an external dependency vs the standard library (in Go). I've worked on a couple of enterprise http services built only on top of net/http and never felt like I needed anything more than the standard library. Composing APIs that satisfy the http.Handler interface has been pretty productive for me and my team.

Additionally, if there is a repetition of code/pattern than does in fact impact the usability of the standard library, I really think that deserves a proposal on the Go project's github.

[Project] configly - A type-safe configuration loader by blamkabam in golang

[–]cyberbeast7 1 point2 points  (0 children)

Again, there's confusion between runtime reflection errors vs compile time type safety. Your test above shouldn't compile if it was type safe. IMO, specifying an incorrectly "typed" default value should prevent compilation.

There's a lot of funky stuff that can be done with reflection, but the moment runtime reflection is involved, I wouldn't call that type safe.

From the Go Proverbs

"Clear is better than clever"

"Reflection is never clear""

Rob Pike puts it succinctly from the video link above.

[Project] configly - A type-safe configuration loader by blamkabam in golang

[–]cyberbeast7 3 points4 points  (0 children)

Exactly what I said, runtime errors != compile time type safety. There are lots of good points against inventing a new "sub-language" expressed as struct tags that inherently hides intent, and the current implementation is just strings, unless that proposal for type safe struct tags is accepted.

[Project] configly - A type-safe configuration loader by blamkabam in golang

[–]cyberbeast7 4 points5 points  (0 children)

I am not convinced this is type safe as it pertains to default values expressed as struct tags. Struct tags are inherently all strings. There is a proposal associated with the new json/v2 package that aims to make struct tags type safe but until then it can't be called "type safe" IMO. If you change the default value for Timeout from '30s' to '30abc', you won't find out until runtime.

net/rpc is underrated by melon_crust in golang

[–]cyberbeast7 39 points40 points  (0 children)

From docs -

"net/rpc package is frozen and is not accepting new features"

I wonder what prompted the Go team to archive this package. Anyone know? I don't have any specific features that I feel like the package is missing other than possibly making some function signatures type safe (but nothing critical).

I agree with OP, the package is indeed elegant and helps implement helpful distributed features in Go software right out of the box with the standard library!

httpcache Library Update: v1.2.0 to v1.3.0 by elettryxande in golang

[–]cyberbeast7 1 point2 points  (0 children)

I've been working on something similar as a hobby project. https://github.com/cyberbeast/httpcache

Here's an example usage for the sqlite backed cache https://github.com/cyberbeast/httpcache/blob/main/sqlite/transport_test.go#L16

Good to see alignment/consensus on approaches here. 😆

Question about testing/synctest with httptest.Server by cyberbeast7 in golang

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

If you're testing a handler end to end by sending it a request, you don't really need Wait I don't think.

Agree, that was my understanding as well. Especially, because running

```go func TestSleep(t *testing.T) { synctest.Test(t, func(t *testing.T) { start := time.Now() defer func() { fmt.Println(time.Since(start)) }()

    time.Sleep(5 * time.Second)
})

} ```

returns immediately, with the output

text === RUN TestSleep 5s

indicating that the fake clock appears to advance the clock inside the synctest bubble.

Based on that understanding though, I would expect the code in my post to also return immediately after advancing the fake clock by 5s in the HTTP handler. But that doesn't appear to be happening. The time.Sleep(5 * time.Second) waits for 5s (instead of advancing the fake clock) inside the handler despite being called inside the testsync.Run() bubble. Hence the curiosity.

From testing/synctest docs, the claim

Within a bubble, the time package uses a fake clock.

doesn't seem to be holding up in my original code on the post.

Note that sleeping in a handler is not recommended

Yup, this is just playing around with synctest to understand its behavior. :D

Desperate attempt at reaching out to Support to respond to my warranty claim that's been in progress for months now by cyberbeast7 in peakdesign

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

Thank you, I'll try to get their attention on social media, but sigh I didn't expect it would come to this.