This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-12-12
Channels
- # adventofcode (67)
- # announcements (8)
- # babashka (46)
- # beginners (154)
- # calva (5)
- # cider (9)
- # clara (5)
- # clj-kondo (34)
- # cljdoc (31)
- # cljsrn (4)
- # clojure (146)
- # clojure-europe (5)
- # clojure-italy (3)
- # clojure-losangeles (2)
- # clojure-nl (149)
- # clojure-spec (22)
- # clojure-uk (73)
- # clojured (6)
- # clojurescript (95)
- # clojureverse-ops (3)
- # cryogen (7)
- # cursive (12)
- # data-science (1)
- # datomic (9)
- # docker (1)
- # emacs (1)
- # figwheel-main (1)
- # hyperfiddle (1)
- # jobs (3)
- # malli (29)
- # nrepl (2)
- # off-topic (61)
- # pathom (6)
- # pedestal (1)
- # planck (1)
- # reitit (19)
- # shadow-cljs (52)
- # spacemacs (5)
- # tools-deps (24)
- # vim (30)
- # yada (6)
@yannvahalewyn Forgot to mention it yesterday, but yada deserves a mention. It's both data driven (data > functions > macros) and fully support the async story.
Definitely! I was a bit short yesterday with making the slides and didn’t include some important ones.. Other ones would be: • Git! Because it has a plumbing and porcelain (composition vs arrangement) • How Datomic is build: it just has a simple protocol and can compose multiple persistence backends like S3, Postgres, H2, DynamoDB..
not emphasizing arrangement in a library is perfectly valid imo, let the users arrange it right. Tailwind does this, but also datomic in the sense that you as a consumer can arrange your own datomic out of one or more of those backends
I think a good library offers at least the composition, and may offer one way to arrange them as a “get started quickly” idea but allows to be “remix”’ed 🙂
developers are smart people and I think we are afraid sometimes to open up some internals to the public
maybe because of the ideas of encapsulation coming from years of OO, but I don’t really know why exactly
@stex I also enjoyed your talk btw. The thing about reactions in subscriptions: last time I asked about this in the #re-frame channel (because the docs hinted at this being not recommended anymore) the answer was: events should always be triggered / dispatched as a result of user actions, not by subscriptions
I think the idea is that when a new subscription is consumed, it probably means a new view just got rendered or some input data changed which usually is because of a user action, so @stex’s ideas still align with that no?
I still like it more if say a table gets shown after a click, to let the table declare what he needs instead of guessing what the table will need when the click happens
think in terms of how fulcro co-locates views and queries
Related to your talk I kept wondering if Convention and Composability are mutually exclusive
nope 🙂
You could have a convention be a composable standard.. or even the other way around.. somehow make composable conventions
yeah the order is still a bit unclear indeed
I'd stick to having a convention on composability for a certain standard since, composable standards would increase the overhead by requiring participants to remember which conventions were composed.
well, if I think about it a bit I would say composition over convention stands. You want the base to be totally composable with less “magic”, and then on a higher level, the arrangement level, that’s where you can use conventions more
there seems to be a conflation between convention and "magic" I don't necessarily agree has to exist.
sure, I don’t mean to say they always come together indeed
But when you execute conventions tightly sometimes this can introduce magical elements
which is fine, if it’s on the high level arrangement
It will be Tony that proves his ideas haha, but thanks!
thanks for coming yesterday and listening to what we have to say! There were some really interesting conversations that came out of it and I sure learned a lot!
From the javascript world they speak highly about using the Apollo React client with a GraphQL backend, to handle state in a nice way. Should also be able to build something similar, not unlike your solution, in reframe. So you could just say witch data you need in the view, and on the background it does the http request if needed (using re-graph). Not sure how fulcro works, but I guess it's something similar?
I learned that if you tell people to tell the person next to them 1 fact about them it will start massive amounts of conversations
Something I've been cooking up recently: Preliminary classpath docs for babashka: https://github.com/borkdude/babashka/tree/classpath#classpath Mac binary: https://2278-201467090-gh.circle-artifacts.com/0/release/babashka-0.0.41-SNAPSHOT-macos-amd64.zip Linux binary: https://2282-201467090-gh.circle-artifacts.com/0/release/babashka-0.0.41-SNAPSHOT-linux-amd64.zip Feedback welcome.
@borkdude Thanks! I’ve read the addition in the docs does surprises me that they don’t encourage this approach. It’s basically the approach I’ve shown in the first part of my talk 😄. If you trigger http-requests only by user-interaction, you still need to be aware of all the dependencies: user opens table -> event -> what http requests are required for the table? It’s also hard to reuse components this way. Let’s say your page have 50 pages and on 20 of those you include a small widget which requires remote state. Do you really want to couple the user entering a certain page with dispatching things for the specific widget? What if a page stops using that widget? What if you add an extra page? What if you have a large combination of widgets and pages? I do understand this introduces more side-effects to subscriptions, which is less pure. But I’m fine with that 😄.
@borkdude Would it be a good idea to have the ability to set class paths in an environment variable? (instead of --classpath
argument. e.g. export BABASHKA_CLASSPATH=...
) ?
@stex We have an event for each page open, which will trigger the init events for the widgets, which will then trigger fetching their data
@kevin.van.rooijen I think that makes sense, planck also has PLANCK_CLASSPATH
@kevin.van.rooijen Note that nothing from the classpath gets loaded unless you use require
True, but then you could require in your PRELOADS, correct? I think that would actually be really helpful
@kevin.van.rooijen Are you interested in testing a version with BABASHKA_CLASSPATH?
ok, here's the link: https://2303-201467090-gh.circle-artifacts.com/0/release/babashka-0.0.41-SNAPSHOT-macos-amd64.zip
@borkdude That works for simple pages, yet you are having the same problems right? You need to know which widgets are used on the specific page.
anyway, not to criticise any approach, just thought I'd mention the comment from the re-frame folks
@borkdude Haha, but you need to keep the widgets on the page in sync with the dispatch 😄 .
Yep, I’ll discuss in #re-frame if I have some more time. Just wanted to check if you’re having the same issues. Sounds like you’re fine with the simple approach, do think this will get hard when you do traditional REST on the backend and need to join in the frontend.
@stex We have quite a complex page with lots of widgets, sometimes depending on each other. And we have a REST backend.
Like I said, if it works, it works. I should maybe look into fulcro one day, but that couples the backend and the frontend, which was not an option for us
That's the main reason I didn't really look into fulcro yet. I like to keep options open to another back and/or frontend. Like I can test different GraphQL server implementations and to end using the same re-frame code. Because it's composable.
@gklijs So to answer your question about Apollo: I’m not familiar with apollo, but based on how you describe it: yes. this sounds quite like Fulcro. But fulcro also does something extra that maybe Apollo doesn’t. It composes a query with an ident. These two together are a very powerful combination. It’s the how and the what. If you only have a query, all you can do is fetch the data. If you have a query and an ident, you can do loads more things: you can merge queries, nest queries, normalize and denormalize a client db, make mutations, .. example: Say you have a widget that shows a user’s name and another widget with the same user’s email. They both will have the same ident. So if both views render at the same time, the queries will be merged and executed together. The result will go in a normalized client db:
{id {:user/id id :user/name name :user/email email}}
If both widgets render at different times, two fetches will occur but the results will be merged, resulting in the same shape. You can’t do this if queries don’t have an ident.
Other examples would be forms. You query the data you need for the form, but you can mutate that same data in the same spot in the app-db. If you have nested forms you can normalize both querie-results in the app-db, making mutations trivial, but have a denormalized tree to make the rendering of the form easy.
I think Fulcro doesn’t deserve the adoption it deserves. It’s extremely powerful, but based on a very simple idea. I don’t think it’s easy to understand though, and people miss these kinds of brilliant aspects of Fulcro and put it away.@borkdude This is an interesting conversation. It seems that Stefan, me and the fulcro people think colocated queries and views are a great idea, and you + re-frame people don’t. Maybe we could talk about this a bit more
@yannvahalewyn Om(.next) has this too. I don't think it's a bad idea nor do I have a strong opinion on it. I just pointed out that the docs linked to in the presentation yesterday are effectively deprecated and the re-frame folks suggest a different approach.
I don't know what Apollo does either, but sounds similar. You can also add things to the GraphQL schema for client site only date, like 'seen'. I think it also does aggregation maybe even across components. It can replace redux entirely. One of it's problems is because the cashing, and because the db is based on the GraphQL schema there could be inconsistencies. For example if you have a UserPublicView and an UserFriendView, having some fields in common they could diverge.
That last part is solved by fulcro's idents. As for caching, yes. GraphQL and pathom can't really use http caching. You have to bring your own solution to the table
@borkdude fulcro was originally forked from om.next I believe. Interesting to realize we're actually using reframe with om/fulcro ideas
maybe you can blog about it how it exactly works (or an open source lib), that's maybe a better starting point for a discussion
Both are on the table, it will depend on @stex :)
it's pretty interesting indeed if you combine the good parts of re-frame and fulcro, without having to change your backend. arranging ftw!
Exactly
Or "how to make fulcro ideas work with rest" could be a nice blog post idea
(keep in mind this is an absolute better (as in better at everything all the time) and so is impossible, Healthy competition and options are always good.)
I'm considering building something on top of re-graph that does some of the things, but I'm considering a lot, and might not be a good idea to try to build something like that when I won't be using it in production.
@thomas I’m actually getting involved with that project, I think it will be great
@yannvahalewyn be sure not to include a dependency on nokogiri
@borkdude Crap, running git revert head
right now
as for db options, will it consider triplestore-like dbs like datomic / crux / datahike as well as rdbmses?
not out of the box, but attributes will just be open maps so you could implement your own backends, or the community could make plugins for them
right now the plan is to make it work for sql and datomic, two very different backends. We avoid the ActiveRecord style where all follow the same protocol, and the idea is to offer different solutions for both, but not make them transparently swappable. I think that’s a dangerous road to take.
I added foreman because the dev setup is a bit convoluted, you can ignore it if you start the transactor and repl by yourself
@yannvahalewyn imo requiring two "foreign" package managers for a Clojure RAD framework is not attractive
haha yeah sorry
Should’ve gitignored them, thought maybe other devs already have foreman and this way they could start it all up with one command. Do you have other tools / techniques that make this easy?
@yannvahalewyn > Setup For any contributors wanting to run this Run what? why?
is it for running multiple build steps at the same time? if you're already using npm for shadow-cljs you could also use it for that? or just bash? https://github.com/fulcrologic/fulcro-rad/blob/develop/Procfile.dev
question for the clojurescripters, I'm having some troubles with advanced compilation which go beyond my understanding. I've a function (ns my.namespace) (defn ^:export init [] ...)
and I give the browser some HTML with a <script>my.namespace.init()</script>
@skuro if you start typing my
in the console do you see anything appearing? I think in advanced the namespaces might be collapsed into single names
:cljsbuild {:source-paths ["src/cljs" "src/cljc" "env/prod/cljs"]
:compiler
{:output-to "target/cljsbuild/public/js/app.js"
:output-dir "target/cljsbuild/public/js"
:source-map "target/cljsbuild/public/js/app.js.map"
:optimizations :advanced
:infer-externs true
:pretty-print false}}
@borkdude Make is not fine when there are multiple async processes to be started. Anyway, maybe it’s way too early to finetune contributor workflows
@yannvahalewyn I mean Make as a "foreign" build tool, it's generally accepted and installed
:main
Specifies an entry point namespace. When combined with optimization level :none, :main will cause the compiler to emit a single JavaScript file that will import goog/base.js, the JavaScript file for the namespace, and emit the required goog.require statement. This permits leaving HTML markup identical between dev and production.
-c, --compile [ns] Run a compile. If optional namespace specified, use as the main entry point. If --repl follows, will launch a REPL after the compile completes. If --server follows, will start a web server that serves the current directory after the compile completes.
@skuro I have an example of a project with exports here: https://github.com/borkdude/sci/blob/master/src/sci/impl/js.cljs