javascript devices architecture: building extensible ...

2 downloads 4488 Views 287KB Size Report
JAVASCRIPT DEVICES ARCHITECTURE: BUILDING EXTENSIBLE RICH. WEB APPLICATIONS USING BLACK BOX COMPOSITION. Lim, Seung Chan [ Slim ].
JAVASCRIPT DEVICES ARCHITECTURE: BUILDING EXTENSIBLE RICH WEB APPLICATIONS USING BLACK BOX COMPOSITION Lim, Seung Chan [ Slim ] MAYA Desigin, Inc. 2100 Wharton street suite #702 Pittsburgh, PA 15206 USA [email protected]

ABSTRACT Through the years, the Web browser has steadily matured as a rich application-development platform. For Web applications to stay current with the latest interaction patterns and client-side technologies, it is important that they’re built with flexibility in mind. In this paper, we present our work on a W3C and ECMA standardscompliant JavaScript component architecture that allows Web applications to be built using black box composition to allow for easier extension, substitution, and reuse. Our proposed architecture has six interesting features. First, the components are client-resident, allowing the architecture to be back-end agnostic. Second, standardscompliant HTML and JavaScript are used to define the components. Third, it helps document and expose a set of clearly defined interface contracts for the components. Fourth, by encapsulating the components as black boxes, the learning curve for the components is lowered because they can be used and extended without the need to understand their internal workings. Fifth, the components can be easily integrated into existing Web applications. Sixth, we provide a runtime within which the components can engage in asynchronous communication. Finally, we evaluate the proposed architecture through the development of a sample Web application, and study the ease of extension and component substitution. KEY WORDS Reuse, Extensible Systems, Black Box Composition

1. Introduction The emergence of the Web browser as a thin-client platform has kept much of the effort in Web application engineering on the server. As various research initiatives have focused on the server in recent years [1,2,3], the same amount of effort has not been directed towards the client. As a result, users were trapped with the UI paradigm of frequent full-page refresh and forward/back button navigation. Thus the Web was largely regarded as too sluggish a platform for dynamic applications characterized by richer interaction patterns.

As browsers became more sophisticated with client-side scripting technologies, attempts were made to enhance usability with the use of JavaScript. However, users were slow to adopt the latest browsers; hence efforts seeking better ways to engineer client-side Web applications were kept to a minimum. Instead, the focus shifted to solutions such as Flash [4], which enabled rich user experience at the expense of forgoing Web standards and requiring client-side plug-in installation. In recent years, a few companies did manage to develop sophisticated home-grown JavaScript solutions that provided users with richer interaction in their Web applications. However, adding such rich interaction requires a significant development effort, and more often than not, the perceived high cost can keep smaller companies from implementing such interactions. Furthermore, novel interaction patterns that result from home-grown solutions are often proprietary, and may not be packaged to be readily integrated into other Web applications. This makes reuse very difficult, and, as a result, hampers the adaptation of dynamic interaction patterns in the Web community at large. In this paper we attempt to bring richer interaction capabilities to the Web by proposing a Web standardscompliant architecture that applies proven engineering design practices to facilitate the proliferation and reuse of novel interaction patterns in Web applications. The architecture proposed here borrows heavily from a paradigm called the Information Devices Architecture or IDA. IDA is being designed independently at MAYA Design [5] based upon a carefully selected set of basic ideas and techniques of software engineering. We believe that the architecture can yield maximum scalability, tractability and comprehensiveness to a given system while allowing for transparent communication among disparate components that make up the system at large. JavaScript Devices Architecture is an adaptation of IDA for the JavaScript platform. Perhaps the easiest way to illustrate the architecture is to compare it to one of the best, yet oft overlooked, examples of highly extensible software systems: the

UNIX shell [6]. In a UNIX shell, different executables can interact via a pipe, and as long as the output of the source executable matches the input requirement of the target, a whole new application can be built from their assembly. It is not necessary to understand how the internals of the individual executables work, as long as you know that, for example, ls outputs lines of text and that grep can take that as input to print out only the lines that match the given text pattern. It is also possible to substitute grep with egrep for its performance benefits, since they share the same interface. Similar to the paradigm found in the UNIX shell, our solution uses the black box encapsulation pattern to define clear interface contracts for JavaScript components. Having a clearly defined set of interfaces makes it possible to use the components without requiring the user to understand their internal workings [7]. Furthermore, the standardization of the communication mechanism among these components through our runtime kernel makes it possible to arrange the components in an arbitrary configuration during deployment or run time. As a result, these attributes lead to a highly extensible and configurable system. Moreover, the individual components that makes up the system become easier to reuse and integrate into other existing systems. Finally, the solution uses standard HTML tags to define the inclusion of these black box components in an HTML document, so that the technology can be adapted immediately. Therefore, the proposed model can allow applications to be built such that they are flexible with respect to changing requirements and evolving design.

2. Related Works One way to extend Web applications to enable responsive and dynamic interaction is through the use of plug-ins such as Flash [4] or Curl [8]. The two main disadvantages to this approach are that Web browser plug-ins are not compliant with W3C standards, and that they require additional software installation. Another option is to use embedded controls such as ActiveX or Java applets. However, the former has met with resistance due to potential security concerns and platform-dependency, and the latter with widely varying levels of support and compatibility across browsers and platforms. A more standards-compliant extension paradigm that exists for the Web takes the form of JavaScript toolkits, which are object oriented API sources that may be inserted into an HTML document. JavaScript is a standard embraced by ECMA and has become the primary scripting language used to access the W3C DOM standard. Support for the language has improved across Web browsers over the years as well. There are numerous examples of great toolkits that follow this paradigm. Some of the most notable ones are DynAPI [9], and more recently, Dojo [10]. However, aside from the cost associated with the learning curve behind new APIs,

when one uses third-party APIs that provide a set of object oriented classes, it is possible to run into vendor lock-in problems. For example, if you want to later swap out the class in use for a class from a different vendor, it might require rewriting a significant portion of the code base. Out of fear of such vendor lock-in problems, companies may feel forced to reinvent the wheel and build their own one-off solutions. This decreases the chance of component reuse in the general Webdevelopment community. Moreover, to extend the functionality of the provided classes, you may need to spend a considerable amount of time understanding their internals. Engineers are often afraid of committing to such time-consuming activities and may decide that it is more cost-effective to write such a toolkit on their own.

3. JavaScript Black Box Devices 3.1 Interface Contract Building systems that are highly extensible requires a modular design. In order for a modular system to become extensible, it is desirable to foster an environment where code reuse is attainable at low cost. For low cost code reuse to be feasible, the way in which a given component can be used needs to be clearly communicated [7]. Therefore, a well-defined and unavoidable contract, which governs the components’ interfaces, is crucial [7]. To realize this concept, we first introduce the term “JavaScript devices” to denote components that have attached input and output “terminals” that act as welldefined interfaces through which the components are described and utilized. “Terminals” are the input and output ports through which data flows. Each JavaScript device is able to execute a prearranged (though configurable) behavior, and is made interoperable with other devices by explicitly declaring its input and output specification through these sets of terminals. Devices simply send messages to and from these named terminals, with the powerful consequence that they do not need to know where other devices are deployed in the architecture. In particular, this location independence even allows the execution context to be freely moved between client and server to optimize performance without affecting the behavior of the device. Let’s take an example of how the implementations of two simple devices, TimeOut.js and HelloWorld.js, define their terminals: Table 1. Terminal Specification for TimeOut.js Name Time Out

Direction

Behavior

Message Type

Output

Emits 1 when its timer goes off

Number

Table 2. Terminal Specification for HelloWorld.js Name

Direction

HelloWorld

Input

Behavior Pops up a “Hello World” alert box

Message Type Any

To assemble these devices in our architecture, you need to understand only the terminal specifications, and not their internal workings. This allows applications to be written in terms of interfaces, leading to substantially fewer dependencies [7]. 3.2 Identity and Encapsulation One of the reasons why HTML enjoyed such a high adoption rate was its simple syntax and instant gratification. Authoring in HTML consisted of typing tags with a few added attributes, and the Web browser rewarded the author with an instant rendering of a new user interface component. The code that renders the interface was essentially completely encapsulated within the tag. Our design follows a similar pattern. For each component there is a single JavaScript source file and a
tag that contains a set of special attributes. Multiple instances of a given component can be declared by introducing additional
tags without the need to include the JavaScript source file again. This makes integration simple and intuitive. Furthermore, to prevent name collision issues between devices, we require that each device be associated with a universally unique identifier or UUID [11]. The following code skeleton illustrates how the HelloWorld.js device implementation self-associates itself with a UUID: declareImplementation( "E4D9BBE5C7AC436cABCA04F235FEA34D”, function(props) { // your code goes here }, “My HelloWorld.js Device”);

included, the following example illustrates how an instance of the TimeOut.js device, “bar,” can be set to time out in one second by specifying its “timeout_in” property in its declaration:


3.4 Composition The traditional model employed by most Object-Oriented JavaScript APIs uses inheritance for code reuse. Code reuse via inheritance leads to tightly coupled implementations that often become difficult to extend or replace without the potential of introducing instability to the system [7]. An extensible software system, however, must be able to adapt to new tasks without the need to access their internal implementations [12]. The black box pattern allows the system to stay flexible with respect to changes and extensions by adopting a loosely coupled component architecture. The basic philosophy behind black box composition is that it allows engineers to create new design patterns by interconnecting an arbitrary graph of design patterns, and the resulting pattern can in turn be used in another pattern [7]. In this model, we rely on the substitutability of interfaces and the ability to select appropriate interfaces at deployment or run time to build a system [7]. To illustrate the idea, suppose that we want to take the two devices and create a system that will wait one second before popping up a “Hello World” alert box. Figure 1 illustrates the design of such a system:

The arguments to declareImplementation consist of the device’s UUID, followed by its class constructor, ending with an optional argument that provides its humanreadable name. The implementation of the HelloWorld.js device can be included in an HTML file using the tag:

We can then declare an instance of the HelloWorld.js device and associate it with a local id such as “foo”:


3.3 Parameterization In order to allow a degree of customization to an otherwise immutable black box, we provide a mechanism by which the individual devices can be parameterized during declaration. This also allows multiple instances of the same device to take on different properties. Assuming that the implementation of the TimeOut.js device is

Figure 1. System Diagram

To create this system, we need to define a dataflow between the two devices. To address the dataflow, we introduce the notion of delivery “channels” connecting existing pairs of input and output terminals. There can be many channels between arbitrary pairs of input and output terminals, and when a message is posted on an output terminal, it is delivered to all input terminals that have channels between them. The dataflow shown in Figure 1 can be created with the following function call: connectTerminals([“bar,” “timed_out”], [“foo,” “greet”]);

This instructs all messages posted on the output terminal timed_out on bar to be delivered to the input terminal greet on foo. Messages may arrive at the input terminal greet at any given time with a guarantee that subsequent message arrivals will not interrupt the handling of this

message. Instead, these new messages will get queued for later handling. It should be noted that the destination of all messages posted to the output terminal timed_out is hidden from bar.

Figure 2 illustrates the compositional model used to create this Web application, along with the terminal connections among the JavaScript devices.

4. Runtime Environment 4.1 Asynchronous Message Passing In order to construct and run the individual JavaScript devices and to facilitate the dataflow among them, the architecture provides a runtime kernel called “JavaScript Star,” or “JsStar.” JsStar is a JavaScript source file that contains the minimum amount of code required to implement a kernel that can construct the devices and provide a message-passing infrastructure among them. By default, the kernel process is invoked upon completion of the page load, but this is configurable. The simplest way to activate the kernel is to include the runtime source in the HTML file along with the devices: Figure 2. System Diagram

If a JavaScript device has an input terminal named “%startup,” a message will be sent to the terminal when all the devices in the given HTML document have finished constructing and the terminal connections among all devices have been established. At this point, the JavaScript devices are free to engage in asynchronous message passing. Message arrivals on input terminals can be handled by functions that are defined and registered inside the class constructor, as follows: this.onGreet=function(msg){ alert(“Hello World”); } this.onMsg(“greet,” “onGreet”);

Messages can be posted to an output terminal using the device’s postMessage method: this.postMessage(“timed_out,” 1);

4.2 Runtime Characteristics The JsStar kernel is a 3KB gzipped JavaScript source file that, upon constructing all the devices in the HTML document, sits idle unless a device posts a message that requires delivery. Therefore, it is non-compute intensive and allows the individual JavaScript devices to utilize the CPU cycles they need to carry out their tasks.

5. Architecture Evaluation To gain a better insight into the development of an actual Web application using the proposed paradigm, we will look at a more complex example: an interactive map.

The diagram shows a total of 10 device instances and 6 device implementations used to create the application. There are two devices that warrant special consideration. The devices “zip_code_to_geo_code” and “map” are composite devices made from two JavaScript devices. A composite device is packaged as single HTML file and included in the data flow through the use of another JavaScript device known as the “Composite Device Proxy”. Through a composite device proxy the runtime can deliver messages directly to the related composite devices as if they were just another JavaScript device. 5.1 Rapid Prototyping Capability Starting from a plain HTML page that contains the JsStar kernel, we add the first two JavaScript devices: “zip_code_entry” and “go_button,” which are instances of the Text.js and Button.js device implementations, respectively. We configure the zip_code_entry device to be labeled “Type Zip Code Here,” and the go_button device to be labeled “Go.”

Now we add two additional JavaScript devices: “zip_code_to_geo_code” and “alert,” which are instances of the CompositeProxy.js and Alert.js device implementations. We then configure the zip_code_to_geo_code device to load the zip_code.html composite device. We can then connect the “user_event” output terminal of the go_button device to the “value_request” input terminal of the zip_code_entry

device. The connection from the “value_response” output terminal of the zip_code_entry device is then made to the “zip_code” input terminal of the zip_code_to_geo_code device. Finally, we connect the “geo_code” output terminal of the zip_code_to_geo_code device to the “message” input terminal of the alert device.

corresponding map commands when they are clicked: “pan_south,” “pan_north,” “pan_east,” “pan_west,” “zoom_in,” and “zoom_out.” To route these commands to the map, we connect the “user_event” output terminal of all of the buttons to the “request” input terminal of the map device.

We can now enter a zip code, hit the “Go” button, and observe an alert box displaying the geo code value corresponding to the zip code.

When we reload the page and click the newly added buttons, we are now able to pan and zoom the map without requiring a page refresh.

Notice how the zip_code_to_geo_code device completely encapsulates and hides the complexity of the device’s internals. In practice, the device makes a connection to the zipinfo.com Web site to grab the longitude and latitude value for a given zip code in real time. However, from the perspective of the component user, it is no more complicated than posting a zip code message and letting the runtime deliver the value to the zip_code input terminal of the zip_code_to_geo_code device. Now we can replace the alert device with another instance of the CompositeProxy.js device implementation, identify it as “map,” and configure it to load the “map.html” composite device. We will also need to reconfigure the terminal connections so that the output of the zip_code_to_geo_code device now gets connected to the geo_code input terminal of the new map device. We then set the CSS attributes of the map device so that the view port is large enough to display the entire map image. When we reload the page, we can see the map device rendering a default geographical location.

5.2 Seamless Component Substitution The map device in the previous example uses a homegrown map server that has not been optimized. For a better user experience, we might want to take advantage of a popular online map service such as Map Blast [13]. So we prepare a source file for a standalone JavaScript device called “MapBlast.js” that has the exact same interface contract as the original map.html composite device. We can then replace the old map device by including the JavaScript source code for the MapBlast.js device and replacing the
tag used for the previous map device with the new “map_blast” device. Now when we reload the page, we see the map_blast device rendering the map for the default location. If you enter the zip code and hit “Go,” you’ll also realize that you can interact with the map in exactly the same way as the old map. Notice that the rest of the devices in the system required no modification to make this happen.

We can now enter a zip code, hit “Go,” and watch the map device render the area around the zip code in place without refreshing the page.

To complete the interaction, we add 6 more buttons: north_button, south_button, east_button, west_button, zoom_in_button and zoom_out_button. Since we already have included the source code for the Button.js device, we simply need to add 6 additional
tags with the appropriate labels. The buttons can then be parameterized through the use of the properties attribute to emit

This pattern can be extended to allow one to choose different map devices depending on circumstances. For example, you may opt to use a Flash-based map for browsers that already have the plug-in, after doing primitive plug-in availability inspection on the client-side. If a standard set of geo-coordinate input terminals emerges for devices such as maps, it is conceivable that an economy of software devices will arise. Such economy

will increase the quality and availability of components, and ultimately provide users with better experiences. 5.3 Extension Through Composition Suppose we want to add a feature to the application by displaying the weather for the location specified by the zip code when the user hits “Go.” All we have to do is add a new device called “weather” that takes a zip code as a valid input for its zip_code input terminal. We can then simply connect the value_response output terminal of the zip_code_entry device to the zip_code input terminal of the weather device.

Component architectures based on the black box pattern are not a new concept. However, Web development has yet to benefit from such traditional programming techniques and software engineering design practices. With this paper, the architecture presented has defined the key concepts that enable highly extensible JavaScriptbased Web applications to foster the richer and more responsive user experience that traditional Web applications often lack. Moreover, with sophisticated Web browsers being nearly ubiquitous [15], the timing cannot be better. Please visit http://beaker.maya.com/jda/ .

References: [1] M. Gaedke & Jörn Rehse, Supporting compositional reuse in component-based Web engineering, Proc. ACM Symposium on Applied Computing, Como, Italy 2000, 927-933.

The fact that zip code was used as one of the currencies in the system allowed the application to be quickly extended with a weather device that takes zip code as input.

6. Conclusion Web applications built using the proposed paradigm are insulated from vendor lock-in problems, and also are nimble enough to respond quickly to changes in requirements and feature additions. Since the system follows a modular design pattern, the paradigm naturally lends itself to high level of code reuse as well. Future work will include a Web-based visual IDE that will ease the burden of keeping track of the numerous terminals attached to the devices and aid in visualizing the devices and the established channels among their terminals. For the architecture to help raise the bar on general Web application usability, it will be important to promote a market where JavaScript devices can flourish [14]. Such a market can help raise the visibility and discoverability of high-quality software components that can be used to extend a given system with desired features and interaction capabilities. One opportunity presented by this architecture, as a natural extension of IDA, is to allow for the distribution of compute units between the client and the server. A general-purpose design schematic stored in a repository [11] can hold enough information to arbitrarily determine at run time which components will be executed on the client and which will be executed on the server. The main idea behind this future work is to make it possible for devices to communicate seamlessly regardless of their implementation language, platform, or location.

[2] Ronan Barrett & Sarah Jane Delany, openMVC: A Non-Proprietary Component-Based Framework for Web Applications, Alternate track papers & posters, Proc. 13th international World Wide Web Conference, New York, NY, USA, 2004, 464-465. [3] Jian Yang, Web Service Componentization, Communications of the ACM, 46 (10), 2003, 35-40. [4] Macromedia Flash http://www.macromedia.com/flash/ [5] MAYA Design, Inc. http://www.maya.com/ [6] Software Reuse and Re-engineering http://frakes.cs.vt.edu/5744pdf/reuse.pdf [7] Gamma, E., Helm, R., Johnson, R., & Vlissides, J. Design patterns: Elements of reusable object-oriented software (Reading, MA: Addison-Wesley, 1994). [8] Curl, Inc., http://www.curl.com/ [9] DynAPI http://dynapi.sourceforge.net/ [10] Dojo http://www.dojotoolkit.org/ [11] Peter Lucas & Jeff Senn, Toward the Universal Database: U-forms and the VIA Repository, March 2002 [12] Shriram Krishnamurthi & Matthias Felleisen, Toward a formal theory of extensible software. Proc. 6th ACM SIGSOFT International Symposium on Foundations of Software Engineering, Lake Buena Vista, FL, USA, 1998, 88 – 98. [13] Map Blast http://www.mapblast.com/ [14] T. Ravichandran and Marcus A. Rothenberger Software reuse strategies and component markets Communications of the ACM 46 (8), 2003, 109-114. [15] Browser Market Share Study. http://www.ejanco.com/browser.htm

Suggest Documents