Journeying From C to Go
I've recently started learning a new programming language: Go (a.k.a., Golang). Learning a new language is something that I've been putting off, preferring to earn a living with what I already know instead. However, the tech. world changes quickly, and those of us who work in it need to adapt.
That's not to say that languages like C/C++ are dead or obsolete; far from it. When writing low-level code (e.g., drivers) then C and C++ are great. Likewise, C++ is my preferred language for writing larger desktop applications.
The World is "Going Web and Mobile"
Yes, the world is shifting away from desktop computers in favour of mobile devices and web based apps. I personally think that the mobile app market is harder to crack than web apps. The mobile app markets are saturated with over a million apps, plenty of which are very similar if not "reskinned" clones. I also expect that mobile apps will be increasingly data driven, which means that there'll be web apps sitting behind the scenes.
In my opinion, C and C++ aren't the best languages for developing web apps. Sure, you could write a web app in C++, and there are even toolkits like Wt to help you do so. However, you'd probably achieve the same with less code and less time using a different language. C/C++'s low-level features are not an advantage in this case. You're better off with a runtime library that handles low-level stuff for you (e.g., protect against buffer overruns, which could be exploited by a hacker).
The Quest to Get More Done With Less Code
As an undergraduate student I used to prefer coding in C "in an object orientated manner." I felt that this would give me better control and performance. Eventually I realised that C++ compilers automatically generate the boilerplate alloc/free code that I was writing over and over. So, I started using C++ more and more.
I was happy with C++ reducing the amount of code that I needed to write. However, there was still a lot of memory/object management code, and memory leaks were a pain to track down. Then I discovered smart pointers, and they were great. They removed a lot of the burden of memory management, allowing me to focus more on the program logic rather than the underlying mechanics.
Alas, C++'s smart pointers also result in increasingly verbose code. What used to be a simple pointer (e.g., Object *obj), is now rather large (e.g., long shared_ptr<Object> obj). Things get even worse when you start using containers and their iterators (e.g., vector< shared_ptr<Object> >::iterator currObj). There are also other issues that pop up. For example, memory leaks can still occur if you have circular references, which means using "weak pointers."
Like Java, Go has a Garbage Collector (GC) that handles cleaning up objects that are no longer used. No need to use smart pointers any more, and we're back to more compact code.
I used to dislike GCs because you lose control over when objects are deallocated. When done poorly, GCs can cause an app to pause intermittently while the garbage collector runs. However, GCs have improved over the years, and I'm more willing to accept the added overhead in return for getting results with less effort.
I'm also looking forward to no longer having to write header files, or dealing with subtle include file order issues.
Why Not <insert language name here>?
The question of why not some other language is bound to come up, so I'm going to cover a few of the more obvious choices.
Convention over Configuration
The Go language opts for "convention over configuration." I'm a big fan of this because I really hate having to configure a myriad of config files before I get a working system. I started writing a web-app in Java, and quickly got bogged down with the various options and their config files. There were multiple Object Relational Models (ORMs), multiple web-servers, multiple authentication & authorisation systems, etc. Each item had its own config file(s) that needed to be written. This configurability may offer some advantages, but for me it was frustrating to spend so much time on basic decisions and low-level mechanics. I grew to loathe *.xml config files.
In brief: I don't need infinite configurability; I need something that works well, and is up and running quickly. Having a standard way of doing things (i.e., a set of conventions) cuts down on all those configuration decisions.
Static Typing and Compile-Time Checking Helps Reduce Bugs
Ruby on Rails is quite a popular web framework at the moment. I actually spent some time learning Ruby, and there's a lot to like about it. It's definitely nicer than PHP.
However, the Ruby language uses dynamic typing, and I personally think that static typing is better. With dynamic typing, a variable's type can change dynamically at runtime. While you can do neat things with this, having the types determined statically at compile time means that the compiler can catch a whole heap of bugs before the program is run (e.g., trying to use a string as a database object). This leads to more robust code.
Static typing also makes it easier for the compiler to optimize the code simply because its clear exactly what a variable's type is. Dynamically typed languages have a reputation for being slow. Indeed, I've read multiple stories of people who rewrote Ruby code in Go, and got a bit performance boost (e.g., going from 30 servers to 2).
But... What About Test Driven Development?
Test Driven Development (TDD) was the first thing that a PHP developer brought up when I told him why I prefer static typing. In brief, TDD involves writing automated tests first, and then writing the actual code second.
Yes, TDD is a good development practise. The thing is, though, I can use it with a statically typed language in addition to compile-time checking. In fact, I'm doing just that right now in C++ for Warp3D Nova.
By contrast, with dynamic typed languages such as PHP/Ruby you're a lot more dependent on TDD. You need a lot more tests, and sorry, but it's highly unlikely that you'll write every single test needed to cover the full set of issues that are caught by a compiler with static typing catches. I like having the added safety net, and not getting runtime errors for basic mistakes.
What About Functional Programming?
Functional programming languages such as Haskell are getting more attention these days. I have to admit that I am curious about functional programming, and I'll probably learn Haskell at some point. However, right now I need something that I can put to use in the near-term. Haskell has two issues for me:
- Both Haskell's syntax and functional programming in general are very different from what I'm used to, so it'll take longer for me to get the hang of
- Haskell is still relatively obscure (even compared to Go), meaning that:
- You'll have to write a lot more code yourself (fewer ready-built libraries to access web APIs or do other tasks)
- There's a smaller pool of developers when the time comes to hire people
So, functional programming is something for another day.
Onward to Go
Right, that's enough about the whys and wherefores; it's time to get started. If you're new to Go, then I recommend starting with the "A Tour of Go" tutorial at: https://tour.golang.org/welcome/1
Got any comments or suggestions? Or got an interesting story of your own journey through the programming world? Post a comment below...
** Header image credits:
Original Monopoly image: Copyright bagwold / 123RF Stock Photo
Original Gopher image: Takuya Ueda, Licensed under the Creative Commons 3.0 Attributions license
Composite image: Hans de Ruiter
Post your comment