The way the story (Go)es

Posted on Apr 3, 2025

Which language is the best? Well some will immediately proclaim C! Python! Rust!, a very direct question which the answer should probably be it depends, the context in which you are using the language and what for. Well I am not here to proclaim what is the best language and if you are waiting for such statement fine, it’s brainf**k. Now with that out of the way we will go on a journey of the languages I have picked up and how I ended up using and enjoying Go along with some experiences and opinions.

Miserably Ignorant

My first project of my career was to write API tests in Java using BDD and Cucumber framework and adding new features to the API. I thought to myself great! I did Java at university this should be familiar! Well sort of, you see at university I was writing Java without any frameworks or libraries that modern Java apps are built with. So to my surprise I kept seeing annotations and jumping through the code base file after file drilling through classes and methods and classes and methods…. Ok ok it wasn’t that bad, I was comfortable with writing code and started building a mental model of the codebase that eventually lead to contributing to some features. Write once run anywhere…

Did Java, check, now it was time to do Typescript and enter the fancy world of serverless on a new project I joined.

Jest? Ohh yes let me test! Nock? Yes please mock my network calls! Leftpad? ESM or CommonJS? Why is this not importing? ESM modules? Ok you get it, enter TypeScript, finally types for JavaScript!

Starting a typical project by setting up config for bundling, linting, a starting project structure and testing. All good and ready to start writing code, now don’t forget the npm install oops better update npm! So the work started, more libraries and dependencies were added, need something? Reach for a library and add it into our basket (node_modules), no need to reinvent the wheel! Woah what are utility types? Union types? Awesome, I can be much more expressive and handle more types with my functions!

With all the expressiveness and features I found myself writing functions that took a few types and did few things with them then passed them off to other functions that handled that specific type. Now I remember that I was struggling for a few months even though I was contributing to the project, to keep a mental model of the codebase in my head and sometimes forget some parts of the codebase. Of course with time that resolved it self but it didn’t sit well with me the overwhelming information I had to keep in my head with a flow that was hard to follow given how union types allow for functions to handle a few of them, you suddenly jump here then there and find yourself in a maze which you coded yourself in. Perhaps we have gone a bit overboard with union types? or used utility types which took some time to remember what they were doing?

I am sure our codebase can be improved and made easier to read and maintain but alas when you are excited about implementing features you just learned, you see nails everywhere and the hammer must drop! Yet here I was with a bad aftertaste due to the expressiveness afforded by TypeScript, it was too much for my own good, maybe even contributed to easily creating a maze of my own creation that inevitably becomes a labyrinth, especially if you doing clever tricks with the type system. Don’t get me started on ternary operators….

Perhaps I am not cut out for this software world, always imposter syndrome around the corner ready to sneak in and tell you how it is, like that annoying fly that buzzes as you are about to sleep. Until…

Should I stay or should I Go?

So with the AbstractFactoryBean that runs on 3 billion devices and a type system which you can run Doom on behind us I had the opportunity to work on a project with a language that I heard a lot about from colleagues and friends.

An interesting point about this introduction is that I wasn’t immediately told about some amazing feature or how the library ecosystem is, rather I was told this is a simple language purposefully built to be easy to pick up, readable and maintainable. In fact it lagged many features modern languages now have and somehow that was a good thing I was told. Also surely it’s a given for any language to be readable and maintainable, isn’t that what Clean Code was for right? It didn’t matter what language you used but rather some guardrails on how to write readable code.

Well yes and no, before this introduction I never thought about the philosophy or ethos behind the language I just picked it up learned the syntax, familiarised myself with the library ecosystem and off I went building. Yeah you get told to read Clean Code and DRY etc but at some point the choice of language can get in the way of that without realising. Perhaps I could have paid more attention on the languages I picked up early on, understand their origin, why they exist but yet again I was just starting my career so we will chalk it up to unknown unknowns…

Back on track, ah yes starting to learn Go and building with it on this new project. Go installed, ticket picked up, lets write some code! Well it wasn’t that easy, I spent sometime going through Learning Go with Tests which is a fantastic resource and I recommend it to anyone who wants to pick up Go!

The ways of the Gopher

Learning Go was very interesting, the language only has 25 keywords!

break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

So didn’t take long to get acquainted with the syntax, instead I found something else more challenging when I started Go. The Go language is opinionated, it has a standard library and even has it’s own formatter! My immediate reaction when I picked Go was, let me get the syntax out of the way and learn the library ecosystem to be productive afterall that’s what I did previously. To my surprise when looking up for frameworks and libraries I kept seeing people discouraging it and instead encouraging the use of the standard library or even in case you still need to reach out for one perhaps “a little copying is a bit better than a little dependency” - Rob Pike.

First of all who is Rob Pike and why do they want me to reinvent the wheel or maintain something I am copying!?!? Oh they are one of co-authors of Go, wait a minute they also worked at Bell Labs prior to this and worked with the co-authors of the C programming language (God’s programming language), ok as impressive as a career Rob Pike has this isn’t the place to talk about it, what I am trying to say is that I realised I should pay attention a little bit more about what they and wider Go community are saying. After all I just started my career and as is with any field we must stand on the shoulder of giants and learn from the experience of the ones who came before us.

Ok so the fanboying aside what were my challenges with Go? Well I think Go is more opinionated compared to what I was used to coming from other programming languages especially when it comes to.. QUACK!

Is that a duck I’m hearing? Quack!

Well what do you know about interfaces? An abstraction you say? We all know the classic example of an animal interface and classes implementing them.. So how are interfaces in Go? Who knows! At first I struggled to understand how to use them or when I would opt to use them after all what is duck typing right?

Well to cut the story short I as avoiding interfaces as I didn’t see the use for them until I started working on a project at work. The moment interfaces clicked for me was for testing, instead of passing the actual type to the function I could pass in an interface. OK you say, how did that “click”. Well going back to ducks and quacks, passing an interface means I am expecting the type you pass to have implemented the same function signatures as defined in the interface, otherwise it doesn’t implement it. In other words if it looks like a duck and quacks like a duck, its’ probably a duck! Now I started to understand how powerful duck typing is I started using interfaces to abstract away implementation or type details when I was writing a package that was consuming another package, see the repo pattern for an example of this. Essentially the Go idiom is ‘Accept interfaces, return structs’.

If I lost you a bit there then here is an example that shows the interface in action from another excellent resource that I have used while picking up Go https://gobyexample.com/

I could go on and on about interfaces but understanding them helps with navigating the standard library with it’s own ‘special’ interfaces. Next stop, you guessed it, the standard library.

So you’re telling me I don’t need a framework?

Who doesn’t love a framework? There is something nice about abstracting away the tedious work, having a consistent way of building something and doing it fast! So to my surprise when I was going to build an API in Go I was looking for libraries and frameworks to use but I was keep reading “Why do you need a framework or library can’t you use the standard library” - said an internet stranger to another internet stranger asking about what API framework to use in Go. Strange I thought they are few frameworks like Gin, Echo and GorillaMux but let me check the standard library since everyone is mentioning it, let’s see what the deal is about.

So clicked on the first result which is https://pkg.go.dev/std. Woah, that’s a lot of packages! So… looking for a package that lets me build an API, let’s see net/http package that seems about right. ListenAndServe? ServeMux? Handlers? Ok they seem familiar similar to how express.js works that I used before. Off I went learning about the encoding/json package, the first standard library interface Handler and built an API without a framework.

The standard library has great documentation but also a lot of packages that pretty much can help you build a lot of apps without needing to reach for a library. In fact when I first got exposed to the standard library I was amazed by how much I can get done and still be within the confines of the language, going back to having a consistent way of building something but this time it’s not someone’s open source library who dictates how this particular framework is written and done but rather the language itself.

What a breath of fresh air, no longer do I have to rely on libraries, how each might do it differently oh and breaking changes, by the way did I mentioned Go’s backwards compatibility promise? So not only we get batteries included but also those batteries will last for a long time!

You could say I have become something of a standard library purist but I don’t want to admit that yet… although I do get excited when a new version of Go get’s released with new packages and improvements to the standard library. So far my favourite one has been 1.22 with routing enhancements.

The standard library has a lot of packages and I know that because I haven’t used all of them, so take your time and explore the documentation, interfaces it provides, understand what batteries are included with the language oh and read the standard library code, a great way to learn about packages but also a good way to improve how you write Go.

Readable and maintainable

During the early days of learning Go I found myself reading more Go than I was writing, why? Let’s say I knew how to write Go but not how to write idiomatic Go. I know I told you it’s a simple and easy language to learn, I didn’t lie, however it did take some time to write idiomatic Go. The journey to learn how to write idiomatic Go was interesting to me, it’s one of those things that you pick up as you expose yourself with more Go and write more but especially when reading code.

I have used the http/net package to write an API using the standard library and when I went to read some open source code on how an API was written I was surprised how similar it looked to mine and I just started learning Go! Well I guess there two things here to pay attention to, using the standard library and following idiomatic code will make it surprisingly easier to read a new Go codebase and become effective right away. In fact I was impressed by this because it wasn’t even a framework enforcing this but the language itself!

Now of course we can’t rely on the standard library for everything eventually we will copy code or import dependencies written by the community. But even then idiomatic code is used to create that library right? Well I hope so and so far when I have inspected the code of dependencies I have found that it is.

With a lot of clever tricks and abstractions to solve something elegantly, having an ethos to write readable, simple and maintainable code is a noble value to have. I will probably forget the code I written a year later from now so if it’s not about the next person after you, be kind to your future self.

Community

So far I learned, shipped an app to production and had a taste of how it is to use Go, now it’s time to learn from others! What a better way to do that than to join online forums, meetups and groups that talk about Go and using it! I was part of my internal company’s Go community of interest, until one day I thought to myself it’s great to hear what our colleagues are getting up to with Go but what about other companies? How about other domains and industries? Do other people have a similar experience with Go as me or am I the only standard library purist in here? Am I real? Do we live in a matrix? The curiosity to interact with other Gophers and learn about their journey and criticisms of Go was there.

So what did I do? Well I asked my colleague Joe (who also blogs) if there was a meetup or a local group that hang out and talk about Go. This was right after COVID so to no one’s surprise he told me there is a meetup but has been inactive since COVID. So I went to meetup and checked out the page and yeah the last meetup was on March 2020. To my surprise the owner of the meetup posted if anyone else wanted to take over as organiser and yeah I did comment to ask that I would be down and convinced my colleague Joe to join in on the fun, figuring out how to run a Go meetup well that’s for another post.

With the meetup restarted I met a lot of Gophers who work for various companies and industries, got to learn about the interesting ways Go is used but also ask about people’s journey into Go and what do they like and dislike about the language.

Now with the meetup running I was curious to find any forums online and you go to the usual suspects like Reddit with r/golang however I was surprised to find that there is a Gopher’s Slack, a discord, mailing list and even an IRC channel! All of them are linked here.

With my interactions both in-person and online the Go community is welcoming, friendly and not shy to tell you how opinionated Go is, which makes for learning moments but also verifies my experience and thoughts around how and why we do things the way we do.

So what now?

Well one thing is certain, it has been 0 days since a new JavaScript framework has dropped and that’s also how the tech landscape works, languages come and go, but a few remain. In my experience so far every language has something to offer in terms of learning and gives you a new perspective in how you write code. For that Go holds a special place in my languages tool box and appreciate the ethos and philosophy behind it. It will be my go to language to build almost anything for now while I am still open to playing around with other languages (hey Zig, looking at you).

This is my first “proper” blog post, I am sure my writing and whatever I just rambled on about might not make sense or even not be well written, alas I got to start somewhere. I wanted to share my journey of programming languages

If you have any feedback about this post or general thoughts or equally want to express how bad it is you can yell at me on bluesky.