2016-02-21

The story so far: from JavaScript to PureScript

I took my first steps in the JavaScript world about 5 years ago. Since then, I've had some great times with the language! I made a whole bunch of apps, in a whole bunch of frameworks but always tried to make every project better than the previous one. This has led me on a rollercoaster of many different libraries, frameworks and tools. In this post I'd like to summarize how my personal standards for software development tools came to be, and why PureScript scores so well against those standards.

The JavaScript Ecosystem

About 5 years ago, I was asked to write a full application from scratch. Until then I had worked on legacy systems in the financial sector. My client wanted this app to be an administrative interface to their data, but also wanted a customer facing component. I was NOT looking forward to making a network of distributed installed native applications, so I ended up making an HTML5 Single Page Application with Backbone.js and Ruby on Rails. The decision to make an SPA ended up being the right choice. Both my client and its customers were very happy with the approachability and instant access of the app.

The JavaScript-driven web was, and still is, the only platform that can offer this kind of zero-install software and discoverability. For me, it really is the best way to present software to end users. The reach, discoverability and zero-install philosophy of JavaScript is unparalleled. Nowadays, you can even build your whole software stack in JavaScript. It reaches from DB's and backends to frontends and mobile apps. There is a huge community constantly building and experimenting. Tech giants are funneling huge amounts of resources into making the JavaScript VM's ever faster and more feature-rich.

Takeaway 1: JavaScript as a platform and an ecosystem is pretty amazing.

The JavaScript language

Unfortunately, building this application was often very frustrating. Writing JavaScript felt so extremely brittle. I just slapped some code into a text editor and crossed my fingers that everything would be fine at runtime. After a few rounds of going back and forth between my client's features and the codebase, the effort to manually keep all my code consistent spiraled out of control. I had to keep so much stuff in my head at all times, I often felt depressed after a long night of coding. I write JavaScript for my day job everyday and it gets better, but I never feel writing JavaScript is easy or relaxing.

People often pick on JavaScript's rough edges. Stuff like {} + {} being NaN may be fun to shock people on Twitter with, but in practice it's rarely a problem. For me, the real problems are dynamic typing, runtime code introspection (eg: Function::toString), runtime code evaluation, mutability by default, implicit type coercion, etc. Some people love JavaScript for this dynamism, but it is not for me. It stresses me out. I need guidance and help and I'm looking everywhere to find it.

One of my music teachers once told me that when improvising, constraints make you more creative. This seems counter-intuitive: How can you be more creative when you're allowed to do less? Yet it works! It forces you to come up with radically new approaches. Things that you wouldn't think about if you were allowed to use everything you were using before. I feel the same way about making software: Constraining yourself (by using a type system or adhering to purity) seems harder at first, but your inherent creativity will lead you to new and sometimes better ways of making programs, within that safety net.

Takeaway 2: JavaScript is really hard to write applications in. Any kind of help we can get is more than welcome!

Magic

On the server side, I *hated* working with Ruby On Rails. I managed to coerce it to spit out what I wanted it to, but I felt and still feel the huge amount of magic, configuration and conventions coupled with zero help from any kind of static analysis/compiler made the experience more like chanting random spells out of an old spellbook than software engineering. I never doubted that if somebody knew every spell in the book they'd be a pretty badass wizard, it just wasn't the way I wanted to go on writing programs.

Many developers seem to love magic: "I type two lines of code here and my app now has oAuth authentication, sweet!". That is not me. I hate magic. I want to know how stuff works, so I can understand how my *complete* app works, at least at a conceptual level. This might make me slower at certain tasks than some programmers, but I'm fine with that. Trading this initial speedup for a better understanding of my app is worth it to me.

Takeaway 3: I don't want magic in my code. Explicit is better than implicit.

Functional Programming

After finishing that app, I couldn't believe this was how modern software engineering worked. I knew I needed knowledge and experience, so I immersed myself into a whole bunch of different frameworks, libraries, tools, languages, ideologies, paradigms, you name it, to learn whatever I could about making *good apps*. I started out with familiar languages like Ruby, Java, Perl, ventured on into C# and Clojure and ended up at Haskell and PureScript.

My introduction to PureScript and Haskell came in the form of PureScript by Example. After a deep dive into this amazing book, I started to see the value of writing complete programs with functions. Haskell and PureScript are in many ways very similar, so concepts can often be translated one-to-one.

As I read more and more about FP and PureScript/Haskell, I came across "composition". To make complete programs with functions, composition is essential. For years I never understood what composition meant, but somehow it always felt important. Functional programmers LOVE to use this word. I heard FP celebs like Bodil Stokke, Bartosz Milewski and Erik Meijer rave about it, but never really understood what they were talking about. It made me feel so stupid. How could I be a real programmer if I couldn't figure out this "essential" part of my job?

After hours and hours of reading Bartosz's blog posts, watching YouTube talks and consciously trying to apply these concepts in my code, it finally clicked. Composition really is the essence of programming. To me, composition means being able to write logic in small and simple functions and using composition (formalized by Category Theory) to cleanly "stitch" these functions into the rest of the application. Since I understood that, I look for it in every part of my software toolkit.

Takeaway 4: Building programs with functions is the way to go for me, and composition is essential to make it work.

PureScript

The journey so far has been interesting. Without further ado, I'd like to introduce PureScript, a language that was created by Phil Freeman and has really come into its own since 2015. I'll try to highlight the features I feel are most important and how they relate to the above:

The JavaScript Ecosystem
PureScript is an AltJS language, meaning a language specifically created to compile to JavaScript. PureScript code can very easily reach out to JavaScript code using its Foreign Function Interface. As such, PureScript keeps the reach, the ecosystem and the community of JavaScript while improving other aspects.

The JavaScript Language
PureScript is heavily inspired by Haskell, but adapted for execution on JavaScript VM's. Like Haskell, PureScript is statically typed using a Hindley-Milner type system that allows for extensive type inference. Immutability is the default. The type system and immutability defaults have, almost paradoxically, freed me from the dynamism of JavaScript. The type system is very expressive and strict, and instills a lot of confidence into code that passes its checks. It doesn't replace testing, but in my experience it has made my testing efforts a lot more economical: Any interface requirements are always enforced by the type system. These interface tests take up a lot of my time when writing unit tests in JavaScript. And as you gain more experience, you realize there is a lot you can have the typechecker enforce for you!

Magic
What's in a name: PureScript is "pure", which in this context means that any side-effects in your code need to be expressed in the type signatures of your functions. Haskell also has this property, but PureScript demands you to be more granular: Where a function reading a file as a String in Haskell could have a type signature of "String -> IO String", in PureScript the equivalent type signature would be "forall eff. String -> Eff (fs :: FS | eff) String". A few more words that you probably don't understand at first, but it specifies that this function is not pure. It relies on the file system to produce a String, but that's also the only impure thing this function does.

This purity goes a long way to avoid "magic" making its entrance into your code. Any side effects need to be explicitly expressed in the type system, so you have a much better idea of what a certain function does just by looking at its signature.

Functional Programming
PureScript's a functional programming language, strongly emphasizing functions as the basic building blocks for your applications. Composition is at the core of many PureScript/Haskell concepts and libraries. If you're really interested in composition, studying Category Theory is a good idea. Category Theory is described as "formalized composition", meaning it talks about composition in its purest form. If you're interested, Bartosz Milewksi's blog posts come with my highest recommendations! The subject of Category Theory doesn't exactly make for an easy read, but Bartosz's posts are the best ones I've found so far.

This is obviously not a complete view of the PureScript language. A good starting point is www.purescript.org and Phil Freeman's PureScript by Example.

While writing this post I realized there's a lot more I wanted to say, but I tried to keep this one as short as I could. Stay tuned for more Web and Purescript articles!