Fork me on GitHub
#clojurescript
<
2017-03-26
>
mikepence04:03:34

@ashnur do you have any examples of tools based on datascript that would be better than vue.js?

mikepence04:03:20

I am tasked with creating a google-maps like app but with medical imagery as the "map" ad I would love to do it in clojurescript

mikepence04:03:46

docs would browse, zoom, and annotate the images

mikepence04:03:09

I have done datomic for about a year

tbaldridge04:03:03

@mikepence no reason not to use React + Om.Next or Reframe for that

tbaldridge04:03:02

Any UI framework that is functionally pure is better to a mutable one, IMO

tbaldridge04:03:20

It looks like Vue is mutable?

mikepence04:03:13

appears that vue is declarative and handles the updating of references and whatnot internally

mikepence04:03:38

appreciate the feedback

tbaldridge04:03:58

Could work, but React has more traction in CLJS at the moment

yassin_05:03:11

tbaldridge: hi Tim..Recently watched your short YouTube tut on Pedestal..When can we expect the next ones..I really liked what I saw;)

mikepence04:03:01

won't know til later in the week how much leeway I have to use something like clojurescript

tbaldridge04:03:16

So getting help for vue may be harder

mikepence04:03:03

vue is said to be way simpler than react

mikepence04:03:13

thus my interest

mikepence04:03:53

I would love to see an om.next demo app or a reframe one

tagore04:03:10

vue is simpler, but...

tagore04:03:16

less disciplined

tagore05:03:28

Being simple is... not always a good thing.

tagore05:03:47

For instance I gave a talk about redux recently and...

tagore05:03:16

There was a guy in the audience who just kept asking "So how do you do two-way binfing, like in Angular"

tagore05:03:38

The anser to which is= you don;t.

tagore05:03:06

But he would not shut up, so eventually I wound up having to code for an audience.

mikepence05:03:14

do you prefer redux or om.next?

tagore05:03:46

I haven't worked with OM.next enough to know.

tagore05:03:19

I consider Redux production-ready, if a bit unwieldly.

tagore05:03:41

I'm not sure I can say the same for Om.Next.

tagore05:03:37

Anyway, my heckler was like- well in Angular this is really simple.

mikepence05:03:59

angular is a clusterf*ck

tagore05:03:16

But my point was that if you carry important data on the controller on Angular you deserve what you get 😉.

tagore05:03:35

You can do good disciplined Angular. I have.

tagore05:03:44

Most people don't.

tagore05:03:56

And that's kind of the point I was making- sure, bad Angular looks easy.

tagore05:03:06

Good Angular involves some boilerplate.

tagore05:03:24

Boilerplate is not necessarily bad.

tagore05:03:38

That said, it's not a bad thing to enforce discipline at both the language and the framework level... which is why I'm here and not in #Angular

tagore05:03:09

Cause writing good Angular really is both a lot of work, and a matter of discretion

tagore05:03:23

And Javascript...

fernandohur08:03:20

In Clojure the eval function is available in clojure.core. Any idea where to find it it ClojureScript?

fernandohur09:03:10

Ok so according to the sources It looks like it lives in cljs.js, but for some reason I don’t have that namespace available (`cljs.js` is nil).

fernandohur09:03:52

cljs.user=> (require '[cljs.js :as s])
#object[Error Error: goog.require could not find: cljs.js]
hmmm

grav11:03:20

Afaik, only bootstrapped Cljs has an eval (since you need something that will compile the supplied expression to js). More info here: http://blog.fikesfarm.com/posts/2016-01-22-clojurescript-eval.html

grav13:03:35

Ok, not true. If I make a new figwheel project and run the repl, I can use cljs.js/eval

grav13:03:31

David Nolen states something about eval requiring pulling a lot of extra stuff, and that it doesn’t work with advanced compilation. Don’t know if that could be related to the error you get. https://groups.google.com/d/msg/clojure/FafbgirNa3A/Pjp68tjfBAAJ

fernandohur09:03:47

Thanks @U052XLL3A. It “magically" started working in the end, I’m not entirely sure why. So if I didn’t explicitly write a require for cljs.js it would not be available in the REPL.

tbaldridge13:03:27

@mikepence personally I prefer Om.Next's model because it is explicit. With Reframe (and Reagent), your components can access whatever global state they want and act on it. In Om.Next components must declare to Om what data they want to use, and the library notifies the components when the data is available and hands them the data. The net result is a system with explicit (but not static) connections between components. This is very powerful, since Om.Next can be free to batch HTTP requests, de-de-dup requests, etc.

tbaldridge13:03:01

In addition, nothing is stopping someone from providing specs for those component inputs and outputs, enabling generative testing for the UI.

tbaldridge13:03:57

This is all next to impossible in Reframe, since reframe uses implicit dependencies. It might be possible to hack something like this into Reframe, but it comes by default in Om.Next

isak16:03:10

@tbaldridge do you think subscriptions in re-frame are all that different from queries in om.next? why?

isak16:03:09

I think the concepts are pretty similar, the difference being with subscriptions, you don't need to worry about 1) passing as many props, and 2) worrying about what the component path is, both of which are a source of errors

tbaldridge16:03:19

Implicit vs explicit

tbaldridge16:03:18

Also, what does Reframe give you if the path doesn't exist due to a async load?

tbaldridge16:03:42

In on, render doesn't get called until all the required data exits

tbaldridge16:03:28

Also reframe stores these subscriptions opaquely in closures, in Om.next they are public

isak16:03:24

If components in re-frame exposed said what their subscription as a separate thing (outside the render method), I'm not sure what it would enable. Batching of requests would already be possible by just wrapping whatever function is sending requests, no?

isak16:03:27

Well that depends on your subscription - you could make it say {:state :pending}, for example, and then show a loading indicator

isak16:03:36

Some people say you are not supposed to do these kind of things in subscriptions, but I've yet to hear a good argument for it

tbaldridge16:03:29

It enables testing, bulkbloading (via stuff like graphql), and introspection. In short there's more leverage. More ways to use the data provided to add new functionality without modification of the components.

tbaldridge16:03:48

With reframe the library is completely blind as to the needs of your component. With Om the library can introspect and optimize

isak16:03:17

Ok, you are right, that is a good point

anmonteiro17:03:23

Building on what @tbaldridge said, I feel it's important to clarify it's not all perfect in Om Next. For one, your queries must match the UI component tree, which is sometimes really hard to model. It also gives you too much power, meaning you have to do stuff by hand that sometimes you wish the framework did for you. Things like knowing if you have all data to render (compared to stuff like Relay which has readystate and won't render if it doesn't have all data) is manual, introspection is really hard since there's no well-defined, typed schema like in GraphQL (which again you can probably implement by hand and with Spec, but who wants to implement a type checker in every app?), etc

anmonteiro17:03:32

That said, this is all stuff that Re-frame also doesn't provide, but I'd use a library on top of Om Next that took care of these for me

mikepence17:03:55

I was up all night looking at various things: reagent, re-frame, quiescent, om, and rum. Rum was cute, but om next really struck me as the kind of pure idiomatic clojure that I so love to write.

mikepence17:03:15

or aspire to write

mikepence17:03:02

hoping that my new employer gives me the latitude to make my own tool decisions

mikepence17:03:50

and that I don't have to resort to functional js

isak17:03:25

FWIW, I've found re-frame to be be quite good, and have a nice built in solution for most things. And no complicated, error prone concepts.

mikethompson18:03:29

@tbaldridge >With Reframe (and Reagent), your components can access whatever global state they want and act on it. Using the same logic, Clojure is equally terrible too. After all, functions in Clojure can access whatever global state they want and act on it. But is that way you choose to do, Tim? No, it isn't. So equally, there is absolutely no reason for you to do it in re-frame. In fact, the ENTIRE design of re-frame discourages it. So why would you make this claim so authoritatively? It is just wrong.

tbaldridge18:03:10

Can you show me a reframe example that does what you describe? Code is easier to discuss.

mikethompson18:03:35

PLease just read the docs

mikethompson18:03:25

It doesn't seem you understand re-frame at all, if you are making these claims

tbaldridge18:03:10

I have read the docs.

tbaldridge18:03:37

What I'm saying is the entire structure of reframe is implicit.

tbaldridge18:03:40

You do stuff then ask the library to figure out how it relates to your rendering code

mikethompson18:03:33

> With Reframe (and Reagent), your components can access whatever global state they want and act on it. As you can see, from the above, I am in the first instance specificially calling out this misinformation

tbaldridge18:03:03

Is that statement wrong?

mikethompson18:03:09

Because if that is your measure, then you shouldn't even be using Clojure. Because it is equally true of Clojure functions.

mikethompson18:03:13

Nothing about re-frame encourages the use ofglobals.

tbaldridge18:03:15

Not really, Clojure is statically compiled, if someone use resolve thought their entire Clojure app, then I'd complain about that as well.

tbaldridge18:03:33

Bleh on a phone

tbaldridge20:03:56

@mikethompson now that I'm back at my desk , let met give you and example from the Reframe examples: https://github.com/Day8/re-frame/blob/master/examples/todomvc/src/todomvc/views.cljs#L52-L53

tbaldridge20:03:05

That code is fully dynamic, and opaque to the Reframe library. the library (or framework since both Om.Next and reframe are more like frameworks), has no way of knowing if every call to render will require the same data, or if it was just this one time. There's no way to express when your subscriptions could change, or what drives these changes.

tbaldridge20:03:54

In essence it would be like writing Clojure code like this:

(@(resolve "clojure.core" "println")
 ((@(resolve "clojure.core" "vector") 1 2))

tbaldridge20:03:25

If we wrote code that way ^^ it would drastically reduce the amount of optimizations Clojure could perform on the code.

tbaldridge20:03:57

So with code, and with my UI, I prefer to hand as much information to the framework itself, so it can leverage that information for better tooling, performance, documentation, etc.

john20:03:14

so you're saying, for instance, a type system could check at compile time with om whether a function has correct constraints in a given form, whereas with reframe it couldn't? Or something like that?

tbaldridge20:03:43

No, I'm saying it cuts back on introspection. As far as Reframe is concerned a render function is just an opaque bit of code. It runs the code then sees what the component subscribes to, to try and figure out what the component requires. so it has to run the render to get its dependencies. The same is true in Reagent.

tbaldridge20:03:18

I'd just prefer a model where the framework can query some component and say "what are the parameters you expect", "what is the data you expect?",

john20:03:53

priorities and tradeoffs I suppose. Like with core.async. You win some you lose some.

tbaldridge20:03:30

absolutely, Reframe is great for some tasks, I just tend to have a different set of priorities and needs

Oliver George21:03:24

I resisted reframe for a long time for fear of some of the warts/practicalities but it's proven very effective for some large enterprise apps.

Oliver George21:03:44

I would love some direct response to the om.next query building feature

mikethompson21:03:26

@tbaldridge While I can certainly see that hierarchical GrophQL-like query composition is a nice win in some apps, for mine it is not important. Other considerations are much more influential. So, yes, priorities. As always. And that's why I didn't address that issue above. I was instead disagreeing with a different aspect of what you said - the part I highlighted - I didn't feel I could let that float past without a challenge. (Which has now been done, so we can probably move on)

tbaldridge21:03:10

Well, but since you're here, let me ask you this: aside from any politics of what framework is better than another, doesn't it seem better to have explicit, queryable (as in you can say 'find all components that require X'), introspect-able components?

tbaldridge21:03:50

And to your point though that reframe doesn't use global state, at least any more than Clojure, I don't know that I understand. Doesn't that example I linked show otherwise @mikethompson?

tbaldridge21:03:18

What is @(subscribe [:foo]) but accessing global state?

tbaldridge22:03:02

And yes I realize, saying "isn't X better" ignores the additional book-keeping that may require the programmer to maintain.

mikethompson22:03:55

Monday morning here, and I need to kick start a busy week. So I don't have much time, I can only reiterate what I said before, I don't find I have much use for knowing all components which access X - particularly when in my world, there can be a layering of subscriptions (materialised views). But I'm sure that it is wonderful for a sufficiently hierarchical set of views, and a sufficently graph-like data store in the backend. Like I said, priorities.

mikethompson22:03:19

And, yes, subscribe is clearly a method for accessing what is ultimately global state.