30 March 2014

AngularDart: The future of AngularJS?

The AngularJS team have been working on a port to Dart called, naturally, AngularDart.
They've taken the opportunity to completely rewrite Angular, adding features and patterns which feel quite natural when written in Dart.
At ng-conf 2014, they talked about their intention to port these new features back into AngularJS as part of version 2.0.  So I've been curious to take a look at AngularDart as a sneak peek into the future of AngularJS.

What's Dart?

Dart is an open source language, backed by Google (In the same way Go is), which is designed to replace Javascript as the programming language for web browsers.  It has it's own VM called Dartium, similar to V8 for Javascript, and I believe has some of the original V8 developers working on it.

But since the only browser which comes with Dartium is a special build of Chromium made specifically for Dart development, the Dart SDK comes with dart2js: A transpiler that produces Javascript which can be used in any browser that supports ECMAScript 5.

And the performance from what dart2js produces is fairly impressive.  Though one should always take benchmarks with a grain of salt.

What makes Dart different from any other modern programming language?


There are more transpilers to Javascript than you can poke a stick at.

I think the answer is about the original purpose of the language.  The purpose of Dart was to create a new language for web browsers, which requires it to have a resemblance to Javascript, so that it can interoperate with it.  This is different from, say, Clojure which wasn't written specifically so it could work with Javascript; That was implemented later as ClojureScript.

CoffeeScript is probably the closest example to what Dart is trying to do.  The difference is that CoffeeScript's purpose was always to be compiled down to Javascript.  It was never intended to completely replace Javascript, just to smooth out it's flaws.

Dart also comes with it's own tools.  As well as the dart2js transpiler, you've got pub for package management (think npm and bower), dartanalyzer for linting, docgen for documentation generation, and dartfmt for code formatting.  I'm a big fan of platform enforced formatting.  It takes the decision, and therefore the argument, as far away from me as humanly possible.

First look at AngularDart

"Hello Dart"


The Dart SDK comes with Dart Editor, a customised Eclipse IDE.  The welcome page includes a link for an AngularDart sample (which you can find the source for at github.com/angular/angular.dart), but it just wouldn't be as fun to have everything pre-done for us... well, not the first time, at least.

Go "File -> New Application", pick "Web application" and give it a name (I went with 'intro').  You'll be given some basic boilerplate: a ".dart", ".css", and ".html file, and some files used by 'pub' for package management.  Click "Run" (the green 'play' button) to spin up the application in Dartium.



What you should see is a simple page with the words "Click Me!" which reverse themselves when clicked.
The code is pretty self-explanatory.  It uses "querySelector()" to pick the element, set the text, then add an event listener which reverses the text.  Next we'll change it to use AngularDart instead of the core library.

"Hello AngularDart"


First thing we need is to install the AngularDart package using "pub".
Open up the "pubspec.yaml" file.  You should see an existing "browser: any" dependency.  This means the application depends upon any (ie. latest stable) version of the "browser" package, which is a library for applications that run in a browser, as opposed to using the "io" package if you wanted to run it as a standalone application.  Add "angular: any" to the dependencies and then run "pub get".

Back to the code.
First, lets import AngularDart and bootstrap it:

If everything has gone fine, this should have zero effect on your application. But if you start getting "The built-in library 'dart:json' is not available on Dartium.", run "pub upgrade" to fix it. It means one of the dependencies is still trying to use "dart:json" instead of "dart:convert".

Now we want to replace that click event listener with a directive.  Directives in AngularDart are given a CSS selector, rather than a name plus a type restriction.  However that doesn't mean they support any kind of CSS selector.  You're generally restricted to an attribute or element name.  So we want to change the "#sample_text_id" in the HTML to "[sample-text-id]", since we can't use the 'id' attribute:

Now to write our directive.

Directives are structured differently in AngularDart.  Instead of POJ objects, they're classes with an "@NgDirective" annotation.  Annotations play a big part in AngularDart, and are likely going to do the same for AngularJS 2.0 (Which is causing some contention since annotations aren't part of the ES6 spec, but is supported by Traceur).

Another big difference with AngularDart directives is that you don't use a name and a "restrict" property to decide what elements or attributes they get triggered by.  Instead you add a "selector" with a CSS selector to the annotation.

And last of all we need to make sure the directive gets included in the application bootstrap process. We do this by setting our new "ReverseClickDirective" class as a type on a new module, which gets passed into the "ngBootstrap()" method call.  I'll go into the Module class a bit more later.

All I've done here is a bad recreation of "ng-click", but it gives you an idea of how different AngularDart is compared to AngularJS v1.*, and how different AngularJS v2.* is likely to look.

In depth AngularDart

So you think "hmm, that's some what interesting.  Where should I go from here?".
A wise man once said "Luke, read the source".
The documentation for AngularDart is pretty sparse right now (understandably, since it's still in beta). So your best bet is to go straight to the source code, most of which is pretty well documented with inline comments; especially the public API.

Dependency Injection


In AngularDart, the DI framework has been separated from Angular into it's own package.  But it's still reference quite heavily in the Angular code, so you'll need to understand the DI framework to follow the AngularDart source code.  Remember the "Module" class with it's "type" method that was passed to the "ngBootstrap" method?  That was from the DI package, not from Angular.

Lets start with the Module class because it's really the most important class.  Open up "packages/di/module.dart".  Remember the "value()", "factory()", "service()", "constant()" and "provider()" module methods in AngularJS?  Here they are again, but instead you have:

  • value(Type id, value, {Type withAnnotation, Visibility visibility})
    The "value()" you know and love, but with a twist.
    Instead of "id" being a string, it's a Type (ie. class).  This makes perfect sense in Dart because it supports an (optional) type checking system with classes.
    However, if you're not dealing with a class or you're dealing with multiple instances of the same class you can use annotations, combined with the "withAnnotation" parameter.

    The "visibility" parameter is a function which takes 2 injectors, the requesting and the defining, and returns whether or not the requesting injector has visibility of the instance created by the defining injector.  This is a new DI concept for Angular which we haven't seen in AngularJS v1.*, but was hinted at by Vojta Jina in this talk at ng-conf.  This idea of multiple injectors which can share, or not share, certain injectables is pretty cool.
  • type(Type id, {Type withAnnotation, Type implementedBy, Visibility visibility})
    We've seen type before when we declared our directive class during bootstrap.  It's pretty much what you would expect - give it a class, and expect to get an instance of that class on injection.
    As an added bonus, you can also specify an "implementedBy" subclass to use when the "id" class is required.
  • factory(Type id, FactoryFn factoryFn, {Type withAnnotation, Visibility visibility})
    If you're not a fan of "new", you can use a factory function instead.

    A "FactoryFn" accepts an injector as a parameter, for loading dependencies, and returns the injectable value.
  • install(Module module)
    Used to extend an existing module.
What about "constant()" and "provider()"?
AngularDart has taken the whole "config() phase vs run() phase" concept and thrown it away, making those methods redundant.  If you really need to perform extra configuration on your modules before the application starts running, then you should do it before calling "ngBootstrap()".

Okay, that handles registering injectables.  But how do I declare dependencies?
"factory()" already has this handled because it gets an instance of the injector.  So it just needs to call "injector.get(MyDependency)", and away it goes.
What about "type()"?  Well that's the beauty of a static type system.  The DI framework uses reflection to determine the types expected by the class constructor, and injects those in.  Look at this:


That's how the DI framework works. If it's instantiated through the DI framework, then it will attempt to provide all the dependencies required by it's constructor.

Controllers, Filters, and Directives (Oh my?)

The missing methods from our old AngularJS modules are "controller()", "filter()", and "directive()".

The truth is that they've already been covered by "Module.type()" because, to the DI framework, they're just classes.  The way to declare them differently is to use annotations.

Filters use an "@NgFilter(name)" annotation, where the name is how they're named in the template, and expose a "call(input, params...)" method.

Controllers use an "@NgController(selector, publishAs)" annotation, which is actually a subclass of the @NgDirective annotation class.  "selector" is a CSS selector which is used to apply the controller to the HTML view.  And "publishAs" is the name that the controller instance can be referenced as from the template.  Remember the "ng-controller='x as y'" syntax in AngularJS? same thing. Properties from the controller instance are exposed on the view, and any dependencies declared in the constructor are injected in, including Scope for creating watchers and generating events.

I already showed you a basic directive example, but there's a lot more to be learnt.  If you want to go deeper, I suggest doing the same thing as for AngularJS: Look at the builtin directives.  I also suggest looking at the classes for the annotations too.
There's lots of interesting things, like implementing "NgAttachAware" and "NgDetachAware" to run "attach()" and "detach()" methods when scopes are first created and destroyed.

Components?

There is one new feature of AngularDart which I haven't covered which is a 'component'.
AngularDart components are related to web-components and make use of the Shadow DOM feature in modern browsers; Two things which I am not completely familiar with.  So I'm going to leave them alone for now rather than do them a disservice through my own ignorance.

Final Thoughts

First, Dart.  I'm so-so about Dart.
On one hand, trying to replace JavaScript with something more up to date is a noble ambition.
However Dart, and it's sponsor Google, have failed to win the rest of the web over.  The popular vote is in improving Javascript, rather than outright replacing it, through new standards like ES6 and ES7.
What's the best path?  I can't say.  But the writing on the wall tells me the support for Javascript is (strangely) growing, due in no small part to the success stories being heard about NodeJS.

As for AngularDart, the differences from AngularJS seem to depend on 2 main features: static typing with reflection, and annotations.
ES6 will introduce classes, but there's no suggestion that there will be any optional type checking added to go with it.  That means we can't just pass a class or function into the DI framework as they are (at least, not post-minification).  We'll still need that separate list of injectable types, but instead of strings it should be possible to use classes.
Annotations on the other hand aren't mentioned in any of the ES6 specifications at all.  They're an entirely separate feature which just happens to be in Dart and supported by Traceur.  So if AngularJS v2.* does use annotations, we're either going to be forced to use Traceur, regardless of the browser support for ES6, or we'll have to write them by hand:


Doing them by hand isn't so bad, but it does "kill the mood" some what.  The idea is to improve the syntax, but ends up making it worse.

Aside from those 2 worries, I'm quite keen to see what happens with AngularJS v2.*.
Now to get those last few IE8 users to upgrade...

11 March 2014

GopherJS: Go to Javascript Transpiler

In my last entry I talked about the idea of migrating from a legacy platform to a modern platform by implementing the new platform as a reverse proxy.  That way you can keep your existing platform active while gradually migrating over to the new platform with minimal risk; No need to maintain 2 code bases, and no need to keep your new code on the shelf collecting dust until you've finished porting everything else.  Then I demonstrating how you can do this using Go.

Amongst the feedback from the community (For which I say, thank you to everyone who read, shared, and commented.  It was much appreciated.  Let no one doubt how nice the online Go community is) was the question "What about your common libraries?".  It's a good point.  The reverse proxy solves the problem nicely when porting code route by route.  But you're likely to have some common libraries shared across multiple routes.  If you've only migrated some of those routes, you're going to be dual-maintaining both an old and a new version of that library until all your routes have been ported.

Maybe that's okay.  Maybe you're comfortable with the pace of your migration vs the need to make maintenance changes.  But if you're not in that position, you can use a transpiler to convert your code from the new language back to the old one.  For my situation of moving from Javascript to Go, that means using GopherJS.

GopherJS

GopherJS transpiles Go source code to Javascript, which means you can get all the development and build time advantages of Go (eg. Static type checking, built in code coverage tool, etc.) and then run it in a Javascript library like NodeJS or the browser.  The creator, Richard Musiol, has even setup a GopherJS Playground so you can give it a try online and immediately execute the code in your browser.  You can even use AngularJS.  In fact, that's what the playground uses, along with an AngularJS wrapper library, go-angularjs.

Naturally, there are some limitations. Like you can't run anything anything that requires cgo or anything that needs low level access to the OS (unless you build an adapter for NodeJS).  Even so, it's a pretty impressive list of core packages which are compatible.  And don't let the lack of "net/http" or "database/sql" access scare you away - you can still use existing Javascript libraries to fill those gaps, and I'm going to show you how.

Another thing you need to be aware of is that GopherJS produces Javascript suitable for an ECMAScript 5 (or ES5) compliant environment.  So if you're building code for an older Javascript environment, like IE8 or Windows Host Script, you're going to need shims for at least Object.keys(), Object.defineProperty(), Object.getOwnPropertyNames(), and the various Typed Arrays.

And last, you need to be aware that it's not an all access border between Go and Javascript.  If you want to pass a struct with methods from Go, you need to use "js.MakeWrapper()" to make those methods safe.  Similarly, you can't implement Go interfaces with Javascript objects.  You'll need an intermediary that accesses the Javascript object as a "*js.Object".

What does Go look like in Javascript?


First I'm going to show you what Go code looks like as Javascript.  We eventually want to take an existing Javascript library and convert it to Go, so we need to know what changes (if any) we should make to our code before porting it to Go.

You can see I've created a (rather contrived) Go package called 'pet' which defines a simple 'Pet' struct type, and a factory method called 'New()'.  Since 'Pet' includes a method, 'New()' uses 'js.MakeWrapper()' to make the methods safe to use in Javascript.  Then in 'main' I'm importing 'pet' and the 'github.com/gopherjs/gopherjs/js' package, which gives me access to Javascript context objects like the global scope.  So I attach the 'New()' factory under the namespace 'pet'.

Here's the result when built with GopherJS.

1470 LOC and 45kb, uncompressed and unminified.  The bulk of which is the builtin library.
It will only compile what it needs to.  So if you declare types that are never used, they won't show up in the resulting code.  This goes for core packages too.  If I change that code so it requires "fmt", the result explodes to 12845 LOC and 624kb ("fmt" imports a LOT of stuff).

Lets take a look at what the code we wrote looks like:

You can easily recognise the "pet" package from lines 10-36 in that extract. I wouldn't get too worried about what it's doing there. The important thing is that it's there.

One thing I will draw your attention to is our main method, specifically line 41.
It's creating a map and setting the value of "New" to the function "pet.New()". It's then passing that to "go$externalize" which is a helper method GopherJS uses for turning Go types into primitive Javascript types. Take maps as an example. In Javascript, map keys can only be strings. But in Go, they can be anything. So GopherJS uses it's own special "Go$Map()" type internally, and then tries to convert it to a standard Javascript object when passed to "go$externalize".

Then it's assigning our externalised map to "go$global.pet". "go$global" is an internal variable for referencing the global scope object in Javascript. You can see it being declared on line 2. If used in a browser, it will be equivalent to "window". Otherwise, it's whatever the "GLOBAL" variable currently is. If you're using a Javascript runtime that doesn't include either of these, you'll need to manually declare "GLOBAL" yourself.

Porting a Javascript library to Go


Now we've got an idea of what our Go code will look like when it's converted to Javascript, we can start thinking about how we're going to port a part of our Javascript code to Go without breaking the rest of our Javascript code.

Lets say we've got a 'User' model object which uses the global variable 'DB' to make SQL database calls:

Couple of things we know will be different when we convert this to Go.

  1. The method names will start with an uppercase letter, otherwise they won't be exported.
    This isn't idiomatic for Javascript, but that's OK because we're not writing Javacript.  We're writing Go that runs as Javascript.
  2. DB will need to be an interface, with a new function for registering a DB implementation.
    That way we can switch implementations for Go and Javascript.
  3. In Go, "User" will be a type of struct, not a type of function.
    And while we can create methods for type instances, we can't create static methods like "User.new()". They'll need to go into the package namespace.
  4. While it's possible to wraps all "User" objects with "js.MakeWrapper()" so we can access "user.Save()", that means we also have to create getters and setter for the regular properties.  Rather than add the extra boilerplate, "Save()" will be moved to the package namespace and take the "user" as a parameter.

With that in mind, here's what the refactored API looks like:

The main difference is the addition of the "registerDB()" method for registering a DB interface implementation, rather than finding it on the global scope.

Now to the Go code:

The "Save()" method required a "SaveJS()" wrapper to bridge the JS <-> Go barrier for the "user" object, and "RegisterDBJS()" does the same for the database adapter.  You can find the full working code examples at: https://github.com/rolaveric/gopherjs-demo

There you have it: A Javascript library written in Go with only a little tweaking to the original API.
And without compromising on the quality of our Go code either.

Conclusion

GopherJS bridges that gap between Go and Javascript quite nicely without compromising on quality.
There is a cost in the size of the generating code, but lets remember just how little is provided by Javascript's standard library compared to Go's core library.  And once you get past that initial bootstrap, there's definitely no issue with performance.

So if you're looking for a way to port away from Javascript to Go without dual-maintaining libraries, or if you're so enamoured with Go that you can't bare to write Javascript even for the browser, then GopherJS is for you.

UPDATE: GopherJS has matured since I originally wrote this article.  So with Richard Musiol's help, I've updated the examples to be more conscious of the Go <-> JS barriers.  I've also created a github repo with the examples so they can be tested from end to end.

2 March 2014

Wading into Go

I first took notice of Go last year when I read this article about how Iron.io went from 30 servers down to 2 by converting from Ruby to Go.  Since then I keep peeking back at it, reading a bit more doco here, trying out the tour, and eventually attending the local Go meetups.  There I finally got my burst of inspiration to build a proof of concept for replacing an old enterprise backend I work with, built on Classic ASP, with Go.

The experience was quite fascinating for me because my primary language is Javascript, and my experience with modern server-side web frameworks is pretty shallow.  For example, the way I keep thinking of pointers vs values in Go is the same way I think of objects vs strings in Javascript.  The former is mutable, meaning it's possible to get side effects when it gets passed around, and the later is immutable.  It probably oversimplifies the difference, but it works for me.

The Plan

OK.  We're porting a legacy web application to a new platform.  What's the plan?

It'd be naive to say "X is better than Y, therefore we shall port all our Y to X immediately!" and leave it at that.  There's other questions we need to answer:

  • How long will it take?
  • What does all the X you've written do while you're still dependant on Y?
  • What if there's just some things that Y can do which X can't (yet)?

The answers should be:

  • "A long time" cause that's the truth
  • "It gets used in production" because code has no value until it's used, and
  • "Then you keep using Y for those things" because, as they say, "you don't throw out the baby with the bath water".
The plan is to use the new technology as a reverse proxy which, initially, takes all requests and forwards them on to your legacy back end.  Then, over time, you start porting features from the legacy platform to the new one.  If something goes wrong, you can turn off that route handler and let the legacy platform pick it up again.

Doing this in Go is trivial.  The core library already comes with a simple reverse proxy that suits our needs:


The Martini Web Framework

While the Go core library is very complete, especially for the building of web applications, there is still plenty of room to build libraries on top.  For example, while Go comes with the "testing" library and the "go test" and "go cover" commands, there's space for third-party libraries to define their own DSLs for writing tests, such as GoConvey.  In the same vein, there's plenty room for different web frameworks to implement different opinions and architectures.  My personal favourite is Martini.

Martini is a micro-framework, similar to Sinatra and Express.  It doesn't give you bells and whistles to plug into your application (well, not out of the box), but it does give you a simple way to define chains of request handlers (like filters, if you're coming from Java servlets) and pass values to handlers through dependency injection.

You can have common handlers, called middleware, which run against every request, and handlers for routes.  So you can have a common Authentication handler that identifies the user for every request, and then specific Authorization handlers for different routes that make sure the user has the required access before running the final handler.  Here's an example:


Here's what a request to this code looks like, with the flow of control through the request and response:


But how does the Authorization handler know what the result of the Authentication handler was?  That's where Martini's dependency injection comes into play.

It uses Go's reflect package to determine what types a handler is expecting as parameters.  By default it knows about the http.Request and *http.ResponseWriter objects, which is why Martini also works with any handlers designed for http.HandleFunc().

You can add your own injectables or services by calling the MapTo() method on the martini.Context (Another default injectable) for the request.  MapTo() takes a variable and the type that it should be injected for.  You can also use this to wrap existing services, as Martini does with the *http.ResponseWriter.

Impressions of Go

Now that you've got an idea of what I've been working on, here's some of the impressions that Go made on me.

A well stocked box of goodies


Out of the box, Go comes with a standard library to be proud of.  Take for example the fact that it comes with a simple reverse web proxy, ready to go.  It also comes with a set of packages for compression, including gzip, and 11 different packages for encoding, including JSON, XML, and Base64.  Normally I'd expect to go to third-party libraries or roll my own for at least a few of these.  Not in Go.

And let's not forget the 'go' command line tool itself, which can:
  • Build
  • Test
  • Benchmark
  • Calculate code coverage from tests
  • Format code
  • Fix code written for older versions of Go
  • Host a web server for serving code documentation
  • and retrieve dependant packages from Git and Mercurial repositories
The convention of using the repository domain as the package namespace is a great idea which keeps dependency management nice and simple.  The only drawback I've heard is that it doesn't support the ability to set specific revisions as a dependency, which will make it awkward if a third-party package introduces non-backwards compatible changes.  But there are examples of the community stepping up to fill the gap.

Another favourite feature of mine is "go fmt", and the way the formatting conventions are enforced by the compiler.  I am tired of arguments over code formatting, and I'm glad that the creators of Go have cut those arguments off at the knees, saying "This is how it is - deal with it.  Now, back to the show!".

Third-party support isn't perfect, yet


I had one third-party technology requirement for my Go program; It had to support MS SQL, because that's what the legacy platform was using for persistence.

go-wiki's list of supported SQL drivers included an ODBC driver which is cross-platform, using Free TDS for Mac and Linux, so I thought this wouldn't be a problem.  Sure enough, when I first tested it on Windows, everything seemed fine.  Then I did some benchmarks and realised every stored procedure call was taking a lot longer than it should.  When I tried the same calls with an ADODB driver (which I didn't want to use because it only works on Windows), I was getting much better speeds.

I haven't exhausted all my options yet to fix the issue yet.  For example I've only tested it on Windows, and I haven't explored whether connection pooling will help (I'm currently opening and closing a connection on each query).  But it's an unhealthy reminder that there's likely to be issues like this when moving from legacy platforms to something new like Go.  If I were using Postgres or a NoSQL database, there'd be no problem. But I'm not, and so there is.

Types: The good, the bad, and the "what the?"


Go uses strict typing, which can be a bit of a shock coming from a dynamic typing language like Javascript. Most of the time it makes perfect sense and you wouldn't have it any other way.  Here's a few common examples:

The simplest example possible - a function that expects a number rather than, say, a string.

Unlike Java but similar to Scala, Go treats functions as first class.  This means you can pass functions as parameters to other functions, and return them as results.  But you don't want just any old function, you want one which matches your callback schema: message string as a parameter, and an error (if any) as the result.

One thing that's unique to Go is the way it handles interfaces.  They're implemented implicitly.  So an interface becomes a way of saying "I need 'something' which can do X" rather than "I need a Y, which is 'something' that can do X".  Anything can say "I can do X" will be accepted, and can be declared without even know what a "Y" is.

Interfaces also give us a way to cheat the typing system entirely.  An empty interface can be implemented by anything.  So if we have a function which expects an empty interface, we can pass anything to it.  Or we can have a slice (Equivalent of a Javascript Array) of empty interfaces, which can store anything.  But that just means we need to use type assertions when we try to do something with that value, otherwise we could end up trying to get the substring of a number.

Here's an example which did my head in a bit at first.
The Rows.Scan() method in the database/sql package expects a slice of empty interfaces, which are the destination for the values found in the current row.  Empty interfaces can be anything, right?  So a slice of empty interfaces can contain anything.  That makes sense because you could have numbers, strings, dates, etc. all returned in the same row.

The SQL driver I'm currently using returns everything as strings.  So I thought "OK, I can just pass in a slice of strings.  Strings can be empty interfaces, so therefore a slice of strings can be a slice of empty interfaces, right?

Wrong.

It's not the containers that can be anything, it's the contents.  A container for strings and a container for anything are two different things; If I ask for one, I don't expect the other.
In this example of Rows.Scan(), you can get around it by loading a slice of empty interfaces with the pointers from a slice of strings.

Thankfully this example is the exception, not the rule.  And it demonstrates that if the typing system does start to restrict you, there are ways to bend it to your will.  But it's always better to discover a problem at compile time than run time.

New language insecurity


This isn't really related to Go, it just happened to be the unknown language that I was trying.

I found that doing things in Go took 3-4 times longer than it would have done in Javascript.  When working on something in Javascript I would simply plan it out, and then implement it.  In Go I would plan it out, implement half of it, then go back to the plan, then start implementing from scratch, then back to the plan, then redo the original implementation.

This isn't because there's anything wrong with Go or right with Javascript.  It's because I'm experienced with Javascript and inexperienced with Go.  Experience doesn't just bring competence, it also brings confidence. When I was restarting my work in Go, it's not that it wasn't working, it's that I would start second guessing the design.  "Should that have been a type? Or maybe an interface?  Maybe I should just split these into separate packages... or, maybe less packages?".

Sometimes you need to put your head down and say "If it compiles and my tests pass, that's good enough for me!". You can always comes back to it later when you've: a) Got a more experienced Go developer to critique your work, or b) enough hours reading other people's Go code to form your own opinions.

Conclusion

Coming from Javascript world, Go is an intriguing place that I'd like to get to know better.  The core library is very complete and powerful, though somewhat dry at times.  But this allows the community to build on top of it with their own opinions, like how Martini builds on top of net/http, or GoConvey on top of testing.

If you're interested in Go but haven't found the excuse to give it a try, my advice is: Find that excuse. Rewrite something, anything, just to get a taste for it.  If people at your company are dismissive of the idea, then practices a little "Constructive Disobedience" and do it anyway.  "You decide your own level of involvement".