The Web is a Frustrating Application Platform
Preface: In this article, I am not talking about the web as the document-based hypermedia system. I'm talking about the web platform as a potential replacement for desktop and mobile applications.
I've spent the last few years trying to bring a rich client application to the web platform. The web has enormous promise. It runs almost everywhere. It's secure. It's seamless - customers click a link and land in your application. Deployment doesn't require any installers or code signing tools. HTML and CSS are fantastic for UIs, flows, transitions, typography, and layout. HTTP has excellent tooling.
At the same time, the web is enormously frustrating. I cut my teeth on Windows and Linux. I love having rich control over the quality of the experience delivered to customers. For comparison, on Windows and Linux:
- APIs are low-level. Higher-level functionality is built by the community into user-mode libraries. The platform vendor provides capabilities and the community provides convenience. A web analogue would be jQuery on top of the DOM, or Three.js on top of WebGL.
- APIs are capable. With few exceptions, the entire functionality of the machine is accessible to programs. There are a few security concerns here, but in many cases, it's possible to provide capability without sacrificing security.
- For the sake of performance and flexibility, native platform vendors are somewhat willing to leave a bit of undefined behavior on the table. The specific behavior of an allocator, for example, is left undefined between releases.
Before I get into what I think has to improve at a high level, let me describe some of my specific complaints about the web platform:
- On WebGL, there's no way to detect available VRAM. The current recommendation appears to be to use a "reasonable amount" of VRAM and back off if you run into problems...
- Web Workers had the same problem - there was no way to query the number of available cores. I believe an API is coming that finally exposes this, however.
- Lack of direct access to the browser's message loop. For some bizarre reason, both Mozilla and Google were highly resistant to implementing setImmediate, resulting in some... interesting... polyfills.
- STILL no fast typed array memcpy! This is just ridiculous. The best option I've seen allocates a new aliasing Uint8Array object so it can call .set(). The proposed .copyWithin() doesn't allow copying between two TypedArrays, which means you can't use it for copying XMLHttpRequest data into the asm.js heap.
- CORS, thanks to preflight OPTIONS requests, turns out to be quite expensive to use in practice. For every cross-origin request with credentials or using custom headers, you pay an extra network round-trip for the preflight OPTIONS request. For high performance, you'll want to keep your JSON services on the same domain as your site and bypass CORS entirely. If you don't need credentials, avoid custom headers and stick with query parameters.
- I can't find the mailing list thread, but there was a discussion where it came up that ES6 Promises cannot be implemented in user code, and es-discuss folks considered that acceptable.
- JavaScript stack traces are not standardized and may never be so, as there are apparently security concerns with allowing JavaScript code to inspect the names of functions higher on the stack. In general, handling and reporting application errors on the web is a disaster.
- No weak references. The web API community is resistant to anything that could possibly expose garbage collection implementation details.
- No way to specify priority on XMLHttpRequests, for any supported protocols (HTTP, SPDY, HTTP/2). If you read this blog, you already know the sordid details.
- vector minimum and maximum in SIMD.js will likely sacrifice performance for the sake of cross-platform consistent behavior in the presence of NaNs. Personally, I'd prefer this be left as undefined behavior for maximum performance, but JavaScript convention is that every operation is exactly defined, to the point that all browsers have, in practice, attempted to standardize the order of iteration through hash tables.
- No efficient way to encode and decode between Strings and ArrayBuffer. See the Twitter thread.
Why is the web like this? Why isn't the web more like a typical native platform? My hypothesis follows.
Software and standards are a product of time and the pressures acting upon them. Browser vendors have been burned in the past by trying to advance the platform in a backwards-incompatible way. Thus, there is enormous fear of exposing any undefined behavior. Couple that with security concerns (some well-founded, some not), and you have a recipe for APIs that don't actually expose the full set of functionality required for rich, high-performance applications.
Moreover, there is widespread ambiguity on whether the web should provide high-level or low-level APIs. In mailing list discussions, it seems generally expected that web programmers will call JavaScript APIs directly. Yet, to expose maximum functionality and performance, the APIs should be low-level. This tension was a large source of the discussion around my request to get direct access to protocol priorities in XMLHttpRequest.
Couple all of this with some strong personalities, and you end up with something that's actually rather hostile to systems programmers like myself.
I feel the web standards community is disempowering to developers. Paraphrasing: "You don't want text encodings." "Let's not even bother supporting HTTP/1." "Weak references are too dangerous to put in peoples' hands." [private communication]
Part of me wishes browser vendors would stop playing nice with each other and instead court developers as aggressively as possible, even if that means new incompatible APIs. For example, perhaps asm.js would have never existed without Native Client. :)
I am not alone in this point of view! I recently discovered the Extensible Web Manifesto which aims to correct many of my gripes by focusing on low-level APIs that advance the capabilities of the web platform.
I still think the web has promise. But now I see that the problem isn't that browsers have to catch up with native platform capabilities. Instead, it's politics. The web standards authors need to focus on exposing raw functionality, even if it allows programmers to shoot themselves in the foot.
It's up to you to decide whether the web is the right platform for your app. But I never thought I would say "I miss Microsoft's low-level APIs." :)