4008063323.net

The Evolution of Go: A Programmer's Perspective on Its Quirks

Written on

In my shift to PocketBase, I have been converting all my JavaScript scripts into Go. To clarify, I didn't extensively use JavaScript for my RSS reader on iOS and Android; I relied mainly on the client-side for operations. I even maintained a permanently logged-in 'admin account' to manage cloud syncing seamlessly.

With PocketBase, my goal was to implement everything correctly, which meant developing robust backend code. Initially, I intended to use JavaScript, given Node's capabilities. However, Node doesn't operate on PocketBase, so I opted for Go instead.

My initial impression of Go was rather negative. It struck me as outdated, which, in fact, it is. I would characterize Go as "C with improved memory management and enhanced multithreading capabilities." If you have experience with C, you'll find Go quite familiar—almost too familiar, as if the designers missed out on decades of programming advancements since C's inception.

They did learn one important lesson: manual pointer arithmetic can lead to problems. You might wonder, without pointer arithmetic, how would arrays be handled? Fear not, for the Go creators introduced slices, which are akin to lists but, in a sense, more sophisticated.

The type declarations in Go are also peculiar. For instance, to define a slice of integers, you write []int. For a map that associates strings with integers, you use map[string]int. To declare a pre-initialized map, the syntax looks like this:

unusedNamespaces = map[string]bool{

"http://www.youtube.com/xml/schemas/2015:videoId": true,

}

My RSS parser alerts me when it encounters an unfamiliar namespace. Naturally, I want to avoid constant notifications, so I maintain an extensive list of namespaces to disregard. Since Go lacks built-in sets, I resort to using maps. While this concept isn't overly complex, it does feel unconventional.

At times, this quirkiness makes me consider reverting to JavaScript. But switching back would necessitate adapting my Node packages, particularly the Mozilla Readability package, for PocketBase's JavaScript variant—a challenge I couldn't overcome.

Fortunately, I discovered that the Readability Node package had been ported to Go through the go-readability package. In fact, many Node packages have comparable alternatives in Go.

For instance, there’s a Go package designed for RSS that particularly caught my attention. It effectively manages non-standard elements and known extensions, demonstrating resilience against frequent feed issues. Trust me, there are countless ways to mess up an RSS feed, especially when it comes to getting RFC 822 dates right.

I contemplated using Gofeed to parse RSS instead of converting my existing Dart-based RSS reader. However, Gofeed seems to parse XML and present it in a somewhat RSS-like format, which wouldn't suit my needs. I wasn't keen on writing an extensive wrapper around Gofeed to adapt it to my application’s requirements.

Thus, I decided to proceed with porting my XML and RSS parser to Go as initially intended. To my surprise, the process was quite straightforward. The parser is relatively compact—around 300 lines—and I didn’t need to carry over the encoding detection logic because Go infers that for me. The actual parsing took about two days, but transferring the tests required an additional two days.

One of the reasons I was able to work so quickly was due to my reliance on ChatGPT to help write the code. While it’s not flawless and I encountered some errors, it significantly aided me in the early stages when I was still acclimating to Go's syntax.

After writing a substantial amount of Go code, I've come to realize that it's not as bad as I once thought.

My initial experience with Go was through the Echo Routing framework, which adds layers of complexity on top of Go. However, the core of Go itself is not overly complicated.

The primary challenge lies with pointers. Determining when to use pointers can be perplexing. The general rule isn’t as simple as "use a pointer if it's large," since this introduces considerations of heap versus stack memory. Many structures, like slices, already utilize pointers behind the scenes. Personally, I tend to use pointers primarily with custom structs, which somewhat aligns with pointer usage in other languages, although explicit declaration is necessary in Go.

Another reason I resort to pointers is for handling null values. After using Dart, where I can freely assign null to various types (objects, strings, integers), I find it a bit limiting in Go. There’s no built-in concept of null for non-pointer types; variables default to a zero value—0 for numbers, false for booleans, and the date 0001–01–01 00:00:00 +0000 UTC for timestamps.

As a side note, I once encountered a frustrating bug in a C++ raytracer where I neglected to initialize a variable, resulting in all blue outputs—only on my Linux machine. Fortunately, Go prevents such issues, demonstrating that the language designers are indeed learning.

This challenge regarding null values might explain why PocketBase doesn't allow null SQL values, a topic I delve into here. While you can get close in Go with a nil pointer, it's technically not null; it's simply the zero value of a pointer, pointing to memory address 0. But if you attempt to create a pointer to 0, you can't, as that address is reserved.

Go has other peculiarities, such as its automatic formatting on save. This feature is beneficial if you agree with the formatting standards (which use tabs, by the way). However, if you disagree? Good luck. Personally, I use tabs for indentation, but I recognize that others might prefer alternative methods.

Additionally, Go does not utilize exceptions; it employs 'errors' instead, which are adequate but lack stack trace details. The naming conventions can also be perplexing: camelCase is for private fields, while public fields use PascalCase, except in the case of package names, which revert to camelCase.

This can lead to numerous naming conflicts. For example, if you have a variable named url, you'll be pleased to discover the url package, which facilitates URL operations on your url.

Despite these drawbacks, Go isn't an unpleasant language. While it may lack some modern conveniences, its speed is impressive. I'm frequently amazed by how quickly my test cases execute—pressing the test button and seeing immediate results. In other languages, that would typically take at least a second.

I suppose this speed is a byproduct of stripping away unnecessary syntactic sugar. I also appreciate Go's approach to types; it heavily relies on type inference. You only need to specify types when allocating memory or in function arguments and return types, striking a balance between the flexibility of dynamic typing and the safety of static typing.

Moreover, as I've noted elsewhere, Go simplifies multithreading, making it an excellent choice for server-side programming. This might explain the abundance of Go packages available.

There are reportedly around a million packages for Go, while NPM boasts 2 million. If you eliminate some of NPM's less valuable packages (like is-false), you might find yourself closer to a million. Furthermore, Go can interoperate with other languages and terminal commands, meaning if you rely on an NPM package, there's likely a Go equivalent.

While Go may not be my preferred programming language, I'm beginning to appreciate it more. Initially, I viewed it as a rather foolish language, but it's proving to be more capable than I had anticipated. I do wish for a bit more syntactic sugar, but the available features are functional.

Essentially, it feels like a contemporary iteration of C—modern, in a relative sense.

Recently, I watched a video that featured an illustrative diagram:

In my opinion, the diagram oversimplifies things, as developer velocity and performance are both relative concepts. For instance, while it's possible to write faster C code compared to JavaScript, poor pointer management could lead to slower performance or even crashes due to obscure memory leaks.

Moreover, a significant portion of a language's speed is determined by its compiler. You might assume JavaScript is slow since it's interpreted, but Google’s V8 compiler is remarkably efficient.

A more accurate diagram would encompass three dimensions: the frustration level of using a language, the speed for beginners, and the speed for experienced developers.

Go's reliance on pointers somewhat detracts from its user-friendliness, but honestly, they aren't as troublesome as they seem. Moreover, Go's design choices facilitate rapid code development for both novices and experts alike. As stated in their FAQ:

> Go was born out of frustration with existing languages and environments for the work we were doing at Google. Programming had become too difficult, and language choices were partly to blame. One had to choose either efficient compilation, efficient execution, or ease of programming; all three were not available in the same mainstream language. Programmers who could were choosing ease over safety and efficiency by moving to dynamically typed languages such as Python and JavaScript rather than C++ or, to a lesser extent, Java.

> We were not alone in our concerns. After many years with a pretty quiet landscape for programming languages, Go was among the first of several new languages—Rust, Elixir, Swift, and more—that have revitalized the programming language development scene.

> Go addressed these issues by aiming to combine the ease of programming found in interpreted, dynamically typed languages with the efficiency and safety of statically typed, compiled languages. It also sought to adapt better to contemporary hardware, supporting networked and multicore computing. Furthermore, working with Go was intended to be fast: building a large executable on a single computer should take mere seconds. Meeting these goals led to a reevaluation of several programming approaches from existing languages, resulting in a compositional rather than hierarchical type system, concurrency and garbage collection support, and a strict specification of dependencies—features not easily managed by libraries or tools, necessitating a new language.

Efficient compilation, efficient execution, and ease of programming: Go manages to deliver on all fronts. While I wish it leaned a bit more towards programming ease, it was clearly designed for larger-scale server applications, where the trade-offs are more balanced—and it's not too shabby.

In conclusion, Go is a solid backend language, but the reason behind its name being repeated is that searching "Go how do you do X" yields sparse results. It’s slightly painful to write "Golang" since that’s not its actual name; it's a term used primarily by uninformed hiring managers.

While it may not be the ultimate programming language, it certainly surpasses JavaScript by a significant margin.

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

The Hidden Truths Behind Climate Scientists' Reactions

Exploring the complexities behind climate scientists' responses to rapid climate change and the implications for humanity.

Dr. Fauci Faces Off with MAGA Extremists in Congressional Hearing

Dr. Fauci's recent congressional hearing highlighted ongoing conspiracy theories and political divides that echo the pandemic's dark days.

Creating Databases and Tables in MySQL: A Step-by-Step Guide

This guide walks you through the process of creating databases and tables in MySQL, including essential commands and best practices.

The Greatest Physics Lectures: Insights from Legendary Talks

A look at five impactful physics lectures that shaped scientific thought and education.

The Essential Art of Listening: A Guide to Connection

Discover the profound impact of truly listening and the nuances that distinguish genuine understanding from mere hearing.

# Exploring Feminism and the Allure of Wealth in Romance Novels

An analysis of the tension between feminist ideals and the appeal of wealth in romantic literature.

How SentryPC Transforms Employee Monitoring for Today's Workplaces

Discover how SentryPC can enhance employee monitoring to boost productivity and security in the modern workplace.

Embracing Life Beyond Soap Operas: A Call to Authenticity

Discover the value of living authentically, appreciating life's simple moments, and avoiding the pitfalls of melodrama.