# Transitioning Applets to Apps

## Introduction to Apps <a href="#introduction-to-apps" id="introduction-to-apps"></a>

Apps (applications) are packaged standalone executables that are versioned. They reside in a global app namespace, and there can be multiple versions of a single app name. Developers control the list of authorized users that can find and run the app.

Developers can build a new app version and publish it. Publishing a version makes that version available (visible) to the authorized users, and restricts further modifications to it. Users can choose to run the most recently published version, or any other previously published version.

## **App versions are forever**

You cannot modify published app versions. This ensures that executions of published app versions are always reproducible.

In serious cases, you might want to [remove an app version](https://documentation.dnanexus.com/developer/apps/transitioning-from-applets-to-apps#removing-an-app-version). For example, the published app version has a major bug and you never want users to execute the app. Removed app versions are not reproducible (executions are forbidden), so be careful.

## **Can they be "reverse-engineered" (can users retrieve the shell script and resources used in the analysis)?**

Yes, with `dx get`.

Users can retrieve that information only if the app author has designated the app as "open-source".

## **Where can they store assets?**

1\. Inline using the `resources` folder during `dx build`. 2. In the parent project, accessible via `$DX_PROJECT_CONTEXT_ID` from inside the script.

1\. Inline using the `resources` folder during `dx build`. 2. In a private, read-only container, specific to the app version, accessible via `DX_RESOURCES_ID`.

## Why Transition From Applets to Apps? <a href="#why-transition-from-applets-to-apps" id="why-transition-from-applets-to-apps"></a>

During early development, applets are a convenient way to experiment with analyses inside own projects. Once iterations are over and applets need to be locked down (and perhaps distributed to a wider audience), transitioning to apps is an attractive option.

Once apps are published, they cannot be modified. They can only be updated by newer versions, but the system keeps all previous versions (and these are still accessible by default, unless the app author decides to remove some versions). Apps can carry their own assets in a private container (a kind of read-only project). This enhances reproducibility and minimizes risks.

Apps can be instantly shared across a list of users. In combination with being self-sufficient by storing their own assets, and being locked down, this makes it a more convenient choice for sharing them with less sophisticated users (who only need to run them).

## Making the Transition <a href="#making-the-transition" id="making-the-transition"></a>

To transition an applet into an app, you will need to address the following areas.

### **App Name**

Think of a name for your app. Certain app names, such as `bwa` or `fastqc`, are already taken.

To maintain clarity and avoid naming conflicts, consider using a unique prefix for your applications. For example, if you're developing tools within the Center for Cancer Informatics, you might name them "cci-bwa", "cci-fastqc," and so on. This would result in commands like `dx run app-cci-bwa/1.2`, where "cci-" identifies the application's origin.

### **App Versioning**

Think of an initial version number for your app. Choosing a versioning convention is important for you to perform meaningful app updates later.

DNAnexus strongly suggests the [Semantic Versioning](http://semver.org/) conventions. Under those conventions, your first production version should be `1.0.0`. In `dxapp.json`, add a key called `version` with a string value equal to the version you chose, such as `1.0.0`. For a trivial update (such as a bugfix), you should later increase it to `1.0.1`. For a minor update which is backwards compatible (such as updating the underlying software version of bwa), you should increase it to `1.1.0`. For a major upgrade such as a backwards-incompatible change in the input/output spec, you should increase it to `2.0.0` or higher. The choice depends on the magnitude of changes.

### **Open Source**

Decide if your app is **open-source**. Do you want to let users retrieve the shell script and any other resources associated with the app?

In `dxapp.json`, add a key called `openSource` with a boolean value of *true* or *false*.

### **App Developers**

Decide the app author. Just like applets, apps require storage for their resources and assets, and for that storage they will be billed on a monthly basis to the billing account of the original author of each app.

Additional authors, that is, users who can update the app by building a newer version, can be added or removed at any time, but it is the billing account of the original author that will always be associated with billing of storage for this app.

Do not author apps under a trial account. Whoever you decide to be the original app author, ask them to run the first `dx build` of the app.

### **Authorized Users**

Decide which users will be allowed to access your app. The app author always has access to the app.

If you intend to run the apps under the same user as the one authoring them, you do not need to do anything. Otherwise, in `dxapp.json`, add a key called `authorizedUsers` with a value being an array of strings, corresponding to the entities allowed to run the app. Entities are encoded as *user-username* for single users, or *org-orgname* for organizations. For example, `"authorizedUsers": ["user-george", "org-cci"]`. You can also manage the list of authorized users at any point via `dx list users`, and `dx remove users`.

If you prefer to use `dx`, then omit the `"authorizedUsers"` key from `dxapp.json` altogether. (The list of authorized users is common to all versions of the app).

### **App Assets**

If the app requires assets, that is, files that reside in a project and not inside the `./resources/` folder at `dx build` time, you need to perform the following changes.

In the bash script, when fetching assets, replace `$DX_PROJECT_CONTEXT_ID` with `$DX_RESOURCES_ID`, so that your script fetches the assets from the app's private container and not from inside whatever parent project it may be run. If you want for the same script to be able to function both as an applet and as an app, then add code like the following (which introduces a new variable), and use `$DX_ASSETS_ID` when fetching assets:

```
if [[ "$DX_RESOURCES_ID" != "" ]]; then
  DX_ASSETS_ID="$DX_RESOURCES_ID"
else
  DX_ASSETS_ID="$DX_PROJECT_CONTEXT_ID"
fi
dx download "$DX_ASSETS_ID:/assets/hs37d5.fasta"
```

Create a project with the exact structure that you want your assets to have. For example, create a project with a folder "/assets/" and place `hs37d5.fasta` inside that folder.

In `dxapp.json`, add a key called `resources` with a string value equal to the project ID of the project with the assets, that is, `"resources": "project-BBF4Jp80vVky55Vvgkb0028u"`

When building the app, the system will create a separate read-only copy of the project and associate it with the specific app version. You can safely modify or delete the original project, as it will not affect the app. If your assets don't change across newer versions, you are welcome to keep the original project around and reuse the same project ID in `dxapp.json` when rebuilding the app later. The system will still create a separate read-only copy for each version.

### **Enabled Regions**

Unlike an applet, an app can be run in multiple regions, which are denoted by the **enabled regions** of the app. For a given app version, the set of enabled regions is immutable.

To set the enabled regions for an app, specify the `regionalOptions` key in `dxapp.json`, according to the [`dxapp.json` specification](https://documentation.dnanexus.com/developer/apps/app-metadata).

## **Building the App**

To build the app, run the `build` command:

```
dx build --app --publish
```

The first time you run this command, the system will reserve the app-name in the global namespace, and create the first version of the app according to the `version` key in `dxapp.json`.

You can still build this as an applet, by omitting the `--app` and `--publish` options.

## **Updating the App**

To perform subsequent updates, after you make any changes to the code, increment the version in `dxapp.json`, and rerun the `dx build --app --publish` command.

## Publishing an App <a href="#publishing-an-app" id="publishing-an-app"></a>

In the examples above, you will notice that new app versions are built and published simultaneously, by supplying the `--publish` option to `dx build`. Publishing an app version makes it available to authorized users and ensures that it can no longer be modified.

DNAnexus suggests following that workflow, but it is not a requirement.

* You can build an app version without publishing it by omitting the `--publish` option. The generated app version will only be accessible by the app developers, that is, the original app author and any users added via `dx add developers`, and not by authorized users. You can use this flow if you want to first test the new app version before you publish it.
* During testing, if you find that you must make further changes, you can update the same unpublished app version in-place, without having to generate a new version. Use `dx build --app` again, and if the version in `dxapp.json` matches an unpublished existing version, that version will be overwritten. Once you are happy with the app version, you can publish it by repeating the `dx build` command with the `--publish` argument.

## Accessing Different App Versions <a href="#accessing-different-app-versions" id="accessing-different-app-versions"></a>

Similarly to applets, each app version receives a unique id of the form app-xxxx. It is also accessible via the "app-name/version" scheme, for example, *app-cci-bwa/1.0.0*, which cannot be changed once that app version is published.

Apps have the concept of a default version. If an app has multiple published versions, there is exactly one version always which is the default.

When you run `dx build --app --publish`, the published app version becomes the new default. Typically, the default version is whatever version was most recently published.

Users refer to the default version when using "app-name" with no version qualifier. For example, when executing `dx run app-cci-bwa`. Users who launch apps have a choice of whether to use the default version (by doing `dx run app-cci-bwa`) or to use a specific version (by doing `dx run app-cci-bwa/1.0.0`).

Inside workflows, apps are always versioned. In other words, a workflow always refers to a particular app version (whichever app version was added to the workflow at the time of workflow creation).

When editing the workflow in the DNAnexus web interface, if the default app version is different than the app version in the workflow (which means the app has been updated in the meantime), the website will prompt the user to optionally update the workflow to use the new version.

## Changing the Default App Version <a href="#changing-the-default-app-version" id="changing-the-default-app-version"></a>

If you publish a new app version, such as `app-cci-bwa/1.0.1`, and later realize that you've made a mistake that needs fixing, you have two options:

1. Create a new app version, such as `app-cci-bwa/1.0.2`, that doesn't have the problem and publish it. Publishing will make `1.0.2` the new default version. As a result, users who execute `dx run app-cci-bwa` will run a working version.
2. Mark a previous app version, such as `app-cci-bwa/1.0.0` as the default version. You can do by tagging that version as default using `dx api app-cci-bwa/1.0.0 addTags '{"tags":["default"]}'`.

## Removing an App Version <a href="#removing-an-app-version" id="removing-an-app-version"></a>

Apps cannot be modified once published. However, you can remove a specific app version if necessary. For example, an app version might have a critical flaw or bug and you never want users to execute it. In such cases, you can remove an app version so it's no longer allowed to run.

For removed app versions, users can still get basic information about the version using `dx describe`. However, the input/output spec, actual code, and assets of the removed app version aren't available.

To remove an app version, that version must not be the default. If you need to remove the current default version of an app, you first need to [make another version the default](https://documentation.dnanexus.com/developer/apps/transitioning-from-applets-to-apps#changing-the-default-app-version).

```
# Removes version 1.0.1 of app-cci-bwa and disallows executions by users.
# If this is the only version of the app, the app will be uninstalled for all users.
$ dx api app-cci-bwa/1.0.1 delete '{}'
```
