e1fbe34f93678d3ec49f4ebbb54510e16f04ce5d
[phd-thesis.git] / tiered_vs._tierless_programming / smart_campus.tex
1 \documentclass[../thesis.tex]{subfiles}
2
3 \begin{document}
4 \ifSubfilesClassLoaded{
5 \pagenumbering{arabic}
6 }{}
7
8 \mychapter{chp:smart_campus}{Smart campus application}
9 %\title{Could Tierless Languages Reduce IoT Development Grief?}
10
11 \begin{chapterabstract}
12 \Gls{IOT} software is notoriously complex, conventionally comprising multiple tiers.
13 The developer must use multiple programming languages and ensure that the components interoperate correctly. A novel alternative is to use a single \emph{tierless} language with a compiler that generates the code for each component and ensures their correct interoperation.
14
15 We report a systematic comparative evaluation of two tierless language technologies for \gls{IOT} stacks: one for resource-rich sensor nodes (\gls{CLEAN} with \gls{ITASK}), and one for resource-constrained sensor nodes (\gls{CLEAN} with \gls{ITASK} and \gls{MTASK}).
16 The evaluation is based on four implementations of a typical smart campus application: two tierless and two \gls{PYTHON}-based tiered.
17 %, with two targeting microcontrollers and two targeting supersensors.
18 \begin{enumerate*}
19 \item We show that tierless languages have the potential to significantly reduce the development effort for \gls{IOT} systems, requiring 70\% less code than the tiered implementations. Careful analysis attributes this code reduction to reduced interoperation (e.g.\ two \glspl{EDSL} and one paradigm versus seven languages and two paradigms), automatically generated distributed communication, and powerful \gls{IOT} programming abstractions.
20 \item We show that tierless languages have the potential to significantly improve the reliability of \gls{IOT} systems, describing how \gls{CLEAN}\slash\gls{ITASK}/\gls{MTASK} maintains type safety, provides higher order failure management, and simplifies maintainability.
21 \item We report the first comparison of a tierless \gls{IOT} codebase for resource-rich sensor nodes with one for resource-constrained sensor nodes. The comparison shows that they have similar code size (within 7\%), and functional structure.
22 \item We present the first comparison of two tierless \gls{IOT} languages, one for resource-rich sensor nodes, and the other for resource-constrained sensor nodes.
23 \end{enumerate*}
24 \end{chapterabstract}
25
26 \section{Introduction}%
27 \label{sec_t4t:Intro}
28
29 Conventional \gls{IOT} software stacks are notoriously complex and pose very significant software development, reliability, and maintenance challenges. \Gls{IOT} software architectures typically comprise multiple components organised in four or more tiers or layers~\citep{sethi2017internet,Ravulavaru18,Alphonsa20}. This is due to the highly distributed nature of typical \gls{IOT} applications that must read sensor data from end points (the \emph{perception} layer), aggregate and select the data and communicate over a network (the \emph{network} layer), store the data in a database and analyse it (the \emph{application} layer) and display views of the data, commonly on web pages (the \emph{presentation} layer).
30
31 Conventional \gls{IOT} software architectures require the development of separate programs in various programming languages for each of the components/tiers in the stack. This is modular, but a significant burden for developers, and some key challenges are as follows.
32 \begin{enumerate*}
33 \item Interoperating components in multiple languages and paradigms increases the developer's cognitive load who must simultaneously think in multiple languages and paradigms, i.e.\ manage significant semantic friction.
34 \item The developer must correctly interoperate the components, e.g.\ adhere to the \gls{API} or communication protocols between components.
35 \item To ensure correctness the developer must maintain type safety across a range of very different languages and diverse type systems.
36 \item The developer must deal with the potentially diverse failure modes of each component, and of component interoperations.
37 \end{enumerate*}
38
39 A radical alternative development paradigm uses a single \emph{tierless} language that synthesizes all components/tiers in the software stack. There are established \emph{tierless} languages for web stacks, e.g.\ Links~\citep{cooper2006links} or Hop~\citep{serrano2006hop}.
40 In a tierless language the developer writes the application as a single program. The code for different tiers is simultaneously checked by the compiler, and compiled to the required component languages. For example, Links compiles to HTML and JavaScript for the web client and to SQL on the server to interact with the database system. Tierless languages for \gls{IOT} stacks are more recent and less common, examples include
41 Potato~\citep{troyer_building_2018} and \gls{CLEAN} with \gls{ITASK}\slash\gls{MTASK}~\citep{lubbers_interpreting_2019}.
42
43 \Gls{IOT} sensor nodes may be microcontrollers with very limited compute resources, or supersensors: resource-rich single board computers like a Raspberry Pi. A tierless language may target either class of sensor node, and microcontrollers are the more demanding target due to the limited resources, e.g.\ small memory, executing on bare metal etc.
44
45 Potentially a tierless language both reduces the development effort and improves correctness as correct interoperation and communication is automatically generated by the compiler. A tierless language may, however, introduce other problems. How expressive is the language? That is, can it readily express the required functionality? How maintainable is the software? Is the generated code efficient in terms of time, space, and power?
46
47
48 This paper reports a systematic comparative evaluation of two tierless language technologies for \gls{IOT} stacks: one targeting resource-constrained microcontrollers, and the other resource-rich supersensors. The basis of the comparison is four implementations of a typical smart campus \gls{IOT} stack~\citep{hentschel_supersensors:_2016}. Two implementations are conventional tiered \gls{PYTHON}-based stacks: \gls{PRS} and \gls{PWS}. The other two implementations are tierless: \gls{CRS} and \gls{CWS}. Our work makes the following research contributions, and the key results are summarised, discussed, and quantified in \cref{sec_t4t:Conclusion}.
49
50 \begin{description}
51 \item[C1] We show that \emph{tierless languages have the potential to significantly reduce the development effort for \gls{IOT} systems}.
52 We systematically compare code size (\gls{SLOC}) of the four smart campus implementations as a measure of development effort and maintainability~\citep{alpernaswonderful,rosenberg1997some}.
53 The tierless implementations require 70\% less code than the tiered implementations. We analyse the codebases to attribute the code reduction to three factors.
54 \begin{enumerate*}
55 \item Tierless languages benefit from reduced interoperation, requiring far fewer languages, paradigms and source code files e.g.\ \gls{CWS} uses two languages, one paradigm and three source code files where \gls{PWS} uses seven languages, two paradigms and 35 source code files
56 %\jscomment{check out \url{https://editorsmanual.com/articles/numerals-vs-words-for-numbers/} - do we agree with this?}
57 (\cref{table_t4t:multi,table_t4t:languages,table_t4t:paradigms}).
58 \item Tierless languages benefit from automatically synthesized, and hence correct, communication between components that may be distributed.
59 \item Tierless languages benefit from high-level programming abstractions like compositional and higher-order task combinators (\cref{sec_t4t:ProgrammingComparison}).
60 \end{enumerate*}
61
62 \item[C2] We show that \emph{tierless languages have the potential to significantly improve the reliability of \gls{IOT} systems}. We demonstrate how tierless languages preserve type safety, improve maintainability and provide high-level failure management. For example, we illustrate a loss of type safety in \gls{PRS}. We also critique current tool and community support (\cref{sec_t4t:Discussion}).
63
64 \item[C3] We report \emph{the first comparison of a tierless \gls{IOT} codebase for resource-rich sensor nodes with one for resource-constrained sensor nodes}. The tierless smart campus implementations have a very similar code size (within 7\%), as do the tiered implementations. This suggests that the development and maintenance effort of simple tierless \gls{IOT} systems for resource-constrained and for resource-rich sensor nodes is similar, as it is for tiered technologies. The percentages of code required to implement each \gls{IOT} functionality in the tierless \gls{CLEAN} implementations is very similar, as it is in the tiered \gls{PYTHON} implementations. This suggests that the code for resource-constrained and resource-rich sensor nodes is broadly similar in tierless technologies, as in tiered technologies (\cref{sec_t4t:resourcerich})
65
66 \item[C4] \emph{We present the first comparison of two tierless \gls{IOT} languages, one designed for resource-constrained sensor nodes (\gls{CLEAN} with \gls{ITASK} and \gls{MTASK}), and the other for resource-rich sensor nodes (\gls{CLEAN} with \gls{ITASK}).}
67 We show that the bare metal execution environment enforces some restrictions on \gls{MTASK} although they remain high level. Moreover, the environment conveys some advantages, e.g.\ better control over timing (\cref{sec_t4t:ComparingTierless}).
68 \end{description}
69
70 The current work extends~\citep{lubbers_tiered_2020} as follows. Contributions C3 and C4 are entirely new, and C1 is enhanced by being based on the analysis of four rather than two languages and implementations.
71
72 \section{Background and related work}%
73 \label{sec_t4t:Background}
74
75 \subsection{\texorpdfstring{\Acrlong{UOG}}{University of Glasgow} smart campus}%
76 \label{sec_t4t:UoGSmartCampus}
77 % Jeremy
78 The \gls{UOG} is partway through a ten-year campus
79 upgrade programme, and a key goal is to embed pervasive sensing infrastructure into
80 the new physical fabric to form a \emph{smart campus} environment.
81 As a prototyping exercise, we use modest commodity
82 sensor nodes (i.e.\ Raspberry Pis) and low-cost, low-precision sensors
83 for indoor environmental monitoring.
84
85 We have deployed sensor nodes into 12 rooms in two buildings. The \gls{IOT} system has an online data store, providing live
86 access to sensor data through a RESTful \gls{API}.
87 This allows campus stakeholders to add functionality at a business layer above the layers that we consider here. To date,
88 simple apps have been developed including room temperature
89 monitors and campus utilization maps~\citep{hentschel_supersensors:_2016}.
90 A longitudinal study of sensor accuracy has also been
91 conducted~\citep{harth_predictive_2018}.
92
93 \subsection{\texorpdfstring{\Gls{IOT}}{IoT} applications}%
94 \label{sec_t4t:Stacks}
95
96 Web applications are necessarily complex distributed systems, with client browsers interacting with a remote webserver and data store. Typical \gls{IOT} applications
97 are even more complex as they combine a web application with a second distributed system of sensor and actuator nodes that collect and aggregate data, operate on it, and communicate with the server.
98
99 Both web and \gls{IOT} applications are commonly structured into tiers, e.g.\ the classical four-tier Linux, Apache, MySQL and PHP (LAMP) stack.
100 \Gls{IOT} stacks typically have more tiers than webapps, with the number depending on the complexity of the application~\citep{sethi2017internet}. While other tiers, like the business layer~\citep{muccini2018iot} may be added above them, the focus of our study is on programming the lower four tiers of the \gls{PRS}, \gls{CRS}, \gls{PWS} and \gls{CWS} stacks, as illustrated in \cref{fig_t4t:iot_arch}.
101
102 \begin{landscape}
103 \begin{figure}[ht]
104 \includegraphics[width=\linewidth]{arch}
105 \caption{%
106 \gls{PRS} and \gls{PWS} (left) together with \gls{CRS} and \gls{PRS} (right) mapped to the four-tier \gls{IOT} architecture.
107 Every box is the diagram denotes a source file or base.
108 Bold blue text describes the language or technology used in that source.
109 The network and perception layer are unique to the specific implementation, where the application and presentation layers are shared between implementations.
110 }%
111 \label{fig_t4t:iot_arch}
112 \end{figure}
113 \end{landscape}
114 %
115 \begin{enumerate}
116
117 \item Perception Layer {--} collects the data, interacts with the environment, and consists of devices using light, sound, motion, air quality and temperature sensors.
118 \item Network Layer {--} replays the communication messages between the sensor nodes and the server through protocols such as \gls{MQTT}.
119
120 \item Application Layer {--} acts as the interface between the presentation layer and the perception layer, storing and processing the data.
121
122 \item Presentation Layer {--} utilises web components as the interface between the human and devices where application services are provided.
123
124 \end{enumerate}
125
126
127 \subsection{The benefits and challenges of developing tiered \texorpdfstring{\gls{IOT}}{IoT} stacks}
128
129 Using multiple tiers to
130 structure complex software is a common software engineering practice that provides significant architectural benefits for \gls{IOT} and other software. The tiered \gls{PYTHON} \gls{PRS} and \gls{PWS} stacks exhibit these benefits.
131 \begin{enumerate}
132
133 \item Modularity: tiers allow a system to be structured as a set of components with clearly defined functionality. They can be implemented independently, and may be interchanged with other components that have similar functionality~\citep{maccormack2007impact}. In \gls{PRS} and \gls{PWS}, for example, a different NoSQL DBMS could relatively easily be substituted for {MongoDB}
134
135 \item Abstraction: the hierarchical composition of components in the stack abstracts the view of the system as a whole. Enough detail is provided to understand the roles of each layer and how the components relate to one another~\citep{belle2013layered}. \Cref{fig_t4t:iot_arch} illustrates the abstraction of \gls{PRS} and \gls{PWS} into four tiers.
136
137 \item Cohesion: well-defined boundaries ensure each tier contains functionality directly related to the task of the component~\citep{lee2001component}. The tiers in \gls{PRS} and \gls{PWS} contain all the functionality associated with perception, networking, application and presentation respectively.
138
139 \end{enumerate}
140
141 However, a tiered architecture poses significant challenges for developers of \gls{IOT} and other software. The tiered \gls{PYTHON} \gls{PRS} and \gls{PWS} stacks exhibit these challenges, and we analyse these in detail later in the paper.
142
143 \begin{enumerate}
144
145 \item Polyglot Development {--} the developer must be fluent in all the languages and components in the stack, known as being a full stack developer for webapps~\citep{mazzei2018full}. That is, the developer must correctly use multiple languages that have different paradigms, i.e.\ manage significant \emph{semantic friction}~\citep{ireland2009classification}. For example the \gls{PWS} developer must integrate components written in seven languages with two paradigms (\cref{sec_t4t:interoperation}).
146
147 \item Correct Interoperation {--} the developer must adhere to the \gls{API} or communication protocols between components. \Cref{sec_t4t:codesize,sec_t4t:resourcerich} show that communication requires some 17\% of \gls{PRS} and \gls{PWS} code, so around 100 \gls{SLOC}. \Cref{sec_t4t:Communication} discusses the complexity of writing this distributed communication code.
148
149 \item Maintaining Type Safety {--} is a key element of the semantic friction encountered in multi-language stacks, and crucial for correctness. The developer must maintain type safety across a range of very different languages and diverse type systems, with minimal tool support. We show an example where \gls{PRS} loses type safety over the network layer (\Cref{sec_t4t:typesafety}).
150
151
152 \item Managing multiple failure modes {--} different components may have different failure modes, and these must be coordinated. \Cref{sec_t4t:NetworkManagement} outlines how \gls{PRS} and \gls{PWS} use heartbeats to manage failures.
153 \end{enumerate}
154
155
156 Beyond \gls{PRS} and \gls{PWS} the challenges of tiered polyglot software development are evidenced in real world studies. As recent examples, a study of GitHub open source projects found an average of five different languages in each project, with many using tiered architectures~\citep{mayer2017multi}.
157 An earlier empirical study of GitHub shows that using more languages to implement a project has a significant effect on project quality, since it increases defects~\citep{kochhar2016large}.
158 A study of \gls{IOT} stack developers found that interoperation poses a real challenge, that microservices blur the abstraction between tiers, and that both testing and scaling \gls{IOT} applications to more devices are hard~\citep{motta2018challenges}.
159
160 One way of minimising the challenges of developing tiered polyglot \gls{IOT} software is to standardise and reuse components. This approach has been hugely successful for web stacks, e.g.\ browser standards. The W3C
161 Web of Things aims to facilitate re-use by providing standardised metadata and other re-usable technological \gls{IOT} building blocks~\citep{guinard_building_2016}. However, the Web of Things has yet to gain widespread adoption. Moreover, as it is based on web technology, it requires the \emph{thing} to run a web server, significantly increasing the hardware requirements.
162
163 \section{Tierless languages}%
164 \label{sec_t4t:TiredvsTierless}
165
166 A radical approach to overcoming the challenges raised by tiered distributed software is to use a tierless programming language that eliminates the semantic friction between tiers by generating code for all tiers, and all communication between tiers, from a single program.
167 %\adriancomment{Also referred to as multi-tier programming, tierless language applications usually utilise a single language, paradigm and type system, and the entire system is simultaneously checked by the compiler~\citep{weisenburger2020survey}.}
168 Typically a tierless program uses a single language, paradigm and type system, and the entire distributed system is simultaneously checked by the compiler.
169
170 There is intense interest in developing tierless, or multitier, language technologies with a number of research languages developed over the last fifteen years, e.g.\ \citep{cooper2006links, serrano2006hop, troyer_building_2018, 10.1145/2775050.2633367}. These languages demonstrate the
171 advantages of the paradigm, including less development effort, better maintainability, and sound semantics of distributed execution. At the same time a number of industrial technologies incorporate tierless concepts, e.g.\ \citep{balat2006ocsigen, bjornson2010composing, strack2015getting}. These languages demonstrate the benefits of the paradigm in practice. Some tierless languages use (embedded) \glspl{DSL} to specify parts of the multi-tier software.
172
173 Tierless languages have been developed for a range of distributed paradigms, including web applications, client-server applications, mobile applications, and generic distributed systems. A recent and substantial survey of these tierless technologies is available~\citep{weisenburger2020survey}. Here we provide a brief introduction to tierless languages with a focus on \gls{IOT} software.
174
175 \subsection{Tierless web languages}
176 % Standalone DSLs
177 There are established tierless languages for web development, both standalone languages and \glspl{DSL} embedded in a host language.
178 Example standalone tierless web languages are Links~\citep{cooper2006links} and Hop~\citep{serrano2006hop}.
179 From a single declarative program the client, server and database code is simultaneously checked by the compiler, and compiled to the required component languages. For example, Links compiles to HTML and JavaScript for the client side and to SQL on the server-side to interact with the database system.
180
181 An example tierless web framework that uses a \gls{DSL} is Haste~\citep{10.1145/2775050.2633367}, that embeds the \gls{DSL} in \gls{HASKELL}. Haste programs are compiled multiple times: the server code is generated by the standard \gls{GHC} \gls{HASKELL} compiler~\citep{hall1993glasgow}; Javascript for the client is generated by a custom \gls{GHC} compiler backend. The design leverages \gls{HASKELL}'s high-level programming abstractions and strong typing, and benefits from \gls{GHC}: a mature and sophisticated compiler.
182
183
184 \subsection{Tierless \texorpdfstring{\gls{IOT}}{IoT} languages}
185 The use of tierless languages in \gls{IOT} applications is both more recent and less common than for web applications.
186 Tierless \gls{IOT} programming may extend tierless web programming by adding network and perception layers.
187 The presentation layer of a tierless \gls{IOT} language, like tierless web languages, benefits from almost invariably executing in a standard browser. The perception layer faces greater challenges, often executing on one of a set of slow and resource-constrained microcontrollers. Hence, tierless \gls{IOT} languages typically compile the perception layer to either \gls{C}\slash\gls{CPP} (the lingua franca of microcontrollers), or to some intermediate representation to be interpreted.
188
189 \subsubsection{\texorpdfstring{\Glspl{DSL}}{DSLs} for microcontrollers}
190 Many \glspl{DSL} provide high-level programming for microcontrollers, for example providing strong typing and memory safety.
191 For example Copilot~\citep{hess_arduino-copilot_2020}
192 and Ivory~\citep{elliott_guilt_2015} are imperative \glspl{DSL} embedded in a functional language that compile to \gls{C}\slash\gls{CPP}. In contrast to \gls{CLEAN}/\gls{ITASK}/\gls{MTASK} such \glspl{DSL} are not tierless \gls{IOT} languages as they have no automatic integration with the server, i.e.\ with the application and presentation layers.
193
194
195 \subsubsection{\texorpdfstring{\Gls{FRP}}{Functional reactive programming}}
196 \Gls{FRP} is a declarative paradigm often used for implementing the perception layer of an \gls{IOT} stack.
197 Examples include mfrp~\citep{sawada_emfrp:_2016}, CFRP~\citep{suzuki_cfrp_2017}, XFRP~\citep{10.1145/3281366.3281370}, Juniper~\citep{helbling_juniper:_2016}, Hailstorm~\citep{sarkar_hailstorm_2020}, and Haski~\citep{valliappan_towards_2020}.
198 None of these languages are tierless \gls{IOT} languages as they have no automatic integration with the server.
199
200 Potato goes beyond other \gls{FRP} languages to provide a tierless \gls{FRP} \gls{IOT} language for resource rich sensor nodes~\citep{troyer_building_2018}. It does so using the Erlang programming language and sophisticated virtual machine.
201
202 TOP allows for more complex collaboration patterns than \gls{FRP}~\citep{wang_maintaining_2018}, and in consequence is unable to provide the strong guarantees on memory usage available in a restricted variant of \gls{FRP} such as arrowized \gls{FRP}~\citep{nilsson_functional_2002}.
203
204 \subsubsection{Erlang/Elixir \texorpdfstring{\gls{IOT}}{IoT} systems}
205 A number of production \gls{IOT} systems are engineered in Erlang or Elixir, and many are mostly tierless.
206 That is the perception, network and application layers are sets of distributed Erlang processes, although the presentation layer typically uses some conventional web technology.
207 A resource-rich sensor node may support many Erlang processes on an Erlang VM, or low level code (typically \gls{C}\slash\gls{CPP}) on a resource-constrained microcontroller can emulate an Erlang process.
208 Only a small fraction of these systems are described in the academic literature, example exceptions are~\citep{sivieri2012drop,shibanai_distributed_2018}, with many described only in grey literature or not at all.
209
210 \subsection{Characteristics of tierless \texorpdfstring{\gls{IOT}}{IoT} languages}%
211 \label{sec_t4t:characteristics}
212
213 This study compares a pair of tierless \gls{IOT} languages with conventional tiered \gls{PYTHON} \gls{IOT} software. \gls{CLEAN}\slash\gls{ITASK} and \gls{CLEAN}/\gls{ITASK}/\gls{MTASK} represent a specific set of tierless language design decisions, however many alternative designs are available. Crucially the limitations of the tierless \gls{CLEAN} languages, e.g.\ that they currently provide limited security, should not be seen as limitations of tierless technologies in general. This section briefly outlines key design decisions for tierless \gls{IOT} languages, discusses alternative designs, and describes the \gls{CLEAN} designs. The \gls{CLEAN} designs are illustrated in the examples in the following section.
214
215 \subsubsection{Program splitting}
216
217 A key challenge for an automatically segmented tierless language is to determine which parts of the program correspond to a particular tier and hence should be executed by a specific component on a specific host, so-called tier splitting.
218 For example a tierless web language must identify client code to ship to browsers, database code to execute in the DBMS, and application code to run on the server. Some tierless languages split programs using types, others use syntactic markers, e.g.\ pragmas like \cleaninline{server} or \cleaninline{client}, to split the program~\citep{cooper2006links,10.1145/2775050.2633367}. It may be possible to infer the splitting between tiers, relieving the developers from the need specify it, as illustrated for Javascript as a tierless web language~\citep{10.1145/2661136.2661146}.
219
220 In \gls{CLEAN}\slash\gls{ITASK}/\gls{MTASK} and \gls{CLEAN}/\gls{ITASK} tier splitting is specified by functions, and hence is a first-class language construct.
221 For example in \gls{CLEAN}\slash\gls{ITASK} the \cleaninline{asyncTask} function identifies a task for execution on a remote device and \cleaninline{liftmTask} executes the given task on an \gls{IOT} device. The tier splitting functions are illustrated in examples in the next section, e.g.\ on \cref{lst_t4t:itaskTempFull:startdevtask} in \cref{lst_t4t:itaskTempFull} and \cref{lst_t4t:mtaskTemp:liftmtask} in \cref{lst_t4t:mtaskTemp}.
222 Specifying splitting as functions means that new splitting functions can be composed, and that splitting is under program control, e.g.\ during execution a program can decide to run a task locally or remotely.
223
224 \subsubsection{Communication}\label{ssec_t4t:communication}
225
226 Tierless languages may adopt a range of communication paradigms for communicating between components. Different tierless languages specify communication in different ways~\citep{weisenburger2020survey}. Remote procedures are the most common communication mechanism: a procedure/function executing on a remote host/machine is called as if it was local. The communication of the arguments to, and the results from, the remote procedure is automatically provided by the language implementation. Other mechanisms include explicit message passing between components; publish/subscribe where components subscribe to topics of interest from other components; reactive programming defines event streams between remote components; finally shared state makes changes in a shared and potentially remote data structure visible to components.
227
228 \Gls{CLEAN}\slash\gls{ITASK}/\gls{MTASK} and \gls{CLEAN}/\gls{ITASK} communicate using a combination of remote task invocation, similar to remote procedures, and shared state through \glspl{SDS}.
229 \Cref{lst_t4t:itaskTempFull} illustrates: \cref{lst_t4t:itaskTempFull:startdevtask} shows a server task launching a remote task, \cleaninline{devTask}, on to a sensor node; and \cref{lst_t4t:itaskTempFull:remoteShare} shows the sharing of the remote \cleaninline{latestTemp} \gls{SDS}.
230 %\mlcomment{I think this is fine}
231
232 \subsubsection{Placement}
233
234 In many \gls{IOT} systems the sensor nodes are microcontrollers that are programmed by writing the program to flash memory. This means that without extra effort, physical access to the microcontroller is needed to change the program making updates challenging.
235 Hence, most \gls{IOT} systems compile sensor node code directly for the target architecture or via an existing language such as \gls{C}\slash\gls{CPP}.
236
237 Techniques such as over-the-air programming and interpreters allow microcontrollers to be dynamically provisioned, increasing their maintainability and resilience.
238 For example Baccelli et al.\ provide a single language \gls{IOT} system based on the RIOT \gls{OS} that allows runtime deployment of code snippets called containers~\citep{baccelli_reprogramming_2018}.
239 Both client and server are written in JavaScript. However, there is no integration between the client and the server other than that they are programmed from a single source.
240 Mat\`e is an example of an early tierless sensor network framework where devices are provided with a virtual machine using TinyOS for dynamic provisioning~\citep{levis_mate_2002}.
241
242 Placement specifies how data and computations in a tierless program are assigned to the
243 devices/hosts in the distributed system. Different tierless languages specify placement in different ways, e.g.\ code annotations or configuration files, and at different granularities, e.g.\ per function or per class~\citep{weisenburger2020survey}.
244
245 \Gls{CLEAN}\slash\gls{ITASK}/\gls{MTASK} and \gls{CLEAN}/\gls{ITASK} both use dynamic task placement, similar to dynamic function placement.
246 In \gls{CLEAN}\slash\gls{ITASK}/\gls{MTASK} sensor nodes are programmed once with the \gls{MTASK} \gls{RTS}, and possibly some precompiled tasks.
247 Thereafter a sensor node can dynamically receive \gls{MTASK} programs, compiled at runtime by the server.
248 In \gls{CLEAN}\slash\gls{ITASK} the sensor node runs an \gls{ITASK} server that recieves and executes code from the (\gls{IOT}) server~\citep{oortgiese_distributed_2017}.
249 %The \gls{ITASK} server decides what code to execute depending on the serialised execution graph that the server sends~\citep{oortgiese_distributed_2017}.
250 Placement happens automatically as part of the first-class splitting constructs outlined in \cref{ssec_t4t:communication}, so \cref{lst_t4t:mtaskTemp:liftmtask} in \cref{lst_t4t:mtaskTemp} places \cleaninline{devTask} onto the \cleaninline{dev} sensor node.
251
252 \subsubsection{Security}
253
254 Security is a major issue and a considerable challenge for many \gls{IOT} systems~\citep{10.1145/3437537}. There are potentially security issues at each layer in an \gls{IOT} application (\cref{fig_t4t:iot_arch}). The security issues and defence mechanisms at the application and presentation layers are relatively standard, e.g.\ defending against SQL injection attacks. The security issues at the network and perception layers are more challenging. Resource-rich sensor nodes can adopt some standard security measures like encrypting messages, and regularly applying software patches to the operating system. However microcontrollers often lack the computational resources for encryption, and it is hard to patch their system software because the program is often stored in flash memory. In consequence there are infamous examples of \gls{IOT} systems being hijacked to create botnets~\citep{203628,herwig_measurement_2019}.
255
256 Securing the entire stack in a conventional tiered \gls{IOT} application is particularly challenging as the stack is implemented in a collection of programming languages with low level programming and communication abstractions. In such polyglot distributed systems it is hard to determine, and hence secure, the flow of data between components. In consequence a small mistake may have severe security implications.
257
258 A number of characteristics of tierless languages help to improve security. Communication and placement vulnerabilities are minimised as communication and placement are automatically generated and checked by the compiler. So injection attacks and the exploitation of communication/placement protocol bugs are less likely. Vulnerabilities introduced by mismatched types are avoided as the entire system is type checked. Moreover, tierless languages can exploit language level security techniques. For example languages like Jif/split~\citep{zdancewic2002secure} and Swift~\citep{chong2007secure} place components to protect the security of data. Another example are programming language technologies for controlling information flow, and these can be used to improve security. For example Haski uses them to improve the security of \gls{IOT} systems~\citep{valliappan_towards_2020}.
259
260 However many tierless languages have yet to provide a comprehensive set of security technologies, despite its importance in domains like web and \gls{IOT} applications. For example Erlang and many Erlang-based systems~\citep{shibanai_distributed_2018,sivieri2012drop}, lack important security measures. Indeed security is not covered in a recent, otherwise comprehensive, survey of tierless technologies~\citep{weisenburger2020survey}.
261
262 \Gls{CLEAN}\slash\gls{ITASK} and \gls{CLEAN}/\gls{ITASK}/\gls{MTASK} are typical in this respect: little effort has yet been expended on improving their security. Of course as tierless languages they benefit from static type safety and automatically generated communication and placement. Some preliminary work shows that, as the communication between layers is protocol agnostic, more secure alternatives can be used. One example is to run the \gls{ITASK} server behind a reverse proxy implementing TLS/SSL encryption~\citep{wijkhuizen_security_2018}. A second is to add integrity checks or even encryption to the communication protocol for resource-rich sensor nodes~\citep{boer_de_secure_2020}.
263
264 \section{Task-oriented and \texorpdfstring{\gls{IOT}}{IoT} programming in \texorpdfstring{\gls{CLEAN}}{Clean}}
265
266 To make this paper self-contained we provide a concise overview of \gls{CLEAN}, \gls{TOP}, and \gls{IOT} programming in \gls{ITASK} and \gls{MTASK}. The minor innovations reported here are the interface to the \gls{IOT} sensors, and the \gls{CLEAN} port for the Raspberry Pi.
267
268 \Gls{CLEAN} is a statically typed functional programming language similar to \gls{HASKELL}: both languages are pure and non-strict~\citep{achten_clean_2007}.
269 A key difference is how state is handled: \gls{HASKELL} typically embeds stateful actions in the \haskellinline{IO} Monad~\citep{peyton_jones_imperative_1993,wiki:IO}.
270 In contrast, \gls{CLEAN} has a uniqueness type system to ensure the single-threaded use of stateful objects like files and windows~\citep{barendsen_smetsers_1996}.
271 Both \gls{CLEAN} and \gls{HASKELL} support fairly similar models of generic programming~\citep{ComparingGenericProgramming}, enabling functions to work on many types. As we shall see generic programming is heavily used in task-oriented programming~\citep{GenericProgrammingExtensionForClean,HinzeGenericFunctionalProgramming}, for example to construct web editors and communication protocols that work for any user-defined datatype.
272
273 \subsection{\texorpdfstring{\Acrlong{TOP}}{Task-oriented programming}}
274
275 \Gls{TOP} is a declarative programming paradigm for constructing interactive distributed systems~\citep{plasmeijer_task-oriented_2012}.
276 Tasks are the basic blocks of \gls{TOP} and represent work that needs to be done in the broadest sense.
277 Examples of typical tasks range from allowing a user to complete a form, controlling peripherals, moderating other tasks, or monitoring a database.
278 From a single declarative description of tasks all of the required software components are generated.
279 This may include web servers, client code for browsers or \gls{IOT} devices, and for their interoperation.
280 That is, from a single \gls{TOP} program the language implementation automatically generates an \emph{integrated distributed system}.
281 Application areas range from simple web forms or blinking \glspl{LED} to multi-user distributed collaboration between people and machines~\citep{oortgiese_distributed_2017}.
282
283
284 \Gls{TOP} adds three concepts: tasks, task combinators, and \glspl{SDS}. Example basic tasks are web editors for user-defined datatypes, reading some \gls{IOT} sensor, or controlling peripherals like a servo motor.
285 Task combinators compose tasks into more advanced tasks, either in parallel or sequential and allow task values to be observed by other tasks.
286 As tasks can be returned as the result of a function, recursion can be freely used, e.g.\ to express the repetition of tasks.
287 There are also standard combinators for common patterns.
288 Tasks can exchange information via \glspl{SDS}~\citep{ParametricLenses}.
289 All tasks involved can atomically observe and change the value of a typed \gls{SDS}, allowing more flexible communication than with task combinators.
290 \glspl{SDS} offer a general abstraction of data shared by different tasks, analogous to variables, persistent values, files, databases and peripherals like sensors. Combinators compose \glspl{SDS} into a larger \gls{SDS}, and
291 parametric lenses define a specific view on an \gls{SDS}.
292
293
294
295 \subsection{The \texorpdfstring{\gls{ITASK}}{iTask} \texorpdfstring{\gls{EDSL}}{eDSL}}%
296 \label{sec_t4t:itasks}
297
298
299 The \gls{ITASK} \gls{EDSL} is designed for constructing multi-user distributed applications, including web~\citep{TOP-ICFP07} or \gls{IOT} applications.
300 Here we present \gls{ITASK} by example, and the first is a complete program to repeatedly read the room temperature from a digital humidity and temperature (DHT) sensor attached to the machine and display it on a web page (\cref{lst_t4t:itaskTemp}).
301 The first line is the module name, the third imports the \cleaninline{iTask} module, and the main function (\cref{lst_t4t:itaskTemp:systemfro,lst_t4t:itaskTemp:systemto}) launches \cleaninline{readTempTask} and the \gls{ITASK} system to generate the web interface in \cref{fig_t4t:itaskTempSimple}.
302
303 Interaction with a device like the DHT sensor using a protocol like 1-Wire or gls{I2C} is abstracted into a library. So the \cleaninline{readTempTask} task starts by creating a \cleaninline{dht} sensor object (\cref{lst_t4t:itaskTemp:dhtDef}) thereafter \cleaninline{repeatEvery} executes a task at the specified \cleaninline{interval}. This task reads the temperature from the \cleaninline{dht} sensor, and with a sequential composition combinator \cleaninline{>>~} passes the \cleaninline{temp} value to \cleaninline{viewInformation} that displays it on the web page (\cref{lst_t4t:itaskTemp:viewInformation}).
304 The tuning combinator \cleaninline{<<@} adds a label to the web editor displaying the temperature. Crucially, the \gls{ITASK} implementation transparently ships parts of the code for the web-interface to be executed in the browser, and \cref{fig_t4t:itaskTempSimple} shows the UML deployment diagram.
305
306 \begin{lstClean}[%
307 numbers=left,
308 caption={SimpleTempSensor: a \gls{CLEAN}\slash\gls{ITASK} program to read a local room temperature sensor and display it on a web page},
309 label={lst_t4t:itaskTemp}]
310 module simpleTempSensor
311
312 import iTasks
313
314 Start :: *World -> *World [+\label{lst_t4t:itaskTemp:systemfro}+]
315 Start world = doTasks readTempTask world [+\label{lst_t4t:itaskTemp:systemto}+]
316
317 readTempTask :: Task Real
318 readTempTask =
319 withDHT IIO_TempID \dht -> [+\label{lst_t4t:itaskTemp:dhtDef}+]
320 repeatEvery interval ( [+\label{lst_t4t:itaskTemp:repeat}+]
321 temperature dht >>~ \temp -> [+\label{lst_t4t:itaskTemp:readDHT}+]
322 viewInformation [] temp <<@ [+\label{lst_t4t:itaskTemp:viewInformation}+]
323 Label "Temperature" [+\label{lst_t4t:itaskTemp:label}+]
324 )
325 \end{lstClean}
326
327 \begin{figure}[ht]
328 \centering
329 \begin{subfigure}[t]{.2\textwidth}
330 \centering
331 \fbox{\includegraphics[width=.9\textwidth]{readTempTask}}
332 \caption{Web page.}
333 \end{subfigure}%
334 \begin{subfigure}[t]{.8\textwidth}
335 \centering
336 \includegraphics[width=\textwidth]{simpleTempSensor}
337 \caption{Deployment diagram.}
338 \end{subfigure}
339 \caption{\Gls{ITASK} SimpleTempSensor.}%
340 \label{fig_t4t:itaskTempSimple}
341 \end{figure}
342
343 SimpleTempSensor only reports instantaneous temperature measurements. Extending it to store and manipulate timed temperature records produces a tiny tierless web application: TempHistory in \cref{lst_t4t:TempHistory}. A tierless \gls{IOT} system can be controlled from a web interface in exactly the same way, e.g.\ to view and set the measurement frequencies of each of the room sensors. \Cref{lst_t4t:itaskTemp:Measurement} defines a record to store \cleaninline{time} and \cleaninline{temp} measurements. Task manipulations are derived for \cleaninline{Measurement} (\cref{lst_t4t:itaskTemp:derive}) and these include displaying measurements in a web-editor and storing them in a file.
344 \Cref{lst_t4t:itaskTemp:measurementsSDS} defines a persistent \gls{SDS} to store a list of measurements, and for communication between tasks. The \gls{SDS} is analogous to the SQL DBMS in many tiered web applications.
345
346 TempHistory defines two tasks that interact with the \texttt{mea\-sure\-ments\-SDS}: \texttt{mea\-sure\-Task} adds measurements at each detected change in the temperature.
347 It starts by defining a \cleaninline{dht} object as before, and then defines a recursive \cleaninline{task} function parameterized by the \cleaninline{old} temperature.
348 This function reads the temperature from the DHT sensor and uses the step combinator, \cleaninline{>>*}, to compose it with a list of actions.
349 The first of those actions that is applicable determines the continuation of this task. If no action is applicable, the task on the left-hand side is evaluated again.
350 The first action checks whether the new temperature is different from the \cleaninline{old} temperature (\cref{lst_t4t:itaskTemp:action1}). If so, it records the current time and adds the new measurements to the \cleaninline{measurementsSDS}.
351 The next action in \cref{lst_t4t:itaskTemp:action2} is always applicable and waits (sleeps) for an interval before returning the old temperature.
352 On \cref{lst_t4t:itaskTemp:launch} \cleaninline{task} is launched with an initial temperature.
353
354 \begin{lstClean}[%
355 numbers=left,
356 caption={TempHistory: a tierless \gls{CLEAN}\slash\gls{ITASK} webapplication that records and manipulates timed temperatures},
357 label={lst_t4t:TempHistory}]
358 module TempHistory
359
360 import iTasks, iTasks.Extensions.DateTime
361
362 :: Measurement = {time :: Time, temp :: Real} [+\label{lst_t4t:itaskTemp:Measurement}+]
363 derive class iTask Measurement [+\label{lst_t4t:itaskTemp:derive}+]
364
365 measurementsSDS :: SimpleSDSLens [Measurement] [+\label{lst_t4t:itaskTemp:measurementsSDS}+]
366 measurementsSDS = sharedStore "measurements" []
367
368 measureTask :: Task () [+\label{lst_t4t:itaskTemp:measureTask}+]
369 measureTask =
370 withDHT IIO_TempID \dht ->
371 let task old =
372 temperature dht >>* [+\label{lst_t4t:itaskTemp:step}+]
373 [ OnValue (ifValue ((<>) old) \temp -> [+\label{lst_t4t:itaskTemp:action1}+]
374 get currentTime >>~ \time ->
375 upd (\list.[{time=time, temp=temp}:list]) measurementsSDS
376 @! temp)
377 , OnValue (always (waitForTimer False interval @! old))[+\label{lst_t4t:itaskTemp:action2}+]
378 ] >>~ task
379 in task initialTemp [+\label{lst_t4t:itaskTemp:launch}+]
380
381
382 controlSDS :: Bool -> Task [Measurement]
383 controlSDS byTemp =
384 ((Label "# to take" @>> enterInformation []) -|| [+\label{lst_t4t:itaskTemp:enter}+]
385 (Label "Measurements" @>> [+\label{lst_t4t:itaskTemp:view}+]
386 viewSharedInformation
387 [ ViewAs (if byTemp (sortBy (\x y->x.temp < y.temp)) id)]
388 measurementsSDS)) >>*[+\label{lst_t4t:itaskTemp:viewend}+]
389 [ OnAction (Action "Clear") (always
390 (set [] measurementsSDS >-| controlSDS byTemp))
391 , OnAction (Action "Take") (ifValue ((<) 0)
392 (\n.upd (take n) measurementsSDS >-| controlSDS byTemp))
393 , OnAction (Action (if byTemp "Sort time" "Sort temp")) (always
394 (controlSDS (not byTemp)))
395 ] [+\label{lst_t4t:itaskTemp:actionend}+]
396
397 mainTask :: Task [Measurement]
398 mainTask = controlSDS False -|| measureTask
399 \end{lstClean}
400
401 The \cleaninline{controlSDS} task illustrates communication from the web page user and persistent data manipulation. That is, it generates a web page that allows users to control their view of the temperature measurements, as illustrated in \cref{fig_t4t:TempHistory}. The page contains
402 \begin{enumerate*}
403 \item a web editor to enter the number \cleaninline{n} of elements to display, generated on \cref{lst_t4t:itaskTemp:enter}.
404 \item A display of the \cleaninline{n} most recent temperature and time measurements, \crefrange{lst_t4t:itaskTemp:view}{lst_t4t:itaskTemp:viewend}.
405 \item Three buttons that are again combined with the step combinator \cleaninline{>>*}, \crefrange{lst_t4t:itaskTemp:viewend}{lst_t4t:itaskTemp:actionend}. The \cleaninline{Clear} button is \cleaninline{always} enabled and sets the \gls{SDS} to an empty list before calling \cleaninline{controlSDS} recursively. The \cleaninline{Take} button is only enabled when the web editor produces a positive \cleaninline{n} and updates the \cleaninline{measurementsSDS} with the \cleaninline{n} most recent measurements before calling \cleaninline{controlSDS} recursively. The final action is \cleaninline{always} enabled and calls \cleaninline{controlSDS} recursively with the negation of the \cleaninline{byTemp} argument to change the sorting criteria.
406 \end{enumerate*}
407
408 \begin{figure}[ht]
409 \centering
410 \begin{subfigure}[t]{.5\textwidth}
411 \centering
412 \fbox{\includegraphics[width=.95\textwidth]{TempHistory1}}
413 \caption{Web page sorted by time.}
414 \end{subfigure}%
415 \begin{subfigure}[t]{.5\textwidth}
416 \centering
417 \fbox{\includegraphics[width=.95\textwidth]{TempHistory2}}
418 \caption{Web page sorted by temperature.}
419 \end{subfigure}
420 \caption{Web pages generated by the \cleaninline{TempHistory} \gls{CLEAN}\slash\gls{ITASK} tierless web application.
421 The \cleaninline{Take} button is only enabled when the topmost editor contains a positive number.
422 }%
423 \label{fig_t4t:TempHistory}
424 \end{figure}
425
426 \begin{figure}[ht]
427 \centering
428 \includegraphics[width=.95\textwidth]{TempHistory}
429 \caption{Deployment diagram of the \gls{ITASK} TempHistory tierless web application from \cref{lst_t4t:TempHistory}.}%
430 \label{fig_t4t:TempHistoryDiagram}%
431 \end{figure}
432
433 \Cref{fig_t4t:TempHistory} shows two screenshots of web pages generated by the \cleaninline{TempHistory} program. \Cref{fig_t4t:TempHistoryDiagram} is the deployment diagram showing the addition of the persistent \cleaninline{measurementsSDS} that stores the history of temperature measurements.
434
435 \subsection{Engineering tierless \texorpdfstring{\gls{IOT}}{IoT} systems with \texorpdfstring{\gls{ITASK}}{iTask}}%
436 \label{sec_t4t:itaskIOT}
437
438 A typical \gls{IOT} system goes beyond a web application by incorporating a distributed set of sensor nodes each with a collection of sensors or actuators. That is, they add the perception and network layers in \cref{fig_t4t:iot_arch}. If the sensor nodes have the computational resources to support an \gls{ITASK} server, as a Raspberry Pi does, then \gls{ITASK} can also be used to implement these layers, and integrate them with the application and presentation layers tierlessly.
439
440 As an example of tierless \gls{IOT} programming in \gls{CLEAN}\slash\gls{ITASK} \cref{lst_t4t:itaskTempFull} shows a complete temperature sensing system with a server and a single sensor node (\gls{CRTS}), omitting only the module name and imports.
441 It is similar to the SimpleTempSensor and TempHistory programs above, for example \cleaninline{devTask} repeatedly sleeps and records temperatures and times, and \cleaninline{mainTask} displays the temperatures on the web page in \cref{fig_t4t:cwtsweb}. There are some important differences, however. The \cleaninline{devTask} (\crefrange{lst_t4t:itaskTempFull:sensorfro}{lst_t4t:itaskTempFull:sensorto}) executes on the sensor node and records the temperatures in a standard timestamped (lens on) an \gls{SDS}: \cleaninline{dateTimeStampedShare} \cleaninline{latestTemp}.
442 The \cleaninline{mainTask} (\cref{lst_t4t:itaskTempFull:main}) executes on the server: it starts \cleaninline{devTask} as an asynchronous task on the specified sensor node (\cref{lst_t4t:itaskTempFull:startdevtask}) and then generates a web page to display the latest temperature and time (\cref{lst_t4t:itaskTempFull:displaystart,lst_t4t:itaskTempFull:displayend}).
443
444 The \cleaninline{tempSDS} is very similar to the \cleaninline{measurementsSDS} from the previous listings.
445 The only difference is that we store measurements as tuples instead of tailor-made records.
446 The \cleaninline{latestTemp} is a \emph{lens} on the \cleaninline{tempSDS}.
447 A lens is a new \gls{SDS} that is automatically mapped to another \gls{SDS}.
448 Updating one of the \glspl{SDS} that are coupled in this way automatically updates the other.
449 The function \cleaninline{mapReadWrite} is parameterized by the read and write functions, the option to handle asynchronous update conflicts (here \cleaninline{?None}) and the \gls{SDS} to be transformed (here \cleaninline{tempSDS}).
450 The result of reading is the head of the list, if it exists.
451 The type for writing \cleaninline{latestTemp} is a tuple with a new \cleaninline{DateTime} and temperature as \cleaninline{Real}.
452
453 \begin{lstClean}[%
454 numbers=left,
455 caption={\gls{CRTS}: a tierless temperature sensing \gls{IOT} system. Written in \gls{CLEAN}\slash\gls{ITASK}, it targets a resource-rich sensor node.},
456 label={lst_t4t:itaskTempFull}]
457 tempSDS :: SimpleSDSLens [(DateTime, Real)]
458 tempSDS = sharedStore "temperatures" []
459
460 latestTemp :: SDSLens () (? (DateTime, Real)) (DateTime, Real)
461 latestTemp = mapReadWrite (listToMaybe, \x xs-> ?Just [x:xs]) ?None tempSDS
462
463 devTask :: Task DateTime
464 devTask = [+\label{lst_t4t:itaskTempFull:sensorfro}+]
465 withDHT IIO_TempID \dht ->
466 forever ([+\label{lst_t4t:itaskTempFull:forever}+]
467 temperature dht >>~ \temp ->
468 set temp (dateTimeStampedShare latestTemp) >-|
469 waitForTimer False interval) [+\label{lst_t4t:itaskTempFull:waitForTimer}+][+\label{lst_t4t:itaskTempFull:sensorto}+]
470
471 mainTask :: Task ()
472 mainTask [+\label{lst_t4t:itaskTempFull:main}+]
473 = asyncTask deviceInfo.domain deviceInfo.port devTask [+\label{lst_t4t:itaskTempFull:startdevtask}+]
474 -|| viewSharedInformation [] [+\label{lst_t4t:itaskTempFull:displaystart}+]
475 (remoteShare latestTemp deviceInfo) [+\label{lst_t4t:itaskTempFull:remoteShare}+]
476 <<@ Title "Latest temperature" [+\label{lst_t4t:itaskTempFull:displayend}+]
477 \end{lstClean}
478
479 \begin{figure}[ht]
480 \centering
481 \begin{subfigure}[t]{.2\textwidth}
482 \centering
483 \fbox{\includegraphics[width=.9\textwidth]{cwts}}
484 \caption{Web page.}
485 \end{subfigure}%
486 \begin{subfigure}[t]{.8\textwidth}
487 \centering
488 \includegraphics[width=\textwidth]{devTaskDiagram2}
489 \caption{Deployment diagram.}
490 \end{subfigure}
491 \caption{Tierless \gls{ITASK} \gls{CRTS} temperature sensing \gls{IOT} system.}%
492 \label{fig_t4t:cwtsweb}
493 \end{figure}
494
495 \subsection{The \texorpdfstring{\gls{MTASK}}{mTask} \texorpdfstring{\gls{EDSL}}{eDSL}}%
496 \label{sec_t4t:mtasks}
497
498 In many \gls{IOT} systems the sensor nodes are resource constrained, e.g.\ inexpensive microcontrollers. These are far cheaper, and consume far less power, than a single-board computer like a Raspberry Pi. Microcontrollers also allow the programmer to easily control peripherals like sensors and actuators via the \gls{IO} pins of the processor.
499
500 Microcontrollers have limited memory capacity, compute power and communication bandwidth, and hence typically no \gls{OS}.
501 These limitations make it impossible to run an \gls{ITASK} server:
502 there is no \gls{OS} to start the remote task, the code of the task is too big to fit in the available memory and the microcontroller processor is too slow to run it.
503 The \gls{MTASK} \gls{EDSL} is designed to bridge this gap: \gls{MTASK} tasks can be communicated from the server to the sensor node, to execute within the limitations of a typical microcontroller, while providing programming abstractions that are consistent with \gls{ITASK}.
504
505 Like \gls{ITASK}, \gls{MTASK} is task oriented, e.g.\ there are primitive tasks that produce intermediate values, a restricted set of task combinators to compose the tasks, and (recursive) functions to construct tasks.
506 \Gls{MTASK} tasks communicate using task values or \glspl{SDS} that may be local or remote, and may be shared by some \gls{ITASK} tasks.
507
508 Apart from the \gls{EDSL}, the \gls{MTASK} system contains a featherlight domain-specific \emph{operating system} running on the microcontroller.
509 This \gls{OS} task scheduler receives the byte code generated from one or more \gls{MTASK} programs and interleaves the execution of those tasks. The \gls{OS} also manages \gls{SDS} updates and the passing of task results.
510 The \gls{MTASK} \gls{OS} is stored in flash memory while the tasks are stored in \gls{RAM} to minimise wear on the flash memory. While sending byte code to a sensor node at runtime greatly increases the amount of communication, this can be mitigated as any tasks known at compile time can be preloaded on the microcontroller.
511 In contrast, compiled programs, like \gls{C}\slash\gls{CPP}, are stored in flash memory and there can only ever be a few thousand programs uploaded during the lifetime of the microcontroller before exhausting the flash memory.
512
513 \subsection{Engineering tierless \texorpdfstring{\gls{IOT}}{IoT} systems with \texorpdfstring{\gls{MTASK}}{mTask}}%
514 \label{sec_t4t:mtaskIOT}
515
516 A tierless \gls{CLEAN} \gls{IOT} system with microcontroller sensor nodes integrates a set of \gls{ITASK} tasks that specify the application and presentation layers with a set of \gls{MTASK}s that specify the perception and network layers.
517 We illustrate with \gls{CWTS}: a simple room temperature sensor with a web display. \gls{CWTS} is equivalent to the \gls{ITASK} \gls{CRTS} (\cref{lst_t4t:itaskTempFull}), except that the sensor node is a Wemos microcontroller.
518
519 \Cref{lst_t4t:mtaskTemp} shows the complete program, and the key function is \cleaninline{devTask} with a top-level \cleaninline{Main} type (\cref{lst_t4t:mtaskTemp:devTask}). In \gls{MTASK} functions, shares, and devices can only be defined at this top level.
520 The program uses the same shares \cleaninline{tempSDS} and~\cleaninline{latestTemp} as \gls{CRTS}, and for completeness we repeat those definitions.
521 The body of \cleaninline{devTask} is the \gls{MTASK} slice of the program (\crefrange{lst_t4t:mtaskTemp:DHT}{lst_t4t:mtaskTemp:setSds}).
522 With \cleaninline{DHT} we again create a temperature sensor object \cleaninline{dht}.
523 The \gls{ITASK} \gls{SDS} \cleaninline{latestTemp} is first transformed to a \gls{SDS} that accepts only temperature values,
524 the \cleaninline{dateTimeStampedShare} adds the data via a lens.
525 The \cleaninline{mapRead} adjusts the read type.
526 This new \gls{SDS} of type \cleaninline{Real} is lifted to the \gls{MTASK} program with \cleaninline{liftsds}.
527 %The \cleaninline{mapRead} ensures that every write to \cleaninline{localSds} is automatically time-stamped when it is written to \cleaninline{latestTemp}.
528
529
530 The \cleaninline{mainTask} is a simple \gls{ITASK} task that starts the \cleaninline{devTask} \gls{MTASK} task on the device identified by \cleaninline{deviceInfo} (\cref{lst_t4t:mtaskTemp:withdevice}). At runtime the \gls{MTASK} slice is compiled to byte code, shipped to the indicated device, and launched. Thereafter, \cleaninline{mainTask} reads temperature values from the \cleaninline{latestTemp} \gls{SDS} that is shared with the \gls{MTASK} device, and displays them on a web page (\cref{fig_t4t:cwtsweb}). The \gls{SDS}---shared with the device using \cleaninline{liftsds}---automatically communicates new temperature values from the microcontroller to the server.
531
532 While this simple application makes limited use of the \gls{MTASK} \gls{EDSL}, it illustrates some powerful \gls{MTASK} program abstractions like basic tasks, task combinators, named recursive and parameterized tasks, and \glspl{SDS}.
533 Function composition (\cref{lst_t4t:mtaskTemp:o}) and currying (\cref{lst_t4t:mtaskTemp:setSds}) are inherited from the \gls{CLEAN} host language.
534 As \gls{MTASK} tasks are dynamically compiled, it is also possible to select and customise tasks as required at runtime.
535 For example, the interval used in the \cleaninline{rpeatevery} task (\cref{lst_t4t:mtaskTemp:rpeatevery}) could be a parameter to the \cleaninline{devTask} function.
536
537 \newcommand{\srcmark}[1]{\marginpar[\small\emph{#1}]{\small\emph{#1}}}
538 \begin{lstClean}[%
539 numbers=left,
540 caption={
541 \Gls{CWTS}: a tierless temperature sensing \gls{IOT} system. Written in \gls{CLEAN}\slash\gls{ITASK}/\gls{MTASK}, it targets a resource-constrained sensor node. Each line is annotated with the functionality as analysed in \cref{sec_t4t:codesize}.},
542 label={lst_t4t:mtaskTemp},
543 ]
544 module cwts
545
546 import mTask.Language, mTask.Interpret, mTask.Interpret.Device.TCP
547 import iTasks, iTasks.Extensions.DateTime
548
549 deviceInfo = {TCPSettings|host="...", port=8123, pingTimeout= ?None} [+\label{lst_t4t:mtaskTemp:co0}\srcmark{CO}+]
550 interval = lit 10[+\label{lst_t4t:mtaskTemp:sn0}\srcmark{SN}+]
551 DHT_pin = DigitalPin D4[+\label{lst_t4t:mtaskTemp:si0}\srcmark{SI}+]
552
553 Start world = doTasks mainTask world[+\label{lst_t4t:mtaskTemp:wi0}\srcmark{WI}+]
554
555 tempSDS :: SimpleSDSLens [(DateTime, Real)]
556 tempSDS = sharedStore "temperatures" [][+\label{lst_t4t:mtaskTemp:di0}\srcmark{DI}+]
557
558 latestTemp :: SDSLens () (? (DateTime, Real)) (DateTime, Real)
559 latestTemp = mapReadWrite (listToMaybe, \x xs-> ?Just [x:xs]) ?None tempSDS[+\label{lst_t4t:mtaskTemp:di1}\srcmark{DI}+]
560
561 devTask :: Main (MTask v Real) | mtask, dht, liftsds v[+\label{lst_t4t:mtaskTemp:devTask}+]
562 devTask =
563 DHT (DHT_DHT DHT_pin DHT11) \dht ->[+\label{lst_t4t:mtaskTemp:DHT}+][+\label{lst_t4t:mtaskTemp:si1}\srcmark{SI}+]
564 liftsds \localSds =[+\label{lst_t4t:mtaskTemp:liftsds}+][+\label{lst_t4t:mtaskTemp:co1}\srcmark{CO}+]
565 mapRead (snd o fromJust) (dateTimeStampedShare latestTemp)[+\label{lst_t4t:mtaskTemp:o}+][+\label{lst_t4t:mtaskTemp:sn1}\srcmark{SN}+]
566 In {main = rpeatEvery (ExactSec interval)[+\label{lst_t4t:mtaskTemp:rpeatevery}+][+\label{lst_t4t:mtaskTemp:sn2}\srcmark{SN}+]
567 (temperature dht >>~.[+\label{lst_t4t:mtaskTemp:temperature}+][+\label{lst_t4t:mtaskTemp:si2}\srcmark{SI}+]
568 setSds localSds)}[+\label{lst_t4t:mtaskTemp:setSds}+][+\label{lst_t4t:mtaskTemp:sn3}\srcmark{SN}+]
569
570 mainTask :: Task Real
571 mainTask
572 = withDevice deviceInfo \dev -> liftmTask} devTask dev[+\label{lst_t4t:mtaskTemp:liftmtask}+][+\label{lst_t4t:mtaskTemp:withdevice}+][+\label{lst_t4t:mtaskTemp:co2}\srcmark{CO}+]
573 -|| viewSharedInformation [] latestTemp[+\label{lst_t4t:mtaskTemp:wi1}\srcmark{WI}+]
574 <<@ Title "Latest temperature"[+\label{lst_t4t:mtaskTemp:wi2}+] // WI
575 \end{lstClean}
576 %
577
578 \begin{figure}[ht]
579 \centering
580 \begin{subfigure}[t]{.2\textwidth}
581 \centering
582 \fbox{\includegraphics[width=.9\textwidth]{cwts}}
583 \caption{Web page.}
584 \end{subfigure}%
585 \begin{subfigure}[t]{.8\textwidth}
586 \centering
587 \includegraphics[width=.95\textwidth]{cwtsDiagram2}
588 \caption{Deployment diagram.}
589 \end{subfigure}
590 \caption{Tierless \gls{ITASK}\slash\gls{MTASK} \gls{CWTS} temperature sensing \gls{IOT} system.}%
591 \label{fig_t4t:cwtsDiagram}
592 \end{figure}
593
594 \section{\texorpdfstring{\gls{UOG}}{UoG} smart campus case study}%
595 \label{sec_t4t:Case}
596 The basis for our comparison between tiered and tierless technologies are four \gls{IOT} systems that all conform to the \gls{UOG} smart campus specifications (\cref{sec_t4t:OperationalComparison}). There is a small (12 room) deployment of the conventional \gls{PYTHON}-based \gls{PRS} stack that uses Raspberry Pi supersensors, and its direct comparator is the tierless \gls{CRS} implementation: also deployed on Raspberry Pis.
597 To represent the more common microcontroller sensor nodes we select ESP8266X powered Wemos D1 Mini microcontrollers. To evaluate tierless technologies on microcontrollers we compare the conventional \gls{PYTHON}\slash\gls{MICROPYTHON} \gls{PWS} stack with the tierless \gls{CWS} implementation.
598
599 %The four systems under comparison are different in architecture ---tiered or tierless--- and type of sensor node hardware ---regular or embedded--- but they share many properties as well.
600
601 %The embedded sensor nodes are all implemented on the ESP8266X powered Wemos D1 Mini microcontroller.
602 A similar range of commodity sensors is connected to both the Raspberry Pi and Wemos sensor nodes using various low-level communication protocols such as \gls{GPIO}, \gls{I2C}, \gls{SPI} and \gls{ONEWIRE}. The sensors are as follows: Temperature \& Humidity: LOLIN SHT30; Light: LOLIN BH1750; Motion: LOLIN \gls{PIR}; Sound: SparkFun SEN-12642; \gls{ECO2}: SparkFun CCS811.
603
604 \Cref{fig_t4t:wemos_prss} shows both a prototype Wemos-based sensor node and sensors and a Raspberry Pi supersensor. Three different development teams developed the four implementations: \gls{CWS} and \gls{CRS} were engineered by a single developer.
605
606 \begin{figure}[ht]
607 \centering
608 \begin{subfigure}[t]{.49\textwidth}
609 \centering
610 \includegraphics[width=.9\textwidth]{wemos}
611 \caption{A Wemos used in \gls{PWS} and \gls{CWS}}.%
612 \end{subfigure}%
613 \begin{subfigure}[t]{.49\textwidth}
614 \centering
615 \includegraphics[width=.9\textwidth]{prss}
616 \caption{A Raspberry Pi used in \gls{PRS} and \gls{CRS}.}%
617 \end{subfigure}
618 \caption{Exposed views of sensor nodes.}%%
619 \label{fig_t4t:wemos_prss}
620 \end{figure}
621
622 \subsection{Tiered implementations}
623 The tiered \gls{PRS} and \gls{PWS} share the same server code executing on a commodity PC (\cref{fig_t4t:iot_arch}). The \gls{PYTHON} server stores incoming sensor data in two database systems, i.e.\ Redis (in-memory data) and MongoDB (persistent data). The real-time sensor data is made available via a streaming websockets server, which connects with Redis.
624 There is also an HTTP REST \gls{API} for polling current and historical sensor data, which hooks into {MongoDB}.
625 Communication between a sensor node and the server is always initiated by the node.
626
627 \Gls{PRS}'s sensor nodes are %powered by the
628 relatively powerful Raspberry Pi 3 Model Bs. There is a simple object-oriented \gls{PYTHON} collector for configuring the sensors and reading their values. The collector daemon service marshals the sensor data and transmits using \gls{MQTT} to the central monitoring server at a preset frequency.
629 The collector caches sensor data locally when the server is unreachable.
630
631 In contrast to \gls{PRS}, \gls{PWS}'s sensor nodes are microcontrollers running \gls{MICROPYTHON}, a dialect of \gls{PYTHON} specifically designed to run on small, low powered embedded devices~\citep{kodali2016low}.
632 To enable a fair comparison between the software stacks we are careful to use the same object-oriented software architecture, e.g.\ using the same classes in \gls{PWS} and \gls{PRS}.
633
634 \Gls{PYTHON} and \gls{MICROPYTHON} are appropriate tiered comparison languages. Tiered \gls{IOT} systems are implemented in a whole range of programming languages, with \gls{PYTHON}, \gls{MICROPYTHON}, \gls{C} and \gls{CPP} being popular for some tiers in many implementations. \gls{C}\slash\gls{CPP} implementations would probably result in more verbose programs and even less type safety.
635 The other reasons for selecting \gls{PYTHON} and \gls{MICROPYTHON} are pragmatic. \gls{PRS} had been constructed in \gls{PYTHON}, deployed, and was being used as an \gls{IOT} experimental platform.
636 Selecting \gls{MICROPYTHON} for the resource-constrained \gls{PWS} sensor nodes facilitates comparison by minimising changes to the resource-rich and resource-constrained codebases.
637 We anticipate that the codebase for a tiered smart campus implementation in another imperative/object-oriented language, like \gls{CPP}, would be broadly similar to the \gls{PRS} and \gls{PWS} codebases.
638
639 \subsection{Tierless implementations}
640
641 The tierless \gls{CRS} and \gls{CWS} servers share the same \gls{ITASK} server code (\cref{fig_t4t:iot_arch}), and can be compiled for many standard platforms.
642 They use
643 SQLite as a database backend.
644 Communication between a sensor node and the server is initiated by the server.
645
646 \Gls{CRS}'s sensor nodes are Raspberry Pi 4s, and execute \gls{CLEAN}\slash\gls{ITASK} programs.
647 Communication from the sensor node to the server is implicit and happens via \glspl{SDS} over \gls{TCP} using platform independent execution graph serialisation~\citep{oortgiese_distributed_2017}.
648
649 \Gls{CWS}'s sensor nodes are Wemos microcontrollers running \gls{MTASK} tasks. Communication and serialisation is, by design, very similar to \gls{ITASK}, i.e.\ via \glspl{SDS} over either a serial port connection, raw \gls{TCP}, or \gls{MQTT} over \gls{TCP}.
650
651 \begin{figure}[ht]
652 \centering
653 \begin{subfigure}[t]{.49\textwidth}
654 \centering
655 \fbox{\includegraphics[width=.75\textwidth]{cwss_web}}
656 \caption{\Gls{CWS} and \gls{CRS}.}
657 \end{subfigure}%
658 \begin{subfigure}[t]{.49\textwidth}
659 \centering
660 \fbox{\includegraphics[width=.75\textwidth, height=.2\textheight, keepaspectratio]{sensordata.png}}
661 \caption{\Gls{PWS} and \gls{PRS}.}
662 \end{subfigure}
663 \caption{Web interfaces for the smart campus application.}%
664 \label{fig_t4t:webinterfaces}
665 \end{figure}
666
667 \subsection{Operational Equivalence}%
668 \label{sec_t4t:OperationalComparison}
669
670
671 To ensure that the comparison reported in the following sections is based on \gls{IOT} stacks with equivalent functionality, we demonstrate that \gls{PWS}, \gls{CWS} and \gls{CRS}, like \gls{PRS}, meet the functional requirements for the \gls{UOG} smart campus sensor system. We also compare the sensor node power consumption and memory footprint.
672
673 \subsubsection{Functional Requirements}%
674 \label{sec_t4t:Validation}
675
676 The main goal of the \gls{UOG} smart campus project is to provide a testbed for sensor nodes and potentially other devices to act as a data collection and computation platform for the \gls{UOG} smart campus. The high-level functional requirements, as specified by the \gls{UOG} smart campus project board, are as follows. The system should:
677 %\mlcomment{can be inline as well}
678 \begin{enumerate}
679
680 \item be able to measure temperature and humidity as well as light intensity,
681
682 \item scale to no more than 10 sensors per sensor node and investigate further sensor options like measuring sound levels,
683
684 \item have access to communication channels like WiFi, Bluetooth and even wired networks.
685
686 \item have a centralised database server,
687
688 \item have a client interface to access information stored in the database,
689
690 \item provide some means of security and authentication,
691 %\item have some means of providing security and authentication.
692
693 \item have some means of managing and monitoring sensor nodes like updating software or detecting new sensor nodes.
694
695 \end{enumerate}
696 All four smart campus implementations meet these high-level requirements.
697
698 \subsubsection{Functional Equivalence}
699
700 Observation of the four implementations shows that they operate as expected, e.g.\ detecting light or motion. To illustrate \cref{fig_t4t:webinterfaces} shows the web interface for the implementations where \gls{CWS} and \gls{CRS} are deployed in a different room from \gls{PWS} and \gls{PRS}.
701
702 All four implementations use an identical set of inexpensive sensors, so we expect the accuracy of the data collected is within tolerance levels. This is validated by comparing \gls{PRS} and \gls{PWS} sensor nodes deployed in the same room for some minutes. The measurements show only small variances, e.g.\ temperatures recorded differ by less than \qty{0.4}{\celcius}, and light by less than \qty{1}{lux}. For this room monitoring application precise timings are not critical, and we don't compare the timing behaviours of the implementations.
703 %\adriancomment{Maybe include a reference for accepted standards of variation between the same type of sensors?}
704 % Phil: lets see what the reviewers say
705
706
707 \subsubsection{Memory and Power Consumption}%
708 %\subsubsection{Memory Consumption}%
709 \label{sec_t4t:MemPower}
710
711 \paragraph{Memory} By design sensor nodes are devices with limited computational capacity, and memory is a key restriction. Even supersensors often have less than a \unit{\gibi\byte} of memory, and microcontrollers often have just tens of \unit{\kibi\byte{}s}.
712 %In a tiered implementation the memory residency of the sensor node code can be minimised by carefully crafting it in a language that minimises memory residency. However, ...
713 As the tierless languages synthesize the code to be executed on the sensor nodes, we need to confirm that the generated code is sufficiently memory efficient.
714
715 \begin{table}
716 \centering
717 \caption{\Gls{UOG} smart campus sensor nodes: maximum memory residency (in bytes).}%
718 \label{tbl_t4t:mem}
719 \begin{tabular}{rrrr}
720 \toprule
721 \multicolumn{1}{c}{\gls{PWS}} & \multicolumn{1}{c}{\gls{PRS}} & \multicolumn{1}{c}{\gls{CWS}} & \multicolumn{1}{c}{\gls{CRS}}\\
722 \midrule
723 \num{20270} & \num{3557806} & \num{880} & \num{2726680}\\
724 \bottomrule
725 \end{tabular}
726 \end{table}
727
728 \Cref{tbl_t4t:mem} shows the maximum memory residency after garbage collection of the sensor node for all four smart campus implementations. The smart campus sensor node programs executing on the Wemos microcontrollers have low maximum residencies: \qty{20270}{\byte} for \gls{PWS} and \qty{880}{\byte} for \gls{CWS}. In \gls{CWS} the \gls{MTASK} system generates very high level \gls{TOP} byte code that is interpreted by the \gls{MTASK} virtual machine and uses a small and predictable amount of heap memory.
729 In \gls{PWS}, the hand-written \gls{MICROPYTHON} is compiled to byte code for execution on the virtual machine. Low residency is achieved with a fixed size heap and efficient memory management. For example both \gls{MICROPYTHON} and \gls{MTASK} use fixed size allocation units and mark\&sweep garbage collection to minimise memory usage at the cost of some execution time~\citep{plamauer2017evaluation}.
730
731 The smart campus sensor node programs executing on the Raspberry Pis have far higher maximum residencies than those executing on the microcontrollers: \qty{3.5}{\mebi\byte} for \gls{PRS} and \qty{2.7}{\mebi\byte} for \gls{CRS}. In \gls{CRS} the sensor node code is a set of \gls{ITASK} executing on a full-fledged \gls{ITASK} server running in distributed child mode and this consumes far more memory.
732 %The memory used is actually very similar to the memory usage of the server with a single client connected.
733 In \gls{PRS} the sensor node program is written in \gls{PYTHON}, a language far less focused on minimising memory usage than \gls{MICROPYTHON}. For example an object like a string is larger in \gls{PYTHON} than in \gls{MICROPYTHON} and consequently does not support all features such as \emph{f-strings}.
734 Furthermore, not all advanced \gls{PYTHON} feature regarding classes are available in \gls{MICROPYTHON}, i.e.\ only a subset of the \gls{PYTHON} specification is supported~\citep{diffmicro}.%\mlcomment{reference \url{https://docs.micropython.org/en/latest/genrst/index.html} ? It contains an overview of supported features}
735
736 In summary the sensor node code generated by both tierless languages, \gls{ITASK} and \gls{MTASK}, is sufficiently memory efficient for the target sensor node hardware. Indeed, the maximum residencies of the \gls{CLEAN} sensor node code is less than the corresponding hand-written (Micro)\gls{PYTHON} code. Of course in a tiered stack the hand-written code can be more easily optimised to minimise residency, and this could even entail using a memory efficienthat thet language like \gls{C}\slash\gls{CPP}. However, such optimisation requires additional developer effort, and a new language would introduce additional semantic friction.
737
738 \paragraph{Power} Sensor nodes and sensors are designed to have low power demands, and this is particularly important if they are operating on batteries. The grey literature consensus is that with all sensors enabled a sensor node should typically have sub-\qty{1}{\watt} peak power draw.
739 %\pwtcomment{Mart can you provide some evidence? A citation?}.
740 %\mlcomment{There only seems to be anecdotal evidence of this. See: \url{https://www.element14.com/community/people/neilk/blog/2019/02/14/investigating-the-power-consumption-of-a-wemos-d1-mini-esp8266}}
741 %\pkcomment{We can state that our own measurements are consistent the experience of others.}
742 The Wemos sensor nodes used in \gls{CWS} and \gls{PWS} have the low power consumption of a typical embedded device: with all sensors enabled, they consume around \qty{0.2}{\watt}.
743 The Raspberry Pi supersensor node used in \gls{CRS} and \gls{PRS} use more power as they have a general purpose ARM processor and run mainstream Linux. With all sensors enabled, they consume \qtyrange{1}{2}{\watt}, depending on ambient load. So a microcontroller sensor node consumes an order of magnitude less power than a supersensor node.
744
745
746 \section{Is Tierless \texorpdfstring{\gls{IOT}}{IoT} Programming Easier than Tiered?}%
747 \label{sec_t4t:ProgrammingComparison}
748
749
750 This section investigates whether tierless languages make \gls{IOT} programming \emph{easier} by comparing the \gls{UOG} smart campus implementations. The \gls{CRS} and \gls{CWS} implementations allow us to evaluate tierless languages for
751 resource-rich and for resource-constrained sensor nodes respectively. The \gls{PRS} and \gls{PWS} allow a like-for-like comparison with tiered \gls{PYTHON} implementations.
752
753
754 %\subsection{Temperature Sensor Illustration}
755
756 \subsection{Comparing Tiered and Tierless Codebases}%
757 \label{sec_t4t:codesize}
758 %A comparison of the Temperature sensor in \gls{PYTHON} Micropyton, Itask \& \gls{MTASK}.
759
760 \paragraph{Code Size} is widely recognised as an approximate measure of the development and maintenance effort required for a software system~\citep{rosenberg1997some}. \gls{SLOC} is a common code size metric, and is especially useful for multi-paradigm systems like \gls{IOT} systems. It is based on the simple principle that the more \gls{SLOC}, the more developer effort and the increased likelihood of bugs~\citep{rosenberg1997some}. It is a simple measure, not dependent on some formula, and can be automatically computed~\citep{sheetz2009understanding}.
761
762 Of course \gls{SLOC} must be used carefully as it is easily influenced by programming style, language paradigm, and counting method~\citep{alpernaswonderful}. Here we are counting code to compare development effort, use the same idiomatic programming style in each component, and only count lines of code, omitting comments and blank lines.
763
764 \Cref{table_t4t:multi} enumerates the \gls{SLOC} required to implement the \gls{UOG} smart campus functionalities in \gls{PWS}, \gls{PRS}, \gls{CWS} and \gls{CRS}. Both \gls{PYTHON} and \gls{CLEAN} implementations use the same server and communication code for Raspberry Pi and for Wemos sensor nodes (rows 5--7 of the table).
765 The Sensor Interface (SI) refers to code facilitating the communication between the peripherals and the sensor node software. % formerly hardware interface
766 Sensor Node (SN) code contains all other code on the sensor node that does not belong to any another category, such as control flow. % formerly device output
767 %Server communication denotes code that provides the high level communication between the sensor node and the server.
768 Manage Nodes (MN) is code that coordinates sensor nodes, e.g.\ to add a new sensor node to the system. % formerly device management
769 Web Interface (WI) code provides the web interface from the server, i.e.\ the presentation layer.
770 Database Interface (DI) code communicates between the server and the database\strut(s).
771 Communication (CO) code provides communication between the server and the sensor nodes, and executes on both sensor node and server, i.e.\ the network layer.
772
773 The most striking information in \cref{table_t4t:multi} is that \emph{the tierless implementations require far less code than the tiered implementations}. For example 166/562 \gls{SLOC} for \gls{CWS}\slash\gls{PWS}, or 70\% fewer \gls{SLOC}. We attribute the code reduction to three factors: reduced interoperation, automatic communication, and high level programming abstractions. We analyse each of these aspects in the following subsections.
774
775 \begin{table}
776 \centering % used for centering table
777 \caption{Comparing tiered and tierless smart campus code sizes: \gls{SLOC} and number of source files. \gls{PWS} and \gls{CWS} execute on resource-constrained sensor nodes, while \gls{PRS} and \gls{CRS} execute on resource-rich sensor nodes.}%
778 \label{table_t4t:multi}
779 \begin{tabular}{l l c c c c } % centered columns (4 columns)
780 \toprule
781 & & \multicolumn{2}{c}{Tiered \gls{PYTHON}} & \multicolumn{2}{c}{Tierless \gls{CLEAN}} \\
782 Code location & Functionality & \gls{PWS} & \gls{PRS} & \gls{CWS} & \gls{CRS} \\
783 \midrule
784 Sensor Node & Sensor Interface & 52 & 57 & 11 & 11\\
785 & Sensor Node & 178 & 183 & 9 & 4\\
786 \midrule
787 Server & Manage Nodes & \multicolumn{2}{c}{76} & 35 & 30\\
788 & Web Interface & \multicolumn{2}{c}{56} & \multicolumn{2}{c}{28}\\
789 & Database Interface & \multicolumn{2}{c}{106} & \multicolumn{2}{c}{78}\\
790 \midrule
791 Communication & Communication & 94 & 98 & 5 & 4\\
792 \midrule
793 Total \gls{SLOC} & & 562 & 576 & 166 & 155 \\
794 \textnumero{} Files & & 35 & 38 & 3 & 3 \\
795 \bottomrule
796 \end{tabular}
797 \end{table}
798
799 \paragraph{Code Proportions.} Comparing the percentages of code required to implement the smart campus functionalities normalises the data and avoids some issues when comparing \gls{SLOC} for different programming languages, and especially for languages with different paradigms like object-oriented \gls{PYTHON} and functional \gls{CLEAN}. \Cref{fig_t4t:multipercentage} shows the percentage of the total \gls{SLOC} required to implement the smart campus functionalities in each of the four implementations, and is computed from the data in \cref{table_t4t:multi}. It shows that there are significant differences between the percentage of code for each functionality between the tiered and tierless implementations. For example 17\% of the tiered implementations specifies communication, whereas this requires only 3\% of the tierless implementations, i.e.\ 6$\times$ less. We explore the reasons for this in \cref{sec_t4t:Communication}. The other major difference is the massive percentage of Database Interface code in the tierless implementations: at least 47\%. The smart campus specification required a standard DBMS, and the \gls{CLEAN}\slash\gls{ITASK} SQL interface occupies some 78 \gls{SLOC}. While this is a little less than the 106 \gls{SLOC} used in \gls{PYTHON} (\cref{table_t4t:multi}), it is a far higher percentage of systems with total codebases of only around 160 \gls{SLOC}. Idiomatic \gls{CLEAN}/\gls{ITASK} would use high level abstractions to store persistent data in an \gls{SDS}, requiring just a few \gls{SLOC}.
800 The total size of \gls{CWS} and \gls{CRS} would be reduced by a factor of two and the percentage of Database Interface code would be even less than in the tiered \gls{PYTHON} implementations.
801
802
803 \begin{figure}
804 \centering
805 \includegraphics[width=.7\linewidth]{bar_chart.pdf}
806 \caption{Comparing the percentage of code required to implement each functionality in tiered/tierless and resource-rich/constrained smart campus implementations.}%
807 \label{fig_t4t:multipercentage}
808 \end{figure}
809
810 \subsection{Comparing Codebases for Resource-Rich/Constrained Sensor Nodes}%
811 \label{sec_t4t:resourcerich}
812
813 Before exploring the reasons for the smaller tierless codebase we compare the implementations for resource-rich and resource-constrained sensor nodes, again using \gls{SLOC} and code proportions. \Cref{table_t4t:multi} shows that the two tiered implementations are very similar in size: with \gls{PWS} for microcontrollers requiring 562 \gls{SLOC} and \gls{PRS} for supersensors requiring 576 \gls{SLOC}.
814 The two tierless implementations are also similar in size: \gls{CWS} requiring 166 and \gls{CRS} 155 \gls{SLOC}.
815
816 There are several main reasons for the similarity. One is that the server-side code, i.e.\ for the presentation and application layers, is identical for both resource rich/constrained implementations. The identical server code accounts for approximately 40\% of the \gls{PWS} and \gls{PRS} codebases, and approximately 85\% of the \gls{CWS} and \gls{CRS} codebases (\cref{fig_t4t:multipercentage}). For the perception and network layers on the sensor nodes, the \gls{PYTHON} and \gls{MICROPYTHON} implementations have the same structure, e.g.\ a class for each type of sensor, and use analogous libraries. Indeed, approaches like CircuitPython~\citep{CircuitPython} allow the same code to execute on both resource-rich and resource-constrained sensor nodes.
817
818
819 Like \gls{PYTHON} and \gls{MICROPYTHON}, \gls{ITASK} and \gls{MTASK} are designed to be similar, as elaborated in \cref{sec_t4t:ComparingTierless}. The similarity is apparent when comparing the \gls{ITASK} \gls{CRTS} and \gls{ITASK}\slash\gls{MTASK} \gls{CWTS} room temperature systems in \cref{lst_t4t:itaskTempFull,lst_t4t:mtaskTemp}. That is, both implementations use similar \glspl{SDS} and lenses; they have similar \cleaninline{devTask}s that execute on the sensor node, and the server-side \cleaninline{mainTask}s are almost identical: they deploy the remote \cleaninline{devTask} before generating the web page to report the readings.
820
821 In both \gls{PYTHON} and \gls{CLEAN} the resource-constrained implementations are less than 7\% larger than the resource-rich implementations. This suggests that \emph{the development and maintenance effort of simple \gls{IOT} systems for resource-constrained and for resource-rich sensor nodes is similar in tierless technologies,} just as it is in tiered technologies.
822 A caveat is that the smart campus system is relatively simple, and developing more complex perception and network code on bare metal may prove more challenging. That is, the lack of \gls{OS} support, and the restricted languages and libraries, may have greater impact. We return to this issue in \cref{sec_t4t:ComparingTierless}.
823
824
825 \subsection{Reduced Interoperation}%
826 \label{sec_t4t:interoperation}
827 \begin{table}
828 \centering
829 \small
830 \caption{Smart campus implementation languages comparison.}%
831 \label{table_t4t:languages}
832 \begin{tabular}{lllllll}
833 \toprule
834 & & \multicolumn{4}{c}{Languages}\\
835 \midrule
836 Code Location & Functionality & \gls{PWS} & \gls{PRS} & \gls{CWS} & \gls{CRS}\\
837 \midrule
838 Sensor Node & Sensor Int. & \gls{MICROPYTHON} & \gls{PYTHON} & \gls{MTASK} & \gls{ITASK}\\
839 & Sensor Node & \gls{MICROPYTHON} & \gls{PYTHON} & \gls{MTASK} & \gls{ITASK}\\
840 \midrule
841 Server & Manage Nodes & \multicolumn{2}{c}{\gls{PYTHON}, \gls{JSON}} & \multicolumn{2}{c}{\gls{ITASK}}\\
842 & Web Int. & \multicolumn{2}{c}{HTML, PHP} & \multicolumn{2}{c}{\gls{ITASK}}\\
843 & Database Int. & \multicolumn{2}{c}{\gls{PYTHON},\gls{JSON},Redis} & \multicolumn{2}{c}{\gls{ITASK}}\\
844 \midrule
845 Communication & Communication & \gls{MICROPYTHON} & \gls{PYTHON} & \gls{ITASK},\gls{MTASK} & \gls{ITASK}\\
846 \midrule
847 & Total & 7 & 6 & 2 & 1\\
848 \bottomrule
849 \end{tabular}
850 \end{table}
851
852 \begin{table}
853 \centering
854 \small
855 \caption{Smart campus paradigm comparison.}%
856 \label{table_t4t:paradigms}
857 \begin{tabular}{llll}
858 \toprule
859 & & \multicolumn{2}{c}{Paradigms}\\
860 \midrule
861 Code Location & Functionality & \gls{PYTHON} & \gls{CLEAN}\\
862 \midrule
863 Sensor Node & Sensor Int. & imperative & declarative\\
864 & Sensor Node & imperative & declarative\\
865 \midrule
866 Server & Manage Nodes & imperative & declarative\\
867 & Web Int. & both & declarative\\
868 & Database Int. & both & declarative\\
869 \midrule
870 Communication & Communication & imperative & declarative\\
871 \midrule
872 & Total & 2 & 1 \\
873 \bottomrule
874 \end{tabular}
875 \end{table}
876
877 The vast majority of \gls{IOT} systems are implemented using a number of different programming languages and paradigms, and these must be effectively used and interoperated. A major reason that the tierless \gls{IOT} implementations are simpler and shorter than the tiered implementations is that they use far fewer programming languages and paradigms. Here we use language to distinguish \glspl{EDSL} from their host language: so \gls{ITASK} and \gls{MTASK} are considered distinct from \gls{CLEAN}; and to distinguish dialects: so \gls{MICROPYTHON} is considered distinct from \gls{PYTHON}.
878
879 The tierless implementations use just two conceptually-similar \glspl{DSL} embedded in the same host language, and a single paradigm (\cref{table_t4t:languages,table_t4t:paradigms}). In contrast, the tiers in \gls{PRS} and \gls{PWS} use six or more very different languages, and both imperative and declarative paradigms. Multiple languages are commonly used in other typical software systems like web stacks, e.g.\ a recent survey of open source projects reveals that on average at least five different languages are used~\citep{mayer2015empirical}. Interoperating components in multiple languages and paradigms raises a plethora of issues.
880
881 Interoperation \emph{increases the cognitive load on the developer} who must simultaneously think in multiple languages and paradigms. This is commonly known as semantic friction or impedance mismatch~\citep{ireland2009classification}. A simple illustration of this is that the tiered \gls{PRS} source code comprises some 38 source and configuration files, whereas the tierless \gls{CRS} requires just 3 files (\cref{table_t4t:multi}). The source could be structured as a single file, but to separate concerns is structured into three modules, one each for \glspl{SDS}, types, and control logic~\citep{wang_maintaining_2018}.
882
883 The developer must \emph{correctly interoperate the components}, e.g.\ adhere to the \gls{API} or communication protocols between components. The interoperation often entails additional programming tasks like marshalling or demarshalling data between components. For example, in the tiered \gls{PRS} and \gls{PWS} architectures, \gls{JSON} is used to serialise and deserialise data strings from the \gls{PYTHON} collector component before storing the data in the Redis database (\cref{lst_t4t:json}).
884 %e.g.\ to marshall and demarshall data between components.
885
886 %\mlcomment{A listing must have a caption for it to be labeled and referenced}
887 \begin{lstPython}[caption={\Gls{JSON} Data marshalling in \gls{PRS} and \gls{PWS}: sensor node above, server below.},label={lst_t4t:json}]
888
889 channel = 'sensor_status.%s.%s' % (hostname,
890 sensor_types.sensor_type_name(s.sensor_type))
891 self.r.publish(channel, s.SerializeToString())
892
893 [+\dotfill+]
894
895 for message in p.listen():
896 if message['type'] not in ['message', 'pmessage']:
897 continue
898
899 try:
900 status = collector_pb2.SensorStatus.FromString(message['data'])
901 \end{lstPython}
902
903 To ensure correctness the developer \emph{must maintain type safety} across a range of very different languages and diverse type systems, and we explore this further in \cref{sec_t4t:typesafety}. The developer must also deal with the \emph{potentially diverse failure modes}, not only of each component, but also of their interoperation, e.g.\ if a value of an unexpected type is passed through an \gls{API}. We explore this further in \cref{sec_t4t:NetworkManagement}.
904
905 \subsection{Automatic Communication}%
906 \label{sec_t4t:Communication}
907
908 In conventional tiered \gls{IOT} implementations the developer must write and maintain code to communicate between tiers. For example \gls{PRS} and \gls{PWS} create, send and read \gls{MQTT}~\citep{light2017mosquitto} messages
909 between the perception and application layers. \Cref{table_t4t:multi} shows that communication between these layers require some 94 \gls{SLOC} in \gls{PWS} and 98 in \gls{PRS}, accounting for 17\% of the codebase (bottom bars in \cref{fig_t4t:multipercentage}). To illustrate, \cref{lst_t4t:mwssmqtt} shows part of the code to communicate sensor readings from the \gls{PWS} sensor node to the Redis store on the server.
910
911 Not only must the tiered developer write additional code, but \gls{IOT} communication code is often intricate. In such a distributed system the sender and receiver must be correctly configured, correctly follow the communication protocol through all execution states, and deal with potential failures. For example line 3 of \cref{lst_t4t:mwssmqtt}: \pythoninline{redis host = config.get('Redis', 'Host')} will fail if either the host or IP are incorrect.
912
913 \begin{lstPython}[caption={Tiered communication example: \gls{MQTT} transmission of sensor values in \gls{PWS}.},label={lst_t4t:mwssmqtt}]
914 def main():
915 config.init('mqtt')
916 redis_host = config.get('Redis', 'Host')
917 redis_port = config.getint('Redis', 'Port')
918 r = redis.StrictRedis(host=redis_host, port=redis_port)
919 p = r.pubsub()
920 p.psubscribe("sensor_status.*")
921 for message in p.listen():
922 if message['type'] not in ['message', 'pmessage']:
923 print "Ignoring message %s" % message
924 [+\ldots+]
925 \end{lstPython}
926
927 In contrast, the tierless \gls{CWS} and \gls{CRS} communication is not only highly automated, but also automatically correct because matching sender and receiver code is generated by the compiler. \Cref{table_t4t:multi} shows that communication is specified in just 5 \gls{SLOC} in \gls{CWS} and 4 in \gls{CRS}, or just 3\% of the codebase (bottom bars in \cref{fig_t4t:multipercentage}).
928
929
930 \Cref{lst_t4t:mtaskTemp} illustrates communication in a tierless \gls{IOT} language. That is, the \gls{CWTS} temperature sensor requires just three lines of communication code, and uses just three communication functions. The
931 \cleaninline{withDevice} function on \cref{lst_t4t:mtaskTemp:withdevice} integrates a sensor node with the server, allowing tasks to be sent to it. The
932 \cleaninline{liftmTask} on \cref{lst_t4t:mtaskTemp:liftmtask} integrates an \gls{MTASK} in the \gls{ITASK} runtime by compiling it and sending it for interpretation to the sensor node.
933 The \cleaninline{liftsds} on \cref{lst_t4t:mtaskTemp:liftsds} integrates \glspl{SDS} from \gls{ITASK} into \gls{MTASK}, allowing \gls{MTASK} tasks to interact with data from the \gls{ITASK} server.
934 The exchange of data, user interface, and communication are all automatically generated.
935
936 \subsection{High Level Abstractions}%
937 \label{sec_t4t:abstractions}
938
939 Another reason that the tierless \gls{CLEAN} implementations are concise is because they use powerful higher order \gls{IOT} programming abstractions.
940 For comprehensibility the simple temperature sensor from \cref{sec_t4t:mtasks} (\cref{lst_t4t:mtaskTemp}) is used to compare the expressive power of \gls{CLEAN} and \gls{PYTHON}-based \gls{IOT} programming abstractions.
941 There are implementations for all four configurations: \gls{PRTS} (\gls{PYTHON} Raspberry Pi Temperature Sensor)\footnotemark, \gls{PWTS}\footnotemark[\value{footnote}]\todo{the dataset will be uploaded, the DOI is reserved.}
942 \footnotetext{Lubbers, M.; Koopman, P.; Ramsingh, A.; Singer, J.; Trinder, P. (2021): Source code, line counts and memory stats for PRS, PWS, PRT and PWT.\ Zenodo.\ \href{https://doi.org/10.5281/zenodo.5081386}{10.5281/zenodo.5081386}.}, \gls{CRTS}\footnotemark{} and \gls{CWTS}\footnotemark[\value{footnote}] \todo{the dataset will be uploaded, the DOI is reserved.}
943 \footnotetext{Lubbers, M.; Koopman, P.; Ramsingh, A.; Singer, J.; Trinder, P. (2021): Source code, line counts and memory stats for CRS, CWS, CRTS and CWTS.\ Zenodo.\ \href{https://doi.org/10.5281/zenodo.5040754}{10.5281/zenodo.5040754}.}
944 but as the programming abstractions are broadly similar, we compare only the \gls{PWTS} and \gls{CWTS} implementations.
945
946 Although the temperature sensor applications are small compared to the smart campus application, they share some typical \gls{IOT} stack traits.
947 The architecture consists of a server and a single sensor node (\cref{fig_t4t:cwtsDiagram}).
948 The sensor node measures and reports the temperature every ten seconds to the server while the server displays the latest temperature via a web interface to the user.
949
950 \Cref{table_t4t:temp} compares the \gls{SLOC} required for the \gls{MICROPYTHON} and \gls{CLEAN}\slash\gls{ITASK}/\gls{MTASK} Wemos temperature sensors: \gls{PWTS} and \gls{CWTS} respectively. The code sizes here should not be used to compare the programming models as implementing such a small application as a conventional \gls{IOT} stack requires a significant amount of configuration and other machinery that would be reused in a larger application. Hence, the ratio between total \gls{PWTS} and \gls{CWTS} code sizes (298:15) is far greater than for realistic applications like \gls{PWS} and \gls{CWS} (471:166).
951
952 \begin{table}
953 \centering
954 \caption{Comparing \gls{CLEAN} and \gls{PYTHON} programming abstractions using the \gls{PWTS} and \gls{CWTS} temperature sensors (\gls{SLOC} and total number of files.)}%
955 \label{table_t4t:temp}
956 \begin{tabular}{llccl}
957 \toprule
958 Location & Functionality & \gls{PWTS} & \gls{CWTS} & Lines (\cref{lst_t4t:mtaskTemp})\\
959 \midrule
960 Sensor Node & Sensor Interface & 14 & 3 &~\ref{lst_t4t:mtaskTemp:si0},~\ref{lst_t4t:mtaskTemp:si1},~\ref{lst_t4t:mtaskTemp:si2}\\
961 & Sensor Node & 67 & 4 &~\ref{lst_t4t:mtaskTemp:sn0},~\ref{lst_t4t:mtaskTemp:sn1},~\ref{lst_t4t:mtaskTemp:sn2},~\ref{lst_t4t:mtaskTemp:sn3}\\
962 Server & Web Interface & 17 & 3 &~\ref{lst_t4t:mtaskTemp:wi0},~\ref{lst_t4t:mtaskTemp:wi1},~\ref{lst_t4t:mtaskTemp:wi2}\\
963 & Database Interface & 106 & 2 &~\ref{lst_t4t:mtaskTemp:di0},~\ref{lst_t4t:mtaskTemp:di1}\\
964 Communication & Communication & 94 & 3 &~\ref{lst_t4t:mtaskTemp:co0},~\ref{lst_t4t:mtaskTemp:co1},~\ref{lst_t4t:mtaskTemp:co2}\\
965 \midrule
966 % \multicolumn{2}{c}{Total (\textnumero{} Files)} & 298 (27) & 15 (1) \\
967 Total \gls{SLOC} & & 298 & 15 \\
968 \textnumero{} Files & & 27 & 1 \\
969 \bottomrule
970 \end{tabular}
971 \end{table}
972
973 The multiple tiers in \gls{PRS} and \gls{PWS} provide different levels of abstraction and separation of concerns.
974 %in order to facilitate interoperation of the components.
975 However, there are various ways that high-level abstractions make the \gls{CWS} much shorter than \gls{PRS} and \gls{PWS} implementations.
976
977 Firstly, functional programming languages are generally more concise than most other programming languages because their powerful abstractions like higher-order and/or polymorphic functions require less code to describe a computation.
978 Secondly, the \gls{TOP} paradigm used in \gls{ITASK} and \gls{MTASK} reduces the code size further by making it easy to specify \gls{IOT} functionality concisely.
979 As examples, the step combinator \cleaninline{>>*.} allows the task value on the left-hand side to be observed until one of the steps is enabled;
980 and the \cleaninline{viewSharedInformation} (line 31 of \cref{lst_t4t:mtaskTemp}) part of the UI will be automatically updated when the value of the \gls{SDS} changes. Moreover, each \gls{SDS} provides automatic updates to all coupled \glspl{SDS} and associated tasks. Thirdly, the amount of explicit type information is minimised in comparison to other languages, as much is automatically inferred~\citep{hughes1989functional}.
981
982 \section{Could Tierless \texorpdfstring{\gls{IOT}}{IoT} Programming Be More Reliable than Tiered?}%
983 \label{sec_t4t:Discussion}
984
985
986 This section investigates whether tierless languages make \gls{IOT} programming more reliable. Arguably the much smaller and simpler code base is inherently more understandable, and more likely to be correct. Here we explore specific language issues, namely those of preserving type safety, maintainability, failure management, and community support.
987
988 \subsection{Type Safety}%
989 \label{sec_t4t:typesafety}
990 Strong typing identifies errors early in the development cycle, and hence plays a crucial role in improving software quality. In consequence almost all modern languages provide strong typing, and encourage static typing to minimise runtime errors.
991 % Phil: so widely known that a citation is unnecessary~\citep{madsen1990strong}.
992 That said, many distributed system components written in languages that primarily use static typing, like \gls{HASKELL} and Scala, use some dynamic typing, e.g.\ to ensure that the data arriving in a message has the anticipated type~\citep{epstein2011towards,gupta2012akka}.
993
994 In a typical tiered multi-language \gls{IOT} system the developer must integrate software in different languages with very different type systems, and potentially executing on different hardware. The challenges of maintaining type safety have long been recognised as a major component of the semantic friction in multi-language systems, e.g.\ \citep{ireland2009classification}.
995
996 Even if the different languages used in two components are both strongly typed, they may attribute, often quite subtly, different types to a value. Such type errors can lead to runtime errors, or the application silently reporting erroneous data. Such errors can be hard to find. Automatic detection of such errors is sometimes possible, but requires an addition tool like Jinn~\citep{Jinn,Furr2005}.
997 %Such errors can be hard to debug, partly because there is very limited tool support for detecting them
998 %Phil: another possible source to discuss ~\citep{egyed1999automatically}
999
1000 \begin{lstPython}[caption={\Gls{PRS} loses type safety as a sensor node sends a {\tt\footnotesize double}, and the server stores a {\tt\footnotesize string}.},label={lst_t4t:float},morekeywords={message,enum,uint64,double}]
1001 message SensorData {
1002 enum SensorType { TEMPERATURE = 1; [+\ldots+] }
1003 SensorType sensor_type = 1;
1004 uint64 timestamp = 2;
1005 double float_value = 3;
1006 }
1007 [+\dotfill+]
1008 channel = 'sensor_status.%s.%s' % (hostname,
1009 sensor_types.sensor_type_name(s.sensor_type))
1010 self.r.publish(channel, s.SerializeToString())
1011 \end{lstPython}
1012
1013 Analysis of the \gls{PRS} codebase reveals an instance where it, fairly innocuously, loses type safety. The fragment in \cref{lst_t4t:float} first shows a \pythoninline{double} sensor value being sent from the sensor node, and then shows the value being stored in Redis as a \pythoninline{string} on the server. As \gls{PWS} preserves the same server components it also suffers from the same loss of type safety.
1014
1015 \emph{A tierless language makes it possible to guarantee type safety across an entire \gls{IOT} stack}. For example the \gls{CLEAN} compiler guarantees static type safety as the entire \gls{CWS} software stack is type checked, and generated, from a single source. Tierless web stack languages like Links~\citep{cooper2006links} and Hop~\citep{serrano2006hop} provide the same guarantee for web stacks.
1016
1017
1018 \subsection{Failure Management}%
1019 \label{sec_t4t:NetworkManagement}
1020
1021 Some \gls{IOT} applications, including smart campus and other building monitoring applications, require high sensor uptimes. Hence, if a sensor or sensor node fails the application layer must be notified, so that it can report the failure. In the \gls{UOG} smart campus system a building manager is alerted to replace the failed device.
1022
1023 In many \gls{IOT} architectures, including \gls{PRS} and \gls{PWS}, detecting failure is challenging because the application layer listens to the devices. When a device comes online, it registered with the application and starts sending data.
1024 When a device goes offline again, it could be because the power was out, the device was broken or the device just paused the connection.
1025
1026 If a sensor node fails in \gls{CWS}, the \gls{ITASK}\slash\gls{MTASK} combinator interacting with a sensor node will throw an \gls{ITASK} exception.
1027 The exception is propagated and a handler can respond, e.g.\ rescheduling the task on a different device in the room, or requesting that a manager replaces the device. That is, \gls{ITASK}, uses standard succinct declarative exception handling.
1028
1029 \begin{lstClean}[caption={An \gls{MTASK} failover combinator.},label={lst_t4t:failover}]
1030 failover :: [TCPSettings] (Main (MTask BCInterpret a)) -> Task a
1031 failover [] _ = throw "Exhausted device pool"
1032 failover [d:ds] mtask = try ( withDevice d (liftmTask mtask) ) except
1033 where except MTEUnexpectedDisconnect = failover ds mtask
1034 except _ = throw e
1035 \end{lstClean}
1036
1037 In the \gls{UOG} smart campus application, this can be done by creating a pool of sensor nodes for each room and when a sensor node fails, assign another one to the task.
1038 %If the pool of sensor nodes for a room is exhausted, contact a manager.
1039 \Cref{lst_t4t:failover} shows a failover combinator that executes an \gls{MTASK} on one of a pool of sensor nodes.
1040 If a sensor node unexpectedly disconnects, the next sensor node is tried until there are no sensor nodes left.
1041 If other errors occur they are propagated as usual.
1042
1043
1044 Currently, \gls{PRS} and \gls{PWS} both use heartbeats to confirm that the sensor nodes are operational, and will report failures. At the cost of extending the codebase, failover to an alternate sensor node could be provided.
1045
1046 \subsection{Maintainability}
1047
1048 Far more engineering effort is expended on maintaining a system, than on the initial development. Tiered and tierless \gls{IOT} systems have very different maintainability properties.
1049
1050 The modularity of the tiered stack makes replacing tiers/components easy. For example in \gls{PWS} or \gls{PRS} the MongoDB NoSQL DBMS could be readily be replaced by an alternative like {CouchDB}. Because a tierless compiler must generate code for components, replacing them may not be so easy. If there are \gls{ITASK} abstractions for the component then replacement is straightforward. For example replacing SQLite with some other SQL DBMS simply entails recompilation of the application.
1051 However incorporating a component that does not yet have a task abstraction, like a NoSQL DBMS, is more involved. That is, a foreign function interface to the new component must be implemented, along with a suitable \gls{ITASK} abstraction for operations on the component.
1052
1053 Many maintenance tasks are smaller in scale and occur within the components or tiers. Consider a simple change, for example if the temperature value recorded by a sensor changes from integer to real.
1054
1055 All tiers of a tiered stack must be correctly and consistently refactored to reflect the change of temperature data type: so changes at the perception, network, application and presentation layers. A \gls{PWS} developer works in seven languages and two paradigms to effect the change (\cref{table_t4t:multi}), and must edit many source files. Many programming errors are either detected at runtime when testing the stack, or worse not automatically detected and produce erroneous results.
1056
1057 In a tierless language the source code is much smaller and so it is easier to comprehend, i.e.\ to understand what refactoring is required. A \gls{CWS} developer works in only two languages and a single paradigm to effect the change, and will edit no more than three source files (\cref{table_t4t:multi}). Moreover, the compiler will statically detect many programming errors.
1058
1059 More substantial in-component maintenance raises similar issues as for tiered implementations. If the maintenance activity requires a new task combinator, this is readily constructed in \gls{ITASK}, but may require changing the \gls{DSL} implementation in \gls{MTASK}, i.e.\ to change the compiler and the byte code interpreter. That is, \gls{MTASK} is more \emph{brittle} than \gls{ITASK}.
1060
1061 In summary, while a tiered approach makes replacing components easy, refactoring within the components is far harder in a multi-tier multi-language \gls{IOT} implementation than in a tierless \gls{IOT} implementation.
1062
1063 \subsection{Support}%
1064 \label{sec_t4t:support}
1065 %\mlcomment{I've shortened this quite a bit}
1066 Community and tool support are essential for engineering reliable production software. \gls{PRS} and \gls{PWS} are both \gls{PYTHON} based, and \gls{PYTHON}\slash\gls{MICROPYTHON} are among the most popular programming languages~\citep{cass2020top}. \gls{PYTHON} is also a common choice for some tiers of \gls{IOT} applications~\citep{tanganelli2015coapthon}.
1067 Hence, there are a wide range of development tools like \glspl{IDE} and debuggers, a thriving community and a wealth of training material. There are even specialised \gls{IOT} Boards like PyBoard \& WiPy that are specifically programmed using \gls{PYTHON} variations like \gls{MICROPYTHON}.
1068
1069 In contrast, tierless languages are far less mature than the languages used in tiered stacks, and far less widely adopted.
1070 This means that for \gls{CWS} and \gls{CRS} there are fewer tools, a far smaller developer community, and less training material available.
1071
1072 \Gls{CWS} and \gls{CRS} are both written in \glspl{DSL} embedded in \gls{CLEAN}, a fairly stable industrial-grade but niche functional programming language.
1073 The \glspl{DSL} are implemented in \gls{CLEAN} but require experimental compiler extensions that are often undocumented.
1074 There are few maintainers of the \glspl{DSL} and documentation is often sparse.
1075 Acquiring information about the systems requires distilling academic papers and referring to the source code.
1076 There is a \gls{CLEAN} \gls{IDE}, but it does not contain support for the \gls{ITASK} or \gls{MTASK} \glspl{DSL}.
1077
1078 \section{Comparing Tierless Languages for Resource-rich/constrained Sensor Nodes}%
1079 \label{sec_t4t:ComparingTierless}
1080
1081 This section compares two tierless \gls{IOT} languages: one for resource-rich, and the other for resource-constrained, sensor nodes. Key issues are the extent to which the very significant resource constraints of a microcontroller limit the language, and the benefits of executing on bare metal, i.e.\ without an \gls{OS}.
1082
1083 With the tierless \gls{CLEAN} technologies described here, \gls{ITASK} are always used to program the application and presentation layers of the \gls{IOT} stack. So any differences occur in the perception and network layer programming.
1084 If sensor nodes have the capacity to support \gls{ITASK}, a tierless \gls{IOT} system can be constructed in \gls{CLEAN} using only \gls{ITASK}, as in \gls{CRS}. Alternatively for sensor nodes with low computational power, like typical microcontrollers, \gls{MTASK} is used for the perception and network layers, as in \gls{CWS}.
1085 This section compares the \gls{ITASK} and \gls{MTASK} \glspl{EDSL}, with reference to \gls{CRS} and \gls{CWS} as exemplars. \Cref{table_t4t:languagecomparison} summarises the differences between the \gls{CLEAN} embedded \gls{IOT} \glspl{EDSL} and their host language.
1086
1087 \begin{table}
1088 \small
1089 \caption{Comparing tierless \gls{IOT} languages for resource-rich sensor nodes (\gls{ITASK} \gls{EDSL}), for resource-constrained sensor nodes (\gls{MTASK} \gls{EDSL}), and their \gls{CLEAN} host language.}%
1090 \label{table_t4t:languagecomparison}
1091 \begin{tabularx}{\textwidth}{lXXX}
1092 \toprule
1093 Property & \gls{CLEAN} & \gls{ITASK} & \gls{MTASK}\\
1094 \midrule
1095 Function for an \gls{IOT} System & Host Language & Specify distributed workflows & Specify sensor node workflow \\
1096 \midrule
1097 Referentially transparent & Yes & Yes & Yes \\
1098 Evaluation strategy & Lazy & Lazy & Strict\\
1099 Higher-order functions & Yes & Yes & No \\
1100 User-defined datatypes & Yes & Yes & No \\
1101 Task oriented & No & Yes & Yes \\
1102 Higher-order tasks & {--} & Yes & No \\
1103 Execution Target & Commodity PC & Commodity PC and Browser & Microcontroller\\
1104 Language Implementation & Compiled or interpreted & Compiled and interpreted & Interpreted\\
1105 \bottomrule
1106 \end{tabularx}
1107 \end{table}
1108
1109 \subsection{Language Restrictions for Resource-Constrained Execution}
1110
1111 Executing components on a resource-constrained sensor node imposes restrictions on programming abstractions available in a tierless \gls{IOT} language or \gls{DSL}. The small and fixed-size memory are key limitations. The limitations are shared by any high-level language that targets microcontrollers such as BIT, PICBIT, PICOBIT, Microscheme and uLisp~\citep{dube_bit:_2000,feeley_picbit:_2003,st-amour_picobit:_2009,suchocki_microscheme:_2015, johnson-davies_lisp_2020}.
1112 Even in low level languages some language features are disabled by default when targeting microcontrollers, such as runtime type information (RTTI) in \gls{CPP}.
1113
1114 Here we investigate the restrictions imposed by resource-constrained sensor nodes on \gls{MTASK}, in comparison with \gls{ITASK}. While \gls{ITASK} and \gls{MTASK} are by design superficially similar languages, to execute on resource-constrained sensor nodes \gls{MTASK} tasks are more restricted, and have a different semantics.
1115
1116 \Gls{MTASK} programs do not support user defined higher order functions, the only higher order functions available are the predefined \gls{MTASK} combinators.
1117 Programmers can, however, use any construct of the \gls{CLEAN} host language to construct an \gls{MTASK} program, including higher order functions and arbitrary data types. For example folding an \gls{MTASK} combinator over a list of tasks.
1118 The only restriction is that any higher order function must be macro expanded to a first order \gls{MTASK} program before being compiled to byte code.
1119 %\mlcomment{Pieter: Refine paragraph about macro expansion and currying/HOF}
1120 As an example in \cref{lst_t4t:mtaskTemp} we use \cleaninline{temperature dht >>~.} \cleaninline{setSds localSds} instead of \cleaninline{temperature dht >>~.} \cleaninline{\\temp -> setSds localSds temp}.
1121 %However, this is limited to situations where the expressions are expanded to the required \gls{MTASK} types, i.e.\ the host language acts as a macro language for \gls{MTASK}.
1122 %\mlcomment{I've refined this. The host language does not offer limited use of HOF and currying. It only appears to offer, just macro expansion}.
1123 %\pwtcomment{I've rewritten: please check.}
1124
1125 In contrast to \gls{ITASK}, \gls{MTASK} programs have no user defined or recursive data types. It is possible to add user defined types---as long as they are not sum types---to \gls{MTASK}, but this requires significant programming effort.
1126 Due to the language being shallowly embedded, pattern matching and field selection on user defined types is not readily available and thus needs to be built into the language by hand.
1127 Alleviating this limitation remains future work.
1128
1129 \Gls{MTASK} programs mainly use strict rather than lazy evaluation to minimise the requirement for a variable size heap. This has no significant impact for the \gls{MTASK} programs we have developed here, nor in other \gls{IOT} applications we have engineered.
1130
1131 \Gls{MTASK} abstractions are less easily extended than \gls{ITASK}. For example \gls{ITASK} can be extended with a new combinator that composes a specific set of tasks for some application.
1132 Without higher order functions the equivalent combinator can often not be expressed in \gls{MTASK}, and adding it to \gls{MTASK} requires extending the \gls{DSL} rather than writing a new definition in it.
1133 On the other hand, it is possible to outsource this logic to the \gls{ITASK} program as \gls{MTASK} and \gls{ITASK} tasks are so tightly integrated.
1134
1135 \subsection{The Benefits of a Bare Metal Execution Environment}
1136
1137 Despite the language restrictions, components of a tierless language executing on a microcontroller can exploit the bare metal environment. Many of these benefits are shared by other bare metal languages like \gls{MICROPYTHON} or \gls{C}\slash\gls{CPP}. So as \gls{MTASK} executes on bare metal it has some advantages over \gls{ITASK}. Most notably \gls{MTASK} has better control of timing as on bare metal there are no other processes or threads that compete for CPU cycles.
1138 This makes the \gls{MTASK} \cleaninline{repeatEvery} (\cref{lst_t4t:mtaskTemp}, \cref{lst_t4t:mtaskTemp:sn2}) much more accurate than the \gls{ITASK} \cleaninline{waitForTimer} (\cref{lst_t4t:itaskTempFull}, \cref{lst_t4t:itaskTempFull:waitForTimer}).
1139 While exact timing is not important in this example, it is significant for many other \gls{IOT} applications.
1140 In contrast \gls{ITASK} cannot give real time guarantees. One reason is that an \gls{ITASK} server can ship an arbitrary number of \gls{ITASK} or \gls{MTASK} tasks to a device.
1141 Such competing tasks, or indeed other \gls{OS} threads and processes, consume processor time and reduce the accuracy of timings.
1142 However, even when using multiple \gls{MTASK} tasks, it is easier to control the number of tasks on a device than controlling the number of processes and threads executing under an \gls{OS}.
1143
1144 An \gls{MTASK} program has more control over energy consumption.
1145 The \gls{MTASK} \gls{EDSL} and the \gls{MTASK} \gls{RTS} are designed to minimise energy usage~\citep{crooijmans_reducing_2021}.
1146 Intensional analysis of the declarative task description and current progress at run time allow the \gls{RTS} to schedule tasks and maximise idle time.
1147 As the \gls{RTS} is the only program running on the device, it can enforce deep sleep and wake up without having to worry about influencing other processes.
1148
1149 The \gls{MTASK} \gls{RTS} has direct control of the peripherals attached to the microcontroller, e.g.\ over \gls{GPIO} pins. There is no interaction with, or permission required from, the \gls{OS}.
1150 Moreover, microcontrollers typically have better support for hardware interrupts, reducing the need to poll peripherals.
1151 The downside of this direct control is that \gls{CWS} has to handle some exceptions that would otherwise be handled by the \gls{OS} in \gls{CRS} and hence the device management code is longer: 28 versus 20 \gls{SLOC} in \cref{table_t4t:multi}.
1152
1153 \subsection{Summary}
1154
1155 \Cref{table_t4t:languagecomparison} summarises the differences between the \gls{CLEAN} \gls{IOT} \gls{EDSL} and their host language.
1156 The restrictions imposed by a resource-constrained execution environment on the tierless \gls{IOT} language are relatively minor. Moreover the \gls{MTASK} programming abstraction is broadly compatible with \gls{ITASK}. As a simple example compare the \gls{ITASK} and \gls{MTASK} temperature sensors in \cref{lst_t4t:itaskTempFull,lst_t4t:mtaskTemp}. As a more realistic example, the \gls{MTASK} based \gls{CWS} smart campus implementation is similar to the \gls{ITASK} based \gls{CRS}, and requires less than 10\% additional code: 166 \gls{SLOC} compared with 155 \gls{SLOC} (\cref{table_t4t:multi}).
1157
1158 Even with these restrictions, \gls{MTASK} programming is at a far higher level of abstraction than almost all bare metal languages, e.g.\ BIT, PICBIT, PICOBIT and Microscheme. That is \gls{MTASK} provides a set of higher order task combinators, shared distributed data stores, etc. (\cref{sec_t4t:mtasks}). Moreover, it seems that common sensor node programs are readily expressed using \gls{MTASK}. In addition to the \gls{CWTS} and \gls{CWS} systems outlined here, other case studies include Arduino examples as well as some bigger tasks~\citep{koopman_task-based_2018,lubbers_writing_2019,LubbersMIPRO}. We conclude that the programming of sensor tasks is well-supported by both \glspl{DSL}.
1159
1160 \section{Conclusion}%
1161 \label{sec_t4t:Conclusion}
1162
1163 \subsection{Summary}
1164
1165
1166 We have conducted a systematic comparative evaluation of two tierless language technologies for \gls{IOT} stacks: one for resource-rich, and the other for resource-constrained sensor nodes. The basis is four implementations of a deployed smart campus \gls{IOT} stack: two conventional tiered and \gls{PYTHON}-based stacks, and two tierless \gls{CLEAN} stacks. An operational comparison of implementations demonstrates that they have equivalent functionality, and meet the \gls{UOG} smart campus functional requirements (\cref{sec_t4t:Case}).
1167
1168 We show that \emph{tierless languages have the potential to significantly reduce the development effort for \gls{IOT} systems}. Specifically the tierless \gls{CWS} and \gls{CRS} stacks require far less code, i.e.\ 70\% fewer \gls{SLOC}, than the tiered \gls{PWS} and \gls{PRS} stacks (\cref{table_t4t:multi}). We analyse the code reduction and attribute it to the following three main factors.
1169 \begin{enumerate*}
1170 \item Tierless developers need to manage less interoperation: \gls{CRS} uses a single \gls{DSL} and paradigm, and \gls{CWS} uses two \glspl{DSL} in a single paradigm and three source code files. In contrast, both \gls{PRS} and \gls{PWS} use at least six languages in two paradigms and spread over at least 35 source code files (\cref{table_t4t:multi,table_t4t:languages,table_t4t:paradigms}). Thus, a tierless stack minimises semantic friction.
1171 \item Tierless developers benefit from automatically generated, and hence correct, communication (\cref{lst_t4t:mtaskTemp}), and write 6$\times$ less communication code (\cref{fig_t4t:multipercentage}).
1172 %and TODO).%~\ref{lst_t4t:mqtt}).
1173 \item Tierless developers can exploit powerful high-level declarative and task-oriented \gls{IOT} programming abstractions (\cref{table_t4t:temp}), specifically the composable, higher-order task combinators outlined in \cref{sec_t4t:itasks}.
1174 Our empirical results for \gls{IOT} systems are consistent with the benefits claimed for tierless languages in other application domains. Namely that a tierless language provides a \textit{Higher Abstraction Level}, \textit{Improved Software Design}, and improved \textit{Program Comprehension}~\citep{weisenburger2020survey}.
1175 \end{enumerate*}
1176
1177 We show that \emph{tierless languages have the potential to significantly improve the reliability of \gls{IOT} systems}. We illustrate how \gls{CLEAN} maintains type safety, contrasting this with a loss of type safety in \gls{PRS}.
1178 We illustrate higher order failure management in \gls{CLEAN}\slash\gls{ITASK}/\gls{MTASK} in contrast to the \gls{PYTHON}-based failure management in \gls{PRS}. For maintainability a tiered approach makes replacing components easy, but refactoring within the components is far harder than in a tierless \gls{IOT} language. Again our findings are consistent with the simplied \textit{Code Maintenance} benefits claimed for tierless languages~\citep{weisenburger2020survey}.
1179 Finally, we contrast community support for the technologies (\cref{sec_t4t:Discussion}).
1180
1181 %\pwtcomment{Pieter: please check discussion of ~\citep{weisenburger2020survey} in preceding 2 paragraphs}
1182
1183 We report \emph{the first comparison of a tierless \gls{IOT} codebase for resource-rich sensor nodes with one for resource-constrained sensor nodes}.
1184 \begin{enumerate*}
1185 \item The tierless implementations have very similar code sizes (\gls{SLOC}), as do the tiered implementations: less than 7\% difference in \cref{table_t4t:multi}. This suggests that the development and maintenance effort of simple tierless \gls{IOT} systems for resource-constrained and for resource-rich sensor nodes is similar, as it is for tiered technologies.
1186 \item The percentages of code required to implement each \gls{IOT} functionality in the tierless \gls{CLEAN} implementations is very similar
1187 as it is in the tiered \gls{PYTHON} implementations (\cref{fig_t4t:multipercentage}). This suggests that the code for resource-constrained and resource-rich sensor nodes can be broadly similar in tierless technologies, as it is in many tiered technologies (\cref{sec_t4t:resourcerich}).
1188 \end{enumerate*}
1189
1190 We present \emph{the first comparison of two tierless \gls{IOT} languages: one designed for resource-constrained sensor nodes (\gls{CLEAN} with \gls{ITASK} and \gls{MTASK}), and the other for resource-rich sensor nodes (\gls{CLEAN} with \gls{ITASK}).} \gls{CLEAN}\slash\gls{ITASK} can implement all layers of the \gls{IOT} stack if the sensor nodes have the computational resources, as the Raspberry Pis do in \gls{CRS}. On resource constrained sensor nodes \gls{MTASK} are required to implement the perception and network layers, as on the Wemos minis in \gls{CWS}. We show that a bare metal execution environment allows \gls{MTASK} to have better control of peripherals, timing and energy consumption. The memory available on a microcontroller restricts the programming abstractions available in \gls{MTASK} to a fixed set of combinators, no user defined or recursive data types, strict evaluation, and makes it harder to add new abstractions. Even with these restrictions \gls{MTASK} provide a higher level of abstraction than most bare metal languages, and can readily express many \gls{IOT} applications including the \gls{CWS} \gls{UOG} smart campus application (\cref{sec_t4t:ComparingTierless}).
1191 Our empirical results are consistent with the benefits of tierless languages listed in Section 2.1 of~\citep{weisenburger2020survey}.
1192
1193 \subsection{Reflections}
1194
1195 This study is based on a specific pair of tierless \gls{IOT} languages, and the \gls{CLEAN} language frameworks represent a specific set of tierless language design decisions. Many alternative tierless \gls{IOT} language designs are possible, and some are outlined in \cref{sec_t4t:characteristics}. Crucially the limitations of the tierless \gls{CLEAN} languages, e.g.\ that they currently provide limited security, should not be seen as limitations of tierless technologies in general.
1196
1197 This study has explored some, but not all, of the potential benefits of tierless languages for \gls{IOT} systems. An \gls{IOT} system specified as a single tierless program is amenable to a host of programming language technologies. For example, if the language has a formal semantics, as Links, Hop and \gls{CLEAN} tasks do~\citep{cooper2006links,serrano2006hop,plasmeijer_task-oriented_2012}, it is possible to prove properties of the system, e.g.\ \citep{Steenvoorden2019tophat}. As another example program analyses can be applied, and \cref{sec_t4t:characteristics} and~\citep{weisenburger2020survey} outline some of the analyses could be, and in some cases have been, used to improve \gls{IOT} systems. Examples include automatic tier splitting~\citep{10.1145/2661136.2661146}, and controlling information flow to enhance security~\citep{valliappan_towards_2020}.
1198
1199 While offering real benefits for \gls{IOT} systems development, tierless languages also raise some challenges. Programmers must master new tierless programming abstractions, and the semantics of these automatic multi-tier behaviours are necessarily relatively complex. In the \gls{CLEAN} context this entails becoming proficient with the \gls{ITASK} and \gls{MTASK} \glspl{DSL}. Moreover, specifying a behaviour that is not already provided by the tierless language requires either a workaround, or extending a \gls{DSL}. However, implementing the relatively simple smart campus application required no such adaption. Finally, tierless \gls{IOT} technology is very new, and both tool and community support have yet to mature.
1200
1201
1202 \subsection{Future Work}
1203
1204 This paper is a technology comparison between tiered and tierless technologies. The metrics reported, such as code size, numbers of source code files, and of paradigms are only indirect, although widely accepted, measures of development effort. A more convincing evaluation of tierless technologies could be provided by conducting a carefully designed and substantial user study, e.g.\ using N-version programming.
1205
1206 A study that implemented common benchmarks or a case study in multiple tierless \gls{IOT} languages would provide additional evidence for the generality of the tierless approach. Such a study would enable the demonstration and comparison of alternative design decisions within tierless languages, as outlined in \cref{sec_t4t:characteristics}.
1207
1208
1209 In ongoing work we are extending the \gls{MTASK} system in various ways. One extension allows \gls{MTASK} tasks to communicate directly, rather than via the \gls{ITASK} server. Another provides better energy management, which is crucial for battery powered sensor nodes.
1210
1211 \section*{Acknowledgements}
1212 Thanks to Kristian Hentschel and Dejice Jacob who developed and maintain \gls{PRS}
1213 and to funders: Royal Netherlands Navy, the Radboud-Glasgow Collaboration Fund, and UK EPSRC grants MaRIONet (EP/P006434) and STARDUST (EP/T014628). We also thank Lito Michala, Jose Cano, Greg Michaelson, Rinus Plasmeijer, and the anonymous TIOT reviewers for valuable feedback on the paper.
1214
1215 \input{subfilepostamble}
1216 \end{document}