Fulcro Developers Guide: Single-page full-stack web applications in clj/cljs
book.fulcrologic.com
book.fulcrologic.com
And then I discovered Clojure and Ring and later Liberator. What I like about my current setup is that I have full control over my framework and my team knows its ins and outs and the corresponding Clojure code is succinct enough to allow developers to come upto speed quickly. Our set up is not sexy but it works and we know how exactly it works.
I am not sure what I would miss if I did not use a framework like this. Is Liberator no longer good enough ?
You probably meant going from jetty to httpkit, ring is just a middleware lib
Of course, you can also use Fulcro to communicate with any sort of backend server, and still take advantage of Fulcro's normalized client-side database: http://book.fulcrologic.com/#Networking, http://book.fulcrologic.com/#_the_secret_sauce_normalizing_t...
I opened the links as new tabs on iOS Chrome to check them out, and it turns out they don’t go to the anchors unless I switch to the tab in a short enough time. Not sure if Chrome or the page itself (presumably using Fulcro?) is to blame here, but it was disappointing to find 3 tabs all open to the top of the page when I switched over to read them instead of the relevant sections.
Thanks for the links though, they gave me something intriguing to explore!
Just today I was thinking how nice it is to have the backend route tree available in both backend and frontend code, so e.g. it's easy to tell in advance in cljs whether the user has permission to use a specific endpoint. The route tree includes authorized roles and I wrote a simple auth middleware to enforce them.
In my fairly large Clojure+ClojureScript app I do not use a framework, mostly because nothing existed when I started. I pick libraries and make them work together. This has advantages, but also brings endless frustration when I have to deal with stuff like web authentication, file uploads, or Oauth2. I really wish there were good solutions for these kinds of generic problems.
Also, not all choices made by the framework are necessarily a good fit for every application size. I used to like Reagent, and I still think it's great for learning. But then it became limiting, I switched to Rum and never looked back.
But in general, why not take the Clojure approach and use the right tool for the right thing? You don't have to chain yourself for life to a framework, you can use a framework for one app and use a bunch of separate libraries in another. I think in the Java world there is so much incidental complexity, that you have to choose a single framework and stick with it, as it's likely the only thing you will be able to learn. Not so in the Clojure world.
I know that everything I need already exists, but I have yet to find a complete tutorial (Rails Depot, for example) that actually works. There's always some gap that isn't explained or some step that fails because the guide is 2+ years old.
So while I do agree that choosing your own libraries (and essentially building your own custom framework, because that's what they all end up as) is preferable long term, it is incredibly frustrating trying to build that first webapp.
I stopped using Clojure about 5 years ago, after two long consulting jobs using Clojure. I decided Clojure was not a perfect fit for me (and, really, neither is Common Lisp, Racket, and Haskell - more favorite languages) but I am very happy to see the Clojure ecosystem still creating such great tools around the language and functional composition.
I gave Clojure another look more recently because of the bindings for the mxnet deep learning library, so I guess I didn’t completely drop it.
God, I'm loving this already. The only other framework I know that could do this for a book is Meteor.
I've been running node shops for the last several years, and love Clojure since having hosted a couple meetups a while back.
That and being most influenced by lispy/ai culture from SICP, CTM, PAIP, AIMA books. Node is getting tiresome due to not being able to trust the ecosystem quality (which takes away some of the common justification of huge ecosystem).
Not worried about hiring since not open to fresh grads from universities or bootcamps without lots of training anyway (which can include a new lang). Are there crappy/charlatan Clojure devs out there or is it more of an elite/experienced culture?
With stuff like Fulcro, could we replace our basic REST APIs and business logic without having to re-invent too much?
I'm sure you can find crappy or charlatan Clojure devs, but I was generally impressed with the Clojure devs I met in #clojure or at the cons. Overall I found the community to have high levels of both knowledge/experience and patience in explaining things thoroughly and precisely to people who were asking questions.
Are you not doing Clojure development anymore? If so, why?
I switched jobs and language choice was not my #1 criterion. A very interesting opportunity that aligned well with my values (and paid better to boot), but was in a completely different tech stack (Python DS ecosystem, with some Scala). I love the language, think it's wonderfully concise yet expressive way to think about code, runs on a great platform for the web, and is a great fit for when team size exceeds codebase size (though not so much the other way around). All my fun software projects are still in Clojure or Clojurescript; I just wrote some today to scrape doggy listings.
Do you have a blog or is there another way to contact you? I'm interested in what you wrote in your profile.
If you’re thinking of migrating - especially if it’s just a rest API - just start with Ring (& maybe bidi for routing). It’s not really a framework - you can pick and choose what else fits into your stack well after that. Clojure libraries tend to be very stateless and end up composing surprisingly well. I think Fulcro is a bit more useful if you’re building a frontend from scratch with React.
In terms of hiring - it’s very similar to a niche language. You get less folks that are specialists in Clojure like people are specialists in Node or Ruby. It’s also an easy to teach the language so you can bring most people up to speed in a month or so. Our hiring process favors generalists - and Clojure fits in well for that role. I don’t think specialists would have a good time with Clojure though - it’s not the kind of language that is easy to use as a means to an end.
In regards to dev-quality, I find that people that are interested in Clojure are typically good engineers, not due to the qualities of the language, but due more to its relatively niche-ness, attracting more enthusiasts.
I don't know anything about your stack, or Fulcro, but I've had no issue using Compojure for doing REST stuff.
EDIT: Just an FYI, I should point out that I work at a really big megacorporation, not a small startup or anything.
Using Clojure (other Lisps have it way worse than Clojure so they are not even worth mentioning in an enterprise context) is a bit like using an extremely new cutting edge language like Rust or Nim where there's no high quality libraries for anything except the lowest common denominator but without the massive community and support. Yes Node has its issues. But at the end of the day, you still need to get things shipped. Elegant code that would look at home in SICP is useless when money is on the line and you can't ship. Clojure et al. is very much NOT a "Move Fast and Ship" type of language. If it's for a game jam where no one's using Unity and everyone's doing OpenGL or one of those dinky little Lua game dev suites, sure go for it. If it's your company, use Go and get things into production first.
Don't get me wrong, I love Clojure. There are a lot of smart people doing interesting things with it. It's probably the most advanced of all Lisps in terms of beginner-friendly tooling alone (shoutout to the Nightcode and Parinfer authors!) and it's Java interop is tremendously powerful in the right domain. Just that the ecosystem feels at times like Android 1.5 with its terrible fragmentation problems. The main corporate sponsor behind the language gives off apathetic vibes to community needs and the lack of featureful, maintained libraries is covered up under the guise of "Big frameworks bad! Elite programmers build their own!"
lein new luminus myapp +postgres +auth +swagger
This will create an app using Postgres as the database with a Swagger UI set up out of the box.During development mode you'd run the app with:
lein run
Any changes you make in the source will be automatically reflected when you reload the page. You can also connect the editor to the REPL that gets started on port 7000 by default.You can package this app for production with:
lein uberjar
and you can run the resulting jar as: java -jar -Dconf=config.edn myapp.jar
You really don't have to hand roll your app and go hunting for libraries unless that's something you want to do.A lot of libraries are not updated because they do not need any updates. This is surprising to people coming from other languages, but is fairly common in the Clojure world. I use many libraries which haven't been touched in 3-5 years and it is fine: they don't need updates.
> Auth systems etc. are half-baked with 10 different implementations on GitHub
Here I would agree — authentication is a problematic area. I use buddy, which I had to integrate into my ring+sente app manually with quite a bit of pain. Friend has the wrong abstractions, IMHO, and does not get the job done.
For the rest, I can only say that I don't understand the sentiment. It's true what you say about lots of Clojure libs, they were one off projects from someone and work has stopped on them. But I am able to move fast and ship with Clojure. For me, I can actually move faster with it. That's one of my main reasons for liking it so much.
There's a Java lib for everything complex. And there's a quality Clojure lib for everything common. I've never not found what I needed. And in general, I don't need as many things because the core libs are so full featured.
I'm not trying to deny your experience. It just makes me curious how my experience can be so different and almost opposite. That's why I've concluded that it's just not for everyone. It seems you are either a FPer or you aren't. And you are either a Lisper or you aren't. And with Clojure, you have to be both a Lisper and a FPer.
We're a very young business, iterating fast through
features, being very careful about writing maintainable
code. We have full stack Node apps and full stack Clojure
apps. This is a short thread on the difference technology
(or would it be language?) choices have made for us.I also think it's very easy to tell a crappy/charlatan Clojure dev from a good one just by looking at a small sample of his code.
* Full-stack example [0], implementing the RealWorld spec using the Walkable SQL library and the Duct server-side framework
* Fulcro's implementation [1] of UI state machines (recent HN discussion on the topic [2])
* Fulcro training video series, from the creator Tony Kay [3]
* An answer to why Fulcro [4]
* How Fulcro differs from Om [5]
* Fulcro's integration with the Semantic UI React toolkit [6]
* Where Fulcro is headed next, in v3 [7]
To me Fulcro is Clojure's missing framework. With Fulcro (and thanks to Clojure/Script), applications are composed and painted onto the screen -- this is thanks to the REPL and hot-reloading that preserves state. For a demonstration, see the Fulcro training playlist on YouTube [3].
Some personal favorite Fulcro features: (A) the built-in support viewer [8], which can take state history serialized on the client and play it back on a developer's machine (like a basic, self-hosted https://logrocket.com). (B) Workspaces [9], which is similar to https://storybook.js.org.
#fulcro is very active on the Clojurians Slack http://clojurians.net (or Zulip! https://clojureverse.org/t/introducing-clojurians-zulip/3173)
[0]: https://github.com/walkable-server/realworld-fulcro
[1]: https://github.com/fulcrologic/fulcro-incubator/blob/develop...
[2]: https://news.ycombinator.com/item?id=19268734
[3]: https://www.youtube.com/playlist?list=PLVi9lDx-4C_Rwb8LUwW4A...
[4]: http://fulcro.fulcrologic.com/benefits.html
[5]: http://fulcro.fulcrologic.com/vsom-next.html
[6]: https://github.com/fulcrologic/semantic-ui-wrapper
[7]: https://www.patreon.com/posts/fulcro-3-25683469, https://www.patreon.com/posts/incubator-23082756
What I am curious about is if I use Fulcro, will I write a lot more code to do the same as in Reagent/Rum because it's supposed to play well with a backend that's (for now) non-existent? Does it provide better tools for client-side state management compared to Rum/Reagent (+ re-frame)?
Right now I am using just Rum with its built-in cursors and derived atoms and the experience is okay. I did try DataScript but ended up just with a simple atom for now.
Please also see the links from my reply elsewhere in this thread: https://news.ycombinator.com/item?id=19522998
I am exploring using Fulcro remotes to persist data locally using https://github.com/replikativ/datahike (and sync via https://github.com/replikativ/replikativ)
1- you can (and it's easy) to manage the state when you need
2- operate with multiple remotes
3- talk with graphql remotes (using pathom on client)
4- easily talk with many rest remotes (using pathom on client, or create a pathom server)
5- use the components on server(JVM or Node) to SSR
6- easily use any npm deps (shadow-cljs should help), including any react component lib
7- share client and server mutations on the same file (via clojure reader macros)
...
http://www.hyperfiddle.net/ is probably the closest proof of concept I know of right now, some interesting properties are solved N query problem with smart and pinpoint caching, infinite TTL caches, SQL injection impossible, client exposable query language
Aggregate shapes defined at query time, not at insert time, it's mostly about moving immutable Datoms around not trees that are hard to reconfigure & reuse like nested JSON
I'd suggest looking into the feature set of Datomic, and then ask yourself what would happen if you ran with those concepts in the front end? - Fulcro
Also spec is still in alpha so it will keep getting better.
As well, Clojure has an opt-in solution to type issues: https://clojure.org/about/spec
As far as large projects go, my own experience has been that the dirty truth is that, past a certain size, nothing is statically typed, anyway. Either it's decomposed into a bunch of smaller services that communicate using a weakly-typed messaging system, or it's a monolith that resorts to some sort of stringly typed mechanism for communication among the major components. I know the speakers at tech conferences say we're supposed to keep it strongly typed and use a ports and adapters pattern to limit the scope of impact for type changes, but that just doesn't seem to be how it ever happens in practice.
It makes me think that the Clojure folks might really be on to something, and that, for large business applications, static typing is trying to solve the wrong problem. I'd personally love to get a chance to take its specs system for a spin.
So Clojure IMO is today in this awkward spot of saying "Here, use these new principles of data to go solve problems in this new better way!" but nobody has really deeply figured out what that even means. The whole middle ecosystem layer has yet to be written.
But it's happening, there's a movement of believers coordinated by Rich's talks and working to this common goal. And when it works, the whole 100k+ loc system that can't be changed will be but a memory.
(I am Hyperfiddle co-founder, Hyperfiddle poses the question: is it possible to express sophisticated database applications out of just data? We think we've made enough progress to show that the answer is probably yes. Hyperfiddle apps are not stored in git but rather in Datomic. And for special cases where you do need custom code, you can just drop down a layer seamlessly into Clojure.)
Error messages stopped being a problem with Clojure 1.10.