
Faster, Better DOM manipulation with Dommy and ClojureScript - zackzackzack
http://blog.getprismatic.com/blog/2013/4/29/faster-better-dom-manipulation-with-dommy-and-clojurescript
======
jlongster
ClojureScript is so different from JavaScript that it makes sense write a more
native DOM library for it. As someone with a lisp background, it's very cool
to see a high-profile company like Prismatic using it.

However, macros for javascript are being worked on. sweet.js is coming along
_really_ well, and just needs to continue ironing out bugs and maturing.
<http://sweetjs.org/> I believe that it could have a profound effect on
JavaScript, such as parsing selector string at expand time.

~~~
aria
Other languages can totally have macros, but unless you have homoiconicity,
which lisp languages do, macros aren't easy to use or support. In
ClojureScript, macros are built into the language.

~~~
jlongster
That really only applies to `define-macro` style macros. You can have syntax-
case style macros if the language can disambiguate reading and parsing, which
a lot of them have trouble with, and why they don't support them.

sweet.js figured out how to do that in javascript, so we have full syntax-case
macros just as easily.

~~~
swannodette
Wait so does sweet.js support arbitrary JS execution in macros now?

~~~
jlongster
Not yet, but it's theoretically possibly with all the groundwork that's
already been done. See <https://github.com/mozilla/sweet.js/issues/12>

So I should have said syntax-rules (for now). My bad!

~~~
swannodette
Seems like you would still need to provide something like syntax objects and a
special API to manipulate them?

~~~
jlongster
This involves a longer discussion, and I'm not sure what Tim is thinking along
those lines. Suffice to say, Clojure's macros are always going to be the best,
but I have pretty high hopes that you can get 95% of the way with sweet.js. :)

------
k3n
Interesting, but I'm not sure how appropriate it is to be comparing it to
jQuery in such a head-to-head fashion such as by saying "15x slower", etc.
Does Dommy offer the same features (including the browser support) that jQuery
does? If not, then you're just comparing apples to oranges, and it doesn't
sound like it does (or even plans to) on account that it sounds like there are
design decisions that separate the two with regards to the published API
("Inspired by jQuery, but adapted to be functional in order to better fit with
ClojureScript core").

Also, wouldn't it be more accurate for the selector testing to actually test
against Sizzle[1]?

Other features aren't even present in jQuery, such as templating, and so I'm
not sure why you'd even compare that. Yes people can and do use templates with
jQuery, but that's an implementation detail and is not a concern of the
library itself; jQuery does not coerce or force you to use a slow templating
system, and most any good templating system will also have a compilation step
that is run at build-time. So yeah, you can take some ugly userland jQuery
example code and make specific code that is faster..

1\. <https://github.com/jquery/sizzle>

~~~
connerp
> Does Dommy offer the same features (including the browser support) that
> jQuery does?

No, currently Dommy has a smaller feature set that we think covers a majority
of use cases, while maintaining reasonable browser support. Our general
philosophy is to add functionality as we need it or others request it. I don't
think this makes the comparison invalid. We're comparing the general use cases
(selectors, basic dom manipulation, etc.) that any DOM library should have.
Can you point out a specific comparison that doesn't apply because of api
differences or browser support?

> wouldn't it be more accurate for the selector testing to actually test
> against Sizzle[1]?

Part of the point is to show that you can achieve the same elegant chaining-
like syntax as jQuery without wrapping selections, so maintaining the wrapped
jQuery selectors are important for comparison.

> Other features aren't even present in jQuery, such as templating, and so I'm
> not sure why you'd even compare that.

The point of the templating comparison is to show that macros can provide a
significant performance boost while maintaining a sane syntax.

~~~
k3n
Isn't Dommy basically testing plain JS vs. jQuery at this point? That's kind
of my point.

I'm also curious how well Dommy would perform in the 'real world'; seeing as
everything is compiled down to plain JS, then the divide between library and
implementation is removed. jQuery is a larger download hit on the first visit,
but if it's already in cache (perhaps before they even reach your site) then
the only code required to be downloaded is your app's specific implementation.

In the Dommy example for the templates, the jQuery code is 10 lines -- when
formatted like generated.js (the equivalent Dommy code) and removing 2
unnecessary variable declarations. By contrast, generated.js is around 60
lines (giving you a few on account that there's some empty else-
statements...). I know minification can do wonders, but the jQuery
implementation is clearly going to be much fewer bytes. At what point does it
eclipse the size of the jQuery lib itself? I guess that's up to usage.

If your library _is_ the implementation, then it'd seem like you'd have a lot
more data being sent over the wire, and likely more often as well on account
of any changes to the Dommy which alters the output will have an effect on the
cached files for each of them where that functionality was used. On the other
hand, updating jQuery means only the 1 file has to be re-downloaded -- and not
every userland implementation which uses the API.

------
olenhad
This is super impressive. I'm going to use this for my frontend work now. On a
side note, what's the idiomatic structure, or "design pattern" for cljs front
end code? I would assume something based on MVC, with models comprising of
atoms with watches, Views consisting of hiccup templates and controllers
gluing dom events to models and views. Am I close?

~~~
aria
We internally have a nice component/widget abstraction we use which is not
quite MVC, but we think cleans up a lot of web development. We will release in
the near future once we perfect it.

~~~
Jonovono
Cool! I am wondering if you have worked with other frameworks like
Pedestal.io, C2, or WebFUI, Ganelon. Or any others. What do you think of them?

I am just getting started with Clojure/CS and am evaluating the different
options.

<http://pedestal.io/> <http://keminglabs.com/c2/>
<https://github.com/drcode/webfui> <http://ganelon.tomeklipski.com/>

~~~
codewright
Take a look at Luminus.

------
d0m
>> Again the time saving comes from macros moving the work of parsing the
template data structures from runtime to compile-time and directly generating
efficient JavaScript.

If it ends being javascript string in the ends, how is it 7x faster (or
whatever number)? I mean, sure the compiler could optimize a part of my code,
but other javascript compiler could do it to.. right?

Although I find the Clojure example very sexy, I don't like how the examples
tries to compare to contrived Javascript. I.e. I've been coding javascript for
a couple years and I've never used jQuery "sort/filter/slice". But more
importantly, it uses pre-defined function in Dommy but not in javascript. For
instance:

    
    
      (->> (sel [:ul.my-list :li])
         (sort-by #(-> % (sel :input.last-name) .-value))
    

This uses sort-by where there's:

    
    
      function(a, b) {
        return (
            $(a).find('input.last-name').val()
          .localeCompare(
            $(b).find('input.last-name').val()
          )
        );
    

in Javascript.. Obviously, I can say:

    
    
      $('ul.my-list li').sortBy(function(x) { return x.attr('last-name'); }
    

My point isn't that much that jQuery is longer/shorter, but mostly that if two
examples in two different languages are to be compared, it makes sense to use
the same function.. where in this case sort-by is a high-level sort.

>> One is the loneliest number

It's not just "1" or "more than one", it's also zero. Iterating on a list
makes it such that you can freely think in a high-level way about the
operation and not about the exceptional cases. I.e. $('.blabla').hide(); It
Just Works.

>> (mapv #(add-class! % :first-ten-adults)))

Yes, of course you can use map.. but using $('..').addClass('first-ten-
adults') makes it so much easier to deal with, instead of knowing what works
on one object, what works on multiple objects, what will throw an error if
there's nothing, etc.

Meh.

I think Dommy is a great library but the author didn't do a great job at
explaining why it rocks. I guess attacking a very popular language with its
most popular library doesn't help :p

~~~
laughinghan
Re sort-by: the point there was to show how Dommy gets for free "features"
that have to be added to jQuery and contribute to its code size.

Re one/map: you can still do operations on sets of 0, 1, or any number of
elements, without knowing how many, by always doing map. There's nothing to
keep track of, everything always only works on one object, so you're explicit
about whether you're operating on exactly one object, or whether you don't
care how many objects you're operating on. The latter is just as convenient as
jQuery; the former is safer and deliberate. In jQuery, on the other hand, you
have to keep track of what works on one object and what works on multiple
objects: .text() and .text('a string') are asymmetrical, for example.

------
st3redstripe
Whilst I'm sure this is clever - I guess I'll never understand the obsession
with micro DOM optimisations. When, ever, are we severely held back by the
'speed' of our selectors? It just doesn't happen!

~~~
epidemian
There are some web apps out there that are sluggish as hell if one doesn't
have the latest beefy machine. Gmail or Google Doc running on old hardwere are
examples of this. "Mobile web" apps are _very_ sensitive to DOM manipulation
performance too.

I'm not saying that all sluggish performance in web apps is caused by
inefficient DOM manipulations, but having a DRY _and_ efficient way to express
DOM manipulations could help a lot in that regard =D

------
aria
Author here. Happy to answer any questions/concerns.

~~~
dustingetz
does Dommy provide a pure API on top of the DOM? (e.g., lens based) I don't
immediately understand how one would make that performant given that the DOM
is a mutable data structure.

edit: WebFUI[1] is one clojurescript project trying to provide a pure
interface for dom manipulation; there are others.

[1] <https://github.com/drcode/webfui>

~~~
aria
No. We're not trying to do something pure on top of the DOM. That isn't
feasible for performant manipulation. Being functional is about more than just
immutability.

We use standard manipulation.

------
codewright
Carthago delenda est: when are you re-releasing the software you yanked from
your Github?

~~~
w01fe
We're working on it! We removed the software because it needed extensive
cross-project reorganization, consolidation, and cleanup which just wasn't
possible to do with a clean upgrade path using available resources (3 backend
engineers). Plans are to re-release all of this and more, and we've already
started with Plumbing and Graph: <https://github.com/prismatic/plumbing>.
Which librar(ies) in particular are you most interested in?

------
j_m_b
All this talk of jQuery and no mention of domina
(<https://github.com/levand/domina>) the native clojurescript dom manipulation
library? I've since abandoned css and jquery selectors in favor of using
domina.xpath.

I also want to mention webfui (<https://github.com/drcode/webfui>). It is
authored by Conrad Barski, who also wrote Land of Lisp. He gave a nice talk
about it at the Chicago Clojure meetup group a few months back. He is a fellow
hacker news user so I figured he deserved a shout out.

------
dmix
I'd love to use Clojure and clojurescript to replace js/ruby. It's a shame I
never come across consulting gigs that use it. Or know any local clojure devs,
so I'm still wary of using it on my own projects.

So it continues to only be the ideal choice for pet projects.

------
iamleppert
It would be more interesting if someone wrote something like this for standard
jQuery-compatible syntax. jQuery code in, compiled selectors out. And it's
just standard javascript, so no learning curve to learn or anything.

~~~
staltz
Yes, and a compile step is necessary to produce JS code for those macros.
Sounds like it would be really good with coffeescript, like.

