Normally I learn in a very hands on fashion: either on the job or by making up a job and attempting to solve it with a tool I want to learn.

But sometimes I sign up for (mostly online) courses to get a better understanding of a particular topic; here are some that I've taken, in reverse chronological order, along with some notes on what I got out of each.

Functional Programming in Scala (2015)

In my quest to get a better understanding of "what exactly is a monad?", I started working through the exercises in the book Functional Programming in Scala.

I found the book well written and the exercises well put together, but by this point in time I had already written and reviewed a decent amount of functional programming code, read a lot of blog posts, and participated in several workshops. As a result, I didn't feel compelled to finish it, and ended up stopping halfway.

It's difficult to reflect on what I learned from this book specifically vs how much of it was simply the result of it being the nth thing I read on topic X. I do recommend it if your goal is to learn functional programming in Scala specifically, but as of 2019 it seems like Scala is in decline and I hear that Haskell Programming is a better book for learning functional programming by exercise.

Princeton's Algorithms, Parts 1 & 2 (2015)

The study group that I completed Project Odin with (see below) wanted to tackle Robert Sedgewick's Algorithms Part I and Part II courses on Coursera. I had already studied most of the algorithms covered in university, but I figured a refresher couldn't hurt; to make things interesting, I chose to use it as an opportunity to learn Rust, which was pre-1.0 at the time.

Despite thinking that I already knew the material when I started, it ended up being very much worth it to hear many algorithms explained by the man who literally wrote a book on the topic; his visualizations in particular were fantastic.

I also ended up getting a bit of a trial by fire in Rust, as some of the algorithms weren't (at the time at least) easy to express in Rust without dipping into the unsafe keyword. Many of the exercises were also provided with Java scaffolding, so I had to first port over the Java scaffolding into Rust, which was great because I knew Java inside-out - when some code I ported failed to compile, I could focus wholly on understanding the quirks of Rust's type system without worrying that I made a mistake in the implementation.

Additionally, there were a few other developers also not doing the exercises in Java, which lead to a significant focus on confirming the complexity of our implementations by emperical measurement.. and that quickly evolved into a friendly competition to see who could eek the most speed out of their implementation, with parallelism being fair game. That was fun because it was a chance to use Rust's concurrency building blocks, but also because I had profiled and optimized Java code before, yet Rust was a layer closer to the machine: I got a chance to get some experience with valgrind (specifically cachegrind), prof, and friends.

Project Odin's JavaScript track (2014)

I had done Javascript development in earnest at the start of my professional career, but a lot had changed since then. So, I joined a group of developers looking to learn or brush up on their front-end skills by working through Project Odin's JavaScript module, which was a self-paced open source bootcamp (it still is, but has probably changed a lot since 2014).

The content ended up being quite basic for the most part, but the focussed practice helped me get a lot better at throwing together quick JQuery-esque scripts, and the time I had left over plus "everyone needs to present" rule we had meant that I had a lot of opportunities to go deeper, so it was worthwhile.

Erik Meijer's FP101x (2014)

I had done some basic work with Haskell at university, but I took Erik's FP101x on EDX because I wanted to get a better understanding of thinking as a functional programmer, and solving a collection of problems in Haskell got me that (and, unlike several other problem sets, I knew the problems set in this course would not rely on mutable state for efficient implementations). At the time we were also adopting Scala at Atlassian, and conveniently this helped my understanding there too.