Home  >  Article  >  Backend Development  >  This is all what I&#ve learned about Go in TWO Weeks!

This is all what I&#ve learned about Go in TWO Weeks!

Barbara Streisand
Barbara StreisandOriginal
2024-10-31 04:27:02690browse

This is all what I

What is your approach when you need to learn something new? I have a very specific one and once again I tested it while learning Golang!

There's too much content to talk about, but my aim here is to list things that I found useful and that I specifically took the time to learn properly.

Table of Contents

  • 1. Prologue
  • 2. Meet the CLI
    • 2.1 CLI: go mod
    • 2.2 CLI: go run
  • 3. Comparing Different Syntax's
    • 3.1 Syntax: Classes/Structs and the API Encapsulation
    • 3.2 Syntax: Interface Implementation is WEIRD AS FUC*
  • 4. Stdlib: definitely an AWESOME toolkit
    • 4.1 Packages: Primitive Types
    • 4.2 Packages: Useful Stuff
  • 5. Tests in Go are THAT SIMPLE
    • 5.1 Tests: Basic Testing
    • 5.2 Tests: Jetbrains Boilerplate
    • 5.3 Tests: Running Tests
  • 6. Beware Cyclic Imports
  • 7. Defer this, defer that... But, what is a Defer?
  • 8. Error Management for Noobs
  • 9. Conclusion feat: Low Latency Coding Challenge

1. Prologue

For the last 2 weeks I've been learning and building small applications with Golang. At the moment it's been almost 50h of code through many livestreams and it's been pretty awesome to learn something that I previously had a some small issues with the language.

In this two weeks journey I've crafted:

  • A small and REALLY simple shell
  • A Redis Basic implementation
  • HTTP 1.1 protocol implementation
  • A DNS server implementation
  • and a job test for a really cool company (which will be available at the end of this article).

And all this because my boss asked me, once again, to learn a new technology to work on some ScyllaDB PoC's and demos... I wasn't too happy with the decision, but well, it's my job.

During the last year I've been studying Rust, and it's probably still too complex for me, but I've learnt some really cool concepts that made my switch to Go work like a charm!

In this article I'll give you some tips and advice to speed up your learning flow.

2. Meet the CLI

I'm a PHP developer and I'm used to the BEST CLI ever made (yes, it's Artisan), however through my journey as a developer I've been through awesome projects many of which have been..:

  • Cargo (Rust)
  • NPM (JS)
  • Composer (PHP)
  • and so on...

When I got to the Go environment, it started as a real problem. At least for me, the developer experience of Golang in terms of tools and documentation could be much better. Thinking about this, I decided to go through 3 commands that you HAVE TO LEARN at the beginning.

Remember: this is just a walkthrough with my own explanation of things. If you want detailed information, open the docs :)
Also: go docs sucks please someone put a syntax highlighter there

2.1 CLI: go mod

Depending on whether you want to modularise your application or have an organised environment, this will be the most useful command at first.

The go mod command manages all the dependencies within your project and also takes care of autoremoving anything that's no longer used.

First, inside your new empty folder, let's init a new module inside the project with go mod init:

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

This will create a new file in the project root called go.mod, which is basically the contents at the moment:

  • The module name
  • Your Go version

Here's the file, if you want to check it yourself:

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

After that, the next thing I really liked was the go mod tidy, which basically adds any missing dependencies and removes unused ones.

go mod tidy

This second one is just to keep into your mind that this exists and it's really useful! Probably your environment will run it EVERY TIME and you will get used to see imports vanishing :p

2.2 CLI: go run

This is probably the most common command you'll use, since you HAVE to run your project, but here's how it works:

  • You should point to the file that contains the main() function.
  • This file doesn't have to be in the root of your folder.

The most important thing to remember about this command is that when you run the go run command, it will look for the go.mod file in your current directory and use it as the basis for mapping your whole project (imports, packages, etc). Here's some examples:

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go

Here's our app.go content:

package main

import(
    "fmt"
)

func main () {
    fmt.Println("whats up! don't forget to like this article <3")
}

Now you know the basics to execute an project! Literally, hello world!

3. Comparing Different Syntax's:

My problem with Go has always been the way it's written, but after hours of coding I realised that it's simpler than I thought. As you might have guessed, I have a strong background in PHP and some experience with Rust.

When I started to learn Rust in 2023, fortunately a guy I'm a big fan of, Nuno Maduro (Laravel), gave a talk called "PHP for Rust Developers", which gave me some basic introduction to the syntax and gave me some breathing space while I was completely STOMPED by Rust.

Anyway, it was useful to me at the time, so why not do some comparisons?

3.1 Syntax: Classes/Structs and the API Encapsulation

In OOP we have classes, which is a really cool way of abstracting your code into small pieces, and you have something "like that". Golang can be seen as an odyssey, because it can be an epic development to turn the environment into whatever you want it to be.

Remember, Golang is a "high level language" that provides a "system level" syntax that allows you to easily work with "low level" implementations.

Under the Go syntax, you can

  • [Struct] Define a struct by prefixing it with type, adding your "class/struct" name and then adding a suffix of struct.
  • [Encapsulation] Define the exposure of your class/structure related elements by starting them with UpperCase or LowerCase names.
    • [Visibility: "public"]: Set the item name to uppercase.
    • [Visibility: "private/protected"]: Set the item name in lower case.

And you can use it for: Structs, Struct Fields, Struct Methods. Take a closer look:

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

In Rust, you have an more explicit approach (more oop like languages) where:

  • [Struct] Define an struct using the prefix struct, adding your "Class/Struct" name and that's it.
  • [Encapsulation] If you want something to be public to other "crates", you should add the pub prefix in the part of the code you want to expose.
# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

I'd like to make things explicit like PHP, Java and so on but if you stop to think is LESS CODE to write, but it also impacts the readability.

3.2 Syntax: Interface Implementation is WEIRD AS FUC*

To be really honest, I'm the kind of person who would try to put, I don't know... LARAVEL in Go Environment, but that was already done in Goravel. Anyway, I really like the idea of working with "Interface/Contract Driven Development", and for the first time I got stuck with it in a language.

In Go, interfaces aren't "implemented" in a structure/class, and for an OOP guy like me, it's just crazy to have such a design decision fit into my head. Have a look at what is expected:

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

Now, when it comes to go: you don't have this explicit implementation of an "interface" inside a structure, and that's, hmm... weird? Instead, you just implement the interface's required methods, which go will check for you at compile time. It's fair to know that this is a compiled language and it should never be a problem, but I'm talking about my perspective with Developer Experience!

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

In any case, with some time coding in the language you will get used with it. Now, let's talk about what the base environment offers to you without download anything!

4. Stdlib: definitely an AWESOME toolkit

Now I'm talking about everything that Go serves you with the Standard Library, without download an third party package. Here's some chronological timeline for you:

  • 1st day: WHAT? WHY NOT LIKE JS/Java IN THE MATTER THAT THE TYPE CARRIES ALL METHODS? (And I hate both of them)
  • 1st week: Wait, maybe that's good shit (after understand the packages for primitive types)
  • 2nd week: WHAT? WHY NOT OTHER LANGS HAVE SUCH A GOOD LIBRARIES BY DEFAULT?

I'm not joking about that, every day that I explore go I found some cool library under the standard ones. So, let's start talking about primitive types.

4.1 Packages: Primitive Types

Like PHP, and unlike many other languages (Rust, Java, JS, etc), Golang needs "helper" functions to perform most of the related type operations. We can think of them as "anemic" types, since they don't have "utility" attached to them.

go mod tidy

So if you're working with a "String" type, you have other packages like strconv or strings to manipulate it! But here's a golden rule to never forget which package to look at: if your type is string, look for the same package with a pluralised name!

In a nutshell, this will give you functions related to []Type and Type:

  • String type -> import ("strings") for operations like: Contains(), Upper(), Split() ...
  • Bytes type -> import ("bytes") for operations like Include(), Compare(), Split() ...
  • and so on!

Take a look at the code, so you can validate by yourself:

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go

That's supposed to be simple, but I struggled with that for a while until gets into my head. Maybe using Laravel and their helper functions for too many years made me forget how tough is to code without a Framework :D

4.2 Packages: Useful Stuff

While I was exploring tools and projects, I got a really good introduction to many projects and I'd like to list each of them and the libs I've used:

  • Build your own Shell Challenge:
    • packages:
      • fmt: I/O library (Scan/Read and Write stuff on your screen)
      • os: functions and helpers that talks directly with your Operational System.
      • strconv: cast specific data-types to string or cast string to any defined type.
  • Build your own (HTTP|DNS) Server Challenge:
    • packages:
      • net: integration layer with network I/O protocols such as HTTP, TCP, UDP and Unix Domain Sockets
      • [previous packages...]
  • Mid Level Homework Task assignment?
    • packages:
      • flag: Captures your CLI arguments into variables
      • log: Adds Log's channels to your application
      • crypto/rand: Secure Cryptographic Random Generator
      • math/rand: Math Numbers Random Generator
      • time: Duration/Time Lib

Here's a scrollable view of all the package implementations so you can check them out. There are PLENTY of cool std packages that can be cited here.

ATTENTION: that's a LOT OF CODE! :p
Don't forget to comment your favorite features (besides goroutines and channels) :p

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

Seriously, that's just amazing! So, lets keep going for tests now.

5. Tests in Go are THAT SIMPLE

In my second project using Go, I saw an opportunity to learn tests while creating Requests and Responses objects. Inside the PHP environment, you are probably using a 3rd party library like PHPUnit or Pest. Right? Inside the Go environment, this is EASY! All you need to do is:

  • Create a file inside a package: In person.go you will write the functions you want to test;
  • Create a test file for your package :** create a file called person_test.go and start writing your own tests!

Let's say we have requests.go and requests_test.go in our package folder, where requests.go is:

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

5.1 Tests: Basic Testing

A test in Go is considered PASSED (green) if (t *Testing.T).Errorf() is not called within your test function. It also follows the same concept of encapsulation introduced earlier:

  • Test Functions starting with uppercase are identified by the Test Runner
  • Test Functions starting with lowercase are ignored (usually helper functions)
mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

You can do your own helper functions to test. Just make sure to not trespass the module domain on these tests!

5.2 Tests: Jetbrains Boilerplate

I've been using Goland since day one, so most things have been easier for me. So every time I start a new test, I get this boilerplate with a Unity test structure that runs in parallel (goroutines) by default.

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

5.3 Tests: Running Tests

Ok, now we know how easy it is to write tests in Go, but how about running them? Simple task! All you need to do is navigate to the package folder and run:

go mod tidy

Please write down some tests for your stuff. It's not that hard if you decouple what's needed :p

6. Beware Cyclic Imports

During my last few years of development, I've always tried to modularise all my projects in a way that suits my needs, without getting stuck on "Clean Arch" or "Domain Driven Design" stuff. However, in my first attempts at splitting my packages, I got the "Cyclic Import" error and thought to myself: HOW LONG SINCE I'VE SEEN SOMETHING LIKE THAT?

During my 2 years in PHP, I had the same problem with import hell, where you couldn't not import the same file TWICE in a particular flow. This was before I met the PSR-4 (Autoloading) (which changed my PHP days forever!!) and now, years ago, I'm struggling with this in Go.

Let's consider a scenario of cyclic imports:

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go

When you try to compile something that flags Cyclic Imports in Go, you will receive an error like:

package main

import(
    "fmt"
)

func main () {
    fmt.Println("whats up! don't forget to like this article <3")
}

And in this moment, you have to start breaking down your dependencies/packages in order to avoid it.

TLDR: don't import the same package in a place that will be loaded many times.

7. Defer this, defer that... But, what is a Defer?

I didn't look it up, but it was the first time I'd seen the reserved word defer in a programming language. And since it was not part of the "generic reserved words", I ignored it for a whole week!

Then one of my work mates, Dusan, gave me a memory management lesson in Go after seeing me struggle with the language for a couple of hours. (Yes, this is a shout-out :p)

The thing is: whenever you open a buffer/connection to something, you SHOULD CLOSE IT! I remember when I was working with MapleStory servers (Java) in 2014, the most common problem was memory leaks, simply because the developers didn't close the connections to the DB.

This is OK to FORGET! But it's not OK to pass in the Code Review LOL

Here's an example in Java:

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase

While coding Golang, they give this defer attribute for you to remember to close your stuff right after opening it.

Defer stands for "Deference" which is a way to "Clean" your resources after the execution of that specific portion of code ends.

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2

You can also have many defer's within a function and the DEFER ORDER matters! If you defer database2 and then defer database1, both processes will be cleaned in the same order.

go mod tidy

This is a really simple way to not fuck up prevent your project from having a memory leak. Please remember to use it whenever you stream anything.

8. Error Management for Noobs

Error handling at first will be something like: check if the function you're using returns an error type and validate it EVERY FUCKING TIME! Here's an example of what I'm talking about:

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go

To be honest, I HATE this syntax. However, it's part of the language and will be something you'll come across during your days of coding.

Functions with errors can return error or (T, error), and fortunately Go will not let you forget that.

package main

import(
    "fmt"
)

func main () {
    fmt.Println("whats up! don't forget to like this article <3")
}

Spam your code with err != nil and you will be fine, I promise! :D

9. Conclusion feat: Low Latency Coding Challenge

Aside from all the stress and hours spent trying to understand the environment, it was a cool challenge to learn a new language together with my Twitch viewers. Many of them have been asking me for a long time to check it out and here we are.

All of these points reflect my personal development experience with the language, and the goal was to share things I've gone through during these 2 weeks of studying it.

9.1 Bonus: Coding Challenge

Recently I was challenged by my teammate to complete a ScyllaDB challenge and it taught me a lot about parallelism, pools and rate limiting. This is the kind of challenge that many companies face to make their products perform better!

The goal of the challenge is to create a small Go command line application that inserts some random data into ScyllaDB while rate limiting the number of requests.

You can find the repository challenge here: github.com/basementdevs/throttling-requests-scylla-test. We're also hiring! You can find the open positions in our careers section!

Thank you for reading! I hope this article has provided valuable insights into learning Golang. Feel free to share your thoughts or experiences.

The above is the detailed content of This is all what I&#ve learned about Go in TWO Weeks!. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn