The development of modern web applications has become a complex task. Not only are programmers required to combine database, server and client technologies, but libraries to make the application more responsive and interactive must be integrated as well. Such rich internet applications thus consist of three tiers (database, client and server) where the client tier contains a substantial part of the application logic. Instead of manually reconciling the tiers and their own technologies, tierless programming reduces this complexity by taking a single language approach. This way the programmer focuses on the application logic, while a tierless compiler is responsible for distributing the code across the different tiers.
Instead of forcing the programmer to learn another new language, we advocate an approach where a general-purpose language is used. JavaScript is already the scripting language for browsers, but is now commonly accepted as server language as well. In previous work [1], we describe the tier splitting process that enables tierless JavaScript programs to be transformed into code for client and server tier. The programmer writes the JavaScript logic, adds annotations (@client and @server) to indicate the location of the code. The distributed logic is injected where necessary after the tier splitting.
The tier splitting process works on a program dependence graph, where the statements in the program are nodes and control and data flow dependencies are edges. By using a program slicing algorithm the program is split into two parts, taking into account the dependencies between the statements. The two parts are translated into JavaScript for the client and server tier. For example, cross-tier calls are transformed into remote procedure calls.
However, concerns like offline availability, latency and security transcend the program logic and the distinction between server and client code. Instead of merely programming in terms of server and client locations, it is more desirable to be able to program in terms of “functionalities”. Such functionalities can contain variables, functions, objects,.. and each functionality can be assigned to a certain tier. Based on the dependence graph, we can derive certain metrics of the program. The programmer can then relocate certain functionalities based on these metrics to another tier.
For example, an assistance tool for offline web applications can easily be built by analysing the tierless code, divided into functionalities, and building the dependence graph. Using an extensive query API on top of this graph, all information that is needed to calculate the percentage of offline availability for each functionality is available. These include counting remote data dependencies, thus meaning that data from another tier is accessed. Based on this report the developer can easily change the location of functionalities to gain a higher percentage for functionalities that must completely or partly work offline.
Furthermore, we can extend this to a scenario where not every functionality is assigned to a tier from the beginning. The developer can choose a “placement strategy” that calculates where these functionalities should belong. We think of strategies that focus on security, offline availability, … or a combination of different concerns. The developer can thus experiment with different placement strategies, in combination with the reports of tools we described earlier on, to achieve different placements of the functionality tiers. Once satisfied with the results, the program can then be compiled into distributed client and server code.
[1] L. Philips, C. De Roover, T. Van Cutsem, and W. De Meuter, “Towards tierless web development without tierless languages,” in Proceedings of the 2014 ACM International Symposium on New Ideas, New Paradigms, [25] and Reflections on Programming & Software, ser. Onward! 2014. New York, NY, USA: ACM, 2014, pp. 69–81.