Re-posted from Telia's tech blog.
Aside - about us: Telia Norge is Norway's second largest mobile operator. Our team has spent the past three years with Node.js, React, and (eventually) Redux creating a great webshop (for hardware and subscriptions) to replace an off-the-shelf one, with a great success. Now we set out to make also the lives of our business customers much better - and we picked Clojure and ClojureScript for that.
The short story. I was adding an Ajax call, massaging data into the format it needed, triggering it from the UI, and handling its result or failure - a classical plumbing work. Being able to run any code from my IDE against the live, running application, accessing and changing its state at will, testing tiny code changes - all that resulted in a super quick feedback loop, enabling me to convert quickly on to working code.
One troublesome part of the code was the function formatting the application state into the form that the backend
submit-orderrequired. From a backend error about missing data, I was able to quickly go to running the formatting function against the actual application state, easily comparing the state and formatting output, never leaving my IDE and beloved keyboard shortcuts. As needed, replicating local variables and running parts of the function to zoom in on a particular part, fixing mistakes, and re-running, until all worked.
Another case in point was the display of an error message when the Ajax call failed. As usually, the code did not work at first. Using the REPL, bypassing the UI and browser, I was able to run the "subscription" that should have fetched the error message from the application state and supply it to the Reagent/React component, discovering the wrong data path, and go on to interactively develop the component (watching the magic of the browser updating at the command of my fingers).
connectfunction extracting the relevant part of the state. (Well, I could - but never did - try to use the debugger. Typically I would add a few
console.logto it.) Interactively developing the component would work just as well, as long as I would do something not to loose the state upon reload.
Having direct access to the application state, I was able to effortlessly simulate all the possible cases (resubmission, call in progress, success and error response) and ensure they were correctly handled by the UI.
The React and Redux Dev Tools are very good. Hot code reloading works - when it works. The debugger is your good friend. I have been told that the application should have been able to preserve its state even as the code is hot reloaded, though that has not been my experience. (But that was perhaps because of local component state, not the global app state?) You can simulate the user by sending supported actions from the Redux Dev Tools.
My experience is that the cycle of problem discovery - troubleshooting - fix is much shorter in Clojure and ClojureScript thanks to the REPL. And when you really adopt REPL-driven development, you actually have to deal with troubleshooting problems much less since you produce small, working code changes.
To be frank, there are also some downsides. I will write about the reasons for picking Clojure(Script) and the benefits and drawbacks we have experienced in a future article.