Tuesday, January 13, 2015

The Tower of Babel

Over the years I dived into more languages than I probably should - a quick count reveals over 20 of them. Looking back seven of them were worth the time I spent. Those were the mind benders, total paradigm switchers that gave me a new perspective on the software I wrote. The rest was just slight alterations to things I already saw in other languages with some syntactic sugar sprinkled on top.

Looking at the past I wish I had focused on three of them instead. This post outlines the mistakes I made. I will also outline how & why intend to move forward accounting for the changes in the development landscape.


Early beginnings


Like most people I started with C. Back then my understanding of programming and the language was so shallow that basic tasks posed a significant challenge. The biggest problem I perceive now while looking back was language hopping. It was so easy to get side tracked into other languages that I didn't commit enough time to really grok C.

I made a lot of large mistakes back then:
  • Jumping around between languages
  • Thinking I couldn't grasp something
  • Jumping from one tutorial to another, and another, and another
  • I wish I started learning algorithms & data structures earlier
  • I wish I took time to dive deep instead of rushing to getting something working
My breaking point happened when I got a job in social assistance - it was mostly sitting at a desk and distributing food supplies. This left me with most of the day unfilled with errands and a PC in front of me. I installed Perl on it and started learning, digging deep into every bit of the language.
  • Learning how the interpreter works
  • Reading the perldoc for every module I used, every function I called
  • Writing small scripts to help with my then daily tasks
  • Writing code every day, even for stupid one off tasks or things I wanted to try
Now that I look at it that was one of the best decisions in my career. Perl became my go to language back then. Three months later I got my first job as a Perl programmer - mostly doing web interfaces, marketing mailers & web scrapers. Having learned Perl to the level when the language itself wasn't getting in my way it was far easier to grasp additional concepts:
  • Programming paradigms
  • Algorithms & data structures
  • Abstraction
  • Documentation & good practices (version control, testing etc.)
This was a major stepping stone for me. Picking up any other programming language, framework was a breeze since then. I worked at a corporation doing Oracle PL/SQL for seven years. I programmed in Ada, Ruby, Perl, Python & JavaScript professionally in long term employment. I did contract work for C, C++, Java. I played with Common Lisp, Scheme, Prolog, Erlang & Smalltalk (mostly when I was hospitalized for a long period of time) and now I'm working with a start-up I co-founded where I'm doing Python, Ruby, Javascript, C, Go and recently some Dart.

That all sounds nice, but it wasn't unicorns & rainbows all the way. My first jump from Perl started with Ruby. The move was initiated by my employer at that time. The language felt similar to Perl, I even did an open source project with a friend in it. It felt like a nice step-up from Perl and it did receive a portion of attention from me. Time passed on, and Python was creeping up more & more often. I tried it from time to time and was always surprised how clean & concise the code I wrote compared to my old Perl & Ruby code. That's the point where I made my second biggest mistake. I continiued to write in Python, mostly ditching all the knowledge I accumullated about Perl & Ruby without giving the same amount of time for *properly* learning Python as I went along.

This resulted in watered down understanding of both Python & Ruby. I shipped a lot of applications written in them but they always felt like sub-par solutions. What I should have done back then was settling on Python and really diving into it like I did with Perl.

Jack of all trades


Master of none. That's the best summary I can give for what happened next. I spent tons of time jumping between languages. None of them received so much attention as I gave to Perl when I first commited to learning it really well. Like I mentioned in the intro to this post. I don't regret spending time on seven of them. Here they are in pseudo-random order:
  • Factor
  • Lisp
  • Prolog
  • Smalltalk
  • Erlang
  • Haskell
  • C
Don't get the wrong impression. Even though I spent enough time to grok the base values that all of the above languages provide. I was no where proficient enough in any of them to engage them in my current work. The broad overview they gave me allowed me to realize that I'm really interested in backend software development. Think servers & services vs desktop or web applications.

What I think I should have done, was going through the seven languages listed above to get a broader understanding of the field. Which thankfully I did. What I would change now is the next step. Instead of branching out into more dialetcs and even more esoteric languages - I should have focused on three of them:
  • C
  • Python
  • JavaScript
C is the lingua franca of current software development. No matter in which language you program in, no matter the operating system. You will hit C sooner or later. The years I spent across many obscure languages would bring back more significant return of investment if I only focused on C during that time. Spending more time with C would enable me to tackle on more interesting back-end software.

Python served me well for years and does to this very day. I still think I'm not versed enough with it to be really happy with the software I deliver in the language. Sticking to it seriously would nicely cover the medium spectrum, prototyping, web back-ends & gluing systems together.

JavaScript - there is no going back from the web. Sooner or later you will have to ship something that's mostly consumed from a web browser. If a significant chunk of my time was spent on learning JavaScript years ago - my life would be
easier right now.

Going forward


I'm now focusing on three specific languages. C, Go & Dart. You might notice a pattern there. Something low-level, something in the middle of the stack and a frontend language.

C
The language is hard wired into every platform you might want to develop for. It's also the main development language for OpenBSD so I am personally motivated to understand it deeply in order for being able to contribute back to the project.

Go
I really love Go. It's simple, has amazing tooling and really delivers for back-end software development. I'll cover some of the things I like about Go further in the article.

Dart
Web is here to stay and most of us will have to be able to ship on that platform. Given the choice between Dart and JavaScript - I'll pick Dart without a moment of pause. I still see some issues with the language - mostly not in the areas that people typically point out (no, not browser adoption).

The above trio is my full stack bet for the foreseeable future. I prefer to master them and pick the best one for the job at hand instead of being a jack of all trades like I did before. Yes, Rust is tempting and I spent some time with it. It just doesn't fit the types of applications I'm mostly involved with.

In my humble opinion Go & Dart being young languages deserve some early adopter feedback. So here it is.

What did Go get right?


I'm mostly impressed by Go. The language is simple, expressive enough to not get into your way most of the time and has amazing tooling. I'll mostly focus on the tooling and the ecosystem around the language.

$GOPATH

I think $GOPATH is crucial to the adoption rates Go is currently seeing. I took the Perl PR-challenge for 2015 and it only reminded me how much building things from CPAN sucks - yes, even with perlbrew. Having a simple way to say 'this is the "world"' to the Go toolchain allows for far less frustration. It's baked in, expected and respected by the Go ecosystem.

go fixme

Good languages are rarely stale. Lisp evolves all the time but how do you evolve a language and it's API without the lisp DNA backed into the core? Tooling! If you have a tool that allows backwards incompatible changes while still allowing your users to run a single command to migrate into your new design - purely a win-win situation.

Standard library

I won't go into details there. Suffice to say that they are run in production on heavy traffic sites. I also love the fact that it's pure Go. No FFI bindings to established libraries/apps for core modules. When I deploy an HTTP golang server I know that:
  • It will handle a significant load
  • I will be able to debug it as it's pure Go
It also means that I will have to spend less time fighting with the toolchain in order to get external dependencies pulled in and in the expected places.

Cross compilation


There was a time at Koparo where we had to deploy Ada code to ARMv7 devices. The Ada code wasn't the nicest to deploy out to the defices to say the least. Go literally saved our hides back then. The goxc tools produces nice, statically compiled binaries that ran without issues on the tablets we shipped.

We had to port the Ada compiler to that platform - go back then was a 'might as well try it out' approach that happened to be widely successful and amazingly fun to code. Seeing Jenkins spitting out archives for 20 platform/arch combinations was amazing considering the amount of work it took to get to that point.

go get


Seriously, most languages could take a page from Go here. Combined with $GOPATH, the ability to install any modules posted to github, bitbucket or any hg/git repository is a great step forward compared to centralised library archives that ship with other languages.

pure go


I like the fact that the language is dog fooded. Sure, pushing for the standard library to be pure Go, or even rewriting the compiler & linker itself in Go might be a step to far - but I personally love it and take it as a solid committment
to the language development itself. I think solid languages have accompanying large products written in them. I think a lot of people would take Rust for example a lot less seriously if it wasn't for the fact that Mozilla is dog fooding it by implementing Servo along side the language itself.

go is simple


Go is a small language, it's closer to C than C++ and I really love this. I see myself reaching for Go in situations where I previously picked up Python. This time around I am devoted into spending some serious time in understanding all the quirks of the language on a higher level then just being proficient at it.

I could go on with this list almost ad infinitum. There's really not much wrong that I see with the language itself for the tasks I intend to use it for.

Why I still see warts in Dart?


I really like Dart. JavaScript doesn't even come close in comparison but I still see some issues with the tooling around Dart. This is really surprising considering that the same company that spawned Go is behind the language. I would really wish for the teams to share their discoveries more. Maybe they do - I am just hoping that it will become more apparent over time.

Dart really feels tied down to Eclipse and Chrome. The build instructions for the platform pull down both of those behemoths. The dart:html & dart:io library split up also show how much the language is tied down to the browser - to the point that some libraries have incompatible interfaces (websockets). I think this should be more unified in the future and more transparent for programmers.

To this day, the only code coverage tool I found for Dart is Dartium based. This is a hell to integrate with any CI toolchain. I don't care for the nice polymer UI - I want a programatically parsable coverage of my code base.

Going forward


Valve has the notion of the T shaped skill set. When one should obtain broad knowledge in several skills and deep insight into one area.I personally would like to advertise the M shape. When you try to go deep on each end of the spectrum (low-level, back-end, front-end) with a wide overview of the field. This is how I intend to move forward.