Friday, July 31, 2015

Polymer WebComponents Client served by Java Actors

Front end development productivity has been stalling for a long time. I'd even say regarding productivity, there was no substantial improvement since the days of Smalltalk (Bubble Event Model, MVC done right, component based).

Weird enough, for a long time things got worse: Document centric web technology made classic and proven component centric design patterns hard to implement.

For reasons unknown to me (fill in some major raging), it took some 15 years until a decent and well thought webcomponent standard (proposal) arised: WebComponents. Its kind an umbrella of several standards, most importantly:
  • Html Templates - the ability to have markup snippets which are not "seen" and processed by the browser but can be "instantiated" programmatically later on.
  • Html Imports - finally the ability to include a bundle of css, html and javascript implicitely resolving dependencies by not loading an import twice. Style does not leak out to the main document.
  • Shadow Dom
It would not be a real web technology without some serious drawbacks: Html Imports are handled by the browser, so you'll get many http requests when loading a webcomponent app using html imports to resolve dependencies.
As the Html standard is strictly separated from the Http protocol, simple solutions such as server side imports (to reduce number of http requests) can never be part of an official standard.

Anyway, with Http-2's pipelining and multiplexing features html-imports won't be an issue within some 3 to 5 years (..), until then some workarounds and shim's are required.

Github repo for this blog "Buzzword Cloud": kontraktor-polymer-example

Live Demohttp://46.4.83.116/polymer/ (just sign in with anything except user 'admin'). Requires Websocket connectivity, modern browser (uses webcomps-lite.js, so no IE). Curious wether it survives ;-).

Currently Chrome and Opera implement WebComponents, however there is a well working polyfill for mozilla + safari and a last resort polyfill for ie.
Using a server side html import shim (as provided by kontraktor's http4k), web component based apps run on android 4.x and IOS safari.

(Polymer) WebComponents in short



a web component with dependencies (link rel='import'), embedded style, a template and code


Dependency Management with Imports ( "<link rel='import' ..>" )

The browser does not load an imported document twice and evaluates html imports linearly. This way dependencies are resolved in correct order implicitly. An imported html snippet may contain (nearby) arbitrary html such as scripts, css, .. most often it will contain the definition of a web component.

Encapsulation

Styles and templates defined inside an imported html component do not "leak" to the containing document.
Web components support data binding (one/two way). Typically a Web component coordinates its direct children only (encapsulation). Template elements can be easily accessed with "this.$.elemId".

Application structure

An application also consists of components. Starting from the main-app component, one subdivides an app hierarchically into smaller subcompontents, which has a nice self-structuring effect, as one creates reusable visual components along the way.

The main index.html typically refers to the main app component only (kr-login is an overlay component handling authentication with kontraktor webapp server):



That's nice and pretty straight forward .. but lets have a look what my simple sample application's footprint looks like:

  Web Reality:


hm .. you might imagine how such an app will load on a mobile device, as the number of concurrent connections typically is limited to 2..6 and a request latency of 200 to 500ms isn't uncommon. As bandwidth increases continously, but latency roughly stays the same reducing the number of requests pays off even at cost of increased initial bandwidth for many apps.

In order to reduce the number of requests and bandwidth usage, the JavaScript community maintains a load of tools minifying, aggregating and preprocessing resources. When using Java at the server side, one ends up having two build systems, gradle or maven for your java stuff, node.js based javascript tools like bower, grunt, vulcanize etc. . In addition a lot of temporary (redundant) artifacts are created this way.

As Java web server landscape mostly sticks to server-centric "Look-'ma-we-can-do-ze-web™" applications, its hardly possible to make use of modern javascript frameworks using Java at server side, especially as REAL JAVA DEVELOPERS DO NOT SIMPLY INSTALL NODE.JS (though they have a windows installer now ;) ..). Nashorn unfortunately isn't yet there, currently it fails to replace node.js due to missing API or detail incompatibilities.





I think its time for an unobtrusive pointer to my kontraktor actor library, which abstracts away most of the messy stuff allowing for direct communication of JavaScript and Java Actors via http or websockets.



Even when serving single page applications, there is stuff only a web server can implement effectively:

  • dynamically inline Html-Import's 
  • dynamically minify scripts (even inline javascript)

In essence inlining, minification and compression are temporary wire-level optimizations, no need to add this to the build and have your project cluttered up. Kontraktor's Http4k optimizes served content dynamically if run in production mode.
The same application with (kontraktor-)Http4k in production mode:


even better: As imports are removed during server side inlining, the web app runs under Safari IOS and Android 4.4.2 default browser.

Actor based Server side

Wether its a TCP Server Socket accepting client(-socket)s or a client browser connecting a web server: its structurally the same pattern:

1. server listens for authentication/connection requests.
2. server authenticates/handles a newly connecting client and instantiates/opens a client connection (webapp terminology: session).

What's different when comparing a TCP server and a WebApp Http server is
  • underlying transport protocol
  • message encoding
As kontraktor maps actors to a concrete transport topology at runtime, a web app server application does not look special:


a generic server using actors

The decision on transport and encoding is done by publishing the server actor. The underlying framework (kontraktor) then will map the high level behaviour description to a concrete transport and encoding. E.g. for websockets + http longpoll transports it would look like:


On client side, js4k.js implements the api required to talk to java actors (using a reduced tell/ask - style API).

So with a different transport mapping, a webapp backend might be used as an in-process or tcp-connectable service.

So far so good, however a webapp needs html-import inlining, minification and file serving ...
At this point there is an end to the abstraction game, so kontraktor simply leverages the flexibility of RedHat's Undertow by providing a "resource path" FileResource handler.


The resource path file handler parses .html files and inlines+minifies (depending on settings) html-import's, css links and script tags. Ofc for development this should be turned off.
The resource path works like Java's classpath, which means a referenced file is looked up starting with the first path entry advancing along the resource path until a match is found. This can be nice in order to quickly switch versions of components used and keep your libs organized (no copying required).

As html is fully parsed by Http4k (JSoup parser ftw), its recommended to keep your stuff syntactically correct. In addition keep in mind that actors require non-blocking + async implementation of server side logic, have your blocking database calls "outsourced" to kontraktors thread pool like



Conclusion:
  • javascript frameworks + web standards keep improving. A rich landscape of libraries and ready to use components has grown.
  • they increasingly come with node.js based tooling 
  • JVM based non-blocking servers scale better and have a much bigger pool of server side software components
  • kontraktor http4k + js4k.js helps closing the gap and simplifies development by optimizing webapp file structure and size dynamically and abstracting (not annotating!) away irrelevant details and enterprisey ceremony.

8 comments:

  1. Hello Rüdiger,

    great post and tons of resources to dive into. My feelings after reading (may be wrong):

    - Not sure about productivity stalling, but with similar time you build more complex stuff now

    - YES, WebComponents are great

    - YES, Http/2 has huge potential

    - Document centric is not bad per se: if problem/domain can be naturally modelled in document style (REST in original Fielding sense) then you can leverage external help to reduce latency (proxies, browser cache, CDNs). Seeing Http just as a lame verbose transport, inferior to binary sockets may be true in a lot of use cases, but not all.

    - frontend build tools are increasingly complex and allow more productivity (coffee- & typescript, SASS/Less etc) but add layers, steps and indirections. Its nice to reference font-files and SVGs in CSS, but loading these deeper graphs leads to more waterfall style loading.

    - clever bundling on server-side partly exists, but in the age of Hotspot-VMs Im waiting for the adaptive server-side framework, that optimizes, advertises/pushes the dependent resources much smarter (profiling on statistics, request/user, network (3G/4G/cable); probing browser cache etc).

    - What really counts is "start render" and "page loaded". Even your bundled example looks like a small waterfall. The fontfile (CWB..woff2))seems to be discovered in CSS. If so, probably letting the browser discover the fontfile already before CSS loads, has more end user impact then reducing the backend server's response time by 30%. You can do crazy stuff with prefetching (https://plus.google.com/+IlyaGrigorik/posts/ahSpGgohSDo) and
    soon http/2 push and priorities.

    Cheers!

    ReplyDelete
  2. Hi Joachim,

    "Not sure about productivity stalling, but with similar time you build more complex stuff now"

    Hm .. technically more complex, but from my POV the basic mechanics of mapping data to a visual representation, assist + map + validate user input to form a transaction/change action, then update visualization have not changed significantly and still requires a lot of "hand written" and verbose code. The level of abstraction has not changed for decades (not that I know every GUI framework since the 80's ..)

    "document centric, CDN"

    A big productivity driver in team driven UI development is the ability to encapsulate behaviour + look and processing into a visual component which can be easily reused. I found it hard to achieve something similar with document-centric approaches (especially for enterprise-grade UI, where (frequently) complex input assist + validation is required). It often ended having to add different snippets at different places in order to make a visual component work, in addition there is a lack of composability (nest reusable components into each other) with document centric approaches). Many JS frameworks and server frameworks addressed that, however these where isolated solutions working in scope of a single framework only.

    CDN- mostly everytime i find a website hanging its a slowish cdn request. Ofc improved caching later on might pay off for that ..

    "front end build tools"

    Agree, my gut tells me some of this stuff is kind of over the top and creates its own hell of complexity on top of the existing soup.

    "clever bundling"

    Yeah that's definitely a direction to go for. My example is quite simple, actually one could register several "resource path" providers thereby splitting into several "chunks" of bundled resources. Its also possible with "no-inline" to disable inlining on a by-tag base.

    I admit I am not a webapp super-expert, I am looking for a good tradeoff of "automated optimization" and productivity + simplicity. From what I have tested, "waterfalling" works well up to middle-sized apps. It pays off more on mobile devices as network latency is higher there. Time to render ofc cannot be that well with html imports (except http 2 can be used), however I'd be perfectly fine with a gmail alike splash while SPA loads, I'd rather wait once as with each click.

    Regarding http 2 I am kind of reluctant to rely on it, as it will take some time until this is broadly available.

    The example app imports half of google paper+iron theme + d3 + wordcloud (like ~45 imports) so its actually not that small. I haven't spent time on font resolution, but thanks for the hint, maybe one could automatically inject prefetch statements on server side. Anyway I think adaptive + intelligent runtime webapp optimization is the way to go and I likely will explore further optimizations in this area as I'll spend some time with webapps for the next month (thanks for the link btw. ;-) ).


    ReplyDelete
  3. Hi Rüdiger,
    thanks for replying. One remark, two more links:

    1) with CDN i didnt mean public CDNs for jquery, D3 etc. but offloading own stuff to cloudfront, cloudflare. Its usually closer/faster to end-users. Also helps sometimes for SEO, since it looks like e.g. content from spanish IPs ranks better in spanish Google then content from UK or DE datacenters

    2) If you pay adwords, then pagespeed score ( https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2F46.4.83.116%2Fpolymer%2F&tab=desktop) is relevant for the money you burn per click

    3) A bit more detail then PageSpeed-plugin etc. http://www.webpagetest.org/result/150805_58_VTC/

    ReplyDelete
  4. Hi Joachim, very much aprecciate your comptent comments and additions. Coming from an enterprise application background, I kind of lack knowledge regarding retail web apps.

    ReplyDelete
  5. Btw pagespeed gave me 99 of 100 both on mobile and desktop because of missing html/css minification. As content is delivered gzipped anyway, this would enhance only 2%.

    ReplyDelete
  6. This post is likeable, and your blog is very interesting, congratulations :-)

    ReplyDelete
  7. thank you for the information, it very interesting and useful

    ReplyDelete