Hacker News new | past | comments | ask | show | jobs | submit login
Reactive Clojure: A web language (hyperfiddle.notion.site)
467 points by audionerd 30 days ago | hide | past | favorite | 176 comments



This is not reinvention of PHP as some are commenting. In fact I think this is extremely cool.

If I understand it correctly, it allows you to achieve reactive data flow in a single page app without any boilerplate.

Meaning - you update the database on the server and all the relevant UI(s) will automatically receive the updated data and re-render only the parts of the UI that display that data.

This would require a ton of PHP and Javascript dealing with networking, websockets, routing, serializing data and so on.

Haven't tried it yet, but very curious to see if it works.


The problem with this type of system in my experience is that it’s great until you hit a bug, and then you realize you have no idea what’s going on under all the automagical stuff and you go crazy


How is this different from any other framework? Try fixing a React or Rails bug.

At least their system is only 2k LOC, which will presumably be well documented.


At first glance, this appears to be much more complex. React is a relatively simple DOM diffing library. Rails is a closer comparison, especially with whatever their live-view implementation is. This appears to be doing a lot more than React, at least, including network communication, and database change event propagation. The odds seem much higher that stuff will go wrong, especially under load, and be pretty difficult to reason about.


> At first glance, this appears to be much more complex. React is a relatively simple DOM diffing library.

Their implementation is 2k lines of code. The React repo has 350k lines of code. The Rails repo has 336k lines of code (both of those according to tokei). Of course this includes tests, lots of other stuff, etc. But still, that's two orders of magnitude.


Note that react has a monorepo with a lot of tangentially related packages, such as devtools and alternative renders.


That's true, it's hard to make a fair comparaison between the two.


preact is much simpler than react (~3KB), and whats weird, it's also faster

BTW: code is very easy to read/follow https://github.com/preactjs/preact/


LoC != Complexity. React has one job, and it does it really well, part of that 350k lines of code is a LOT of tests. Just because it has those tests doesn’t mean it’s “much more complex”.

My two cents :)


After a naive removal of the tests (every folder and files that contains tests was deleted), React still has 190k lines of code.

> React has one job, and it does it really well

I'm not sure I agree. It's hard to compare without a minimal copy of React to see how small it can get, but I'm guessing it could be an order of magnitude smaller. For example, React supports different ways of doing things (class components, function compenents, hooks). Backwards compatibility is a great thing, but it's not the same as "having one job and doing it well", it's a different tradeoff. The React team has lots of people that depends on their code, and thus choose stability over being small and nimble. I think that's a responsible choice. But this leads to complexity, and losing the "having one job and doing it well".

As a more general remark, there's a cycle in software. React starts small and nimble, especially compared to the "jQuery behemots of the past". It gets really popular. So people start depending on it. So it grows, and grows, and grows. And then someone else comes out, maybe Photon, maybe Svelte, maybe something else. Compared to React, it's small and nimble. Maybe in 10 years, Photon will be really popular, will be 200k lines of code, and someone will build an alternative because it's too big and complex.

Edit: as a more meta-remark: My message is way longer than yours because I was trying to steelman my argument, and you didn't do the same with yours. Considering you made a small message "defending" React and I did a long one "defending" Photon, I think we already agree about the tradeoffs involved here.


Preact is React without the fluff - https://github.com/preactjs/preact

loc in a node project is hard to judge due to packages and the aforementioned mono repo difference, but the preact functional build artefact is an order of magnitude smaller: 129KiB v 8.2KiB


I’m going to keep scrolling in search of a shorter comment


Why?


Good point I checked and it's nowhere near 350k LOC. React is a monorepo here are some numbers for the main packages, excluding tests:

react = 3k

react-dom = 15k


It absolutely has a strong correlation with complexity.


Clojure tends to be a bit more terse than other languages. 2K of Clojure is a lot of code. Especially if macros get involved. As for the comparisons to React elsewhere; I wonder how much of that is the result of React being battle tested for a long time and expanded, would this still be so short if Facebook was written in it?

I also wouldn’t presume good documentation as a general rule. That’s something that must be proven, not presumed.


I‘d still rather read 2k loc in _any_ language, and undocumented, than 350k loc, perfectly documented.


Sure. But I’d question two things:

1) How often do you actually need to read your framework. I used rails for years and read probably less than 2KLOC out of it, ditto with Java and Spring. Good documentation beats out small code bases.

2) How much of the size difference between these two is down to age and uses? Is React so big because it’s unfocused or poorly written, or is that a consequence of it being used by so many people and projects? If it’s the latter, shouldn’t we expect that this project will end up growing if it got popular, eroding the benefit of its small size.?


> How often do you actually need to read your framework.

This brings us full circle to the question that started this conversation branch:

> it’s great until you hit a bug, and then you realize you have no idea what’s going on under all the automagical stuff

With React and Rails, "hitting a bug" is apparently rare. Maybe we should wait before assuming it will be any different with this Reactive Clojure framework.


In my (quite extensive) experience hitting a bug or another issue with react and rails and when/if the error message and trace are absolute drivel (which happens a lot during normal projects), you usually can find fix by pasting it in Google. In react it usually goes something like: throw everything away yarn/yarn build again and pray for the best by the way.

So I think many people don't need to read anything but just pop into Google read what it is + get the fix.

In smaller frameworks and libraries I am more tempted to just check what the issue is in the source and report a bug if it was not just me being stupid again, but that is also because pasting it in Google might get no results at all.

I remember when just starting out with Rails, my rails colleagues all read the source of everything when there were issues or lack of docs; this was very early on (first public version); now I know no one who does that anymore.

I really would like something that stays small and is around in 10 years and my experience with Clojure is good in that respect. And Haskel projects. Those things that keep growing and keep adding dependencies are nightmares but what can I do.


The question is, are bugs rare in rails because of or in spite of the code size? Obviously more code is more opportunity for mistakes, but more code is also the product of more users and more contributors poring over what’s there.


True With any system


That's true with any system you haven't sufficiently studied.


So yes in a way, but here we're talking about something that synchronises state between a client and DB over http. The possibilities of weird edge cases seem endless :)


So more like Liveview for Phoenix / Elixir is what this kind of sounds like to me, and less so back-end mainly language like PHP.


> Meaning - you update the database on the server and all the relevant UI(s) will automatically receive the updated data and re-render only the parts of the UI that display that data.

> This would require a ton of PHP and Javascript dealing with networking, websockets, routing, serializing data and so on.

I don’t know how it was implemented, but Quora had this back in its early days (~2012). There was some mechanism that "remembered" which table lines were used to generate which UI component, and when that data changed you had a live-reload in your browser. That was really cool to see at the time; I’d love to have more background on its implementation.


> you update the database on the server and all the relevant UI(s) will automatically receive the updated data and re-render only the parts of the UI that display that data.

I really don't like that idea. It seems to me inefficient and error prone.

Let's say you're updating a database. You add some records to one table, and you update some records to some other tables.

If the program automagically updates the UI, then on the first change it will attempt to update the UI (causing lots of processing) , then on the 2nd change to the database it'll update the UI again, and on and on for each change.

Wouldn't it be better to make all your changes to the database then only after that run an updatePage() funiction that updates the web page?


From submission:

"Sounds really slow and chatty right? Actually, NO!

This is not RPC or ORM. The key is to make the language, compiler and runtime in charge of the network, like the JVM owns the heap. Idealized client/server network IO (better than could ever be coded by hand) is an explicit design goal.

How does it work? Functional programming:

- `photon/defn` is a macro that compiles Clojure syntax (s-expressions) to a dataflow signal graph (DAG). - The DAG is lifted and compiled into Missionary reactive signals. Missionary manages reactive execution (incremental maintenance such that a small adjustment to inputs results in a small adjustment to outputs)."


nothing forbids the system to give mechanisms defining rapid sequences of changes, kinda like debounce in js


I think the main risk for this kind of framework is that you spend as much time ironing out these kinds of "edge cases" (debounce, transition states, error states, transactions, authorization, url bar state, scroll bar position, paging, efficient re-renders, etc. etc.), which in practice are crucial to most non-trivial software, as you would have just writing the usual boilerplate and retaining fine-grained control.

It's great that people are innovating and creating new abstractions, and I'm sure there are apps where the tradeoff is worth it (internal CRUD-focused enterprise stuff comes to mind), but my knee-jerk reaction for a large app is that it will make easy things easier and hard things much harder.


I appreciate and have created software that needed to be complex with the associated complex underpinning.

I also have long been looking for a framework that makes easy things easier.


Yes i agree


This is where I'm at with it. "Develop apps like you do now, with a centralized app db, but now the app db (in the browser, most likely a giant Map) is an actual database with a sophisticated query language, an upgrade!"


In this sense it's same as what microsoft is trying to do with Blazor - except they are skipping whole javascript crap and compile to wasm.


Which sounds great until you experience the loading times. Last time I tried it out, the loading times for all the DLLs that a typical application requires was pretty bad. But once it loaded, things were snappy.


I just tried this Blazor demo and its really slow on mobile, even after the noticeable load screen https://www.blazorfluentui.net/calendarPage

Clicking on multiple dates takes time to transition between the two.


> Imagine a programming language runtime whose runtime state (i.e. lexical scope) is partially broadcast over network as it happens, kind of like a remote debugger.

This sounds absolutely terrifying from a security perspective...

What's to stop a malicious client from broadcasting code that deletes my entire database?


> runtime state

> code

Some overlap, but these are essentially two different things.

> What's to stop a malicious client from broadcasting code that deletes my entire database?

Your backend.


Deleting a database is probably a bad example, but my point still stands: even if you are not trasferring code back and forth, runtime state is enough to be a problem.

What if your runtime state includes an `is_authorized` flag or similar? How do you guarantee that this state remains server-side when the entire language conflates server/client side code?

For this to work, there needs to be language-level support for distinguishing untrusted inputs from trusted ones, or else it's a recipe for disaster.


If the compiler is separating server-side code from client-side code, then it's also separating out symbol bindings as well. So it knows where symbols are bound, and where they are referenced, and it can use this to limit information flow.

For example:

    (client
      (let [token (get-client-token)]
        (server
          (let [username (get-username db token)]
            (client
              (dom/p "Hello " username))))))
The compiler can infer that token is defined on the client, then sent to the server, which in turn defines username and sends that back to the client.

It's the same system you'd use in normal server/client architecture, just inlined.


Compile-time macros do indeed seem to be what provides the necessary client/server separation for sensitive data.

That does mean you are trusting the library to implement these macros correctly. In that sense, data security for these symbol bindings is a responsibility of the library, and therefore a risk, as is called out lower on the page.

Once the library is complete however, and a larger part of the community has been able to inspect it, this type of bug should not be an issue. It's one of the most fundamental concerns of the library.


any sort of networking sounds terrifying from a security perspective...

Unfortunately (or fortunately) it's also a corner-stone of computing in general


One thing I admire about the Clojure community is audacious projects like this. While a ton of these seem to run out of steam, they certainly shoot for the stars and tend to come pretty dang close for a while.

For those working in Typescript, Blitz.js seems to do a great job at drastically decreasing the plumbing you have to write to shuttle data between Postgres and React. There’s also a ton of goodies like auth built in. From my first impression it’s the closest the JS community has ever come to a Django, and that’s very high praise in my book.


It's a very impressive project, and something I would definitely try in a greenfield app.

I wish there was somewhere to follow updates that wasn't Twitter though.


Especially for people without Twitter accounts



Interesting, thanks


Sadly the running out of steam effect hits the tooling for the community too. It's really hard to find good, stable clojure tools on the level of those available for Java.


I had another coworker compare Clojure and Java tooling recently. I just don't think it's fair to compare one of the most used languages on the planet to one that is written in the other one. Clojure tooling isn't the best out of some ecosystems I've used, but you can leverage a whole bunch of the Java tools and I certainly have, like stack dump analyzers or profilers, or Maven, etc. Are they perfect for use with Clojure, not always, but things are pretty good IMHO. Cursive is an excellent IDE too, a joy to use with very many bells and whistles and there is also excellent Vim and Emacs support. There are at least 3 build tools that are Clojure-specific (Leiningen, Boot, and deps.edn), or you can integrate with older or other JVM tools pretty easily like Maven. There are multiple testing frameworks, multiple test formatters, and multiple test runners. I could go on, but what specifically do you think is missing or could be better?


Definitely take a look at Cursive, it may be what you're looking for along the lines of stability and out-of-the-box features you'd see in a Java IDE: https://cursive-ide.com/


Or Calva for VS Code.

It's the best dev environment I've used for any language. It's brilliant.


Calva always exploded on me when I tried to set it up on Windows 10. Is it better on a *NIX system?


Never tried it on Windows, but it works pretty well on mac in my experience


I'll try it out on a Linux device, thanks!


it works really fine on Linux.


I find it works great on linux.

On Windows I use it with WSL2 and its works just as well as on linux IME.


This reminds me of Meteor.js[0] from back in the day (2014?), which had a very similar approach—you wrote code that ran on both the frontend and the backend, and database updates were propagated automatically. It suffered from a pretty hard reliance on Mongodb and its own package manager (Atmosphere), and it was at odds with the rest of the JS ecosystem which was settling on NPM.

This project looks very cool! I like the focus on composition, Meteor was lacking that (and really, most other frameworks do as well).

[0] https://www.meteor.com/


Yeah Meteor was an interesting example of an amazing project that fell into a hole based on a couple of bad decisions. It's basically fixed those at this point but become something pretty different in the process. It sounds like it may be something I can use now but I haven't tried it.


Another big problem was that you rarely want exactly the same code on client and server.


one that sort of fell by the wayside when Meteor and Ember got popular, was/is Derby.js/ShareDB. https://github.com/derbyjs/derby https://derbyjs.com/ https://github.com/share/sharedb

The LiveView lead resurgence in server side rendering is exciting. Does anyone have any insight as to why ShareDB never really took off?


Having been fairly close to the Derby.js project I'd guess that the difference between it and just using React and a web API just isn't that much in reality. Live updates of data isn't something most applications need (and very few parts of those that actually do). The added complexity is not to be underestimated, and there are some things inherit with live data which makes it more complex. What happens when one piece of data updates at an unexpected point in data, half-way through a method where you process something? Plus you still have the difference between backend and frontend, just that now it's more difficult to understand where and when what is run where under what conditions.

Then specifically for Derby/Share JS they didn't put enough resources into the project to make it good enough compared to the alternatives.



The language itself was a really interesting halfway point between typescript (near JS syntax) and purescript (stronger type system), before either existed. Plus some extra goodies thrown in.

It's really too bad they bound it so tightly to the framework, as I think there's a chance it could have succeeded as a language in itself. But these reactive shared-code things never seem to work out.


I feel like Meteor lost a lot of ground to Firebase.

I think what we are seeing with these tools to make data synchronization in the frontend more invisible will continue to proliferate.

I am looking forward to the next, rich landscape of interactivity on the web powered by WASM, WebGL, etc.


> I am looking forward to the next, rich landscape of interactivity on the web powered by WASM, WebGL, etc.

All of which will likely be a broken mess on iOS thanks to Apple


i think you mean WebGPU rather than WebGL. also WebTransport will play a big part for truly real-time interactive web apps


Sure thing. Thanks.


So from what I can tell this is conceptually similar to the LiveView model, except that the problem is approached from the perspective of the SPA/client stack instead of the SSR stack. It’s a refreshing idea that I’ve never seen executed like this before.

However I think it’s missing the point of de-coupling. Security would be very hard to reason about, as would handling of intermittent network connections when the real structure of the client and server are abstracted away from you.

Ultimately I think GraphQL with live queries is the best model for this type of reactive work. You get a decoupled client/server, reactivity, support for mobile clients as you have an API, as well as full type-safety on the client.

Nonetheless I applaud the creativity on display here and I hope I’m proven wrong. Maybe this will be the next paradigm shift? Who knows


Mr first thought reading the article was security. After a quick ctrl-f, it was a little disconcerting to find that the only mention of security is in a tacked-on bullet list under the heading "risks"...


why is this any different from any other web api security concerns?


When I edit Clojure I only ever think about indentation: https://shaunlebron.github.io/parinfer/


This is exactly what I've been thinking of lately. I started web development in 1998 and in 2000 I got searching for some way to store data.

At first I tried Macromedia Coldfusion, later acquired by Adobe. Now that I checked on it, it seems to be going strong, to my surprise. It was too hard for me. And it was closed software. There was no way for me to learn it without spending money on it. And it wasn't what I was really looking for.

But I just needed something simple. Something to tinker with. So I found PHP. It was exactly what I needed at the time. Later I also found MySQL.

The amount of garbage required to build a single website is enormous. So enormous that we have gone a full circle and people start using static site generators to create pure HTML sites. Because of speed and few other reasons.

So I got to thinking, why is it that we're building webshops with all these open source technologies, with a huge amount of overhead and "bloat", when all you really need is a few simple things.

Well, as the creator said it, there are a lot of unknowns. Huge learning curve etc. But that's how Linux got started, as a tinkering platform. I really think this is the right path to take. Making an open source web programming language, that handles all the needs directly built-in. I totally agree with the philosophy and if you will, proposed abstraction, of the problem at hand.

But also, it makes me shiver to look at the code and not understand it. So much to learn. But it gives me hope to see, that other's have come to the same conclusions. Looking forward to hearing more!


Clojure (and Lisps in general) really aren't hard to learn. It just takes those of us that come from C-influenced languages like PHP a little longer to be able to read them at a glance because the syntax is slightly different and usually simpler.

Once that lightbulb of the power of a Lisp goes off, there's no turning back. As Eric S. Raymond said, "Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot."


The best tip I ever got for reading Clojure was to ignore the parens and look at the indentation.


If there was one and only one thing I could tell myself from 15 years to do sooner it's LEARN SCHEME. Man I wish I'd stated a decade ago.


Quite a few comments that are dishonest or didn't focus on what the author focused on, but rather on auxiliary things.

There are concrete similarities to PHP, which is effectively what this server/client macro setup gives you at a superficial level. However, from what I'm seeing, this will behave more like a LiveView or Hotwire, with the focus being on optimizing network requests in an automated manner.

My big question with the tool is this: if you're passing environments back and forth, how secure can this feasibly be? Is there an automated limit on what will be considered based on the generated code? How do you handle malicious environments?


This is tangential but also a validation.

FoxPro (& dBase) is a realization of the concept: To deal with databases, you need a database language.

Exist a lot of minor things that our apparent "general-purpose" languages lack in the moment you need to deal with certain niches. From very small stuff as not-even available decimals, dates, currencies, units types, to lack of simple way to transform data, to ad-hoc queries, to ad-hoc data validations, to lack of relationship modeling, etc.

Even if you say "linq!, ActiveRecord!, functional!, lisp!, pandas!..." and others all that are a shadow of what the dBase family provides.

How far? I was not in worry about all the stuff everyone worry about today (injection? orms? impedance mismatch? reactivity? <- an over-complicated patch on top of unfit languages for it, so kudos for this idea!). That is what make me put some time aside in build a language in the spirit of it, because is so much details that are not available if the languages is not designed with data(as of the kind of business) in mind.

So, in short, most languages, even php, python, ruby, ... are not that good for web programming (and worse for database programming!), just that are not that terrible, either.


When the framework does so much for you, I always worry about what it looks like at scale when you need to start optimizing. Can you instrument all the plumbing, if something breaks can you get at it to fix it? How will you add caches at various different layers? On the browser, http cache, db cache, CDN, etc.? If the generated JavaScript that’s ultimately running on the browser has a bug, how many layers of library do I have to sift through to fix it? When I want to simulate the network for testing or deal with intermittent connection failures on the frontend how hard it is to plug in? What do schema migrations look like? What do deployments across a fleet of servers look like (there’s some point in time when some servers are old and some servers are new…)?

These are problems with any framework, but the more all-in-one a framework attempts to be the harder it is to get in between the joints with your glue gun to fix things up.

That said, this is Clojure and usually you have pretty easy access to all the intermediate bits and bobs and macros so maybe it’ll be great.


This is beautiful. I used to think about this problem deeply. The best imaginary system I did imagine was:

- A system that starts with our database schema

- a language in the front-end that abstracts away server connection and db access

- this imaginary language should allow defining react-like components but treat the db as a local datastore

- Most clients are UI stricture interpolated with that user’s data queried from the central db. So this imaginary front-end language should allow querying from user-level views from the db

Most of what I read from the post, looks like a realization of this dream.


>"- A system that starts with our database schema

- a language in the front-end that abstracts away server connection and db access"

Optimal data layout for storage and for processing / presentation can be quite different. Automatically mapping one to another I think can not be efficiently implemented in automatic fashion. I've tried different frameworks that claim to achieve it but at some point you always hit the wall. As a result I've long abandoned all those attempts and do manual transformation in code that are optimal for my particular situations


You need to treat clients as zero-trust. Your db is just a vector for DOS attack if you don't.


It had me at the title "You don't need a web framework, you need a web language" but then it immediately dived into arbitrary syntax instead of exploring in abstract what a modern web language would entail.


Yeah I had a really hard time understanding even with the backend frontend highlighting


I think the misunderstandings are because they are targeting a specific audience. They aren't trying to teach you Clojure, Datomic, and Reagent because they assume you are already knowledgeable about it.

Clojure and Clojurescript are the same language (more or less). They just target the JVM or Javascript.

The author is mixing the frontend (Clojurescript and Reagent) code with the backend (Clojure and Datomic) code in the same expression. Then through their magical system and the beauty of lisp, they pull the frontend and backend parts out to serve them separately.


It does seem a bit convoluted after going through it a couple of times, but I'm down to try it if my reagent React interop still works, e.g. `[:> MyJsComponent {...}]`.

I would say that I am very happy with the FE stack of reagent / reframe at the core. I have long chased the dragon of co-located queries ala GraphQL instead of basic re-frame subscriptions, or redux.connect and pulling fields off a map. Obviously having the ability to be more expressive with data queries is great, but in reality I have come to settle on basic subscriptions into maps, syncing data into my db via events. It's not super pretty but it scales!

This seems like it's trying to push the needle, and I will it.


The Web After Tomorrow beckons: https://tonsky.me/blog/the-web-after-tomorrow/

Well done, @dustingetz!


'compiler managed network' in here is a useful concept

buildsystems are increasingly doing the heavy lifting of telling backend how to deliver a pre-hydrated frontend, and telling frontend how to speak backend's language

would be nicer if this was just types and schemas, so you didn't have to use a full-stack framework to get full-stack accelerations and linting


As a web developer with 25 years of experience and (I thought) up to the minute skills ... I have no idea what any of that means but it sounds cool and important and I want to try it.


It allows you to define a GUI / DOM specification, with transparently embedded serverside commands that do things like "query the database for the list of users who meet criteria X." No annotation or other special action required.

The runtime figures out an efficient and reactive way of parceling out work to the server as needed, and refreshing it only when necessary.


Hats off to the lispers, they do some cool stuff. I think treating code as data they just have a different view of what computation means to the rest of us (or to me at least!)


You don’t have to know everything you see. If you find it interesting then cool but don’t feel compelled to learn every web thing, it’s a never ending rabbit hole.


More work and learning basically in "front end" land, before you can do anything practical -- as usual.


I view it as an attempt to reduce the work required in "front end" land, making full stack development more feasible than it is today.


Because software engineers are known for being people who are averse to learning and trying new things out.


As opposed to actually spending their time building useful practical things?


Yes, that's why I manually input 1s and 0s - no time wasted on learning, only outputting practical things.


I hope you don't live every second of your life building useful practical things.


I do actually. What else are you supposed to do with your time? Life is short, best to use it.


I'd say commenting on Hackernews isn't building something, let alone something useful. So that's at least one thing you do that's not that.


Everyone needs a break from time to time. :P


does nothing practical happen on the front end?


Interesting how no one has mentioned Fulcro. There seems to be a lot of overlap between the two. Anyone who has used both and mind comparing them?

https://fulcro.fulcrologic.com/


Yeah Fulcro has been building up their implementation of these ideas for ages, and used in anger, I think most famously by nubank.

From https://book.fulcrologic.com:

"The core ideas are as follows:

Graphs and Graph Queries are a great way to generalize data models.

UI trees are directed graphs that can easily be "fed" from graph queries.

User-driven operations are modeled as transactions whose values are simply data (that look like calls).

Arbitrary graphs of data from the server need to be normalized (as in database normalization):

UI trees often repeat parts of the graph.

Local Manipulation of data obtained from a graph needs to be de-duped.

Composition is King. Seamless composition is a key component of software sustainability."


Am I wrong or is fulcro frontend only though? You wouldn’t get access to any server resources so you still need to manage syncing state with the server. Or am I wrong about that?


Yeah you were mistaken, it's a full stack design. They recommend https://github.com/wilkerlucio/pathom for the connection. It's GraphQL done right, you write data "resolvers" on the backend, you declare very flexible graph queries on the front end -> this populates client DB and then fulcro uses that to render frontend.

Highly recommend reading through this section: https://book.fulcrologic.com/#FullStack


How does the reactivity work with Datomic? Is it polling those queries? Or I’d it listening to the log of transactions and figuring out when relevant parts have changed?


I think people are overlooking the fact that javascript and css is a hot mess to deal with. We need something like flutter that makes maintaining these easier.


Coincidentally, Alephjs (https://github.com/alephjs/aleph.js) added a commit hours ago that also seems to solve this particular problem for React.

So now there's a React hook (useDeno) that takes a callback that is only executed on the server-side, and the returned value is sent back to the client side transparently.


This reminds me a lot of imba[1], which mixes the front end and the back end. Though ReactiveClojure seems to be more about reasoning in terms of a lisp for all parts of the app, whereas imba is more focused on reducing syntax noise as much as possible.

[1] https://imba.io


I think I fail to see the advantage in the example given. Is the point that there's a server side call attached to the UI component directly? How is this any different than what can already be done with old school full stack like Rails or even smaller libraries like Sinatra/Flask.


If you are trying to allure front end devs, maybe don't use tables in you example.

To my taste, all of that is way too overcomplicated. I don't know why we need to make writing and maintaining web pages more complex with every year that goes by. To my mind, this industry looks completely derailed.


What would you use to represent tabular data like a list of T-shirt orders as in the example? That should be an HTML table. Using tables for positioning is bad in front end. Using HTML tables/sections/headers for document data structure is exactly what HTML is for.


Unless it's two columnns only, tables don't work well on mobile. You end up having to undo in CSS a lot of properties that TD, TH bring by default.


Hi Very interesting read. What would be the possible business models for this to make money?


"Photon will likely be technical alpha for all of 2022 or longer". Wake me up in a couple of years then.


great to see hyperfiddle here, delightful surprise, deserves the attention, kudos @dustingetz, ty for the writeup


Can someone translate this for a relative web dev noob? or can anyone? which may be a better question


A web app includes code that runs on the client and code that runs on the server. For example, code that manipulates the view runs on the client and code that accesses the database runs on the server.

This lets you write a function where some of the code runs on the client, some of the code runs on the server, and the compiler figures out which and emits the network RPC calls for you.


This is very cool, and ambitious, but i have one major objection: the claim that web apps are an about unidirectional data flow from a managed data store to a consuming front end.

That's not the kind of apps I want to build. I want workspaces where I can make and edit and work freely. I don't care to be online to do it, and conserving bandwidth is not a constraint that should define how I use it.

The DAG goes from me to me.


I like how client and server code is separated, but I do wonder how changes in expressions are evaluated.

I'm thinking about autocomplete that on new user input (needle='ad') filters previous result from server (needle='a') in the client before server returns a new response from new input (needle='ad').

Essentially can inner parts of expression update even when they are somewhat dependent on reactive data from server that comes from their parent expression?


Lots of people saying it’s like PHP or liveview with elixir.

We kinda have that with livewire[1] and inertia[2] and as awesome as they are (no separate api etc) they also suffer from the “magic”

[1] https://laravel-livewire.com/ [2] https://inertiajs.com/


My arrow and page up/down keys do not work on this website. Very annoying.


Off topic, but please don't use Notion for static sites. The page is 1.8MB (9.4MB uncompressed) - 1.6MB of that is javascript.


How does this compare to frameworks that abstracts over network calls such as ocsigen/eliom [1] ?

[1]: https://ocsigen.org/tuto/latest/manual/application


This is great. It's the dream that was promised 4-5 years ago of with om and reagent fully realized.


I think no-code/low-code backend is here to stay. Products like Hasura put authorization/ratelimiting/graphql/api-GW on top of trusted postgres. Now BE and no serialization up and down. Simply generate a client based on the graphql schema and off you go.


I've thought of doing this several times, and always shied away at the complexity and nuance that goes into it. Kudos to the devs for having the skill and determination needed to actually make this real. Very impressive work, and I hope it works great in practice.


I think that several of the fallacies of distributed computing are being ignored here.

https://en.wikipedia.org/wiki/Fallacies_of_distributed_compu...


Which ones? And ignored (and potentially irreconcilable) or deferred?


I'm a bit confused, is this a product or a project?


Yes.


To expand on the snarky response, or explain my thinking...

I think more and more the lines are blurred between open source projects, and products. This is good and bad.

It's good because people making money out of open source projects probably means more open source projects, more support available, and a healthier tech industry.

It's bad because as someone with no intention of turning a few open source libraries into a full time job, there's still an expectation of a certain level of polish to them that makes more sense for products. Open source projects with clever names, logos, mission statements, a domain name and marketing site/landing page, marketing copy, flashy documentation, a live preview environment, etc. These are all a lot of work for an open source project, but the stakes are raised to this level by the productised open source projects that can afford to fund this sort of thing.


I get that and I agree with you but then if it's a project why do I need to ask for early access, if it's a product then why launch a web tech on notion? one would expect to build the website with the so called web language and have the proof in the pudding like they say.


I’m very into stuff like this, and I really can’t make heads or tails of what this post is about. There’s a ton of hand waving, and a ton of words, but why not use them to explain exactly what this thing is doing?


looks very overcomplicated for generating an html table, building something more powerful would result in even more complex code. There's a reason why these things get decoupled


> There's a reason why these things get decoupled

This is true, but I also think it's worth evaluating whether the lines along which we've been decoupling applications is the right one. Typically, the line of demarcation has been the client/server boundary, for a bunch of reasons: security considerations (it's also a trust boundary); different computational environment. This split has reinforced itself with the organization of companies into frontend/backend teams.

But there are a bunch of things that it makes a pain-in-the-ass. I've encountered this most with data-heavy apps, where I want to do some analysis on the server (e.g. Python/Pandas), but I want low-latency recalculations on the client in cases where the data is small enough. Doing it “right” requires implementing the same data-level logic in both Python and Javascript. Nobody has time for that, so we end up in our current world of laggy janky SaaS that needs to run off to the server every time you click a button.

Which is to say, I'm excited that people are looking at alternatives (not just this; LiveView was on HN yesterday as well).


Finally the problem which PHP solved more than two decades ago has been solved again. How do we include server-side code in client-side code?

Do we build the client-side on the sever, and render? Why no, that would be PHP.

Let's build the client-side in the browser, and rig a series of complex code-generating primitives disguised by the beauty of a language, to AJAX our way to a presumably good-enough solution.

I think its a serious question whether apps built with this are more performant, easier to use, (and so on) than the equivalent PHP-approach.


Claiming "this is PHP" misses the point entirely, which is turning PHP-like templates into apps that can react to user input


There has got to be a better way of achieving reactive templates than what is described in this project though.


I think Phoenix LiveView (posted recently on HN: https://fly.io/blog/how-we-got-to-liveview/) and Rails Hotwire (https://hotwired.dev/) are the main alternatives that have momentum right now.

The general idea being to abstract away the difference between client and server code, so that you can write code that handles both, in a single file.

> There has got to be a better way

What's offensive about the OP to you? Is it just that you don't like functional programming / Clojure (fair, that's ultimately a matter of taste / aesthetics at some level)? Or is there something about the technical implementation you think is suboptimal?


Thank you for posting those two, I wanted to post them but I don't comment often. Wanted to chip in another contemporary: edelvalle/reactor, which is inspired by LiveView[0].

[0]: https://github.com/edelvalle/reactor

I am using Hotwire for a project, and I'm learning Elixir and Phoenix on the side. Finding edelvalle/reactor was immediately helpful to me though, because I cut my teeth on Python/Django, so reading a Python reference implementation helps me learn nuts and bolts of libraries, faster. (so, I figure that this might help someone else grok how these approaches work.)


Thanks for sharing - I currently work with Django so I'm very happy to see an equivalent library in that ecosystem.

Have you found any issues with Reactor, areas where it's behind Hotwire, etc?


I mean sure but you can’t get over the need to have a two way pipe of some kind to pass events server <-> client. Like no matter what you’ve got two balls of state with bidirectional relationships between them.


What if we put a DOM API into php with a few state hooks? Does that solve it? Because the GP is right, this is PHP.


PHP doesn't reactively and selectively propagate changes between client and server, nor would it be feasible to write such a library in PHP itself. You could maybe achieve something similar with code generation of PHP and JS.


But are you sure propagating changes is desirable ? It looks like a different architecture than the web to me


The use-case here is that the interface is highly interactive and coordinated. The suggested approach and library tries to blur the line between the logical components of client, server and database. Whether that is desirable depends entirely on what the assumptions of your web application are.


You can use SSE with PHP to propagate changes.


That would be a building block to achieve something similar.

Implementing this would however smear your logic all over your client and server and require careful plumbing. SSE doesn't come without caveats either.

The suggested approach here is to abstract away from that plumbing and move to a more declarative, composable expression. Whether you want that or not really depends. I see this as a specialized paradigm to solve a specific category of problems.


You can avoid that just using SSE to notify (no data) the frontend to rerender, you can still render everything in the backend.


Hate towards PHP has absolutely nothing to do with how easy web things are to deploy on it.


There's theoretically some performance benefit to rendering client side over ajax because the pages can be trivially cached, though you then run into the issue of pages being placeholders for a moment while the subsequent request(s!) run. Hence the UX anti-pattern of skeleton screens.


I don’t care for skeleton screens much in any case, but there’s no reason why skeleton screens couldn’t be limited to client-side page loads while the client waits for the data. The server could and should still fetch all the data and send down a fully-rendered page.


I will be so relieved when that anti-pattern goes away.


I really love Clojure--it's a joy to use but, you're right.

Maybe I'm misunderstanding this project but it seems like abstractions on top of abstractions and has little to do with being a "web language". That was PHP, for better or for worse.


You're misunderstanding. The project is proposing writing client-side code and server-side code in the same expression, then having a compiler automatically separate the two parts out and determine how they should communicate.


PHP lets you have a piece of server code that can see the local variables of the client code it's enclosed in? And it's all reactive?

That's amazing!


Regardless of whether PHP solved this particular problem, it also caused a lot of its own due to numerous security issues and documentation that encouraged unsafe use of libraries, until recently.


The pragmatism of rasmus, and how bemused he was that people were using his language to program (vs. template), meant that the BDFL was not a great advocate of the PHP model.

The model is this: run-once-and-die + build-it-on-the-server.

Those two ideas are extremely powerful, a little like immutability, in that they rule out a huge number of issues. The issue with PHP wasn't this model which became associated with the morass of amateurs using the language. A shame.


We did that, it was called PHP, and it turns out DSL are pretty limited outside of their sweat spot. Also they don't evolve as fast as libs and framework.

Case in point: PHP worked well, but framework like Rails and Django became very attractive because their offered more, and used languages that could be good outside of their niche.

And what did the PHP community to stay relevant ? They developed great frameworks, and improved the non web language capabilities.

Turns out the web moves fast, and coding a web app is more than web programming anyway.


Am I missing something or is reactive clojure a web framework for a language too?

I don’t recall Clojure being a web centric language like PHP, ASP, etc.


ClojureScript (JS target) is as web-centric as you can think, with what you can write front-end apps, Node.js apps, React and React Native apps, using Clojure.

Clojure (JVM target) can do back-end web as well as Java can, as well as anything else that Java can.

Clojure is a general-purpose programming language, so it can do pretty much anything.


Not related, but is Notion becoming new Medium?


Hugged to death and I’m afraid there is no wayback archive right now.


This is nice but it doesn't give you a reasoning system for making assertions about components. I'd rather work backwards from that point to a web language but playing around with things dynamically is the most natural and explored model.


Loving this for you...

)))))))))))


Found the one person who uses Notepad.exe because no actual Lisper even notices the indents due to structural editing capabilities of IDE's, much like {} in C-based languages.


Thanks. I hate it.


They chose a parenthesis-language, interesting choice. I don’t think the syntax is going to attract many web devs.


I'd love to know why any time I read something about clojure, it's inevitably cluttered with big words that the author (or some other clojurian) invented that have a lot of deep and important meaning, that make it impenetrable to anyone else.


Premature compositionally in the root of all evil, or something like that. I've looking for better ways to do document.createElement and addEventListener ever since the days of DHTML. Anyone looked into diagram theory already? The only productivity gain I've found is being fluent enough in your stack of choice to do the work to solve a problem and nothing more. And sure, spend the rest of your time researching diagram theory, but try to be honest about why you do it.


Premature compositionality? If something didn't need to be decomposed, it can be recomposed.


As in function composition, a great idea from math but one that is hard to use for anything that isn't a functions with domain and range in R or N.


This syntax is insanely hard to read, is non-standard, and is unclear what is server side and what is client side processed without purple and red highlighting.

Maybe I’ve been in Node.js land too long, but I don’t get why this is better for my productivity or my ability to create efficient web apps.


It's not hard to read, but it's just that you aren't used to it. Try Clojure without this "hard to read" mindset and see how great Lisp as tools are!


Definitely will give it a go when I have some free time!

Also, I can’t edit it right now, but would like to apologize for saying it’s “insanely hard to read”. That was rather harsh and uncalled for.




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

Search: