Hacker News new | past | comments | ask | show | jobs | submit login

I can attest that full stack (server-browser) Clojure code sharing works very-very smoothly. I've been developing web applications like that for some time now, and apart from less context swithing (because it's the same language on both sides), sizeable parts of the code are cross-compiled to run both on the browser and the JVM with very little or no extra effort.

Example 1: I'm using Clojure's Spec library for validation. There is code that is used on the browser to validate the input that users enter into forms, and the same exact code is used on the HTTP endpoints that are called when the user attempts to submit the form.

Example 2: I'm using the Tongue library to provide client-side translations of the whole UI, but the same data files and library are used in some cases on the server to generate files that contain translated strings.

Example 3: The web UI logic is written using pure data manipulation (thank the Re-frame library for that) and because of that we are able to unit test it on the JVM without having to go through the complecity of launching and driving a browser on our CI server.




Thank you so much for the response!

Number 3 has me totally stoked; since that's incredibly valuable-- or like a dream to me to be honest, could you speak more about how that works? Is it just from using re-frame (which I'm looking at as I write this)? Is it able to test for visual regressions because of the pure-data UI? Or like how have you found that testing functionality in practice has it been saving y'all a lot of bugs and headaches you think?


The way Re-frame works, almost all of your application logic is represented with immutable tuples and maps (called "events" in Re-frame jargon). The parts that can't be represented this way, i.e. need to access the DOM, are moved to the edges of the codebase and are called "effects" and "coeffects". In practice, 80-90% of your application code can be represented as events, while the remainder becomes effects and coeffects. Your application logic is effectively a finite state machine and you can unit test all of it.

The visual part of Re-frame is handled by reagent, which is a minimalist React wrapper that represents React components as pure functions, JSX as built-in Clojure data structures literals (hiccup), and state transformations using Clojure's idiomatic atom data structure. Re-frame builds on top of this base, by enforcing that a single atom (called db) holds all of the state and providing a DSL to create cursors into parts of it.

Like most things in Clojure, Re-frame's initial setup is not a straitjacket and you can swap out the state atom with e.g. an in-memory datalog database using posh/re-posh and make the data retrieval completely declarative too.


Agreed... would love to hear more about this as well....


Check out my reply to rubyn00bie.


Much of the client-side code is about manipulating the DOM. Such code must assume the DOM-API exists. So such code can not run on the server unless there is some kind of ducky DOM environment there as well. And since client-side relies much on destructively manipulating the DOM, how can such code be tested on the immutable clojure server?

> sizeable parts of the code are cross-compiled to run both on the browser

But not all, right? I think the challenge would be knowing which parts can run on both the client and server, so you can know which parts can be moved between client and server.

But code is typically intended to run on either the server, or the browser. What would be the practical benefit of moving code between those environments?

I have not used Clojure so I'm asking because I have a similar circumstance with Node.js on the server, and DOM-manipulating JavaScript on the browsers, and its not easy to move code between those environments, and secondly, I don't much see the need for doing so. Naturally testing everything on the server would be nice, but I'm not sure how my DOM-manipulating client-code can be tested on the server.


I did a project where we used ClojureScript both on the server and the client. The server ran on Node.js and so most libraries could be used on both the server and client. We used reagent to render our app which made it possible to use reacts render DOM to string functionality.

Essentially the app was developed as an isometric app, and we had some additional stuff in the server part of the application.

While running ClojureScript serverside might not be everyone's cup of tea, it worked well for us.


> Much of the client-side code is about manipulating the DOM. Such code must assume the DOM-API exists. So such code can not run on the server unless there is some kind of ducky DOM environment there as well. And since client-side relies much on destructively manipulating the DOM, how can such code be tested on the immutable clojure server?

The same way as it's done in React. Think of a client app as a loop reacting to user /network events and turning state into html. The same way it's done on server.


Precisely. There's a lot of (___domain) data manipulation before it gets to the DOM, and that's where cross-platform clojure (CLJC) excels.


> Think of a client app as a loop reacting to user /network events and turning state into html.

Then who, which part of the code, inserts that HTML into the DOM? Is that done by user-code or some library (when using Clojure)?


There is a library called reagent which is a wrapper for React, check it out: https://reagent-project.github.io/

It uses a the same data format as hiccup template library which can be used on server side - https://github.com/weavejester/hiccup

That's why the same code can be used on client and server. The simplicity of the process (uses pure functions to turn immutable data structures to html) means that it can be also easily unit tested.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: