When not to use Fulcro?
Fulcro is great for writing non-trivial, full-stack business SPA web applications, which display and modify data from a general data store. But it can’t possibly be perfect for every kind of web app. So when is it less then a perfect fit? Possibly still usable, but not as beneficial?
Here are some areas, which I will explore below:
Trivial apps (⇒ use e.g. Helix)
You don’t control the backend
Backend-driven apps (BE decides the data 🌲 to be displayed)
Very simple data, i.e. data that does not benefit from normalization
Extremely dynamic UIs (no fixed UI ↔ query tree)
Very heavy integration with JS higher-order components (use JS!)
Areas where you don’t get the maximal value out of Fulcro
1. Trivial apps
Applications that do not have a backend, or where you only care about rendering data you already have, or where the operation is very limited. You can very well still build it with Fulcro, and if you know it well and are comfortable with it, it will still be the best choice for you, but you won’t benefit from most of what Fulcro has to offer. You can perhaps consider a simple React wrapper, such as Helix.
If you don’t want a Single-Page Application, then perhaps you should rather explore something like htmx or a DIY simple app.
2. You don’t control the backend
If you do not control the backend but are given a REST or GraphQL API, you will need to do extra plumbing to use Fulcro. It doesn’t necessarily make Fulcro a worse choice then other solutions, because those will likely also require plumbing to fit the given API to their model. But it is more work and you are less productive and efficient then if you control the backend and can build it with Pathom.
(Remember that you can also use Pathom on the frontend, and it has been used to adapt both REST and GraphQL APIs.)
3. Backend-driven apps (BE decides the data 🌲 to be displayed)
Fulcro’s assumption is that there is a general data store (such as an SQL database or Datomic) and that the UI decides what data it needs. If it is the reverse, and the backend has a fixed idea of what data and in what form should displayed, then Fulcro’s component queries are a pointless duplication. You could simply make every query ['*]
i.e. "give me everything", but you likely also don’t need normalization (see the next point) and it is a question of what value provided by Fulcro still applies.
4. Very simple data, i.e. data that does not benefit from normalization
Fulcro’s data normalization is great to make finding and modifying data trivial, and to ensure that a change is visible everywhere. If this isn’t relevant for your application then a lot of the value of Fulcro is wasted.
5. Extremely dynamic UIs
A key assumption in Fulcro is that the UI is somewhat static and we can code a compile-time tree of components and their queries. If your UI, or a significant part of it, cannot be defined at compile time but only at run time, probably because it is heavily data-driven, then again you only leverage a portion of the value that Fulcro offers. You can still build pretty dynamic UIs, with recursive queries, dynamic queries, and React hooks (primarily use-component
), but you really need to know what you are doing and be sure that Fulcro is still a good tool for the job.
Fulcro’s author has actually used it to build a 3D game board platform leveraging three.js, but not everybody is Tony Kay. Let me quote him, because it is interesting:
I wrote a 3d game board platform with Fulcro using three.js. I actually put a second reconciler in place for this. So, the standard DOM/application features were standard Fulcro, and all data was in the client db, but I had a separate reconciler that would take any data representing 3d objects and “sync them” to three.js when they changed. Of course that involved a bit of low-level js interop. The interaction also had to come from three, but I found it to be quite tractable and made the web-based UI and data loading/normalization in place. So, I would say that “extremely dynamic UI” is one of those things where the base libraries are still useful, but you do end up wanting “more” than is canned. That said, what app doesn’t need “more” of something that isn’t provided?
That said, if you have only small parts that are dynamic (only defined at run-time), then Fulcro has you covered. See e.g. Fulcro RAD’s ToOnePicker for related entities or the Fulcro cookbook’s recipe Solving mutually recursive elements with lazy loading with hooks and dynamic components and its DynamicRecipe
component.
6. Very heavy integration with JS higher-order components
If most of your job is putting together existing React components, and especially if those are higher-order components, then the accumulated price of ClojureScript’s JS interop and Fulcro’s React interop may not be worth the benefits anymore. You might be better of writing your app in TypeScript.
When Fulcro is the best
Let me be lazy and quote Tony Kay again:
The real places it shines is in it’s target niche: business web application development.
Lots of normalized data
Full stack problems already addressed
Can benefit from things like RAD for fast development of “supporting” screens (there are a LOT of these in a real business, and the less time you spend making them the better). E.g. the screens that let your staff support your users without a dev getting involved.
I built it for building startups. Many of the decisions in design were made around the challenges that occur there: Maintaining simplicity, reducing the number of ad-hoc inventions around simple problems, minimal drag on developers as real users are brought on (e.g. RAD lets you off-load simple data fix and diagnostic tasks to support), best-in-class hot code reload behaviors for fast iteration on problems, good visibility into the inner workings of the live application, minimal repetition/boilerplate, testability (if you follow the pure rendering paradigm, most things are pure functions and very testable). internationalization, etc.
#fulcro Slack 2023-07-10
Summary
I have described various areas where the benefits of Fulcro are diminished, and you need to carefully consider the benefits and costs based on your particular case.
Relevant wise words from Tony:
Personally my advice on technology choice is to heavily consider the human factors first. Can you even use Clojure(script) and get buy-in from the company/peers? If you’re asking people to move from significantly different technology then people problems are your biggest problems.