Showing posts with label HTML5. Show all posts
Showing posts with label HTML5. Show all posts

Single Page Applications And The Impending Concurrency Explosion

Ok explosion might be a little dramatic but bear with me for a moment.

Going from a Multi Page Application (MPA, did I just coin a retronym?) to a Single Page Application (SPA) is like going from a single synchronization lock (coarse-grained locking) to multiple synchronization locks (fine-grained locking).

Anyone who has made that journey knows that it is fraught with peril. Even for a solo developer it can be difficult to implement without error. For a team of developers, with varying level of application domain familiarity and developer expertise, it is far more daunting.


How is going from an MPA to an SPA like this concurrency problem?

With an MPA the full page submit is analogous to acquiring a single lock. The state of the app is updated in one fell swoop.

With an SPA the same amount of state will be distributed across separate async requests that fire, largely, in response to user interaction. Since the user drives the requests any ordering requirements must be enforced by the developer(s).

Each of these requests is like acquiring one of many locks (e.g., read-only consumers only need the read lock, which is shareable, whereas read-write consumers need both the read and write lock (not shareable)). On the user interface, independently queryable data can update different UI widgets in parallel*. This increases the perceived interactivity of the web app but comes at the cost of increased complexity.

It can be difficult to coordinate multiple lock scenarios even when all of the developers working on the project are co-located. Part of this difficulty stems from the difficulty modeling concurrency - there are many notations available and none used by everyone.

Throw in developers distributed geographically, varying levels of expertise, even varying languages and the coordination required to prevent lock-related errors becomes quite substantial.

The theory of it is sound but in practice there are often subtle data dependencies that don't reveal themselves when all data is fetched and the page is rendered in one fell swoop. That is, the dependencies don't show up until teasing apart the data needed for the various dynamic portions of the page. In other words, the data access patterns of an SPA are going to be different than the data access patterns of an MPA.

The res:// Protocol And Phoning Home

Problem

An internal tool phones home.

Why does it phone home?

It’s a WPF app that defers most of the heavy lifting to a web app rendered through a Web Browser control.

Initial Approach

Easy enough – clone the website. But where to host it? The tool needs to run without network access.

Second step

Store the contents of the site in the executable itself. It’s a .NET WPF app and this seems like the sort of problem embedded resources were intended to solve.

Unfortunately the WPF web browser control, a light wrapper around IE’s ActiveX control, doesn’t know* how to read from managed resources. It *does* however, know how to read from native/win32/PE resources.

How do we store a native resource in a .NET executable?

.NET executables conform to the PE (Portable Executable) format that all windows executables use. Native resources (native is a retronym in this case, before .NET this was the only kind of resource) are defined as part of the PE spec.

It turns out that Visual Studio automatically creates a native/win32 resource for console projects. This resource stores the icon that the shell uses to represent the executable. And it allows you to specify this file, a compiled resource file (*.res), instead of having it automatically generated.

But how do we get a compiled resource file?

The resource related tooling in Visual Studio for .NET projects assumes use of .NET resources. These are a totally different kettle of fish than native/win32 resources. The MSDN article “About Resource Files” explains how to create compiled resource files (spoiler alert: there’s a resource compiler).

But HTML content assumes a directory structure

Native resources predate the WWW by several years. There’s no support for hierarchically arranged files. There are resource types (e.g., RT_BITMAP, RT_FONT, etc…) but other than resource type the structure is entirely flat. This necessitated some manual mapping/flattening of the HTML.

The cloned website included javascript, css and image content. Most of the image content was due to the ExtJS javascript library. Other than the image content there were very few links: each of these was manually converted to a res:// link.

CSS allows references to resources (e.g., background images) via its URL function. Modern CSS libraries make heavy use of the URL function. It turns out that there were several dozen files referenced this way. Fortunately URL accepts relative and absolute URLs. These were programmatically flattened, included in the compiled resource (.res) file and the referencing URL function updated with the res:// link.

All of the files, including images (*.png), javascript and style sheets, were included in the compiled resource file as type RT_HTML (#23) yielding internal URLs in the form res://MyExecutableName.exe/#23/MappedFileName.ext.

AngularJS: To input type=number or input type=text?

Suppose you have objects that contain numeric properties and these objects are bound to HTML form elements.
HTML5 introduced support for input type=”number” which preserves type fidelity (e.g., object.someProperty starts off as a number in the typeof === ‘number’ sense and remains that way after the user has entered a different number). Preserving type fidelity makes change detection (that is, detecting if the user has changed the model) very simple – angular.equals() can be used directly.
There seem to be two general approaches:
  1. Bind the numeric properties to input type=text form elements then, on save, make sure to cast them back to numeric form (ala parseFloat()).
    1. This tends to complicate the save handler. The data has to be massaged back into numeric form before sending it back to the database.
    2. It also tends to complicate change detection – since the original values from the database are Numbers but angular’s binding does not preserve this type fidelity when bound to input type=text.
    3. It also complicates internal manipulation – e.g., if changing one property requires the recalculation of other properties then this logic will need to account for numbers that get converted into strings via angular binding.
    4. This approach is supported in pretty much every browser.
  2. Bind the numeric properties to input type=number form elements.
    1. This simplifies change detection (angular.equals()).
    2. This simplifies the save handlers.
    3. This simplifies internal manipulation since all manipulators can be certain that they’re dealing with Number variables.
    4. NULL valued numerics are still a problem as these may need to be detected and then defaulted to 0 (or some other numeric default).
    5. Browser support for input type=number is not good.
I would much prefer approach 2 which takes advantage of browser support for numerics and let angular preserve type fidelity throughout model binding. The potential cost of handling NULLs when data is fetched from the database is IMHO small compared to the extra cost of converting back and forth between numbers and strings. Unfortunately, if you have to support any version of IE below 12/Edge then this approach won’t work. [8/2016 EDIT - thank you HTML5 Shim!]

Debugging JavaScript With Chrome’s Developer Tools

While going through this chrome developer tools doc to get a better handle on JavaScript debugging in Chrome, I ran across these:

  1. ESC toggles the console drawer.
  2. Chrome’s version of “step over library source” is to provide a way to Blacklist files. e.g., Blacklisting angular.js would prevent the debugger from stepping into angular.js during the debugging session.
  3. Chrome’s version of “first chance exceptions” is to provide a way to pause on caught exceptions (stop sign with a pause symbol on it, don’t forget to check “Pause on Caught Exceptions”).
  4. Right click a breakpoint to make it a conditional breakpoint.

Setting a Breakpoint when the DOM changes

Breakpoints can be set based on when an element’s DOM hierarchy changes, one of its attributes is changed and when the element is removed from the DOM. These breakpoints can be set through the right click menu on an element (Elements pane, element –> right click –>  Break On). These breakpoints show up in the DOM Breakpoints side panel.

Setting a Breakpoint when a JavaScript event is triggered

This can be done from the Sources panel, Event Listener Breakpoints side panel. All supported events are listed in tree form (e.g., mouse –> mouseout for the mouse out event).

Dealing with Minification

Minification, which reduces the amount of data downloaded by the browser, tends to make JavaScript much harder for human debugging. The {} icon at the bottom of the source pane (Sources panel) is the ‘Pretty Print’ button. The Pretty Print button attempts to de-minify the source.