Learning a new language, or how I gained familiarity with Go
jvt.me
jvt.me
For someone who doesn't know what a function, a pointer, and a string is, there's more work to be done.
One of the reasons Go is praised for simplicity is that it only requires us to know basic concepts. You already know how to call a function and store some integers in a struct. All you need is to get used to the new syntax.
For those who like to flex their brains and learn to think in new ways, this could be a disadvantage, but for someone overwhelmed with information it's a godsend.
On the other hand, if you always limit yourself to Go then it will be harder to pick up other technologies that take advantage of concepts not featured there.
OMG, you are so right! I feel the same. Knowing what the standard libraries bring (or don't bring) for each language that one learsn is immensely helpful. Sometimes this helps me decide which language to use for particular use-case/project, or sometimes it helps me better understand what the level of effort will be for a project if i use langugae X vs language Y, and on and on, etc. I feel like a tour of each language's standard libraries is a must when learning a new language; or at least a cusrosry review of the most important and/.or most often used functions, etc. of said standard libs.
Learning the standard library, and the patterns it has encouraged in the community, takes years and is a moving target. Even a basic (accurate) "feel" for things generally takes weeks, regardless of how "simple" the language is. You might be able to produce code prior to that, but being able to predict where something should be, or how to find it, takes time.
Can you help me understand what this style of dependency injection solves for in java?
I use packages to encourage separation of concerns
Bonus fx points for being able to start/stop services as well. However, this tends to factor more into single binary apps (which is what I've built), more than say restful web endpoints (also built, but don't use this feature of fx as much).
Unless you are trying to add tests to legacy code, where you also wouldn't have much say in the use of fx, wouldn't the stated testing difficultly already force you away from that dependency mess?
struct Foo {
}
func (f *Foo) doSomething() {
client := pkg.NewClient()
client.doHttpRequest()
}
vs. struct Foo {
client Client
}
func (f *Foo) doSomething() {
f.client.doHttpRequest()
}
func NewFoo(client Client) *Foo {
return &Foo{ client: client }
}
var FooModule = fx.Provide(NewFoo)
then to use it... struct Bar {
foo *Foo
}
func NewBar(foo *Foo) *Bar {
return &Bar{foo: foo}
}
var BarModule = fx.Provide(NewBar)
how do you unit test the first example? There is no easy way to that without having the client do things special internally, which leads to a rats nest of issues and doesn't scale. Easier to just pass in a mock client and make sure the right http request/responses are being done.fx kind of highly encourages the second approach for all of your code. It is a bit more boilerplate, but by default, I'm always going to be thinking about passing my dependencies around instead of just being lazy and doing NewClient in the function.
I also get to take advantage of the fact that Client is just magically passed into my constructor. If there is some error doing so (like I forget to Provide), then fx will give me errors at start up. My dependency chain is clear. It just feels nicer to me.
Once again, of course I can write it the second way without fx... but it is kind of nice that every time I want to use Foo, I don't have to type NewFoo() in a constructor... I just reference *Foo.
By the way, mockery [1] generates super easy to use mocks for exactly this workflow.
Absolutely. This is true in most, if not all, languages. But when you're in the driver's seat, able to make choices like whether or not to use fx, why would you bolt on testing after the fact?
Not much you can do about legacy code, if that's what you have to deal with, but when dealing with legacy code it is unlikely the authors used fx, so...
Passing context around is an interesting one too
No, go doesn't have exceptions. :D
To answer the sibling comment (I don't have enough karma to go deeper), Java NIO channels are barely usable. Using them is the quickest way to inject bugs into your code I've seen in Java.
Go channels are closer to blocking queues or a selection of concurrent queues depending on whether it's bounded or unbounded, or whether you use select, etc.
* returning an error code from functions in C and all the time writing "err = f(); if (err != 0) .."
* returning a potentially null reference from a method in Java and all the time writing "var ref = f(); if (ref != null) .."
Exceptions were supposed to save us from this drudgery in late 90s. They did if you ask me. Options are a nice alternative if FP is your cup of tea.
Except for native support for CSP and that programs should be written in a CSP style. Learning Go and skipping CSP is not learning Go.
Learning Go seems to be inevitably "learning CSP", using way too much "CSP", then eventually coming to your senses and going back to atomic types and locks for probably 70% of cases.
The misconception is pretty widespread and cancerous to the community. Ignoring CSP is ignoring Go's best feature for writing better code. It takes some time to learn to do well (I'm still working on it) as it is a different paradigm than most people are used to, but it is well worth the effort IMO.
- Pointers. These take a while to understand and use effectively. https://www.timr.co/go-interfaces-the-tricky-parts
- Error handling. Very different than exceptions
- Interfaces. Not quite the same as Java's and used differently in some cases
- Channels. Java doesn't have these
- Context. passing these around everywhere instead of just sticking on a threadlocal.
Go will flex your brain plenty since you have to unlearn what you thought were good programming practices such as only one return statement per method.
I think it took me a day to realize this when my code wasn't compiling.
That, and goroutines + channels (especially blocking behavior).
Go has some interesting ideas about models/ORM's, OpenAPI, validation, templates, embedded binary files and other things. When types matter, like in Go, code generation is often very important as well which isn't as common in scripting languages.
https://goa.design/ for grpc/rest servers based on specs
https://gokit.io/ for microservices
https://github.com/mustafaakin/gongular demonstrates object-based validation using struct tags
https://sqlc.dev/ for generated models based on SQL (skip the whole idea of an ORM)
https://github.com/jmoiron/sqlx for more traditional object population from SQL
https://pkg.go.dev/errors for an understanding of wrapping errors and nested error causes
https://gqlgen.com/ for auto-generated revolvers based on GraphQL schemas
https://pkg.go.dev/io#Reader all the Reader/Writer/Closer's as they are everywhere since Go cares about performance and therefore streaming abilities. No more string passing.
As mentioned in the article, flags matter in Go. The most popular https://cobra.dev/ and the simpler https://pkg.go.dev/github.com/peterbourgon/ff/v3/ffcli provide some good examples
This comment is mostly for web apps, different domains will require looking at all the approaches taken in https://github.com/avelino/awesome-go by leading packages
Yikes.
When types matter, you make a newtype and use UnmarshalText!
A large portion of the Go community uses/abuses struct tags so knowing about them and seeing a system designed around them is important even if you won't use gongular because you're using ent or goa.
echo, buffalo, gin, etc... all use object struct tags for input data binding and there are two large validation packages that focus on this use.
I don't have many yet, just 3 (if you have ideas, lemme know). But porting them has already helped me start learning Zig and FreePascal; two languages I've been meaning to learn for a while.
Is there a good book for people without a compsci background to better understand terms?
I've been learning Rust (and lots of go) as my first language and the terminology of things really throws me off, I feel like simple concepts are wrapped around what sound like confusing math words/phrasing.
I'm partially trying to learn syntax, language'isms and vocabulary at the same time.
What do you mean understand terms?
If you need help with programming check out the link in my profile and we can set some time up - it will be more beneficial than buying a book
All the power to you to get through challenge mode. My first languages were C and javascript when the documentation was pretty much just books, but the amount of resources online these days is just incredible. After you learn a couple of them the rest get a lot easier. If you're stuck on math-related computer stuff I liked the Schaum's outline of essential computer mathematics a lot for getting up to speed. [3]
If you're looking to make things a little bit easier you could aim for higher level languages which don't require you to think as hard about what you mentioned because it's abstracted away. Python is popular for this reason and has a ton of immediate practical use, but I also like Ruby and Lua for ease of writing. Just keep in mind that these languages tend to get comparatively harder to use the larger or tighter your program's requirements get.
[1] https://doc.rust-lang.org/reference/glossary.html
[3] https://www.abebooks.com/9780070379909/Schaums-Outline-Essen...
This isn't going to solve your immediate problem, but the trick is to build your own compsci background. Data Structures, Algo, Operating Systems, Discrete Math, etc. courses are all available online various platforms (youtube has a lot of the lectures). I went through lectures and problems from Cornell, Stanford, CMU and MIT online for free. It is gonna take some time, but I suggest starting to chip away at the lectures. It's a nice break from actively hacking on something.
The language itself is neat. Obviously very fast. Ergonomically sort of clunky (as compared to other languages, like TS or Python), but I think that'll smooth over with time. It also makes "hard things" in other languages simple, especially its threading and inter-thread communication.
https://www.amazon.com/Programmers-Brain-every-programmer-co...
perl: This is the worst language I've come across. There are multiple different ways to do the exact same thing, sometimes the rules are understandable but mostly they are insane. For example, the "or" vs "||" is ridiculous to me, and the different namespaces between scalars and vectors such that you can have $a[$a] if I remember correctly. To me, it's a mess of hacks and 'this sounds like a great idea' that makes it almost impossible to maintain over long term.
ruby: In my opinion, ruby suffers the same fundamental problem as php, which is that designers learn to use it instead of those with CS backgrounds, and produce terrible code and terrible practices. I developed on php for a few years, and the company had a hard time finding new employees that would meet the hiring bar because everyone that applied didn't have a CS background so the entire company pivoted to Java. With ruby, you also have inexplicable shortcuts that make code very hard to read, like no distinction between member functions and member variables, things being optional or not like ?, etc. Reading ruby was extremely hard to me, and if you have a large codebase, it's torture.
scala: I know scala is revered by many but I hated it, but admittedly I only used it for a few brief and painful months. It's the first coding language I used that I couldn't survive without an IDE to help me figure out where code was coming from. It was basically impossible to trace through code without an IDE, at least for me. I think it does the same thing that perl does, which is give multiple ways to do the same thing which makes it very hard to read, and the "you don't have to do this if you want" mentality which also makes it hard to read especially for noobs. I hated it.
In my opinion, the easiest language to work in is go. Go has an opinionated, single way to do things, and go fmt is the ultimate arbiter or coding style. No more arguments! I LOVE that you have no choice because it means you have less cognitive load to worry about. Yes, you lose creativity but at the benefit of maintainability. It's not my favorite language, but in terms of how easy it is to jump into a codebase, I feel that it's go. The only thing that I don't like is that package names and struct names are hard to differentiate, so you need the IDE to sort that out for you. For example tool.func1() could either being an package or a struct, so this needs IDE help as well.
My favorite language is Python. I can do things in Python in 5-10 mins that would take me 1 hour in C++ to do in boiler plate. To me, it's the most productive language if you want to get stuff done as quickly as possible. It doesn't scale like compiled languages, but that's a problem for success and most don't reach that stage in the first place.
I found it very hard to do with map[string]interface{} or figuring out which kind of structs to create...
For JSON there seem to be many libs now which can do this.
And especially for a language like Golang where there's a pretty good, comprehensive, official interactive tour[1], I don't know why you'd watch a guy type for 4 hours.