Multitier programming

Last updated

Multitier programming (or tierless programming) is a programming paradigm for distributed software, which typically follows a multitier architecture, physically separating different functional aspects of the software into different tiers (e.g., the client, the server and the database in a Web application [1] ). Multitier programming allows functionalities that span multiple of such tiers to be developed in a single compilation unit using a single programming language. Without multitier programming, tiers are developed using different languages, e.g., JavaScript for the Web client, PHP for the Web server and SQL for the database. [2] Multitier programming is often integrated into general-purpose languages by extending them with support for distribution. [3]

Contents

Concepts from multitier programming were pioneered by the Hop [4] and Links [5] languages and have found industrial adoption in solutions such as Ocsigen, [6] Opa, [7] WebSharper, [8] Meteor [9] or GWT. [10]

Multitier programming provides a global view on the distributed system. This aspect has been shown similar to other programming paradigms such as choreographic programming, [11] macroprogramming, [12] and aggregate computing. [13] [14]

Context

The code of the different tiers can be executed in a distributed manner on different networked computers. For instance, in a three-tier architecture, a system is divided into three main layers – typically the presentation, business, and data tiers. This approach has the benefit that by dividing a system into layers, the functionality implemented in one of the layers can be changed independently of the other layers. On the other hand, this architectural decision scatters a cross-cutting functionality belonging to several tiers over several compilation units.

In multitier programming, the different tiers are implemented using a single programming language. Different compilation backends take into account the destination tier (e.g., Java for a server and JavaScript for a web browser). Consequently, a functionality that is spread over tiers can be implemented in a single compilation unit of a multitier program.

Example

At their core, multitier languages allow developers to define for different pieces of code the tiers to which the code belongs. The language features that enable this definition are quite diverse between different multitier languages, ranging from staging to annotations to types. The following example shows an Echo client–server application that illustrates different approaches. In the example, the client sends a message to the server and the server returns the same message to the client, where it is appended to a list of received messages.

Echo application in Hop.js

serviceecho(){varinput=<inputtype="text"/>return<html><bodyonload=~{varws=newWebSocket("ws://localhost:"+${hop.port}+"/hop/ws")ws.onmessage=function(event){document.getElemenetById("list").appendChild(<li>${event.data}</li>)}}><div>${input}<buttononclick=~{ws.send(${input}.value)}>Echo!</button></div><ulid="list"/></body></html>}varwss=newWebSocketServer("ws")wss.onconnection=function(event){varws=event.valuews.onmessage=function(event){ws.send(event.value)}}

Hop uses staging to embed code that is to be run on the client into a server-side program: Using the ~{…} notation, the code for the onload (Line 4) and onclick (Line 10) handlers is not immediately executed but the server generates the code for later execution on the client. On the other hand, the ${…} notation escapes one level of program generation. The expressions hop.port (Line 5), event.data (Line 6) and input (Line 9 and 10) are evaluated by the outer server program and the values to which they evaluate are injected into the generated client program. Hop supports full stage programming, i.e., ~{…} expressions can be arbitrarily nested such that not only server-side programs can generate client-side programs but also client-side programs are able to generate other client-side programs.

HTML can be embedded directly in Hop code. HTML generated on the server (Line 2–14) is passed to the client. HTML generated on the client can be added to the page using the standard DOM API (Line 6). Hop supports bidirectional communication between a running server and a running client instance through its standard library. The client connects to the WebSocket server through the standard HTML5 API (Line 5) and sends the current input value (Line 10). The server opens a WebSocket server (Line 17) that returns the value back to the client (Line 20). So-called services, which are executed on the server and produce a value that is returned to the client that invoked the service. For example, the echo service (Line 1) produces the HTML page served to the web client of the Echo application. Thus, the code in a service block is executed on the server.

funecho(item)server{item}funmain()server{page<html><body><forml:onsubmit="{appendChildren(<li>{stringToXml(echo(item))}</li>, getNodeById("list"))}"><inputl:name="item"/><buttontype="submit">Echo!</button></form><ulid="list"/></body></html>}main()

Links uses annotations on functions to specify whether they run on the client or on the server (Line 1 and 5). Upon request from the client, the server executes the main function (Line 18), which constructs the code that is sent to the client. Links allows embedding XML code (Line 7–15). XML attributes with the l: prefix are treated specially. The l:name attribute (Line 10) declares an identifier to which the value of the input field is bound. The identifier can be used elsewhere (Line 9). The code to be executed for the l:onsubmit handler (Line 9) is not immediately executed but compiled to JavaScript for client-side execution. Curly braces indicate Links code embedded into XML. The l:onsubmit handler sends the current input value item to the server by calling echo. The item is returned by the server and appended to the list of received items using standard DOM APIs. The call to the server (Line 9) does not block the client. Instead, the continuation on the client is invoked when the result of the call is available. Client–server interaction is based on resumption passing style: Using continuation passing style transformation and defunctionalization, remote calls are implemented by passing the name of a function for the continuation and the data needed to continue the computation.

Echo application in ScalaLoci

@multitierobjectApplication{@peertypeServer<:{typeTie<:Single[Client]}@peertypeClient<:{typeTie<:Single[Server]}valmessage=on[Client]{Event[String]()}valechoMessage=on[Server]{message.asLocal}defmain()=on[Client]{valitems=echoMessage.asLocal.listvallist=Signal{ol(items()map{message=>li(message)})}valinp=input.renderdom.document.body=body(div(inp,button(onclick:={()=>message.fire(inp.value)})("Echo!")),list.asFrag).render}}

ScalaLoci is a language that targets generic distributed systems rather than the Web only, i.e., it is not restricted to a client–server architecture. To this end, ScalaLoci supports peer types to encode the different tiers at the type level. Placement types are used to assign locations to data and computations. ScalaLoci supports multitier reactives – language abstractions for reactive programming that are placed on specific locations – for composing data flows cross different peers.

The application first defines an input field (Line 11) using the ScalaTags library. [15] The value of this field is used in the click event handler of a button (Line 15) to fire the message event with the current value of the input field. The value is then propagated to the server (Line 6) and back to the client (Line 9). On the client, the value of the event are accumulated using the list function and mapped to an HTML list (Line 10). This list is then used in the HTML (Line 16) to display the previous inputs.

List of multitier programming languages

Related Research Articles

<span class="mw-page-title-main">Client–server model</span> Distributed application structure in computing

The client–server model is a distributed application structure that partitions tasks or workloads between the providers of a resource or service, called servers, and service requesters, called clients. Often clients and servers communicate over a computer network on separate hardware, but both client and server may reside in the same system. A server host runs one or more server programs, which share their resources with clients. A client usually does not share any of its resources, but it requests content or service from a server. Clients, therefore, initiate communication sessions with servers, which await incoming requests. Examples of computer applications that use the client–server model are email, network printing, and the World Wide Web.

A distributed system is a system whose components are located on different networked computers, which communicate and coordinate their actions by passing messages to one another. Distributed computing is a field of computer science that studies distributed systems.

In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions. It is a declarative programming paradigm in which function definitions are trees of expressions that map values to other values, rather than a sequence of imperative statements which update the running state of the program.

<span class="mw-page-title-main">Transclusion</span> Including one data set inside another automatically

In computer science, transclusion is the inclusion of part or all of an electronic document into one or more other documents by reference via hypertext. Transclusion is usually performed when the referencing document is displayed, and is normally automatic and transparent to the end user. The result of transclusion is a single integrated document made of parts assembled dynamically from separate sources, possibly stored on different computers in disparate places.

In computer science, an object can be a variable, a data structure, a function, or a method. As regions of memory, objects contain a value and are referenced by identifiers.

<span class="mw-page-title-main">DBLP</span> Computer science bibliography website

DBLP is a computer science bibliography website. Starting in 1993 at Universität Trier in Germany, it grew from a small collection of HTML files and became an organization hosting a database and logic programming bibliography site. Since November 2018, DBLP is a branch of Schloss Dagstuhl – Leibniz-Zentrum für Informatik (LZI). DBLP listed more than 5.4 million journal articles, conference papers, and other publications on computer science in December 2020, up from about 14,000 in 1995 and 3.66 million in July 2016. All important journals on computer science are tracked. Proceedings papers of many conferences are also tracked. It is mirrored at three sites across the Internet.

ObjVlisp is a 1984 object-oriented extension of Vlisp–Vincennes LISP, a LISP dialect developed since 1971 at the University of Paris VIII – Vincennes. It is noteworthy as one of the earliest implementations of the concept of metaclasses, and in particular explicit metaclasses. In the ObjVlisp model, "each entity is an instance of a single class. Classes are instances of other classes, called metaclasses. This model allows for extension of the static part of OOL, i.e. the structural aspects of objects considered as implementation of abstract data types"

MapReduce is a programming model and an associated implementation for processing and generating big data sets with a parallel, distributed algorithm on a cluster.

Eventual consistency is a consistency model used in distributed computing to achieve high availability that informally guarantees that, if no new updates are made to a given data item, eventually all accesses to that item will return the last updated value. Eventual consistency, also called optimistic replication, is widely deployed in distributed systems and has origins in early mobile computing projects. A system that has achieved eventual consistency is often said to have converged, or achieved replica convergence. Eventual consistency is a weak guarantee – most stronger models, like linearizability, are trivially eventually consistent.

<span class="mw-page-title-main">Edge computing</span> Distributed computing paradigm

Edge computing is a distributed computing paradigm that brings computation and data storage closer to the sources of data. This is expected to improve response times and save bandwidth. Edge computing is an architecture rather than a specific technology, and a topology- and location-sensitive form of distributed computing.

A fundamental problem in distributed computing and multi-agent systems is to achieve overall system reliability in the presence of a number of faulty processes. This often requires coordinating processes to reach consensus, or agree on some data value that is needed during computation. Example applications of consensus include agreeing on what transactions to commit to a database in which order, state machine replication, and atomic broadcasts. Real-world applications often requiring consensus include cloud computing, clock synchronization, PageRank, opinion formation, smart power grids, state estimation, control of UAVs, load balancing, blockchain, and others.

In computer science, state machine replication (SMR) or state machine approach is a general method for implementing a fault-tolerant service by replicating servers and coordinating client interactions with server replicas. The approach also provides a framework for understanding and designing replication management protocols.

In functional programming, a generalized algebraic data type is a generalization of parametric algebraic data types.

<span class="mw-page-title-main">API</span> Software interface between computer programs

An application programming interface (API) is a way for two or more computer programs or components to communicate with each other. It is a type of software interface, offering a service to other pieces of software. A document or standard that describes how to build or use such a connection or interface is called an API specification. A computer system that meets this standard is said to implement or expose an API. The term API may refer either to the specification or to the implementation. Whereas a system's user interface dictates how its end-users interact with the system in question, its API dictates how to write code that takes advantage of that system's capabilities.

Gradual typing is a type system in which some variables and expressions may be given types and the correctness of the typing is checked at compile time and some expressions may be left untyped and eventual type errors are reported at runtime. Gradual typing allows software developers to choose either type paradigm as appropriate, from within a single language. In many cases gradual typing is added to an existing dynamic language, creating a derived language allowing but not requiring static typing to be used. In some cases a language uses gradual typing from the start.

A distributed file system for cloud is a file system that allows many clients to have access to data and supports operations on that data. Each data file may be partitioned into several parts called chunks. Each chunk may be stored on different remote machines, facilitating the parallel execution of applications. Typically, data is stored in files in a hierarchical tree, where the nodes represent directories. There are several ways to share files in a distributed architecture: each solution must be suitable for a certain type of application, depending on how complex the application is. Meanwhile, the security of the system must be ensured. Confidentiality, availability and integrity are the main keys for a secure system.

In type theory, session types are used to ensure correctness in concurrent programs. They guarantee that messages sent and received between concurrent programs are in the expected order and of the expected type. Session type systems have been adapted for both channel and actor systems.

In computer science, choreographic programming is a programming paradigm where programs are compositions of interactions among multiple concurrent participants.

Servant is a web framework based on the programming language Haskell, with an emphasis on data type safety. It is free and open-source software released under a BSD 3-clause license.

In computer science, macroprogramming is a programming paradigm aimed at expressing the macroscopic, global behaviour of an entire system of agents or computing devices. In macroprogramming, the local programs for the individual components of a distributed system are compiled or interpreted from a macro-program typically expressed by a system-level perspective or in terms of the intended global goal. The aim of macroprogramming approaches is to support expressing the macroscopic interactive behaviour of a whole distributed system of computing devices or agents in a single program, or, similarly, to promote their collective intelligence. It has not to be confused with macros, the mechanism often found in programming languages to express substitution rules for program pieces.

References

  1. Hull, Richard; Thiemann, Peter; Wadler, Philip (2007). "07051 Working Group Outcomes – Programming Paradigms for the Web: Web Programming and Web Services". Programming Paradigms for the Web: Web Programming and Web Services. Dagstuhl Seminar Proceedings. Dagstuhl, Germany: Internationales Begegnungs- und Forschungszentrum für Informatik (IBFI). 07051.
  2. Weisenburger, Pascal; Wirth, Johannes; Salvaneschi, Guido (2020). "A Survey of Multitier Programming" (PDF). ACM Comput. Surv. 53 (4): 81:1–81:35. doi:10.1145/3397495. S2CID   218517772.
  3. Caldwell, Sam (2016). "General Purpose Languages Extended for Distribution". In Miller, Heather (ed.). Programming Models for Distributed Computing.
  4. 1 2 Serrano, Manuel (2012). "Multitier programming in Hop". Commun. ACM. 55 (8): 53–59. doi:10.1145/2240236.2240253. S2CID   2152326.
  5. 1 2 Cooper, Ezra (2006). "Links: Web Programming Without Tiers". Formal Methods for Components and Objects. Lecture Notes in Computer Science. Vol. 4709. pp. 266–296. doi:10.1007/978-3-540-74792-5_12. hdl:20.500.11820/ef5f100a-0366-4b85-8ef1-622fd7fbb53a. ISBN   978-3-540-74791-8. S2CID   16397220.
  6. 1 2 Balat, Vincent (2006). "Ocsigen: typing web interaction with objective Caml": 84–94. doi:10.1145/1159876.1159889. S2CID   6131454.{{cite journal}}: Cite journal requires |journal= (help)
  7. 1 2 Rajchenbach-Teller, D., & Sinot, Franois-Régis. (2010). Opa: Language support for a sane, safe and secure web. Proceedings of the OWASP AppSec Research, 2010(1).
  8. 1 2 Bjornson, Joel; Tayanovskyy, Anton; Granicz, Adam (2010). "Composing Reactive GUIs in F# Using WebSharper". Implementation and Application of Functional Languages. Lecture Notes in Computer Science. Vol. 6647. Berlin, Heidelberg: Springer-Verlag. p. 49. doi:10.1007/978-3-642-24276-2_13. ISBN   978-3-642-24275-5.
  9. 1 2 Strack, Isaac (January 2012). Getting started with Meteor JavaScript framework. Birmingham. ISBN   978-1-78216-083-0. OCLC   823718999.{{cite book}}: CS1 maint: location missing publisher (link)
  10. 1 2 Kereki, Federico, 1960- (2011). Essential GWT: building for the web with Google Web toolkit 2. Upper Saddle River, NJ: Addison-Wesley. ISBN   978-0-321-70563-1. OCLC   606556208.{{cite book}}: CS1 maint: multiple names: authors list (link) CS1 maint: numeric names: authors list (link)
  11. Giallorenzo, Saverio; Montesi, Fabrizio; Peressotti, Marco; Richter, David; Salvaneschi, Guido; Weisenburger, Pascal (2021). Møller, Anders; Sridharan, Manu (eds.). "Multiparty Languages: The Choreographic and Multitier Cases". 35th European Conference on Object-Oriented Programming (ECOOP 2021). Leibniz International Proceedings in Informatics (LIPIcs). Dagstuhl, Germany: Schloss Dagstuhl – Leibniz-Zentrum für Informatik. 194: 22:1–22:27. doi:10.4230/LIPIcs.ECOOP.2021.22. ISBN   978-3-95977-190-0. S2CID   235748561.
  12. Casadei, Roberto (2023-01-11). "Macroprogramming: Concepts, State of the Art, and Opportunities of Macroscopic Behaviour Modelling". ACM Computing Surveys. Association for Computing Machinery (ACM). 55 (13s): 1–37. arXiv: 2201.03473 . doi: 10.1145/3579353 . ISSN   0360-0300. S2CID   245837830.
  13. Beal, Jacob; Pianini, Danilo; Viroli, Mirko (2015). "Aggregate Programming for the Internet of Things". Computer. Institute of Electrical and Electronics Engineers (IEEE). 48 (9): 22–30. doi:10.1109/mc.2015.261. hdl: 11585/520779 . ISSN   0018-9162. S2CID   26413.
  14. Audrito, Giorgio; Casadei, Roberto; Damiani, Ferruccio; Salvaneschi, Guido; Viroli, Mirko (2022). Ali, Karim; Vitek, Jan (eds.). "Functional Programming for Distributed Systems with XC". 36th European Conference on Object-Oriented Programming (ECOOP 2022). Leibniz International Proceedings in Informatics (LIPIcs). Dagstuhl, Germany: Schloss Dagstuhl – Leibniz-Zentrum für Informatik. 222: 20:1–20:28. doi:10.4230/LIPIcs.ECOOP.2022.20. ISBN   978-3-95977-225-9. S2CID   249961384.
  15. "ScalaTags". www.lihaoyi.com. Retrieved 2021-10-11.
  16. Serrano, Manuel (2006). "Hop: a language for programming the web 2.0": 975–985. doi:10.1145/1176617.1176756. S2CID   14306230.{{cite journal}}: Cite journal requires |journal= (help)
  17. Serrano, Manuel (2016). "A glimpse of Hopjs". Proceedings of the 21st ACM SIGPLAN International Conference on Functional Programming. pp. 180–192. doi:10.1145/2951913.2951916. ISBN   9781450342193. S2CID   18393160.
  18. Fowler, Simon (2019). "Exceptional asynchronous session types: session types without tiers". Proc. ACM Program. Lang. 3 (POPL): 28:1–28:29. doi: 10.1145/3290341 . hdl: 1808/27512 . S2CID   57757469.
  19. Chlipala, Adam (2015). "Ur/Web: A Simple Model for Programming the Web": 153–165. doi:10.1145/2676726.2677004. S2CID   9440677.{{cite journal}}: Cite journal requires |journal= (help)
  20. Radanne, Gabriel (2018). "Tierless Web Programming in the Large". Companion of the Web Conference 2018 on the Web Conference 2018 - WWW '18. pp. 681–689. doi:10.1145/3184558.3185953. ISBN   9781450356404. S2CID   3304415.
  21. Weisenburger, Pascal (2018). "Distributed system development with ScalaLoci". Proc. ACM Program. Lang. 2 (OOPSLA): 129:1–129:30. doi: 10.1145/3276499 . S2CID   53090153.
  22. Philips, Laure (2014). "Towards Tierless Web Development without Tierless Languages". Proceedings of the 2014 ACM International Symposium on New Ideas, New Paradigms, and Reflections on Programming & Software. pp. 69–81. doi:10.1145/2661136.2661146. ISBN   9781450332101. S2CID   15774367.
  23. Philips, Laure (2018). "Search-based Tier Assignment for Optimising Offline Availability in Multi-tier Web Applications". Programming Journal. 2 (2): 3. arXiv: 1712.01161 . doi: 10.22152/programming-journal.org/2018/2/3 . S2CID   11256561.
  24. Reynders, Bob (2014). "Multi-Tier Functional Reactive Programming for the Web". Proceedings of the 2014 ACM International Symposium on New Ideas, New Paradigms, and Reflections on Programming & Software. pp. 55–68. doi:10.1145/2661136.2661140. ISBN   9781450332101. S2CID   16761616.
  25. Carreton, Andoni Lombide (2010). "Loosely-Coupled Distributed Reactive Programming in Mobile Ad Hoc Networks". Objects, Models, Components, Patterns. Lecture Notes in Computer Science. Vol. 6141. pp. 41–60. doi:10.1007/978-3-642-13953-6_3. ISBN   978-3-642-13952-9.
  26. Dedecker, Jessie (2006). "Ambient-Oriented Programming in Ambient Talk". Ambient-Oriented Programming in AmbientTalk. Lecture Notes in Computer Science. Vol. 4067. pp. 230–254. doi:10.1007/11785477_16. ISBN   978-3-540-35726-1.
  27. VII, Tom Murphy (2007). "Type-Safe Distributed Programming with ML5". Trustworthy Global Computing. Lecture Notes in Computer Science. Vol. 4912. pp. 108–123. doi:10.1007/978-3-540-78663-4_9. ISBN   978-3-540-78662-7. S2CID   12534714.
  28. Ekblad, Anton; Claessen, Koen (2015-05-11). "A seamless, client-centric programming model for type safe web applications". ACM SIGPLAN Notices. 49 (12): 79–89. doi:10.1145/2775050.2633367. ISSN   0362-1340.
  29. "Fun (a programming language for the realtime web)". marcuswest.in. Retrieved 2020-05-04.
  30. Leijen, Daan (2014). "Koka: Programming with Row Polymorphic Effect Types". Electronic Proceedings in Theoretical Computer Science. 153: 100–126. arXiv: 1406.2061 . doi:10.4204/EPTCS.153.8. S2CID   14902937.
  31. Neubauer, Matthias (2005). "From sequential programs to multi-tier applications by program transformation". Proceedings of the 32nd ACM SIGPLAN-SIGACT symposium on Principles of programming languages. pp. 221–232. doi:10.1145/1040305.1040324. ISBN   158113830X. S2CID   10338936.
  32. ChongStephen; LiuJed; C, MyersAndrew; QiXin; VikramK; ZhengLantian; ZhengXin (2007-10-14). "Secure web applications via automatic partitioning". ACM SIGOPS Operating Systems Review. 41 (6): 31–44. doi:10.1145/1323293.1294265. hdl: 1813/5769 .
  33. Manolescu, Dragos (2008). "Volta: Developing Distributed Applications by Recompiling". IEEE Software. 25 (5): 53–59. doi:10.1109/MS.2008.131. S2CID   24360031.
  34. Tilevich, Eli (2002). "J-Orchestra: Automatic Java Application Partitioning". ECOOP 2002 — Object-Oriented Programming. Lecture Notes in Computer Science. Vol. 2374. pp. 178–204. doi:10.1007/3-540-47993-7_8. hdl:1853/6531. ISBN   978-3-540-43759-8.
  35. Berry, Gérard; Nicolas, Cyprien; Serrano, Manuel (2011). "Hiphop". Proceedings of the 1st ACM SIGPLAN international workshop on Programming language and systems technologies for internet clients. New York, New York, USA: ACM Press. p. 49. doi:10.1145/2093328.2093337. ISBN   978-1-4503-1171-7. S2CID   1280230.
  36. Thywissen, John A. (2016). "Implicitly Distributing Pervasively Concurrent Programs: Extended abstract": 1. doi:10.1145/2957319.2957370. S2CID   6124391.{{cite journal}}: Cite journal requires |journal= (help)
  37. Zdancewic, Steve (2002). "Secure program partitioning". ACM Trans. Comput. Syst. 20 (3): 283–328. doi:10.1145/566340.566343. S2CID   1776939.
  38. Guha, Arjun; Jeannin, Jean-Baptiste; Nigam, Rachit; Tangen, Jane; Shambaugh, Rian (2017). Lerner, Benjamin S.; Bodík, Rastislav; Krishnamurthi, Shriram (eds.). "Fission: Secure Dynamic Code-Splitting for JavaScript". 2nd Summit on Advances in Programming Languages (SNAPL 2017). Leibniz International Proceedings in Informatics (LIPIcs). Dagstuhl, Germany: Schloss Dagstuhl–Leibniz-Zentrum fuer Informatik. 71: 5:1–5:13. doi:10.4230/LIPIcs.SNAPL.2017.5. ISBN   978-3-95977-032-3.
  39. Chong, Stephen (2007). "SIF: Enforcing Confidentiality and Integrity in Web Applications".{{cite journal}}: Cite journal requires |journal= (help)
  40. Groenewegen, Danny M. (2008). "WebDSL: a domain-specific language for dynamic web applications": 779–780. doi:10.1145/1449814.1449858. S2CID   8073129.{{cite journal}}: Cite journal requires |journal= (help)
  41. Sewell, Peter (2005). "Acute: high-level programming language design for distributed computation": 15–26. doi:10.1145/1086365.1086370. S2CID   1308126.{{cite journal}}: Cite journal requires |journal= (help)
  42. Hemel, Zef (2011). "Declaratively programming the mobile web with Mobl". Proceedings of the 2011 ACM international conference on Object oriented programming systems languages and applications. pp. 695–712. doi:10.1145/2048066.2048121. ISBN   9781450309400. S2CID   10480906.
  43. Richard-Foy, Julien (2013). "Efficient high-level abstractions for web programming". Proceedings of the 12th international conference on Generative programming: Concepts & experiences. pp. 53–60. doi:10.1145/2517208.2517227. ISBN   9781450323734. S2CID   14305623.