The Go Programming Language - My First impression

The Go Programming Language - My First impression

Table of contents

No heading

No headings in the article.

As a developer with experience in several object-oriented programming languages, it can be challenging to switch to a new language that follows different paradigms. However, learning a new programming language can be rewarding, especially when it offers unique features that enhance your development experience. This is why I decided to explore the Go programming language, and in this article, I will share my first impressions of the language.

Go, also known as Golang, is an open-source programming language developed by Google. Since its release in 2009, Go has quickly become a popular choice among developers due to the reasons below:

Simplicity: One of the most significant advantages of Go is its simplicity. Unlike verbose languages like Java, Go has a simple syntax that makes it easy to learn and understand. With Go, you can write concise, readable code that is easy to maintain and scale. Go's simplicity also makes it an ideal choice for large-scale projects with many contributors.

Speed: Another advantage of Go is its speed. Go was designed with performance in mind, and it delivers. Go is known for its blazingly fast speed and small memory footprint. This makes Go an excellent choice for building high-performance systems like network servers, microservices, and web applications.

Concurrency: Go was designed with concurrency in mind, making it easy to write concurrent code. With Go's built-in concurrency support, you can create lightweight and efficient concurrent programs that can handle thousands of concurrent connections. Just adding a "go" prefix to a function makes it concurrent, allowing you to take full advantage of multi-core processors.

Large Community: Despite being a relatively new language, Go has a large and active community. The Go community is constantly developing new libraries and tools, making finding solutions to common programming problems easy. Go's large community also ensures that the language will continue evolving and improving.

Growing Demand: As more companies move towards cloud computing and microservices architecture, the demand for Go developers continues to grow. Companies like Uber, Dropbox, and Google have already adopted Go, and many more are following suit. Learning Go can open up new job opportunities and career paths for experienced developers like yourself.

I started learning the go language by reading the book 'The Go Programming Language' written by Alan Donovan and Brian Kernighan before proceeding to read another text on Web programming in Go. These texts helped me understand the pitfalls often experienced by developers like me coming from OOP backgrounds and how to avoid these pitfalls. I wrote a simple Todo rest server in Go before writing this article, you can check it here to see a complete working Go code.

These are some of the things I have experienced while learning Go so far:

  1. Unlearning Object-Oriented Programming Concepts

One of the first things I had to unlearn when I started learning Go was the object-oriented programming (OOP) concepts from other languages. Go does not support most OOP tools out of the box. There are no classes, no inheritance, no outright generics, etc. Instead, there is the struct type, which is basically a group of fields that is the closest to a class in other languages. There are no “methods,” but you can attach a function to a struct. You can apply a struct to any type in Go, as a matter of fact. The truth is, you need to drop your OOP ideas and learn procedural programming when you switch to Go. In Go, there is no inheritance, and instead, the language encourages developers to use interfaces to define behavior. Composition is the way OOP is done in Go, in which you embed a type a in type b to make type b "act" like type a. This approach allows for more flexibility in designing software systems and enables you to create loosely coupled code that is easier to test and maintain.

  1. Resource Protection

Resource protection is another thing I had to get used to when learning Go. In other languages, you might use private protection or an _ to declare file-level protection for some methods or fields you don't want to expose beyond the file where they are declared. In Go, there are only two access declarations: all fields or methods whose name starts with a capital letter are exported, while those with a lowercase letter are restricted to the package. You can only hide something from other packages. Other resources can access any data declared in the same package, even if you declare them private by using a lowercase letter. You have to bear that in mind when designing your interfaces.

  1. Error Handling

Error handling is different in Go than in other languages. If you are coming from pure OOP terrains, you are likely used to using try blocks to contain codes that can throw exceptions and then dealing with errors in a catch block. In Go, every function that can fail returns a separate error field that you can use to check the completion status of the function. Since Go functions can return multiple results, it is a convention in Go to return any error in the function as the last field in the function response so that the function caller can handle it. Even though this leads to a lot of if err!=nil checks littering your code, you will get used to this method quickly as it allows you to handle errors immediately and fail fast when possible.

Here is an example of a function that returns an error:

 func divide(a, b float64) (float64, error) { 
    if b == 0 { 
        return 0, errors.New("division by zero") 
    } 
    return a / b, nil 
}

This function takes two float64 values, a and b, and returns a float64 value, as well as an error. If b is equal to zero, the function returns an error with the message "division by zero". Otherwise, the function returns the result of dividing a by b.

When calling a function that returns an error, it is common to check if the error value is nil:

result, err := divide(4, 0) 
if err != nil { 
    fmt.Println("Error:", err) 
} else { 
    fmt.Println("Result:", result) 
}

In this example, we call the divide function with the values 4 and 0, which will result in an error. We then check if the error value is nil, and print the error message if it is not. If the error value is nil, we print the result of the division.

Although there is something close to an exception in Go, called a panic(), and there is a recover() close to catch blocks, they often symbolize errors that should never have happened in the first case (usually arising from bad code or the programmers' fault) or critical errors that can affect the whole initialization of the application and warrant a shutdown.

  1. Loops

Another thing that took some getting used to when learning Go was the fact that there is no while or do-while loop. In fact, the for loop is the only loop that you can use in Go. However, the for loop is versatile and can be configured to suit different looping scenarios.

The basic syntax of the for loop is as follows:

for init; condition; post { 
    // code block to be executed 
}

where init initializes a counter variable, condition is a boolean expression that is evaluated before each iteration of the loop, and post is a statement that is executed at the end of each iteration. The loop will continue to execute until the condition evaluates to false.

For example, the following code prints the numbers 0 to 9:

for i := 0; i < 10; i++ { 
    fmt.Println(i) 
}

You can also use the for loop to create an infinite loop, which can be useful in some situations. For example, the following code creates an infinite loop that prints the word "hello" indefinitely:

for { 
    fmt.Println("hello") 
}

To exit an infinite loop or any other for loop, you can use the break statement.

In addition to the basic for loop, Go language also provides a range clause that can be used to iterate over arrays, slices, strings, maps, and channels. The syntax for the range clause is as follows:

for index, element := range iterable { 
    // code block to be executed 
}

where index is the index of the current element, element is the value of the current element, and iterable is the array, slice, string, map, or channel to be iterated over.

For example, the following code prints the index and value of each element in a slice of strings:

fruits := []string{"apple", "banana", "cherry"} 
for i, fruit := range fruits { 
    fmt.Printf("Index: %d, Value: %s\n", i, fruit) 
}

Output:

Index: 0, Value: apple 
Index: 1, Value: banana 
Index: 2, Value: cherry
  1. Concurrency is not Parallelism

In Go, concurrency is not the same as parallelism. Although both terms are often used interchangeably, they have different meanings in the context of Go programming. Concurrency refers to the ability of Go programs to handle multiple tasks simultaneously, where different tasks may be in various states of completion. This allows the program to be more efficient in its use of resources and to handle multiple inputs and outputs without being blocked. On the other hand, parallelism refers to the actual execution of multiple tasks at the same time on multiple processors or cores. While Go makes it easy to write concurrent programs, achieving parallelism in Go requires more effort and typically involves explicit use of goroutines and channels to distribute work across multiple processors or cores. It took me some time to fully grasp the concept of concurrency, goroutines, and channel communication in Go.

In conclusion, my first impression of Go programming language has been a positive one. Coming from an object-oriented background, it took some time to adjust to Go's procedural approach to programming and its lack of some familiar object-oriented concepts. However, Go's simplicity, speed, and powerful concurrency capabilities have impressed me. Additionally, the learning curve for Go was relatively smooth, thanks in part to the well-written book "The Go Programming Language" I mentioned earlier. Overall, I am excited to continue learning and exploring the capabilities of Go and incorporating it into my future projects.

Let's GO!