Skip to content
Permalink
Browse files

Issue #460: Fretboard: Update documentation

Closes #460: Fretboard: Update documentation
  • Loading branch information...
fercarcedo authored and pocmo committed Jul 20, 2018
1 parent ee164fc commit 050b98f41743ccad319bdb8263b1067944971431
Showing with 117 additions and 98 deletions.
  1. +117 −98 components/service/fretboard/README.md
@@ -12,24 +12,10 @@ Use gradle to download the library from JCenter:
implementation "org.mozilla.components:fretboard:{latest-version}
```

### Filters
Fretboard allows you to specify the following filters:
- Buckets: Every user is in one of 100 buckets (0-99). For every experiment you can set up a min and max value (0 <= min <= max <= 100). The bounds are [min, max).

- appId (regex): The app ID (package name)
- version (regex): The app version
- country (regex): country, pulled from the default locale
- lang (regex): language, pulled from the default locale
- device (regex): Android device name
- manufacturer (regex): Android device manufacturer
- region: custom region, different from the one from the default locale (like a GeoIP, or something similar).
For this to work you must provide a RegionProvider implementation when creating the Fretboard instance.

### Creating Fretboard instance
In order to use the library, first you have to create a new Fretboard instance. You do this once per app launch
(typically in your Application class onCreate method). You simply have to instantiate the Fretboard class and
provide the ExperimentStorage and ExperimentSource implementations, and then call the loadExperiments method
to load experiments from local storage:
In order to use the library, first you have to create a new `Fretboard` instance. You do this once per app launch
(typically in your `Application` class `onCreate` method). You simply have to instantiate the `Fretboard` class and
provide the `ExperimentStorage` and `ExperimentSource` implementations, like this:

```Kotlin
class SampleApp : Application() {
@@ -40,25 +26,10 @@ class SampleApp : Application() {
experimentSource,
experimentStorage
)
fretboard.loadExperiments()
}
}
```

Additionally, Fretboard allows you to specify a custom RegionProvider in order to specify a custom region,
different from the one of the current locale (perhaps doing a GeoIP or something like that):

```Kotlin
val fretboard = Fretboard(
experimentSource,
experimentStorage,
object : RegionProvider {
return custom_region
}
)
```


#### Using Kinto as experiment source
Fretboard includes a default source implementation for a Kinto backend, which you can use like this:

@@ -69,34 +40,6 @@ val fretboard = Fretboard(
)
```

It expects the experiments in the following JSON format:
```json
{
"data":[
{
"name": "",
"match":{
"lang":"",
"appId":"",
"regions":[],
"country":"",
"version":"",
"device":"",
"manufacturer":"",
"region":""
},
"buckets": {
"min": "0",
"max": "100"
},
"description":"",
"id":"",
"last_modified":1523549895713
}
]
}
```

#### Using a JSON file as experiment storage
Fretboard includes support for flat JSON files as storage mechanism out of the box:

@@ -107,58 +50,34 @@ val fretboard = Fretboard(
)
```

#### Creating custom experiment source
You can create a custom experiment source simply by implementing the ExperimentSource interface:
### Fetching experiments from disk
After instantiating `Fretboard`, in order to load the list of already downloaded
experiments from disk, you need to call the `loadExperiments` method (don't call it
on the UI thread, this example uses a coroutine):

```Kotlin
class MyExperimentSource : ExperimentSource {
override fun getExperiments(syncResult: SyncResult): SyncResult {
// ...
return updatedExperiments
}
}
```

The getExperimentsMethod takes a SyncResult object, which contains the list of already downloaded experiments and
a last_modified date, and returns another SyncResult object with the updated list of experiments.

As the getExperiments receives the list of experiments from storage and a last_modified date, it allows you
to do diff requests, if your storage mechanism supports it (like Kinto does).

#### Creating custom experiment storage
You can create a custom experiment storage simply by implementing the ExperimentStorage interface, overriding
the save and retrieve methods, which use SyncResult objects with the list of experiments and a last_modified date:

```Kotlin
class MyExperimentStorage : ExperimentStorage {
override fun save(syncResult: SyncResult) {
// save result to disk
}
override fun retrieve(): SyncResult {
// load result from disk
return result
}
launch(CommonPool) {
fretboard.loadExperiments()
}
```

### Updating experiment list
Fretboard provides two ways of updating the downloaded experiment list from the server: the first one is to directly
call updateExperiments on a Fretboard instance, which forces experiments to be updated immediately and synchronously
call `updateExperiments` on a `Fretboard` instance, which forces experiments to be updated immediately and synchronously
(do not call this on the main thread), like this:

```Kotlin
fretboard.updateExperiments()
```

The second one is to use the provided JobScheduler-based scheduler, like this:
The second one is to use the provided `JobScheduler`-based scheduler, like this:
```Kotlin
val scheduler = JobSchedulerSyncScheduler(context)
scheduler.schedule(EXPERIMENTS_JOB_ID, ComponentName(this, ExperimentsSyncService::class.java))
```

Where ExperimentsSyncService is a subclass of SyncJob you create like this, providing the Fretboard instance via the
getFretboard() method:
Where `ExperimentsSyncService` is a subclass of `SyncJob` you create like this, providing the `Fretboard` instance via the
`getFretboard` method:

```Kotlin
class ExperimentsSyncService : SyncJob() {
@@ -168,7 +87,7 @@ class ExperimentsSyncService : SyncJob() {
}
```

And then you have to register it on the manifest, just like any other JobService:
And then you have to register it on the manifest, just like any other `JobService`:

```xml
<service android:name=".ExperimentsSyncService"
@@ -178,7 +97,7 @@ And then you have to register it on the manifest, just like any other JobService

### Checking if a user is part of an experiment
In order to check if a user is part of a specific experiment, Fretboard provides two APIs: a Kotlin-friendly
withExperiment API and a more Java-like isInExperiment. In both cases you pass an instance of ExperimentDescriptor
`withExperiment` API and a more Java-like `isInExperiment`. In both cases you pass an instance of `ExperimentDescriptor`
with the id of the experiment you want to check:

```Kotlin
@@ -192,7 +111,7 @@ otherButton.isEnabled = fretboard.isInExperiment(descriptor)

### Getting experiment metadata
Fretboard allows experiments to carry associated metadata, which can be retrieved using the kotlin-friendly
withExperiment API or the more Java-like getExperiment API, like this:
`withExperiment` API or the more Java-like `getExperiment` API, like this:

```Kotlin
val descriptor = ExperimentDescriptor("first-experiment-id")
@@ -203,7 +122,7 @@ textView.setText(fretboard.getExperiment(descriptor)?.payload?.get("message"))
```

### Setting override values
Fretboard allows you to force activate / deactivate a specific experiment via setOverride, you
Fretboard allows you to force activate / deactivate a specific experiment via `setOverride`, you
simply have to pass true to activate it, false to deactivate:

```Kotlin
@@ -219,6 +138,106 @@ fretboard.clearOverride(context, descriptor)
fretboard.clearAllOverrides(context)
```

### Filters
Fretboard allows you to specify the following filters:
- Buckets: Every user is in one of 100 buckets (0-99). For every experiment you can set up a min and max value (0 <= min <= max <= 100). The bounds are [min, max).
- appId (regex): The app ID (package name)
- version (regex): The app version
- country (regex): country, pulled from the default locale
- lang (regex): language, pulled from the default locale
- device (regex): Android device name
- manufacturer (regex): Android device manufacturer
- region: custom region, different from the one from the default locale (like a GeoIP, or something similar).
For this to work you must provide a RegionProvider implementation when creating the `Fretboard` instance.
- release channel: release channel of the app (alpha, beta, etc)

### Specifying custom values for filters
Additionally, Fretboard allows you to specify a custom `ValuesProvider` object in order to return a custom region,
different from the one of the current locale (perhaps doing a GeoIP or something like that), or the app
relase channel (alpha, beta, etc). It also allows you to override the values for other experiment properties
(such as the appId, country, etc):

```Kotlin
val fretboard = Fretboard(
experimentSource,
experimentStorage,
object : ValuesProvider {
override fun getRegion() {
return custom_region
}
override fun getReleaseChannel() {
return app_channel
}
}
)
```

### Creating a custom experiment source
You can create a custom experiment source simply by implementing the `ExperimentSource` interface:

```Kotlin
class MyExperimentSource : ExperimentSource {
override fun getExperiments(snapshot: ExperimentsSnapshot): ExperimentsSnapshot {
// ...
return updatedSnapshot
}
}
```

The `getExperiments` method takes an `ExperimentsSnapshot` object, which contains the list of already downloaded experiments and
a last_modified date, and returns another `ExperimentsSnapshot` object with the updated list of experiments.

As the `getExperiments` receives the list of experiments from storage and a last_modified date, it allows you
to do diff requests, if your storage mechanism supports it (like Kinto does).

### Creating a custom experiment storage
You can create a custom experiment storage simply by implementing the `ExperimentStorage` interface, overriding
the save and retrieve methods, which use `ExperimentsSnapshot` objects with the list of experiments and a last_modified date:

```Kotlin
class MyExperimentStorage : ExperimentStorage {
override fun save(snapshot: ExperimentsSnapshot) {
// save snapshot to disk
}
override fun retrieve(): ExperimentsSnapshot {
// load snapshot from disk
return snapshot
}
}
```

### Experiments format for Kinto
The provided implementation for Kinto expects the experiments in the following JSON format:
```json
{
"data":[
{
"name": "",
"match":{
"lang":"",
"appId":"",
"regions":[],
"country":"",
"version":"",
"device":"",
"manufacturer":"",
"region":"",
"release_channel":""
},
"buckets": {
"min": "0",
"max": "100"
},
"description":"",
"id":"",
"last_modified":1523549895713
}
]
}
```

## License

This Source Code Form is subject to the terms of the Mozilla Public

0 comments on commit 050b98f

Please sign in to comment.
You can’t perform that action at this time.