untangled

NEW CHANNEL: #fulcro
tony.kay 2017-05-31T01:58:07.857610Z

that is what untangled is

tony.kay 2017-05-31T01:58:29.860355Z

the networking, parser, along with a simplification of the loading story

tony.kay 2017-05-31T01:58:35.861070Z

@urbank

tony.kay 2017-05-31T01:58:50.862838Z

vanilla om next doesn’t do much without those

tony.kay 2017-05-31T01:59:37.868761Z

then you’ll find you need to augment the merge story, because the basic merge is too naive. Then you’ll find you want to augment merge behavior to handle return values from mutations…then you’ll have re-written Untangled

tony.kay 2017-05-31T02:01:31.884791Z

Untangled does make a specific trade-off that you might decide against: you don’t write any client-side parsing. It is all db->tree. I think that is a net win, but you lose the ability to customize the local read emitters to do things like handle parameters on query keywords and joins

tony.kay 2017-05-31T02:01:58.888063Z

My opinion is to just store those params (and the effects of them) in app state instead.

tony.kay 2017-05-31T02:02:58.895198Z

All told (client, server, forms, i18n) Untangled is about 1600 lines of code. It really isn’t that large. The docs are much much bigger 🙂

tony.kay 2017-05-31T02:04:01.902692Z

I’d love to hear what your resistance is to Untangled…do you think it is heavy? If so, why? Can you point to the place where it is heavy?

urbank 2017-05-31T08:05:31.717394Z

@tony.kay Well, mostly I was just curious in general if there was an example where you would opt against using untangled - for some reason that I hadn't thought of. So I suppose, more specifically, when, if ever, would the trade-off of of not using custom parsers not be worth it in your view? As to my resistance to Untangled. If I was in more of a hurry, I would probably have ran with it when I first found it, but I have the "luxury?" of meandering around, because a rewrite of our front-end isn't imminent. 🙂 Anyway, the main point is that, at least in theory, I really like the idea of components having arbitrary parsers to access the state of a component, and I also like the idea of QueryParams, because it seems to me to be a nice separate way of expressing modifiers for a component's query. Untangled, as far as I can see, asks you to put all these things into the mutation functions and essentially cache read computation by default.

tony.kay 2017-05-31T15:28:23.085449Z

@urbank You have understood it very well, it seems. I like the idea of the client parsing and query params, but in practice they just cost too much IMHO in terms of application complexity. Go through the use-cases in your UI of those params. Now consider that you can compute those things every time in a parser, which is nested somewhere in a recursive algorithm, or you can compute it on mutation, where it is a direct transform.

tony.kay 2017-05-31T15:30:03.126760Z

Yes, you have a cache invalidation problem now, but you also have a clear set of events (loads or user) that will logically go with that data. Say you’re paginating…the cached list of thing on the current page is trivial to keep correct. Next page, prior page, and list refresh.

tony.kay 2017-05-31T15:31:16.157499Z

I personally would rather think of it that way: next page…ok, where is the code to calculate that? In the mutation that I am looking at on the button that says “Next Page”. I don’t have to wade through the query, find that part of the parser, search for the function that handles that bit of the query, etc.

tony.kay 2017-05-31T15:31:44.168913Z

And if you’re using defmutation and IntelliJ, you get IDE jump-to for the mutation, so there is no searching at all.

tony.kay 2017-05-31T15:31:53.172754Z

Much smoother experience.

tony.kay 2017-05-31T15:36:17.279229Z

The Om Parser, as a generalization, is great. But as far as I’m concerned it should generally be used to “hook up” to a database format. E.g. it is trivial to hook a server-side query to Datomic. I haven’t had time yet, but an sql->tree is something I’d like to make (or see made) for this. You’ll still want to have top-level control of the parser on the server (security, etc), but for the most part queries that you send to the server are looking for a sub-graph that the db has.

tony.kay 2017-05-31T15:37:44.313418Z

Now, all that said: it would it be cool to add hooks to db->tree so you could escape into your own function for some part of a query. Then you’d have the best of both worlds (mostly automatic query interpretation, with param support when you want it).

tony.kay 2017-05-31T15:40:58.391480Z

Oh, and InitialAppState. That was one of the major tricks to getting the whole experience clean. That gives you easy refactoring: you just pick up components and re-compose them. The data automatically corrects itself. With a parser…well, have fun…your recursive tree just changed underneath you 😕

tony.kay 2017-05-31T15:42:53.437338Z

The Untangled in the Large youtube videos give some indications of this. There is one on developing components in isolation. Realize that with InitialAppState you can compose ANY component OR screen (with an ident, which they should all have) into a devcard (including server interactions and mutations), then move it into your application unchanged. No parsers required at any time. You don’t get that kind of rapid dev with stock Om Next unless you use a similar technique.

tony.kay 2017-05-31T15:44:05.466296Z

Use the tricks for mocking servers with javascript, and you can develop your full-stack components in devcards without needing the real server yet.

tony.kay 2017-05-31T15:45:29.499976Z

The point I’m trying to make (hopefully it is obvious) is that a recursive parser algorithm will get in your way a lot. You will find clever ways to make it better, but how “clever” do you really want to be in production code that random future engineers will need to work on and understand?

tony.kay 2017-05-31T15:46:02.513143Z

@mitchelkuijpers How goes your form?

mitchelkuijpers 2017-05-31T15:47:00.536906Z

I added a simple join in my form:

{[:ui.company/autocomplete '_] (om/get-query entity-auto-complete/CompanyAutoComplete)}
Works like a charm

mitchelkuijpers 2017-05-31T15:47:47.556116Z

I only need to put the temporary value somewhere, and then I only add the company id in the form

tony.kay 2017-05-31T15:49:28.596844Z

temp value?

mitchelkuijpers 2017-05-31T15:49:29.597455Z

Works pretty good actually @tony.kay still figuring out where the put the temp value but probably just somewhere on the form under a :ui key

mitchelkuijpers 2017-05-31T15:50:32.622657Z

If you select a company with id 1, I save the number 1 in the form. But when I render the value I want to do a query on the selected value: [:company/name :company/website :db/id]

tony.kay 2017-05-31T15:51:34.647801Z

why not just add an attribute (not form field) to the entity itself to hold the name?

tony.kay 2017-05-31T15:51:47.653044Z

then your mutation just sets both (or all)

tony.kay 2017-05-31T15:52:14.663660Z

the form commit only commits declared fields…you can have other fields in your query and entity

tony.kay 2017-05-31T15:52:28.669336Z

no :ui prefixing necessary 🙂

mitchelkuijpers 2017-05-31T15:53:06.684591Z

What do you mean by entity the Form component or the :ui.company/autocomplete thing?

tony.kay 2017-05-31T15:53:12.686708Z

Form

mitchelkuijpers 2017-05-31T15:53:20.690299Z

Ah yeah that was my idea

tony.kay 2017-05-31T15:53:52.702901Z

right…then if you need to fill in the form (say you edit from server), you’d query for those things and pre-fill them as well (even though you only save the ID)

mitchelkuijpers 2017-05-31T15:53:57.704847Z

Might still prefix it with Ui to never accidentally send it to the server

tony.kay 2017-05-31T15:54:10.709960Z

you want to query from the server 🙂

mitchelkuijpers 2017-05-31T15:54:15.712098Z

Yes I was doing exactly that

tony.kay 2017-05-31T15:54:22.714922Z

and form commit will never commit anything that isn’t declared a field

mitchelkuijpers 2017-05-31T15:54:30.718040Z

Ah nice

mitchelkuijpers 2017-05-31T15:54:46.724434Z

That was what I saw, also not ding anything if there are no changes

tony.kay 2017-05-31T15:55:05.732605Z

technically, you can submit :ui prefixed fields if you declare them…that prefix is only known by read logic

mitchelkuijpers 2017-05-31T15:55:34.744523Z

true

tony.kay 2017-05-31T15:55:46.749331Z

glad to hear it is working for you 😄

mitchelkuijpers 2017-05-31T15:56:42.771707Z

Yeah definately

mitchelkuijpers 2017-05-31T15:57:14.784531Z

It hurts a little bit now but we want to move over all forms to this. We now have some add-hoc stuff that I want to rid off

mitchelkuijpers 2017-05-31T15:57:32.791644Z

(This is the last part we need to port from re-frame to untangled)

tony.kay 2017-05-31T15:57:57.801756Z

yeah, NAVIS ran into the same thing. I had the forms support in my head from a long time back, but apps got written before the forms support existed…with some pain

mitchelkuijpers 2017-05-31T15:58:39.819145Z

Addhoc validation always gets messy

tony.kay 2017-05-31T15:58:39.819151Z

still more I want to do with it…like automatic form rendering if you don’t mind a stock look.

1👍
mitchelkuijpers 2017-05-31T15:59:22.836552Z

Ah thats awesome for prototyping

tony.kay 2017-05-31T15:59:38.842897Z

it is..and sometimes ok for production 😉

mitchelkuijpers 2017-05-31T16:00:42.871606Z

Yeah I created a atlas-crm.shared.forms namespace with our own ::text things and all other stuff. And thinking about just mapping over the form-spec keys to render the fields when the forms are simple enough

mitchelkuijpers 2017-05-31T16:01:47.898263Z

And I could do the same for queries, adding the right queries to form elements can be a little brittle

urbank 2017-05-31T17:18:25.554892Z

@tony.kay You make a convincing case for mutations being both more efficient and in many respects less complex than parses. The shape of my data is now much more clear then when I started researching what to use for the rewrite, and there's also a bit of a lull in development, so I should now have time to make a few POCs with a few different approaches. I will see where it leads me.

tony.kay 2017-05-31T23:31:42.204732Z

@urbank would love to hear what you decide and why.