When you need to build a wide-scale production with a large number of programmers, JS is decent, but it misses the mark. The structure you’ll need is provided by TypeScript. But, what about GO? It’s been showing up all over the place lately.
When discussing languages, we also mean the system that runs them, and since the majority of microservice code is server-side, we’ll use NodeJS and Typescript sparingly.
TypeScript soon changed, and adding structure to the project was a natural evolution as additional individuals joined us. With interfaces and type checking, as well as go-to-definition and parameter order checks, it was a true save in terms of knowledge transfer, refactoring, and code readability. Now, GO is a brand-new language that I’m presently integrating into the project, and it’s not meant to replace any of the existing microservices. I’ve already developed two GO modules and am considering more.
As if one new language wasn’t enough, we’ll dive into two.
Isn’t it true that everyone now uses GO?
Not quite; Twitter recently switched to NodeJS, Microsoft uses it in their Azure cloud, Netflix uses it, as do Walmart, PayPal, LinkedIn, Yahoo, Google, Uber, and a slew of other companies. GO can be observed in and around the entire docker industry (including projects like Docker, Kubernetes, Prometheus monitoring, and more). GO is a programming language that is used in YouTube, Bitbucket, Facebook, Netflix, and other places. So, which is the better option? It’s not as simple as that; let’s look at the specifics.
In comparison to NodeJS, GO is a relatively new language, first publicly announced in 2009 and only reaching v1.0 in 2012. Its growth rate is moderate. There are significant distinctions that distinguish it from all other currently available languages:
- The programming language market in the last decade has been overtaken by semi-compiled languages and scripts, which gained traction because they are easier to use cross-platform. GO is a modern compiled language (at long last!). However, such languages result in a product that is both easy to hack (when distributed) and difficult to optimize (no JIT engine can beat a CPU-optimized native binary). GO has all of the standard String handling / OS / IO / Server/serialization & parsing commands, as well as a lightning-fast garbage collection engine that only stops the process for a few milliseconds at a time, for a 1.7MB overhead in your executable. It can also cross-compile to various operating systems and CPU architectures without the need to maintain these systems around because it generates fully working executables for all target systems on a single build machine (think of the DevOps benefits compared to Cpp builds). The compilation is lightning quick, and even a huge project can be completed in seconds.
- From the start, GO features a parallel structure that is modeled after a pipeline flow network. This approach is quite similar to the C# TPL DataFlow architecture, or an in-process micro-services architecture, in that it comprises groups of same-code parallel workers (goroutines) that are interconnected via producer-consumer queues (channels). With some fancy algorithms, it also hides all the internal workings of threads, including thread pooling and all thread-per-core issues.
Adopting GO isn’t easy; it has an opinionated model for how projects should be laid out on disk and how dependencies should be kept and managed (gopath, packages), its internal syntax is designed for compiler optimization, and it’s less attribute than existing languages, which isn’t entirely a bad thing. Structs are just used to store data; functions can be added to them at any time, from any code (so, no sealed classes). There are no end-of-line semicolons, and an unused parameter is a compiler fault, and unused imports are erased by the format utility (which is unusual if you’re like me and used to pressing “format code” after every second keystroke).
It’s also worth noting that pointers aren’t a problem in GO because the language is forgiving, allowing the same “.” operator to be used for both (unlike Cpp, which requires “->” for members under pointers), and there’s an automatic conversion between pointers and values in function calls.
Ultimately, as with all cross-OS programming, using native (cpp) components is not recommended because it is difficult to get cpp to compile when shifting between Windows and Unix-based systems (Max/Linux). This is further exacerbated by GO’s friendly nature toward integration with natively compiled libraries, which results in many prominent libraries that use existing open-source cpp assets. (I’m talking to you, Git2GO.)
The first thing you notice when looking at the GO marketplace is that, unlike npm and npmsearch, there are no nice, organized repositories with module ratings and adaptable search engines. To find the best pick, you’d have to search the forums and experiment on your own. Package storage is distributed, with each package being downloadable from its owner’s preferred git repository, which sounds like a neat trick but can lead to missing packages/versions in the future. This mechanism also doesn’t lend itself well to in-company caching, as nexus does for npm.
Tooling: For a decent GO IDE, we recommend VsCode and IntelliJ, both with their respective GO plugins, but there aren’t many others to try, excluding “text editor on steroids” apps like atom and sublime.
Another issue GO has is its debugger; the delve debugger is the only debugger for GO, and it has yet to mature and release version 1.0; there was version 0.10 (which had several annoying bugs), and now with 0.12, and it feels like it has only recently become fully usable, and there is still a long way to go for true maturity.
It takes some practice to learn asynchronous code writing (if you’re not already familiar with JS), but it improves performance, and once you’ve become used to dealing with promises, it looks simple as pie.
Tooling: TypeScript has two good IDEs to pick from VsCode, a free Microsoft OpenSource tool that is also cross-platform, and IntelliJ 2016 or 2017, prior versions were not that good for TS, and VisualStudio 2015 was far too heavy to be of any practical use. Debugging and remote debugging (attaching to processes, etc.) is simple enough, and as the project progresses, you’ll see several useful features for memory and CPU profiling for performance optimizations.
To summarize all that has been said here, here is a nice comparative table for all of the features:
- Easy to learn with familiar syntax
- Time to market is short.
- Full Stack
- Marketplace & modules
- Maturity of the debugger/profiler
- Installation of the framework
- Disk-based JS source
- Compiled binaries on all platforms
- Portable and no framework
- Parallel model built-in
- Performance: GC and native code optimizations
- With native code integrates
- Fewer modules online
- Package search & management
- Higher performance level
- JSON parsing into multiple sorts
Both languages are cross-platform, quick to compile, and have a thriving community, but they are oriented differently. One could even argue that they are complementary: by using NodeTS for the majority of your services, you can get up and running quickly, with access to all of the npm modules, easy JSON parsing, and loose typing that makes server writing a breeze, and by using GO for client-side distributable components, image thumbnailing, video encoding, and all complex data conversions, you can build a system that is the best of both worlds. The polyglot environment afforded by the microservices architecture enables all of this.