JavaScript & Canonical Web Architecture
In late 1998 and early 2000 I wrote material on "Standard Operating Environments" (SOE) for a big Telco's "Enterprise Architecture". They wanted to contain technology proliferation, avoid systems interoperability issues and build teams having common set of technical skills to ease moving people across projects. Back then there where two completing Web Application development frameworks:
- Java Application Servlets and Java Server Pages - build on top of Sun Java and supported by tools such as IBM WebSphere, WebLogic, Apache Tomcat and JBOSS Application Servers and
- Microsoft .NET - in all its expanding guises and including: IIS, MTS, ActiveX/COM/DCOM/COM+ and ASPs (Active Server Pages) or .NET
My brain goes foggy looking back at the evolving set of Microsoft and other technologies. Many of the concepts of JSP and ASP architectures were made available via an Open Source alternative:
- LAMP (Linux, Apache, MySQL and PHP) - where PHP provided an open source variation of JSPs and ASPs
Last time I attempted using web development tools in any depth (in 2010) I found CSSs (cascading style sheets) completely non-intuiative. Now though through a process of slow osmosis, I kind of "get" how CSSs work. In 2010 I also looked at "AJAX", purchasing two very fat O'Reilly books:
- JavaScipt - The Definitive Guide (5th Edition) (C)opyright 2006 (Javan Rhinoceros) - now up to 7th Edition (2020)... &
- Ajax - The Definitive Guide (1st Edition) (C)opyright 2008 (Wooly Monkey)
The learning curve looked steep and was far removed from the HTML form based templates of prior tooling.
Fast forward to 2022, once more I have a need for some Web development as part of a short Proof of Concept (PoC) project. I have a programmer allocated to assist (or two if including myself ;-) ), so what technology should we use ?
Read on to find out, how "architecture decision" drove selection of development approach and for an architectural introduction to JavaScript and its tooling.
Status: Mid Nov 2022 - First cut of prototype UI completed and intial draft of blog completed
NOTE: "JavaScript" - trademark is owned by Oracle (was owned by Sun)
The Canonical Web Architecture
Having been in deep freeze on Web application development for over ten years I need to:
- Determine what language and tools to use,
- Develop a UI that uses a Thrift based server for resouce access and
- Built and deploy the solution on Ubuntu platforms
Developing the Web application quickly (!!) is only constant from "way back when".
Lets start from the lens of "A Canonical Web Architecture":
This defines a "high level" view of Web Application architecture, with these common components:
- Browser - which has JavaScript Engine and HTML renderer
- [Optional: Web Server] - which could be external to application server to provide "reverse proxy" and SSL termination
- Application Server - which could be either a framework server, such as Apache Tomcat or JBOSS for Java based web applications or NodeJS for JavaScript based web applications
- [Optional: Database Layer] - for persistence, not required in my case, as I am using micro-services layer ("External Systems" pattern)
- [Optional: External Systems] - in my case this is exposed as Thift based micro-services (written in Java).
The architecture does not look simple... nor potentially quick to implement. If I proceeded based on historical frameworks, then I would end up installing: Apache Web Server (or NGINX), Apache Tomcat (or JBOSS) and this is before even writing a single line of application code.
To strip out complication and make this as simple as possible, my determination was to avoid unnecessary infrastructure components and layers. Ideally the architecture would be just have an "Application Server" directly exposing the Web URI, with caveat that I can put a reverse proxy in front of this in future if needed.
That strips the Canonical Web Architecture down to single "Application Server" plus the Thrift micro-services server. Stripping out the "platform infrastructure" and using micro-service is consistent with "server-less" paradigm. Its not that there are no servers, rather that that this logic is now managed within the application framework and as part of application development and deployment.
Next decision.. what should I build the "server-less" Web application with in 2022 ?
Server-less Application for Web UI
In a classic Web Application framework the Web Server or Application Server is responsible for handling the HTTP/S protcol and passes request to the Web application through callbacks with Request/Response parameters.
In the case of JSP, ASP & PHP the call back is passed to a "template form" which extracts data from the Request and completes the form, by getting data from database or other systems, passing this back response as HTTP/XML payload.
The basic architecture is the same irrespective of Language or Framework:
---
--- Java Servlet
---
public interface Servlet {
...
void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
...
}
---
--- NodeJS
--- 1. First request handler
const RequestListener = function (req, res) { ... }
--- 2. Now pass to server creation function
const server = http.createServer(RequestListener);
---
--- or using JavaScript ES6 "arrow function" shorthand for this same thing
---
const server = http.createServer( (req, res) => { ... });
---
--- C# .NET
---
public virtual void ProcessRequest (System.Web.HttpContext context);
--
--- where HttpContext wraps both request & repsonse object
---
public sealed class HttpContext : IServiceProvider
The goal is to strip back the infrastructure needs and keep our UI application simple by having the "application" being the "Application Server" as much as possible. Doing a quick review of options, candidates for developing the UI could be:
- Go - has some nice features (multiple return values, delayed execution), is supported by Thrift and relatively easy to learn if you have previously used C/C++ or Java.
- Java - is a general purpose language with lots of class libraries, but these are targetted for creating WAR files for deployment into a Java application server. Though deployment via embedded Jetty is also possible and more consistent with minimalistic approach.
- JavaScript - is the programming language for the browser and so knowlege of this is required for Web UI development. Its structure shares a lot with Scheme Lisp dialect, having "eval/apply" functions that allow code to be treated as data and it has 'C' like syntax. Server client code is generated by Thrift.
- PHP - is hugely prevalent and supported as target for Thrift generated client library, but no "simple" serverless deployment option is available. A web app needs to use either NGINX or Apache Web Server.
- Python - has many advocates and it is supported by Thrift. However in using it for creating test Thrift clients, I found the syntax and indentation based structuring construct, too fiddly and prone to errors ... This is personal opinion, likely readily refuted, but as I am the "second developer" of target UI my opioion gets airplay ;-) .
- Ruby on Rails - has reputation for providing UI development innovation (as well as naming innovation ;-) , as this is "Rails" framework written in Ruby programmming language). Uses Ruby (an OO based programming language for Model View Controller (MVC) for Web UI development.
All these options are mature and have large user bases. The criteria for selection and use include:
- Learning Curve - for language and framework / libraries (which is obviously bias'ed toward current developer skill set: Java, C/C++, Lisp).
- Adoption & Support - extent of use and availability of documentation, knowledge and expertise.
- Openess and Community - is it "open", does it have clear standards process attached to it and does it have an active community involved in its onging development.
- Utility, Tools and Libraries - are there development tools, does it have libraries required for development of our UI and can it be readily integrated with Thrift micro-services and can I use the knowledge elsewhere (i.e. applicable for client-side and server-side programming).
- Small Footprint - low infrastructure need and ease of deployment (conceptually "serverless" not AWS Lamba "serverless).
So before venturing an opinion I looked at what the current trends are in the market (see below Appendies for details).
This showed that PHP, Java, JavaScript have strongest market support across a range of different areas. Putting the options into a simple "Decision Model" for assessment (Just Enough Architecture in action) with criteria for:
- Scoring - Exceeds or Better = 1, Meets = 0, Does not Meet or Worse = -1
- Mandatory/Screening Criteria - Thrift support and Small Footprint deployment
The result was:
JavaScript scored highest, even with low learning curve score (as target developers were JavaScript novices), based on "Small Footprint" and "Utility (Front End/Back End skills reusability) scoring.
NOTE #1: The low score for "Learning Curve" is evidenced by the two fat O'Reilly titles, that got put on the shelf some time back and my electing to tackle my last Web UI development task using PHP. PHP is much simpler, both conceptually and in practice, with easy to grasp HTML template model. In this case though PHP is not an option as it needs to be deployed via a Web Server, failing the mandatory "Small Footprint" criteria. Ditto for Java and "Ruby on Rails". The higher scores for JavaScript, Go and Java for Openess and Community is that they have formal process and corporate support to evolve, rather than pure community model or strong central controller. While the "Learning Curve" criteria is coloured as it could lends itself to personal bias, in this case did not really impact scoring.
NOTE #2: The "Decision Model" architecture work product should have screening critieria (for inclusion/exclusion) and clearly defined scoring criteria for assessment. This is preferable to "Pros/Cons" assessment which typically do not use consistent criteria across the alternates. If you have a set of Pros/Cons turn each of these into an assessment criteria which can then be applied consistently to each option. For a complex assessment, group criteria together into categories of concern and use weighting to apply to scores and overall groups.
NOTE #3: If we update scoring for Java based on use of embedded Jetty then it, would now pass mandatory screening criteria and come in with better scope than Go. So Java scores better than newer more fashionable options.
JavaScript Language, Engines and Frameworks
Opting to use JavaScript, here are some basic facts and about the language and tools for JavaScript development.
Some history..
JavaScript was developed at Netscape back in 1995. It is an interpreted language with roots in Scheme Lisp and 'C' style syntax. The original interpreter was embedded in the Netscape brower and subsequently reversed engineered by Microsoft. The Microsoft JScript JavaScript interpreter was realeased in 1996. Due to resulting variations in behaviour Netscape choose to submit the language into a standardization process via the European Computer Manufacturers Association (ECMA) in 1997. The result was the first version of the "ECMAScript", as JavaScript was a registered trademark of Sun, who where early partner in its development with Netscape. The ECMScript specification has contined to evolve, with most current version being "13th Edition – ECMAScript 2022". These editions are abbreviated as "ES6" for 6th Edition or more recently by year "ES2017".
JavaScript Engines
There are now three major JavaScript execution engines:
- V8 Engine - developed by Google and used in Google Chrome and Microsoft Edge browers and for the NodeJS server side JavaScript execution environment
- MonkeySpider - is the evolution of the Mozilla engine and is used in FireFox browser
- JavaScriptCore - is the Apple engine and used in the Safari browser
JavaScript Tools and Frameworks
When JavaScript was introduced in the browser, it was common to serve up a JavaScript payload having URI references to externally sourced code. These external code snippets would be pulled by the JavaScript engine from external web servers:
Serving JavaScript that contains references to external libraries raises multiple issues:
- Security - as external environment cannot be trusted (addressed by disallowing use of URI to serverr different to the originating source server)
- Dependency Failure - as the library reference could either fail to load or the version of the referenced library could change, breaking the overall JavaScript program.
These same issues occur in server-side based JavaScript environments as well. The issue is inherent to JavaScript programs, as distribution is always via source code. With Javascript source is directly executed and there is no intermediate compiled object code. The JavaScript development tools help to manage the building of JavaScript programs using the source code based modules. The development process and example applicable tools are illustrated here (just focusing on the coding and building):
The diagram uses V8, NodeJS, Yarn, Sass, Gulp, JQuery & Git to show the roles of various tools. In taxonomy of tools, I use Java development as an analogy, where "==" means simillar to not equivalent. From above diagram, have:
- V8 - the JavaScript engine, the barebones to run a JavaScript program (== Java VM)
- NodeJS - a service side JavaScript runtime environment, provides the V8 engine, a set of libraries and other tool to make V8 useful (== Java JRE/JDK)
- Yarn - a JavaScript Package manager. Manages code libraries (as web accessible repository) used to build your JavaScript program and pulls these down into your local build environemt (== Maven for a Java project, except that Maven maintains a repository of jar files, rather than source files)
- Sass - is pre-processor for "sass" based cascading style sheets (CSSs). Sass provides a languge for definition and processing of css files. The reason this exists is that CSS were originally mostly hand crafted as part of HTML template definition, now css have become part of sophisticated HTML rendering and needed extension to lend itself to programatic manipulation. Sass if one of a number of css preprocessors (== ??, no Java equivalent)
- Gulp - a JavaScript build tool that brings together all the "bits" of your JavaScript program, so it has everything required to create a consolidated downloadable (to client side/browser) set of JavaScript programs. It also supports changing library namespaces referenced names to avoid clashes and to reduce the size of the JavaScript program (== Java ANT)
- JQuery - is just an example of a JavaScript library, it is the most widely used libraries as it is provides DOM (Document Object Model). You need it to serve, manipulate and tranverse HTML documents on client & server sides (== Apache Xerces2 Java XML Parser, one of many DOM/XML/HTML libraries)
- Git - git is git is git and as JavaScript libraries are distributed as source code (no Jar files here thank you) the library manager like Node Package Manager and Yarn all pull code directly from git based respositorise (== git :-) is agnostic to language of source code)
Finally as many of the JavaScript tools are written in JavaScript, these also require a JavaScript runtime environment. So it does not matter if you are creating client-side or server-side JavaScript programs, you will need JavaScript runtime environment for your JavaScript tooling. Hence why "2. Build" "chevron" in the "JavaScript Tool Chain" diagram above has "greyed-out" V8 and NodeJS logos. In this case NodeJS is there to run the tools, rather than being the used tool.
Dependency Management across Libraries
This needs to be addressed by JavaScript program build tools. This is the role of the JavaScript Package Manager. The packae manger provide a function analogous to that of Maven when building Java applications.
As part of the JavaScript program build process, the "package.json" file provides specification of which JavaScript libraries at what version are required to build the program. This is used by both NodeJS and Yarn. Taking directives from the "package.json" file, the build process brings in all the required JavaScript code into local build environment. Here is an example Yarn "package.json" from an Open Source "Commento" project:
{
"name": "commento",
"version": "1.0.0",
"main": "index.js",
"repository": "git@gitlab.com:commento/commento.git",
"author": "Adhityaa <c.adhityaa@gmail.com> Anton Linevych anton@linevich.net",
"license": "MIT",
"private": true,
"devDependencies": {
"chartist": "0.11.0",
"fixmyjs": "2.0.0",
"gulp": "4.0.2",
"gulp-clean-css": "3.9.4",
"gulp-concat": "2.6.1",
"gulp-eslint": "5.0.0",
"gulp-html-minifier": "0.1.8",
"gulp-rename": "1.3.0",
"gulp-sass": "4.0.1",
"gulp-sourcemaps": "2.6.4",
"gulp-uglify": "3.0.0",
"highlightjs": "9.10.0",
"html-minifier": "3.5.7",
"jquery": "3.2.1",
"normalize-scss": "7.0.1",
"sass": "1.5.1",
"uglify-js": "3.4.1",
"vue": "2.5.16"
},
"dependencies": {
"eslint": "^5.10.0"
}
}
This file provide an equivalent to the Java/Eclipse/Maven ".pom" file, which defines all the libraries that are needed to be pulled into the Java compilation process.
Next pulling all the JavaScript files together...
JavaScript Modules
Historically JavaScript had no concept of modules, you simply had files and Javascript and you could concatenate these together prior loading to execution engine or have different <script>...</script> embedded tags in your html to load different JavaScript files.
JavaScript's initial modularity mechanism was introduced through writing loading utilities which then applied the result to the "eval" function (this submits string to the JavaScript interpreter). This evolved into the "require()" statement to import and exposing definitions through "module.export" object. This practice was adopted by NodeJS and become know as "CommonJS module". As JavaScript continued to evolve through ECMA proces ES6 introduced modules into the language through the import/export declarations. Thus ES6 import/export are part of JavaScript Language, while Node "require" & "module.export" are operations on objects.
Much of the information you find via google search is illustrated using examples with "require". There are are significant differences in behaviour between the "CommonJS module" and ES6 (this is covered in section on asynchronous and Promises in "JavaScript - The Language" below). In Node how a given set of directories is managed is via the "package.json" file, which can have a entry for:
- "type": "module" – treat all .js files in this directory and below (until there is another "package.json" file as ES6 modules and enable "strict" mode (i.e. enforce ES6 language compliance, including import/export declaration support)
- "type": "commonjs" - enable module/modules based modules through "require" and "module" classes.
Note that in Node:
- you can "import" legacy "CommonJS module" based code (this needs awareness of "package.json" placement within your source hiearchy to behave correctly,
- but you cannot use "require" based import within ES6 modules (.js files).
Node behavior is also controllable using different file extensions, with .mjs for ES6 modules and .cjs for "CommonJS module" code. Personally I do not think using file extension naming is a good idea and expect that all new JavaScript will end up being ES6 compliant.
For browser, control of module type is via script tag: <script type="module"> for ES6 compliance.
So to code and simple example...
Here is example of import for Node code. As my "resouce interface" is via Thrift based server, I needed to import the Thrift compiler generated code (thrift generated code uses "commonjs") which was imported into my ES6 UI module:
---
--- The ES6 Imports for EX.js using the thrift generated code
--- NOTE: The ../gen-nodejs is the directory for the Thrift generated code
--- The directory structure used here is important to ensure correct behaviour
--- EX-PROJECT
--- /gen-nodejs <<== generated code (commonjs) --- packjage.json <<="=" package.json to turn on "common.js" ---- ex "module" (es6 strict) ex.js ui (es6) ex-pages.js support $ cat . ... import * as ini from 'ini'; fs 'fs'; thrift 'thrift'; ldtypes '.. gen-nodejs ex_thrfit_types.js'; ld exthrift.js'; express 'express'; pages '. x-pages.js'; the corresponding "package.json" file that is in same directory (. ) module note: this type="=" (ie es6) { "type" : "module", "dependencies": "ini": "^3.0.1", "express": "^4.18.2", "thrift": "^0.16.0" } and which up above at level .. common.js not es6 strict "commonjs", }<>
NOTE: you need to use Thrift compiler "--gen js:node,es6" flags to get this result.
To bring together all the JavaScript module into working code you can use:
- Node & Node Package Manager - for simple Server Side JavaScript and
- Node, Yarn, Gulp and Saas - for larger "AJAX" Web UI projects
So in summary:
- A JavaScript module is simply a JavaScript file that is flagged as such (explicity via package.json, script attribute or filename convention or or implicity via inclusion of require/import/export directives)
- You can import a module with "require" class invocation or ES6 "import" declaration
- You can define exposed variables, functions, classes etc within a JavaScript file using "module.export" (& "export") and ES6 "export"
- There are behaviour differences in "commonjs" & ES6 "module" mechanims
- You can use ES6 "import" to import "commonjs" modules, but you cannot use "commonjs" "require" within ES6 modules.
- You can control the module type using "package.json", file name extensions and <script type="module"> tag
- Other build tools such as: Yarn, Gulp, Saas will be applicable depending on your project needs and if your Web UI is just using Server Side JavaScript or both Server Side and Client Side (browser based) JavaScript.
JavaScript - the Language
As a language JavaScript itself should look pretty famillar to any C/C++ & Java developer. The "learning curve" scoring relates more the JavaScript execution model than its does to the core language itself. The ES6 updates provided many signficant extensions to the language with introduction of explicit classes (vs. prototype based templates) including inheritance via the "class" and "extends" keywords and with the "strict" directive abandoned full backward compatability with original JavaScript specification.
Examples of this need to flag "strict" compliance was the introducion of many new reservered words including: class, extends, const, let which could have been used as identifiers in older JavaScript programs and so would break these if executed with "strict" compliance.
The complication of JavaScript is that it was designed to run in browser and so has an asynchronous threaded execution model based on an event loop (just like many GUI frameworks).
This "asynchronous" model can cause surprises if you are not well aware of it as function that you would typically expect to act synchronously (reading a file) returns before the completion and you need to allow for this in your code.
Before ES6 this was typically managed via inclusion of callback functions for return of result and with ES6 JavaScript uses "Promises" as a generic way of handling management of asynchromous completion of requests.
Specific examples of differences in the asynchronous behavior can be seen when using the "CommonJS module" vs the ES6 "module":
- CommonJS module - require is executed synchronously while
- ES6 import - is handled asynchronously.
With ES2017 the async, await keywords where introduced to provide more control of the asynchronous execution model and allow programmer control the behaviour and avoid need for Promise.
Here is a trivial example using ES6 Promise to for a request to Thrift server:
//
// 1. Open Connection to Thrift Server
//
// Import the general and generated service functions
import * as thrift from 'thrift';
import * as ex from '../gen-nodejs/EX.js';
const host = "127.0.0.1";
const port = "9090";
let lastErr = null;
let exRes = null;
let exPromise = null;
// Check if we have a Promise
function isPromise(prom) {
return prom != null && typeof prom.then === 'function';
}
// Handle error/exception case
ferr = function(err) { console.log("ERR>> EX: ", err); lastErr = err; };
// get our connection to Thrift based server
let connection = thrift.createConnection(host, port, {
transport : thriftTransport,
protocol : thriftProtocol
});
connection.on('error', ferr);
// create our client which provide handle to call our service methods
const exClient = thrift.createClient(ex, connection);
//
// 2. Now call async thrift service (exService):
//
let arg1 = {...};
let arg2 = {...};
exPromise = exClient.exService(arg1, arg2)
.then((res) => { console.log('DBG>> exService got: ', res);
if (! (isPromise(res))) exRes = res;
return res;})
.catch(ferr);
if (isPromise(exPromise)) {
console.log('DBG>> Yep - got promise as expected!');
else {
console.log('DBG>> What, no promise!!!');
}
//
// Explanation:
// a. call the Thrift service function (exService) via client handle
// b. using "then" method set up the function that will receive result
// c. allow for error/exception case using "catch" method
// d. NOTE: while this looks like a "try/catch" clause, it acts asychronously, so we squirel the results in the lastErr / exRes variables for later retrieval
//. e. NOTE: the isPromise function looks to see if the returned object
// is a promise. The only thing that defines an object
// as a promise is that is has a "then" method,
// so we just test to see if the object has a "then" method
//
That is it for JavaScript, as this was not supposed to be a tutorial on JavaScript, but a review of main architecture and concepts.
An experienced Java developer will find the core language pretty familiar. The ES6 additions mean that JavaScript now has full object oriented development capabilities.
The only other JavaScript concept that might be a bit foreign is in the use of "closures". This uses functions that encapsulate lexically scoped identifiers so these can be accessed outside of the initial local scope of the function definition. These should be famillar to Java developers who have used its "lamba" enhancements and to someone who has used Scheme Lisp.
And on to AJAX (or fat book #2)
As discussed above you can build a Web Application using straight JavaScript server-side programming model. But JavaScript's origins were to help create more dynamic Web pages via client-side programming using the JavaScript engine on the Browser.
This has evolved over the years from simple scripting of traditional HTML web pages to AJAX and beyond.
So what is AJAX ? The original acronym stands for "Asynchronous Javascript And Xml".
The "asynchronous" is in relation to typical http/s request where a request is made and the user waits until all the data is loaded and then the browser renders the result. With JavaScript on the browser this can execute (behaviour is controllable) on its own execution thread that is independent from the main user thread. This allow the JavaScript to make further request asynchronously and so decouples the http rendering from the request made back to server via the JavaScript program.
In original AJAX these request are made through the XMLHTTPRequest method which is used to make further HTTP requests (GET, POST, UPDATE, DELETE etc) with results returned via XML in response body.
That is the XML part, but XMLHTTPRequest does not mandate XML for payload and any data format can be returned with JSON now being the preferred format, as working with JSON in JavaScript is very easy and JSON representation is very close to JavaScript object representation.
As part of the evolution the XMLHTTPRequest has now been supplanted by "fetch" request as perferred way to get data.
NOTE: while AJAX has "asychronous" in its acronym, both the JavaScript in browser and in Node use an event loop model to achieve their asynchronous model. The result is that by default there is only a single thread within the engine executing. This simplifies things for programmers as they do not need worry about ensuring thread safety across multiple executing thread.
The structural components
So in 2010 looking at the combination of "AJAX - The Definitive Guide" and "JavaScript - The Definitive Guide" this all seemed too daunting and not a way to fast track Web UI development. I retreated to PHP, which served my purpose. Revisiting this in 2022, is AJAX still as complicated as "fat book #2" would have you believe ?
Happily, I believe the answer is no. To make something large and complex you need to follow a simple strategy:
- Understand the scope of ambition
- Identify key use cases which will test the structural concepts
- Look to distill the essential abstractions and foundation on which you can build
- Start with the simple core and build up from this
- Expect to have to refactor/refine if things get to complicated or you cannot readily accommodate new needs
- Try not to underestimate the difficulting ahead (most troubled projects start with failure to anticipate the complexity ahead of them).
The problem with "fat book #2" is that it starts with a survey of ways of doing things that runs to 200 pages and then go into details on how to implement lots of different user interface elements. It fails to to capture (2) & (3), so the reader is lost before even starting.
It is important understand that AJAX did not relie on new technologies, it simply used the existing technology in a new way. The core of this was usage model was:
- Document Object Model (DOM) - provided structural view of html document, which JavaScript uses to supports navigation and manipulation of the document. If you create your initial document programatically on server side, then it is easier to think about its manipulate on client side later ...
- Browser Events - allow you to hook JavaScript invocation to browser events (button press. mouse entry/exit, mouse click, page load etc). This allows you to control via JavaScript how the page responds to events
- Uses CSS to control page behaviour, not just its "look" / "style" - examples of this is that CSS can be used to make things visible/invisible, within viewport or out of viewport
- html <div> tags - to identify html structural elements (ie DOM hiearchy) that can be replaced/manipulated via Document Object Model (DOM) and can be assigned CSS styles. Note that div does not mark out document semantic structure (like: header, body, nav etc), just its DOM structural aspects, so div is not likely to go away soon
- fetch (was XMLHTTPRequest) to get data and your client side JavaScript program behave asychnonously to the currently rendered html page
These are the core structural elements that were used to create AJAX web applications and now simply "web applications" as the AJAX qualification has become redundant.
As always you can do this from scratch or you can leverage existing frameworks and tools to create your client-side scripted web application.
Frameworks and Web Standards
There a number of client side JavaScript and CSS frameworks and libraries available. A survey of these (by popularity/adoption) is given in the appendices.
For my pretty simple UI needs I have elected to:
- Modularise HTML elements generation to simplify html responses from NodeJS express and allow easy application of CSS definition to elements
- Provide limited fetch and browser event support to allow request of asynchronous request with
- DOM element replacement to display last request result (returned via JavaScript Promises)
One aspect of Web Programming in 2022 that is now different is that it is all HTML from now on, as w3c.org XHTML efforts have not been adopted by the browser vendors (WHATWG - Apple, Google, Microsoft & Mozilla). To quote:
- "The XML syntax for HTML was formerly referred to as "XHTML", but this specification does not use that term (among other reasons, because no such term is used for the HTML syntaxes of MathML and SVG)."
So while WHATWG "living standard" may sound like "not stable", the rally around HTML provides greater certainty than the XML driven mania of XHTML, XFORM, XFRAME etc... XHTML is dead long live HTML.
NOTE: more details likely to follow as UI development evolves.
Realising Canonical Web Architecture in 2022
Adoption of JavaScript for both server-side and client-side development has proved to be viable.
- NodeJS with express has allowed rapid development of Web Application, while avoiding need for seperate HTTP and Application Servers
- Using fetch and JQuery can achieve asynchronous retreival and render the results
- Thrift compiler still generates "CommonJS module" code (even with --gen js,node,es6 flags), but using "package.json" type flag and ability to import "commonjs" module via ES6 "import" means you can work around this
- Understanding the ES6 changes NodeJS thread and asychronous Promise model and how these impact Thrift integration was area requiring most "exploration" to get working (documentation is poor)
- 80% of what you find via google has past its "use by date", as is much of "fat book #2" :-)
- But "fat book #1" 7th Edition is both thinner than 5th Edition, technically current and a better place to go for introduction to modern Web Application Development (Chapter 15: JavaScript in Web Browsers)
The first cut of our prototype Web UI is done, using JavaScript only and the learning curve barrier for AJAX development initially faced in 2010, was no longer an impediment. This is due to API improvements and starting simple with no dynamic content and then adding this once once comfortable with DOM and JavaScript.
As always the problem I found was that while there is lots of small technically detailed material, there not much in the way of high level architectural and conceptual context to make wading through the technical details productive. Hence this post.
Closing:
- expect a refresh with additional technical details on this blog as PoC UI gets further improvments in look, feel and function and
- follow up in "Just Enough Architecture - Technical Tips" blog on Thrift with JavaScript where there is a gap in the documentation required to get this doing quickly.
References and Links:
Java/Jakarta Servlets and JSPs - helped to create the greate divide between Java and .NET and now packaged as Java Enterprise Edition or Java EE
Microsoft .NET and ASPs - Microsoft provided the Active Server Page and ASP.NET as an alternative to Java and JSPs. Now open sourced as ASP.NET
PHP - while there was battle going on with Java & .NET, PHP quietly become the most popular way to develope forms based Web applications. Can be officially found at php.net (the .net that beats .NET, in "server side languge" use share according to w3tech.com survey)
V8 JavaScript Engine - to execute JavaScript requires an engine. On the Server side the Google Open Sourced V8 Javascript Engine is likely the most used and embedded engine. It is also used as JavaScript engine in the Chrome Browser
NodeJS - NodeJS is a JavaScript runtime framework, for executing JavaScript on server. It includes a combination of V8 JavaScript engine with a set of libraries (http & express - libraries provide alternate ways to build HTTP servers with NodeJS) and an package manager (Node Package Manager). The use of NodeJS to provide the runtime environment does not dictate what other JavaScript framework / component libraries you might wish to use. With NodeJS you can have server-side JavaScript and with browser have client side JavaScript code. The server side and client side JavaScript enviornments are independent. There are many AJAX implementations that do not use Server-Side JavaScript.
express - a simple JavaScript http server developement framework, helps realise the ambition of having Web Application that is the Application Server.
JQuery - DOM object manipulation for JavaScript
Apache Thrift - a back to the future distributed systems development tool using IDL (remember SUN/ONC RPC / XDR etc ?) to generate client and server stubs and avoid having to worry about JSON/XML and all that other on the wire packaging nonsense.
C# IHttpHandler.ProcessRequest(HttpContext) Method - handles http request in C#, though generally .NET framework uses ASP templates
Serverless computing - a appliation development pattern that removes need to for knowledge or visibility into the applicaiton deployment infrastructure (such as Web Servers and J2EE application servers).
w3tech.com - collects web infrastructure and tooling data using web crawling
Statista - quotes survery results...
- Frameworks - "Most used web frameworks among developers worldwide, as of 2022"
- Programming Languages - "Most used programming languages among developers worldwide as of 2022"
Structure and Interpretation of Computer Programs - by Abelson & Sussman, provides a deep dive into conceptual models for programming and computing using Scheme Lisp for illustration. JavaScript has many properties that similar to Scheme and chapter 4 - Metalinguistic Abstraction provides details of the "eval/apply" loop which is consistent with JavaScript interpreter. Available as pdf.
JavaScript Reference - Documentation on Mozilla Developer Network
ECMAScript Standard - managed by ECMA International Technical Committee TC39, which manages the language evolution process
JavaScript - The Definitive Guide - while you can get by doing google search for all your JavaScript related questions, this "fat book #1" has much to commend it and is much more current (in 7th Edition guise) and well written than much of what you will find on the web via google and complements the reference material on "Mozilla Developer Network" nicely
Building Web Applications with UML - more about Web Application Architecture in general than "building with UML" (1st Edition being assumed source for "Canonical Web Architecture" as referenced by "Developing Agent-Oriented Information Systems for the Enterprise" - Jaelson Castro, Manuel Kolp & John Mylopoulos, see below, however I first came across this via Grady Booch blog, which is no longer available on line...). 2nd Edition does not have "Canonical Web Architecture" figure.
AJAX - "Asychronous Javascript And Xml" - a web programming model that used the browsers JavaScript engine to create dynamic web content. This is significantly different from traditional web HTTP/HTML model where request resulted in "static" pages and any dynamic behaviour was through downloading of Java, Flash and ActiveX programs using the HTML <object> tag. Now all of these binary program models are obselete, thanks to JavaScript in the browser and alternate programming models like AJAX.
Thrift with JavaScript - my notes on getting these to work..
Appendices
Web Development & Programming Tools Usage
The following usage and survey data provide some useful hints in current trends and usage of Web Development Tools.
w3tech.com data is based on doing web crawling and so provides a view of what is out there, while statista is based on surveys and so give current trends and focus:
PHP's continued dominance as the most prevalent language for server-side programming is readily apparent but down from the 80% it had in 2013. ASP.NET has seen singificant decline from 19% in 2013. Ruby has lifted signficantly from < 1% to 5.7% and Java has staged a comeback from 2.8% in 2013 to 4.5%. JavaScript did not make the cut in 2013 but is now appearing.
The turning off of Flash, first by force by Apple and then its withdrawal by Adobe leaves only JavaScript on the client.
NodeJS appearing in the Web Server category is interesting as this is indicative of it support for "server-less" application server paradigm and its initial motiviation for providing non-blocking I/O model specifically tuned for web applications. Note, no other "server-less" delivery vehicle is on list (including AWS Lamba).
And now the survey results from Statista:
The survey results are hugely slanted to JavaScript based frameworks, paints a signficantly different view that the w3tech.com one, which give much more wait to Ruby, while PHP is not here at all.
On Programming Languages JavaScript is again the most popular, with Python, Java and PHP showing significant share. The appearance of "HTML/CSS" is clear indication of importance of CSS plays in creating "lovely looking" pages (like this one ;-) ).
For productive JavaScript development there are a large number of libraries available. Here is the usage based on web crawling:
Again there is discrepencies between web crawl and survery, but both have JQuery as essential, which other libraries are discretionary and likely a choice of one vs another will be required.