fulcro

Book: http://book.fulcrologic.com, Community Resources: https://fulcro-community.github.io/, RAD book at http://book.fulcrologic.com/RAD.html
currentoor 2021-01-29T00:08:27.107400Z

i believe it's meant to be the pro paid version of guardrails

currentoor 2021-01-29T00:08:53.107600Z

similar to how intelliJ has a free lite version and a pro paid version

tony.kay 2021-01-29T01:53:17.107800Z

You code in Guardrails. Copilot uses the same guardrails info to then do code analysis while you’re editing (instead of needing you to run the code)

tony.kay 2021-01-29T01:53:57.108Z

So, copilot is an add-on tool with IntelliJ integration that is sorta like clj-kondo, but understands the data better, so it can find more interesting errors.

1🆒
2021-01-29T04:40:27.110Z

sanity checking what appears to be a pretty weird bug, in the following example which is run in my :client-did-mount cb, the load! call won’t run until the transact! call finishes and returns to the client, correct?

(fn [mounted-app]
  (comp/transact!
    mounted-app
    `[(current-user/create-user-session ~{:user/id 123})])
  (df/load!
    mounted-app
    [:user/id 123]
    User
    {:target [:current-user]}))

Jakub Holý 2021-01-29T07:51:50.110200Z

transact!! is special and only refreshes the this component I believe. Cannot you use transact! ?

Jakub Holý 2021-01-29T07:53:16.110400Z

start from the RAD template and delete all the RAD stuff. Inline the code that creates app from RAD. That is likely to work.

1👍
Jakub Holý 2021-01-29T07:54:45.110600Z

I believe the action of the mutation is executed before the load! but if there is a remote part to the mutation, that is triggered but not waited for.

Jakub Holý 2021-01-29T08:22:10.111Z

Mermaid looks cool but it is not powerful enough for this case (adding the query and data arrows to the UI tree,.. 😭

Jakub Holý 2021-01-29T09:35:30.111200Z

Great idea, an animation would be awesome. Only I have no idea how to make it 😞

henrik 2021-01-29T11:14:36.114500Z

transact!! just merges {:synchronous? true} into the opts of transact!, and being able to target refreshes is specifically interesting with synchronous transactions, since they only refresh the caller (by default).

avocade 2021-01-29T11:17:59.117200Z

Hey guys, a question regarding globally handling stuff we send to, or ask for, from the backend: Is there a way to always elide certain keywords in loads and mutations, like what we get when using :without in a load!? So we don't have to remove common things explicitly. There is an existing method in fulcro of adding a :ui/ prefix to keys, which maybe could be allowed to be extended? Preferably allowing both keywords and predicate functions

avocade 2021-02-02T13:18:42.217700Z

Thanks, will check those out 👍

henrik 2021-01-29T11:29:03.117600Z

Yeah, so refresh/`only-refresh` seems to be for non-syncronous transactions only. Since synchronous is recommended for value transactions to an input, I'm not sure how to make a parent aware of the input change interactively, when this is necessary.

henrik 2021-01-29T11:38:43.120900Z

Running comp/refresh-component! seems to be an inelegant, but effective, workaround.

Jakub Holý 2021-01-29T11:40:32.121900Z

FYI I have now published https://github.com/fulcro-community/guides/blob/main/minimalist-fulcro-tutorial/index.adoc - but your comments and suggestions are still very welcome! I have also updated https://github.com/fulcro-community/guides/blob/main/learning-fulcro.adoc to include it though I am not sure where exactly it should go. Now it is essentially as the first learning step, which is OK because it is intended as such - but the problem is that it focuses only on "how" and does not explain why Fulcro is the way it is. I feel that the reader should be exposed to the rationale for Fulcro early but I am not sure where to point her/him. https://fulcro.fulcrologic.com/ is too high-level, https://book.fulcrologic.com/#_fulcro_from_10000_feet in a way gets in too much detail and includes some of the same things as in the Tutorial. Any suggestions?

1👍2🙏4🎉
2021-01-30T13:05:23.150400Z

Thanks, I have started reading it. Looks good so far. Small spelling mistake in last sentence of Prerequisities: 'vlue proposition' should be 'value proposition' I can file issue/pr if you prefer.

Jakub Holý 2021-01-30T19:18:12.185500Z

thanks, tkovis already fixed it

yubrshen 2021-02-02T05:27:25.208300Z

@holyjak Thanks very much for the minimalist tutorial! I'm studying in details. I especially appreciate the section on Prerequisites, which is really I need. I'm studying "Key concepts and elements" now. It seems that the following might have a typo App A reference to the current Fulcro application, containing configuration, the client DB, etc. Produced by app/fulcro-app and used when calling transact! or load! when a component's this is not available. Referred to as app in code samples. Maybe, this should be data ?

yubrshen 2021-02-02T05:44:31.208600Z

@holyjak For Client DB The client-side cache of data. It is a map of maps: entity name (e.g. `:person/id`) → entity id value (e.g. `123`) → properties of the entity (e.g. `{:person/id 123, :person/fname "Jo", :person/address [:address/id 3]}`). (For convenience, we use the name of the id property as the "name" of the entity - thus `:person/id`, `:user/username`.) I feel the above still somehow convoluted. I haven't figured out. I wonder if if would be better to separate the description of the abstract structure, then follow with a concrete data samples of a client DB? If the client DB is a map, what are the keys of this map (the highest level)? The entity, such as person, car, etc.? As values of the highest map, themselves maps, what are the maps (keys, values)? For entity person, the map of keys of id, name, age, cars, etc.?

Jakub Holý 2021-02-02T08:01:04.210200Z

@yubrshen You are welcome 🙂 1) What typo? What do you mean by "`this` should be data"? It refers to the first argument of defsc, it is traditionally called this . 2) Thanks, I will think about simplifying. > If the client DB is a map, what are the keys of this map (the highest level)? The entity, such as person, car, etc.? As the text says: "entity name (e.g. `:person/id`)" > As values of the highest map, themselves maps, what are the maps (keys, values)? they are maps from "entity id value (e.g. `123`) → properties of the entity" > For entity person, the map of keys of id, name, age, cars, etc.? Yes. Or, in my example, :person/id, :person/fname, :person/address

yubrshen 2021-02-04T06:26:59.235300Z

@holyjak Thanks! I forgot the special this

yubrshen 2021-02-07T15:28:00.265300Z

@holyjak With English no as my native language, I feel the following for the description of Client DB is clearer to me:

The client-side cache of data. It is
a map of maps:
entity name  → entity id value  → properties of the entity

For convenience, we
use the name (keyword) of the id property
as the "name" of the entity 
thus :person/id for the entity Person

For example,
:person/id -> {:person/id 123, :person/fname "Jo", :person/address [:address/id 3]}

It is fed by initial data and loading data from the backend and can be changed by mutations.
It's just a refactoring, to make it less "complex".

Jakub Holý 2021-02-08T09:21:35.276Z

Thank you! Applied 🙂

Jakub Holý 2021-01-29T11:42:43.122200Z

yes, provide your own replacement for default default-global-eql-transform https://github.com/fulcrologic/fulcro/blob/develop/src/main/com/fulcrologic/fulcro/application.cljc#L157

Jakub Holý 2021-01-29T11:43:24.122500Z

see how RAD does that to exclude f.ex. default-network-blacklisthttps://github.com/fulcrologic/fulcro-rad/blob/develop/src/main/com/fulcrologic/rad/application.cljc#L23

2021-01-29T12:09:28.122900Z

Interesting. I had been wondering if there is some potential for Guardrails and clj-kondo to be friends.

dgb23 2021-01-29T12:30:23.123100Z

An easy and low effort way is to draw the pictures in a series and leave them statically. Another possibility is to draw them as SVG use CSS transitions and a bit of JS to trigger them. If the latter is an option I’m happy to help!

Jakub Holý 2021-01-29T15:02:13.123300Z

I do not know how I would do that. But please give it a try, if you want, the SVG is here https://github.com/fulcro-community/guides/blob/main/minimalist-fulcro-tutorial/fulcro-ui-query-data.svg

dgb23 2021-01-29T15:11:07.123600Z

I’m in a hurry right now, but I could try next week. However a prerequisite would be to use github pages so you can include arbitrary CSS/JS. I don’t know if this is out of scope for this tutorial?

dgb23 2021-01-29T15:13:02.123800Z

Let me first send you a prototype next week when I have time and then we go from there!

1👍
Jakub Holý 2021-01-29T15:13:02.124Z

No, I think it would be a good idea to create GH pages for the fulcro-community guides.

dgb23 2021-01-29T15:13:10.124200Z

cool!

Jakub Holý 2021-01-29T15:13:19.124500Z

thank you!

2021-01-29T17:16:20.125600Z

Hey. thanks for this. very succinct

1❤️1➕
tony.kay 2021-01-29T17:21:22.125800Z

I have one other comment: The query/return of data is not tied to root. The query has a default target of a root key based on a subtree query, which can be re-targeted. This is not an insignificant point. You never really query from root.

Tuomas 2021-01-29T17:33:19.126Z

I myself really like how rust made touched on rationale in it's foreword https://doc.rust-lang.org/book/foreword.html and introduction https://doc.rust-lang.org/book/ch00-00-introduction.html#who-rust-is-for I really think you should start with why

1👀
Jakub Holý 2021-01-29T18:11:18.126500Z

Right, you don't do (df/load! :all-data Root) , you do something like (df/load! :all-projects Project) where Root shows a list of projects and has query like [.. {:all-projects (comp/get-query Project)}] . Is that what you are saying? Now I need to think hard how to make that clear in the figure without just confusing everybody... So the Root query is used to fetch data from the client DB and build props and send them down to Root but it is never used to load the data.

tony.kay 2021-01-29T18:46:49.126900Z

right….never is a strong word, but in real apps that is true

tony.kay 2021-01-29T18:47:34.127100Z

you’re always loading (or merging) some targeted subtree

tony.kay 2021-01-29T18:48:00.127300Z

so, I’d draw the SERVER query from some child node and merge back to that node

tony.kay 2021-01-29T18:48:18.127500Z

where that child might be dashed in some cases (doesn’t exist in graph yet)

tony.kay 2021-01-29T18:48:26.127700Z

the UI query is from root

tony.kay 2021-01-29T18:48:56.127900Z

so, if you change the graph to say “UI Client DB” on the right, then that diagram is absolutely right

tony.kay 2021-01-29T18:49:29.128100Z

but for merge-component and server interaction the in/out lines should connect to a sub-portion of the left graph, not the root

tony.kay 2021-01-29T19:01:29.128300Z

kondo is stricyly a static source analysis in a pre-compiled executable meant to give you Cursive-like feedback on your source in real-time. A dynamic analysis requires a running runtime using your code, and is much slower. So, it has different pros/cons. A static analysis can choose to tolerate syntax errors and other ills in order to give you structural feedback. It can also do some limited localized code comprehension to give you some help. Dynamic analysis needs your code to run in running order and has the same dynamic env drawbacks as REPL usage (load order, reloading dependencies, etc.). So, it is slower and more difficult to use; however, dynamic code analysis can give much broader coverage for finding regressions, cross-code behavioral problems, etc.

tony.kay 2021-01-29T19:02:13.128600Z

They are actually complimentary.

tony.kay 2021-01-29T19:04:58.128800Z

CLJ-kondo - static structural problems and some localized errors Guardrails - Real runtime data flow detecting problems against real use-cases (requires active usage) Copilot - Leverage generated data and “pretend” to run your code to detect the things that Guardrails MIGHT find if you were to run your project enough times. Can actually do a lot more than GR, but the “runtime” mode of GR is also complimentary. Unit Tests - Test specific cases and behaviors you want to prove right Generative tests - Exercise algorithms under some more specific external constraints/proofs. Integration Tests - Simulate real full-stack system use. Finds integration problems and bugs.

tony.kay 2021-01-29T19:05:08.129Z

IMO they all bring something of good value to the table. They just each have different pros/cons. More tools in the toolbox, so to speak.

Jakub Holý 2021-01-29T19:25:04.129300Z

Genius! I will do just that, replace Pathom with Client DB

futuro 2021-01-29T22:32:38.132800Z

The first time Fulcro clicked for me was in the interview with Jacek Schae, specifically because Tony spoke about the original impetus and then the idioms and foundational concepts. I’m afraid I don’t have much in the way of concrete suggestions, but maybe those interviews would help. https://podcasts.apple.com/us/podcast/clojurescript-podcast/id1461500416?i=1000479361034

1👂
2021-01-29T23:27:51.133200Z

Thanks for the detailed explanation @tony.kay.