In this article we introduce two Dart libraries for code distribution: Adaptify and Code Mobility. Both are available on GitHub, so read on to learn the basics before jumping right in and using them.
Distributed systems and applications are widely used. In fact, they are the cornerstones of modern web services. Whether you shop on the internet, send an instant message or watch a video stream: Distribution provides the services fast and reliably.
The architecture of a conventional distributed application is characterized by a static task-to-component assignment. In this architecture the decision on which component a task is performed is already made in the development of the application. Adaptive software pursues a different approach: It provides decision-making at runtime to determine which component should execute the task. In addition, it features concepts for the distribution of the source code. The objectives are a better resource utilization and the creation of software that is more adaptable to requirement changes at runtime.
In my master’s thesis I studied the opportunities of adaptive code execution in theory and practice. For the practical part, I developed two libraries with the Dart programming language. One library is responsible for the decision-making and the other for the code distribution.
The Dart programming language is developed by a team at Google with the self proclaimed goal to run on the client and on the server. Dart allows the use of the same source code on the client and server, thus the development and maintenance effort is reduced.
Dart is an object-oriented language with class-based single inheritance. Variables have a lexical scope, which is determined statically. It supports optional static types and dynamic type assertions at runtime. Among other features, Dart is especially optimized for high performance and asynchronous code execution.
Both libraries are developed with the goal to use them in the browser and the Dart VM. This increases the development effort, but the source code is reusable on both platforms and tasks can be shared and exchanged between the runtime environments. The libraries use abstract classes to ensure uniform interfaces. These abstract classes are the framework for individual implementations. Also, the libraries consist of working implementations for out-of-the-box usage.
The Adaptify library is responsible for the decision-making. It utilizes the three basic resources CPU, memory and bandwidth. For every task used with Adaptify metadata with consumption information for the three resources must be defined. In the metadata the resource requirement is graded into low, medium or high consumption. Additionally, there is a fourth metadata which defines whether a task is time-critical.
Several components of the library interact with each other for the decision-making. At first the resource requirements of a task, as defined before, are determined. In addition, the monitor component provides information about the current capacity of the device. Both information sources are evaluated by an adaptation strategy and a decision is made. Adaptify is able to make a decision based on the resource requirements alone, if no monitor information has been collected or the adaptation strategy doesn’t intend the use of a monitor. The decision is then forwarded to the decision unit which determines a final result and returns it to the application. The decision unit may further process the decision of an adaptation strategy. For example, several adaptation strategies can be evaluated within a decision unit. Subsequently, the decisions are collected and the result is determined by a majority decision.
The implementation with Dart provides several challenges. At first the two very different runtime environments (Dart VM and browser) offer different and very limited options to acquire the capacity information of a system. Furthermore, the comparability of measurements on different devices is a problem that makes it hard to use the results in an adaptation strategy. The implementation and conducted tests revealed that it’s difficult to capture meaningful results for the three resources in both runtimes. Especially the browser complicates the data collection and only limited information are available. Therefore, the manual user input of the performance values is a good strategy to collect information for the monitor. In addition to the collection of information a good adaptation strategy is important. Adaptify currently provides two strategies based on conditional expressions and fuzzy logic. They are tested with user provided values and have proven their suitable for the decision-making in tests.
With the Code Mobility library different concepts of code distribution and execution are implemented. In order to demonstrate the opportunities of the library these concepts are briefly discussed here. The easiest way of code distribution is the use of locally available code. In this case, it’s assumed that the source code is available on all devices and the code can simply be executed on them. If the task is executed remotely, it may be necessary to send additional data to the target device. After the computation the result is returned from the local or remote device and further processed. These types of executions are referred to as local execution and remote execution.
Another concept is remote evaluation, which is similar to Remote Procedure Call (RPC). It enables the remote execution of code on a target device and the receipt of the result. A simple example for the use of remote evaluation is an SQL query, which is sent to the SQL server and executed there. The result of the query is returned to the sender.
Based on these concepts the library provides its functionality. The central piece of Code Mobility is the task, whose execution is the reason for all further functionality. A task consist of the three metadata name, resource identifier and description. This metadata are used to uniquely identify the task in the code distribution and execution and to provide additional information. In principle a task consists of a class that manipulates the input data and returns the result or an error. It’s executed by a taskrunner on either a server or client. This class is responsible for the handover of the input data, the execution of the task and the evaluation of the return values. In addition to an abstract interface for the taskrunner, the library contributes a concrete implementation for the client and server.
The server is also part of the Code Mobility library and is only available for the Dart VM. A server is used to deliver the content and to accept requests for the above described concepts. For communication and data exchange the HTTP protocol and the JSON data format is used. Code Mobility consists of an abstract server class and two concrete implementations: The MobilityServer, which supports all concepts and the limited RepositoryServer that provides only content delivery.
The client controls the local execution of a task, triggers a remote execution/evaluation or queries the source code with code on demand. In all cases, the client delivers the result to the application for further processing. The client is defined with an abstract class to provide unified interface. Furthermore, the library provides clients for the Dart VM and the browser.
The Code Mobility library supports secure connections with the HTTPS protocol using the certificates provided by the system or self-signed certificates. Authentication and authorization of users may be valuable for more complex usage scenarios. Currently the Code Mobility library doesn’t support either, these may be added in future development.
Although both libraries provide a solid foundation, they can be improved with further development. For the Adaptify library additional approaches like strategies using artificial intelligence and improvement for the current algorithms should be considered. Also, benchmarks for detecting the maximum capacity of the system resources aren’t implemented yet and could be added to the library.
The next step forward for the Code Mobility library is the implementation of authentication and authorization. Another step to improve the library will be better error handling and code inspection to ensure that the code can be executed on the target device.
Overall, both libraries provide the required basic functionality for adaptive software and are ready to use. The libraries are documented with dartdoc to ease the usage. Adaptify and Code Mobility are released under the BSD License on Github. For feedback, bug reports or code contribution visit the project sites and feel free to contact me.
Get in touch
Don’t want to get your hands dirty? Our developers have years of experience in developing mobile and web applications. Visit our website for a full portfolio, ask for a quotation at email@example.com or call +49 721 619 021-0.
One thought on “Adaptive Code Execution with Dart”