Hacker News new | past | comments | ask | show | jobs | submit login
Om Next – David Nolen [video] (youtube.com)
259 points by ivank on July 7, 2015 | hide | past | favorite | 48 comments



Quite amazing. This talk is not just about Om Next - its also about ClojureScript.next. Featuring:

  1. AMD, CommonJS, ES6 module support
  2. CLJS in CLJS (yup, that works - including the standalone nodejs based REPL)
Thise in combination are especially huge.

With core.typed being an option as well (once your system starts growing and the design solidifies) looks like the clojure ecosystem is really positioned to be one of the technically strongest available for web development.

And of course, replacing that awkward REST mess seems painfully obvious now (except for duplicated data which seems like something that might yet need solving). Hindsight is 20/20


Does 1) mean we can make use of advanced optimizations (like dead code elimination) on libraries written in one of these formats without any additional configuration?

If so, that would resolve what I consider to be one of the biggest barriers for CLJS/JS interop.


Yes, that’s what swannodette said in the talk. Skip to 33 minutes, or see https://github.com/clojure/clojurescript/wiki/Google-Summer-... and the blog posts at https://mneise.github.io


I'm pretty sure the answer is yes. I watched the video a few hours ago, but I think I remember him saying that.

Of course, just like the current state of affairs, your library has to not thwart advanced optimizations (using eval, accessing properties by strings, etc).


Are you aware of any performance benchmarks? Do you pay for the clojure abstractions?


An old talk (2012) so I'm not sure how accurate it is now, but Nolen discusses performance of ClojureScript. At the very least, you know someone cares and is thinking about it.

http://www.infoq.com/presentations/ClojureScript-Optimizatio...


I felt like it was all over the place. I am not sure if I really care about all the people who are using graphql like syntax for data retrieval, I am not interested datamoic, falcor ect.


Swannodette never disappoints. If you're interested in this approach, you should check out re-frame: https://github.com/Day8/re-frame. The README is a great resource, regardless of whether or not you intend to use the framework.


And for anyone who'd like to jump right in:

https://github.com/Day8/re-frame-template

Includes Figwheel, and (optionally) Secretary.


That README changed my life.


He mentions getting rid of cursors, but I'm not clear how he would replace the modification side of cursors. i.e. I can see how a system like he describes supports nicely querying data, how do it help a component that needs to trigger modifying data?


I imagine you would trigger something like a datomic transaction, which returns a new version of the database.


A group of us talked to him after the talk, and if I understood it correctly, you'd still use the om transact function to trigger modifications.


Exactly my question, this is a big missing piece and something that cursors solve nicely.


> 41:15

Pretty sure Apple won't approve of being able to update iOS apps outside of their regular release cycle. If they don't care, I should be doing that now with my HTML5 app.


Actually it may be fine, if it falls under this exception:

  3.3.2 An Application may not download or install executable code. Interpreted code may only be used in an Application if all scripts, code and interpreters are packaged in the Application and not downloaded. The only exception to the foregoing is scripts and code downloaded and run by Apple's built-in WebKit framework, provided that such scripts and code do not change the primary purpose of the Application by providing features or functionality that are inconsistent with the intended and advertised purpose of the Application as submitted to the App Store.


I believe trigger.io has done this for a couple of years now


You can definitely do that now.


Clojurescript in Clojurescript is demoed in the last 5-6 minutes of the video. I think this is an awesome way to ship a repl with applications.


Yeah, that was a great talk.

I really want to try out Om Next. I've been building a bunch of stuff in Om lately and the Falcor/Relay/GraphQL/Om Next stuff is really going to be great to have at my disposal.

The clojurescript compiling clojurescript stuff looks great too.


Why does the idea of having frontend guys directly query the db without any kind of interface scares me ?

Seems like going the nosql to sql route once again( nosql is great until you realize query language and schema constraints are actually a good thing).

Having some kind of pipe structure and interface between your db and your GUI that can be used as a contract,or as an intermediate level to do data rearranging, and can be documented, without having to know all the db schema internals really seems like a sound approach. Now of course some people tackling very special problems may reach the limits of such an approach, yet i hope it won't become mainstream too soon.


> Why does the idea of having frontend guys directly query the db without any kind of interface scares me ?

I don't think giving frontend a direct path to the db is what the talk is advocating.

You still need a backend in front of the db, even in the special case of using Datomic as the db, to handle things like auth. The difference seems to be that instead of having the backend serve a messy web of REST endpoints for the clients to consume and compose individually, the backend would serve a single endpoint that can speak this new query language. The client can then declaratively request exactly the data it needs in the shape that it needs it in, eliminating an overwhelming majority of network related boilerplate on both the backend and client.

I'm personally extremely excited to see this become mainstream. So much of the front-end code I write on a day-to-day basis involves fetching data from various endpoints and shaping it into a logical structure for my components to display. It's tedious work that provides no intrinsic value. I can't wait to not have to write any more of that and focus my time on solving actual problems.


How does caching work in this scenario? Caching REST responses is fairly straightforward but caching arbitrarily complex queries to a single endpoint seems much more difficult.

Sorry if he answers this in his talk. I haven't had a chance to watch it yet.


I'm not familiar with the approach either, but the video mentioned that you would mainly execute these queries using a client side library. The library would be backend agnostic, and offer remote sync capabilities.

So I believe you can set the primary backend for the library to a local, in-memory data-structure to serve as the local cache, and have the library handle synchronization between the local cache and a remote backend that can also execute these queries.


The caching happens at the "DB" level, where it can happen more efficiently (e.g., Datomic caches segments on peers).


You have to implement it yourself. For some apps, you may need to do this anyway for perf reasons, because you don't want to parse the same HTTP response body more than once.


One solution is to not cache queries, but cache data, as in the case with Datomic.


Of course then you're sacrificing some of the authentication, potentially.


It's worthwhile watching Nubank's talk on how they manage these things with Datomic on the backend [0] - providing a "complete" (filtered) database to the client, http caches for queries based on tx-time, and syncing mobiles data via transactions-since. Takes care of said concerns nicely - I'm just implementing this stuff today however, so I'm not sure how well it'll work in practice.

[0] - https://www.youtube.com/watch?v=7lm3K8zVOdY


Isn't there an argument for abstracting and preparing data at the backend level, rather than facing the db nearly directly from the frontend?


This does that. There's nothing saying that individual query elements have to hit the database directly. Besides authz (which others have mentioned), you have the potential for various caching strategies as well as letting the backend make cost decisions in general about where to get things. It could be that you mostly pass through to a Datomic. It could also be that each element hits a different microservice. The point is that your client doesn't know this or care.


yes this is exactly what it is. it's definitely going to be one of those clutch things in the near future. being able to write some ui code that is acting as if the data is already available to it.


This presentation doesn't go into detail of how thats going to work between Om and Clojure, but if its going to be similar to GraphQL, then there is no problem.

Every field request in GraphQL [1] maps really well to a method invocation on an object (GraphQL even supports arguments). Its not necessary that those objects in turn map directly to actual database entities... and you can of course do many things with methods, like authentication / authorization, or perhaps even (with async servers) delaying get() requests in order to aggregate them into a single IN query

[1]: https://www.youtube.com/watch?v=WQLzZf34FJ8&feature=youtu.be...


Thanks for the link. Very interesting talk.

At then end though, you understand why they had to build such a system : dozens of apps, with weekly releases, and mutliple version support.

Now of course, building an API supporting each of those apps needs is almost equivalent to supporting any kind of query. You might as well create a generic implemention, like GraphQL, which they did.

But for the 99.99% of us, i don't think bypassing the API design phase is a really good idea.


I don't think it qualifies as bypassing the API design phase. You still need to design the classes that map to GraphQL object, the methods they support, the authentication / authorization that those methods require and so on.

All in all its pretty much the same thing as with a classic API. The only difference is you can send multiple (as well as nested) calls in one go, and decide which fields you want to include With this scheme you can even include/exclude fields based on user authorization! For example:

  class UserService {
    email() {
      if (this.context.user.id == this._id) 
        return this._email
      else
        throw new CodedError(403, "Cannot request another users email")
    }
  }
What is necessary now I think is an example open source app implemented with it to demonstrate how the stuff we do with regular APIs would work in GraphQL...


So, in principle I like everything with David's new approach... the main question I have is "How well do 'recursive queries' work when the data relationships between my components is really complex?" I think I will only be able to answer that question by trying this approach myself and seeing how it performs for my needs.

(Another question is: "How am I going to use this when my server's database is a blockchain and not a conventional database [1] like datomic?" but I know that's a niche question I'll have to figure out for myself.)

[1] Just kidding (mostly)


Thats indeed something that doesn't seem to be discussed much, even if you look at graphql's presentation - https://www.youtube.com/watch?v=WQLzZf34FJ8 there seems to be a lot of redundancy when "my friends including their events" is fetched.

I imagine that a scheme based on an UUID and deduplication would work - when constructing the response an object repository is kept and if an object with the same uuid appears twice its replaced with a reference to them.

Going against the "don't extend JSON" best practice, that would be:

  {
    "friends": [{ 
      "name": "Name", 
      "events": [#uuid1, #uuid2]
    }, {
      "name": "Another name",
      "events": [#uuid1, #uuid2]
    }],
  }
  #{
    "uuid1": {"name": "MyEvent", "description": "..."},
    "uuid2": {"name": "OtherEvent", "description": "..."},
  }
And it can support cyclic references too, as a bonus. Ignoring best practices is so... liberating.

Ultimately this is just compression though. Its possible that gzip will be quite sufficient for most cases.


Transit [1] can do this for you.

[1] https://github.com/cognitect/transit-format


I am skeptical about "component knows what data it needs". For example, I have a component with two combo boxes: in the first combo box I select a country and the second combo box is filled with cities of that country.

Now I need a similar thing: in one combo box I choose car brand, and the second combo box is filled with models of that brand. Can I reuse my existing component? If the component knows what data it displays, it can not be used to display different data.


If you need a generic component, then make a generic component. No one is forcing you to specify dependencies in all of your components.


OK :)


David talked about the IQueryParams protocol in the presentation, it basically lets you parametrize the component's data.


I personally built my entire framework on top of Om, so always good to hear what David has to say:

https://github.com/zubairq/coils


I guess the Gregor Kiczales slides are here: http://www.cs.ubc.ca/~gregor/papers/kiczales-oopsla-07-for-v... (page 16)


I was thinking about this the other day and the web just magically solved all my thoughts and wrapped it up into a perfect video.

Really excited about building my project in this (and learning clojure and Om Next).


Is there a description of how react avoids event listeners? How does it observe changes in a model? I've never heard that aspect associated with react before.


It doesn't avoid them. You listen to events, and then you change your model. Based on new model view is rendered using the code you provide (one way rendering - model to code). Then React compares the two instances of rendered view (before the event and after) and renders the changes if there are any.


Has anyone an idea how pagination would work/look like with the presented query syntax?




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: