Ramping up with Golang
or The Adventures of Learning new Things
In this post I'll take a look back on the past year, share my personal experiences, and encourage anyone that is trying something new to keep at it. Here at WeTransfer's platform team we’re constantly looking for ways to make our infrastructure more reliable, resilient and secure while simultaneously aiming to allow our customers – our in-house developers – to ship their code faster and with greater independence.
There are certain standard DevOps lifecycle tools that our team takes off the shelf; and yet there are others that we develop ourselves. Earlier this year my teammate Pablo published a post about one of the tools built by us – the platform team – that’s aimed at enhancing our developers’ workflow. It goes deeper into why we build tools and what we are trying to achieve with our tailor-made solutions.
Golang is our team’s language of choice; we heavily increased our reliance on it nearly two years ago after making the conscious choice to move away from our previous ways of using shell scripts.
That said, I had never used Golang before.
I come from a classical sysadmin / operations background. Over the years I developed a pretty good understanding of mainstream systems and tools, but never learned to professionally code. I mostly learnt – and continue to learn – on the job by relying on Google, Stackoverflow, documentation and The Go Playground. I do pair programming with my teammates as and when needed, continue to rely on their reviews of my PRs and feed off of their feedback. Books and coding challenges (like Exercism) is something I'm aiming to use more.
Seeing that this was an opportunity (or challenge), as well as having teammates who were willing to help (we’ve got fantastic teams of people from various backgrounds with some being very strong coders), I knew this was the perfect time to embrace something new and to truly push myself out of my comfort zone.
Here I try to define my main ways of thinking and working, that continue to help me on a day-to-day basis during this ongoing challenge. I will walk you through my five main takeaways:
that running and testing your code at any point during development takes away blank page anxiety;
that reading documentation is great;
that you shouldn’t try to memorise your thought process - write it down instead;
continue pushing and challenge yourself;
and finally, to talk things through.
Hopefully some of these things can resonate with you and be extrapolated onto whatever you’re doing or learning.
The need to test
The main thing I noticed about myself when taking on a new challenge, was that I needed to have a way to test my changes. Knowing how to compile, where to release and what to test places me in the right mindset and takes away the anxiety of approaching a new task.
I certainly don’t want to discount the importance of unit tests and test driven development approaches, but I found that being able to test my changes manually at this level, provided me with a sense of strength and calm. I’m sure that mindset will transform the more experienced I become and the more I rely on automated tests (and writing tests before functions), but for now it’s become the most efficient way to develop my skills and learnings.
So after 8 months of ramping up with Golang, that remains my first takeaway: embrace the unknown, but don’t let absolutely everything stay unknown. Plan what you want to do, and determine when and how you’re going to test it.
Package documentation is everything
The second thing I’d like to mention is the importance of reading the documentation for the packages that you’re going to use. I understand - it’s super trivial and everyone already knows about it – but I feel like I arrived at this conclusion in a slightly different manner.
I was writing a validation for a string pointer that was returned by a certain third party package, making sure that the returned value wasn’t nil. Turns out, the package I was using actually had a pre-build function that returned the value I needed if it was non-nil, or otherwise of zero value.
I could have used it from get-go to write less code.
That’s my next pointer - read that little bit more. Certain things you need to implement/validate are probably already implemented/validated as a part of the package.
Here’s what comes third: comments. Comments that explain what certain functions do, comments in the form of pseudocode to outline your work, and comments that outline which parts should soon be improved.
You will definitely forget what a certain function does, so write a comment about it. It also helps to give functions and variables sane names that reflect what those functions do, and what those variables represent. On top of that, writing a simple short comment explaining what and why will definitely make things clearer.
If you solved a problem using some non-trivial workaround that you found online - leave a link to the article.
Feel the code
My fourth takeaway was something that struck me very recently as I was extending an existing function. Don’t just read the code you’re about to work with, instead understand exactly what’s happening and make each change purposeful. And, as you make the changes, think of quick ways to better any nearby code. Challenge your mind to find an improvement – it will keep you more focused and involved with the task at hand.
Here’s a silly example: Existing code:
var1 := “something”
var2 := “something else”
return fmt.Sprintf("%v,%v", var1, var2)
Task: add another variable, set it to whatever you like and return it.
Initially, I would’ve just gone ahead and created var3:=”whatever i like” while also modifying the final return to look like return fmt.Sprintf("%v,%v,%v", var1, var2, var3)
Why %v? Probably for consistency with existing code. But generally speaking since all the variables are clearly strings it would be better to use %s instead of %v and be more specific with our formatter. So let’s take a second, complete our task and make the existing code better by changing %v to %s:
return fmt.Sprintf("%s,%s,%s", var1, var2, var3)
It’s a quick win.
Sure, this might not scale very well, and I’d hate to come across as someone who nitpicks their colleagues’ code 24/7. Instead, I’d use it as a learning exercise. For me this is about challenging myself to understand exactly what’s going on and how it can be improved.
Say it out loud
My last tip: rubberducking is super important. Talk about things out loud. Explain concepts to yourself or others via non-technical terms. Explaining things is the best way to further understand them. And using metaphors is the best way (for me) to do that. So let me explain the previous validation that makes sure string pointers are not pointing to a nil value.
I have a coffee machine at home. It’s great but whenever it’s out of water it starts making horrifically loud screeching noises as it struggles to sputter out an espresso... Because it can’t really make coffee. Because it’s out of water. That’s like having a string pointer pointing to nil value. When that happens - everything breaks. So I’ve developed a habit of manual validation. Every morning I check if there is water in the tank. That’s like writing your very own validation.
Now, if my coffee machine were to beep whenever it was out water and in turn prohibit me from making coffee until I refilled the tank – that would be like an inbuilt validation function of the package and I wouldn't have to check it myself. I think we could all agree that that would be a whole lot more convenient.
Golang is a great language to learn and use. We use it both as a “glue” to provide a certain level of abstraction for third party tools, and to create new infrastructure related tools from scratch. Both in a form of binary that runs on local laptops and containerized services running in the cloud.
Right now we use Golang with the Kubebuilder framework to develop CRDs for our Kubernetes clusters. Standing on the shoulders of giants, as some might say.
We are increasing our reliance on the language and it feels great to be able to contribute to future-defining projects, to feel useful, and to know that you’re building something that others use. There is still plenty to learn which is both scary and exciting but I am happy to move forward.
I hope this post inspired you to try something new, while giving you some insights into my personal learning and thinking process.
As one final afterword: this journey of self-discovery has truly allowed me to recognise the most important component of all – consistency. Learning something new requires consistent effort. Do it every day, jump on any opportunity to extend your knowledge, and remember that failure is only truly a failure if you refuse to carry on trying.
Oh and pssst - we’re hiring. Checkout our jobs page at jobs.bywetransfer.com