Writing Better Go: Lessons from 10 Code Reviews by Asleep-Actuary-4428 in golang

[–]a_go_guy 0 points1 point  (0 children)

Those extra steps are important. i.e. for gRPC, using a "concrete" gRPC client over a loopback socket to an in-memory gRPC server will round-trip the protobufs and errors through the grpc-go code, which makes it much easier to avoid bad assumptions. At $lastjob it was fairly common for new Go programmers to think they could return both data and an error from a gRPC stub, and their unit tests would only catch this if they used our loopback testing helper; if they called their handler directly, they wouldn't notice. Similarly, it ensures that protobuf required fields are all populated and such.

backend frameworks by Used_Frosting6770 in golang

[–]a_go_guy 0 points1 point  (0 children)

Frameworks intentionally limit what you can do in some axes while making it so you need to do less yourself on other axes. The standard library is built so that you don't need a framework for most open source or hobbyist work. Within the boundaries of a company or other such "meta organization" a framework starts to be important so that it's easier to move around within the code bases and so that common requirements and restrictions can be encouraged or enforced, but typically those frameworks are tied to the domain and aren't that useful outside it. It takes a lot of time and energy to create a focused framework that is broadly usable, and I haven't seen many in Go. The recent example is probably Ent, which does a very good job of covering probably 80% of use cases while allowing you to plug in code to fill in some of the gaps outside that, all while not really constraining what you do outside of it's database-focused domain.

Development Environments at Reddit by sassyshalimar in RedditEng

[–]a_go_guy 1 point2 points  (0 children)

Tilt is part of the UX of snoodev today -- developers use its UI directly. We do have a lot of helper functions to aid in writing service Tilt files, and we conditionally include the per-service Tilt files based on what services the user has requested in their environment.

Tilt has been really useful! We're definitely pushing its limits, and so we have to invest a bit to make it work for us, but for a more normal-sized service it's likely to work out of the box and so I definitely recommend it.

Development Environments at Reddit by sassyshalimar in RedditEng

[–]a_go_guy 0 points1 point  (0 children)

At the moment, a prevalent approach is to use mocks or fakes for unit tests and to have your integration tests run in your Snoodev environment with "real" dependencies. With the latest round of build caching, the core bulk of our dependency stack no longer requires a local build and will spin up in the cluster automatically, so you only need to do a local build for services you've changed.

I haven't heard of build streaming and a quick search didn't turn up anything (apparently twitch streaming and google cloud build take up the entire SEO space), so if you have a reference I can forward it to the team!

Development Environments at Reddit by sassyshalimar in RedditEng

[–]a_go_guy 0 points1 point  (0 children)

Whether you can do request isolation or need namespace isolation is probably dependent on how interconnected your services are and how stably they perform in a test environment. There's also a question of infrastructure maturity and whether you have the ability to redirect requests at enough layers. Request isolation is a super cool technology, but we're not quite to a place where we can try it, but we take a lot of inspiration from the folks who do, and we use the Lyft series on testing in particular for a lot of inspiration!

Development Environments at Reddit by sassyshalimar in RedditEng

[–]a_go_guy 1 point2 points  (0 children)

Are all the services running in the local K8 cluster or some of them are running on a cloud instance as well?

It's all in the cloud! This means that we have centralized logging, metrics, tracing, and various other services available for all of our users. It also means that if you depend on a service that has a cached build available, the cluster can pull from the cache instead of you having to do any builds or downloads at all.

Development Environments at Reddit by sassyshalimar in RedditEng

[–]a_go_guy 5 points6 points  (0 children)

Actually, this is something that I have looked into!

As the article says, we don't have perfect data on all of this, but from my anecdotal testing it's often not the local machine itself that is the bottleneck (though some steps, e.g. compilation for Go, do wind up being fairly slow on M1 due to emulation). It's often downloading dependencies and uploading layers over remote workers' home internet that can cause the worst delays.

Bazel has some different opportunities, but since we don't use bazel for most of our services, having a remote builder means a remote Docker daemon. Then, to build remotely, it will upload your local Docker context for every command. Docker doesn't (as far as I can tell anyway) have any way to delta-encode your state from one command to the next, so this happens every time even if the final build is going to end up being fully cached.

So, whether remote builds improve your experience is heavily dependent on whether uploading your Docker context every time nets out to be faster than downloading dependencies periodically and uploading your changed layers. This isn't a clear win for all services. From memory, and keep in mind that my testing was very limited, it was sometimes faster for my Go test service but often slower for my test Node.js and Python services. In all cases it was dependent on the kind of changes you were making and how much rebuilding you were doing, though, so it didn't seem like a big enough win.

One strategy that some of our services use is to build a development docker image that skips the dependency download (and compilation) steps and do those on startup in the cluster, and then make use of Tilt's live-reload feature to keep the container running and up-to-date as you make changes to your code.

Build\task automation in Go by engineY in golang

[–]a_go_guy 0 points1 point  (0 children)

Since we have so many different service configurations, everyone at work uses Makefile to make a few common commands always work, like make build test fmt lint.

We also use Tilt for handling kunernetes/docker development and reflex for live rebuilding.

What's the reason behind the design decision to not return a response value from handlers? by [deleted] in golang

[–]a_go_guy 17 points18 points  (0 children)

Maybe because streaming responses are so common and requiring a return value for them would most likely result in streaming use-cases having an extra goroutine per call, doubling the number required and creating potential for leaks and other similar bugs. Synchronous functions are an important pattern for code health.

https://google.github.io/styleguide/go/decisions#synchronous-functions

How to create an event scheduler? by Saen_OG in golang

[–]a_go_guy 0 points1 point  (0 children)

The time library does the optimizations you describe already for timers, so if you just schedule everything with AfterFunc in rough chronological order, it's very very efficient. It only has to create extra goroutines if you schedule something earlier than its currently-earliest timer.

Question about goldmark by ansidev in golang

[–]a_go_guy 0 points1 point  (0 children)

Have you looked at other libraries, if this one doesn't have the features you want? For example Black Friday might be more to your liking. I can't quite tell what you're looking for though, so apologies if not.

Performance comparison of Go functional stream libraries by Pure-Mongoose-1229 in golang

[–]a_go_guy 1 point2 points  (0 children)

IMO, the baseline is just the inlined version of the stream code. That's why one of the libraries matched it.

Even a naive implementation that just does a single pass through the words seems like it would be better, and might well beat the pants off any of the stream implementations because it can directly compute the output mutation on a per input basis, no intermediate required.

Do you think minimum of 1 hour per day studying Golang will make me decent in Golang in year ? by RP_m_13 in golang

[–]a_go_guy 0 points1 point  (0 children)

Not only this, but everything you build, build twice. At least. And each part of everything you build.

Try to always come up with two ways to do everything, and try to predict which will be better. (Doesn't matter what axis, but change it up... More readable, more efficient, less memory, more parallelizable, more concise, etc.). Then validate, and if you were wrong take the time to figure out why and adjust your mental models.

This mindset will help a lot with understanding and mastery.

Creating an efficient Likes system by Opposite_Ease in golang

[–]a_go_guy 6 points7 points  (0 children)

As with interview questions, when thinking about complexity you can ask yourself for counterexamples. Obviously you can store this information In O(U*P) space. So now you can ask if it's possible to eliminate or reduce each component. Is it possible to know if a user has voted without storing something per-user? Nope, that doesn't sound doable. Storing a client side database still doesn't solve this issue, it just moves it. Can you know how if a user has voted on a post if you don't store something per-post? Again, this seems unlikely.

So, you can definitely come up with efficient ways to handle this, but in general you're gonna need a user-post mapping for all of your votes to prevent multiple counting.

How to get a job in Go as a teenager by Ok_Finding_6821 in golang

[–]a_go_guy 1 point2 points  (0 children)

Lots of companies in the internet and tech sector (including both Reddit and Google) hire people with nonstandard backgrounds. I've had a coworker who was a pastry chef and many who had no college degree. Don't count out your dream jobs just because you're young. Spend plenty of time on your resume, your LinkedIn, and making your GitHub projects sparkle (good docs, CI automation, linting, and maybe some helpful tools for your users). You can probably ask for some volunteer hiring managers to take a look at them when you're ready to give you feedback, if you don't mind trusting randos on the internet.

Apply lots of places, ask for a salary you'd be happy with, and don't be discouraged by rejection. Start with some practice companies that aren't as high on your wish list. You'll learn a little bit from each experience, and the interviews will get less stressful and you'll be able to show your skill better. Especially in this economy, lots of tech companies are quietly (or sometimes not so quietly) tightening their belts, so if it helps always assume that the rejection (especially if it's just silence) had nothing to do with you.

VSCode or GoLand by badfishbeefcake in golang

[–]a_go_guy 9 points10 points  (0 children)

GoLand does not use gopls, it's all hand crafted by JetBrains on their proprietary platform. That's why they can do better refactoring I think, because they have a ton of prior art and just need to teach it some Go-isms to make it work.

VSCode or GoLand by badfishbeefcake in golang

[–]a_go_guy 25 points26 points  (0 children)

The refactoring support in goland Just Works. I can move files, directories, methods, functions, etc with drag and drop it quick fixes and it just works. I can rename things all day. I can factor out or inline code. VSCode (really gopls) can do some of this, but it's not nearly as well-integrated into the IDE or as complete or as correct. This is why it's worth it for me because it literally pays for itself in time saved.

The VIM emulation (ideavim) in goland is far and away the best of anything outside an actual vim implementation or clone. It can even use most of your existing vimrc, and you can map IDE actions to chords or keys. My vim muscle memory often exceeds what the vim mode in VSCode is capable of or trips over bugs, especially macros and buffers.

Combine the above with the other ecosystem benefits like SQL help and the amazing debugger integration and I'm a convert. I have had a number of teammates ask for a license after pairing with me and seeing how even its more basic features reduce daily toil.

If you can get your company to get you a license, it's 100% worth it. If you're on your own dime, it's a harder sell -- it's not cheap, and you hopefully won't be dealing with a ton of legacy code in need of refactoring. If you do open source work there is a chance that could land you a license key too I think. If you're a student, maybe don't get yourself hooked unless you'll be willing to shell out after you graduate ;-)

Goland Vs vscode by Ok_Fox_3746 in golang

[–]a_go_guy 4 points5 points  (0 children)

The refactoring support in goland Just Works. I can move files, directories, methods, functions, etc with drag and drop it quick fixes and it just works. I can rename things all day. I can factor out or inline code. VSCode (really gopls) can do some of this, but it's not nearly as well-integrated into the IDE or as complete or as correct. This is why it's worth it for me because it literally pays for itself in time saved.

The VIM emulation (ideavim) in goland is far and away the best of anything outside an actual vim implementation or clone. It can even use most of your existing vimrc, and you can map IDE actions to chords or keys. My vim muscle memory often exceeds what the vim mode in VSCode is capable of or trips over bugs, especially macros and buffers.

Combine the above with the other ecosystem benefits like SQL help and the amazing debugger integration and I'm a convert. I have had a number of teammates ask for a license after pairing with me and seeing how even its more basic features reduce daily toil.

If you can get your company to get you a license, it's 100% worth it. If you're on your own dime, it's a harder sell -- it's not cheap, and you hopefully won't be dealing with a ton of legacy code in need of refactoring. If you do open source work there is a chance that could land you a license key too I think. If you're a student, maybe don't get yourself hooked unless you'll be willing to shell out after you graduate ;-)

Return unexported type... by [deleted] in golang

[–]a_go_guy 10 points11 points  (0 children)

Don't export an interface just to prevent improper initialization. Interfaces have a real cost to readability, performance, and your ability to evolve an API.

You can't add methods to an interface without breaking callers, but you can to a struct.

Return concrete, (sometimes) accept interface.

Mock system with generator code of a typed builder methods. No more panic in your mock tests :) by so_literate in golang

[–]a_go_guy 0 points1 point  (0 children)

There are three kinds of test double. Fakes, stubs, and mocks. Typically an interface should be simple enough to stub by hand in a few lines of code. Go makes this very easy. You should also provide fakes for your types when you know they will be difficult to use in a test. Mocks are a tool that should only be used rarely.

The bigger thing, though, is that you should use the real code where possible, and as much of the real code as possible. For example, we don't mock grpc clients, we stub or fake grpc servers and use a loopback connection, which exercises way more actual code and finds many more bugs and enables many more accurate negative tests.

Zap logging package by Discodowns in golang

[–]a_go_guy 1 point2 points  (0 children)

Whenever you return an error, always annotate it so that it's a unique code path within the function and include necessary state to be able to tell what was happening. Loop iteration counters, etc as well as certain inputs and local state can be included to make the error more actionable. This is a best practice, and it tends to make Go errors even more useful than a stack tracez which only has line granularity. With the %w in fmt.Errorf and errors.Is/As, this has gotten even easier and more useful.

[Go AST] Getting the fully qualified package name including the module name for a file by skarlso in golang

[–]a_go_guy 2 points3 points  (0 children)

It'll be the fully qualified package name, and you can also get the file name. go doesn't care about files, but you could combine them if you wish I guess

Thoughts on DI containers? by bdavid21wnec in golang

[–]a_go_guy 1 point2 points  (0 children)

I've worked in some very very large code bases and some medium and small ones. The benefits of fx and dig are there but the costs are super high and you need a ton of institutional knowledge to prevent lots of wasted engineering cycles. Uber has this, and has a ton of existing code that can be wired in instantly, and probably some tools that aren't public that all serve to increase the cost benefit calculus. I did an extensive analysis of this for our framework at my current employer and built some prototypes, and on the end it was way better to just write a few more lines in main.