Aside - about us: Telia Norge is Norway's second largest mobile operator. Our team is responsible for serving its customers who want to buy subscriptions or hardware (phones, tablets, routers, and accessories) without attending a physical shop.
Updated on Jan 9th - added "easier to get help", improved wording
Three years ago, a small team of experienced developers with an agile and rebellious mindset has been hired for an experiment. The hypothesis was that such a team, sitting together with the business, could increase conversion rates and profitability of the company webshop by enabling rapid development and implementation of business ideas/hypotheses/experiments, tailoring the webshop for what customers needed and wanted. Replacing a webshop from scratch is no simple task but we proceeded one page at a time and the experiment concluded as a glaring success earlier than planned, turning over to a regular product development. A year and something later, we could finally pull the plug on the old webshop.
Fast forward to the present. We now have a full-featured, mature webshop that has been recently evaluated as the third best customer-oriented webshop in Norway (the first place being taken by the only alcohol-selling state company, Vinmonopolet). There is a never-ending stream of work to be done to improve the customer experience, cleanup aged code, and support new business and marketing ideas but we are quite happy with what we have.
It has been now decided to give some love also to our long sidelined business customers and create a dedicated webshop tuned to their needs. The webshops for end-customers (B2C) and businesses and organizations (B2B) are likely to differ significantly so it makes sense to start the new webshop from scratch, while finding ways of reusing what makes sense to reuse (though beware the economics of reuse). When starting a project from scratch, why not also take a (careful) look at the technologies invovled?
Introducing a new technology is obviously a very serious decision, with a non-negligible cost. Yet the gain is sometimes worth it. Let's look at our evaluation of ES6 on Node / browser vs. Clojure and ClojureScript. We want to use the (almost) same language on frontend and backend as we have a positive experience with that from the current project. And we prefer Clojure on JVM over ClojureScript on Node because it is more mature and we prefer the JVM.
Let's look first at a brief overview of the pros and cons, ordered by importance:
- economy (and fun)
- powerful language - immutable data and data manipulation library, macros, much more "good parts" than "bad parts", less code - fewer bugs
- easier to get help
- learning curve (language, tools, best practices)
- setup from scratch
- Dev Tools for React/Redux more mature
Pros & cons in detail
Productivity was our absolute #1 reason for selecting Clojure(Script). We have been sold on the language since we have seen Bruce Hauman's Interactive programming Flappy Bird in ClojureScript years ago. Clojure(Script) gives you a REPL connected to your live application so that you can run code in its context, against its current state, and develop the application as it is running. You can continually evaluate snippets of code as you develop it, just one shortcut away from a feedback on the code you have just modified. I missed that terribly in Node, having to wait for babel to transpile the code and the application to restart and re-fetch the data it needed, providing feedback loop of 10-20 sec at minimum. (We were on our way to cutting that to 1 or few seconds but still it wouldn't be instant - and the application would still lose all local state at every code change.)
Economy (and fun) There are very few Clojure jobs in Oslo yet the Clojure meetups are packed by tens of passionate developers. By using Clojure we ensure that people will stay longer on the team because they haven't that many places to go and because they will have fun working with it. Fun is an underrated aspect. A developer that deeply enjoys working with the language, technology, and ecosystem he or she uses at work is happy and thus more productive. He or she is more likely to put in an extra effort, and will probably brag about it, thus attracting more talent. And we get to keep the developer or two that are always looking for an opportunity where they could use Clojure at work.
JVM Personally, I believe that JVM has superior monitoring and observability capabilities to Node, though I am obviously biased by me experience. So I prefer to have that on the server-side.
Setup from scratch - it will be necessary to set up all integration and plumbing (error reporting, logging, metrics, etc.) anew, while we already have these concerns solved in our current Node.js setup. That is unfortunate, but it is just a one-time, and hopefully relatively low cost. And there are typically quite mature and high-quality libraries.
Aside: What makes the JS -> Clj transition easier
- We rarely use a debugger for Node so we won't miss it. (Though e.g. Cursive's debugger is available and possibly as good as Node's?)
- JS is dynamically typed so that is nothing new to us.
- We already structure code in modules with pure function, using very little object-oriented programming.
- We are already used to destructuring from ES6.
Our experiences so far
- Hot reloading works AND preserves state
- You can bring the app into any desired state easily from the REPL without clicking around
- You can interact with and explore the live app in its current state from the REPL
- We get useful warnings from re-frame when we are missing a handler or a query
- See also our Experience: Awesome productivity with ClojureScript's REPL
- Redux DevTools are better; in re-frisk we could only see the current, not past states (NOTE: That has been fixed in the latest version of re-frisk)
- Errors in the browser are often more difficult to troubleshoot (despite working source maps ;)). Positive: it often names the failing component.
Our team is in a unique position as we have multiple people - possibly 100% of the team - that have Clojure and/or ClojureScript experience. Therefore it makes sense to leverage the increased productivity of Clojure(Script). At the same time, the developers will be more happy, work harder, and less likely to leave. And we might have a unique opportunity to overcome our chronic hiring challenges by offering something few others do.
So far, the past few weeks, has our experience been very positive.
Update: You can read about our experiences with hiring in Experience Report: Hiring for Clojure(Script) is Easy
Appendix: Our stack
We have also considered Om Next, as it is nicely "decomplected," has nice features such as undo and optimistic changes, and supports server-side rendering natively. But it is more verbose (you need to define a class with a
render function) and has steeper learning curve and is thus more difficult to "sell". (I would actually consider Falcro instead; it provides less freedom but is easier to set up and provides some features Om Next cannot.)
(You might want to read other posts from our rebellious product development series)