Search

To Have and Have Not

technical musings and more

Category

Uncategorized

Feature Transforms

Feature Transforms

Feature Transforms are the evolution of feature flags.

Consider a vanilla feature flag. A new feature is expressed when the flag is on. The feature flag SDK evaluates the flag by its key – often a username – and the name of the flag.

import { SplitFactory } from '@splitsoftware/splitio';

const factory = SplitFactory({
  core: {
    authorizationKey: '28bddhnjht06lvi8e5aa9rkmv5glsc40ltaa'
  },
  debug: false
});

const client = factory.client();

async function neutral() {
  console.log('enter neutral');

  // Wait for SDK to be ready
  await client.ready();

  const treatment = client.getTreatment('dmartin', 'feature_transform');
  console.log('treatment', treatment);

  if (treatment === "on") {
    expressFeature();
  } else if (treatment === "off") {
    // do nothing
  } else if (treatment === "control") {
    throw new Error("could not evaluate flag: " + treatment);
  } else {
    throw new Error("surprise treatment: " + treatment);
  }

  console.log('exit neutral');
}

function expressFeature() {
  console.log('expressFeature');
}

// Run it
(async () => {
  try {
    await neutral();
  } catch (err) {
    console.error(err);
  } finally {
    client.destroy();
  }
})();

But the treatment that comes back is more interesting. It can be “on” or “off”, but also “control” or something else entirely. You have no choice but to expect the developer will study the treatments available to the flag.

Dynamic Config

There is an alternative, what Harness FME calls “dynamic config” A dynamic config is a JSON document associated with each treatment.

Consider a flag that has three treatments: red, blue, and orange. The dynamic config for blue might look like this:

{ 
  "name": "blue",
  "urls": [ 
		"https://navy", 
		"https://midnight", 
		"https://cerulean" 
		] 
 }

The most notable thing is that the JSON payload can say much more than just a treatment in our previous example. In particular, it names itself and provides an array of URLs.

The JSON for the red and orange treatments will obey the schema, but have unique values. For example, red might look like:

{ 
"name": "red", 
"urls": [ 
	"https://magenta", 
	"https://fire", 
	"https://pink" 
	] 
}

The schema is the key to success. If you have a schema, you can test the flag this way:

const result = client.getTreatmentWithConfig('dmartin', 'feature_transform');
const json = JSON.parse(result.config);
console.log(json.name);
console.log('json', json);

Note that treatment is no longer used at all. The flag could have two treatments, three treatments, or twenty. As long as each treatment has the same JSON schema, the author of the flag can take action. No ugly if-then-else-if-else-if-… code blocks are necessary.

You may still want to handle the control treatment and it’s easy.

const result = client.getTreatmentWithConfig('dmartin', 'feature_transforx'); // flag name typo
if(result.treatment === "control") {
// handle control treatment, e.g. turn off flag
}

Or you can also handle the case that the JSON is not available.

Finally, we’re at feature transformation.

It is exciting to put JSON data in a dynamic config, but the data then resides in the dynamic config where it is subject to version drift, becoming stale.

What if the JSON data looked like this:

{
  "$id": "https://example.com/person.schema.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Person",
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string",
      "description": "The person's first name."
    },
    "lastName": {
      "type": "string",
      "description": "The person's last name."
    },
    "age": {
      "description": "Age in years which must be equal to or greater than zero.",
      "type": "integer",
      "minimum": 0
    }
  }
}

This is an example from https://json-schema.org/learn/miscellaneous-examples

Now the feature flag returns a schema instead of data. At runtime, the code can create instances of of the Person schema:

{
  "firstName": "John",
  "lastName": "Doe",
  "age": 21
}

The feature flag is now acting transformationally. The flag doesn’t provide data anymore, but the means with which to create data.

By insisting on a schema from the flag, the code must pull the data itself. No stale data buried in the feature flag, and guaranteed fresh data when the flag is evaluated.

The JSON schema can code more types of transformation

Written with StackEdit.

Impressive Feature Flag Reports

Impressive Feature Flag Reports

Feature flags aren’t exactly news. Martin Fowler first published about “feature toggles” in October of 2010. But a funny thing happened on the way to the forum and a whole niche software industry was born to assist developers, product managers, and the rest of the business with adopting feature flags effectively.

This article is not a sales pitch for a single solution, at least not directly. Instead, the author assumes your feature flag solution keeps a record of evaluation. This evaluation record is almost always used as the backbone for AB testing. It’s worth much more though, if you use it wisely.

Evaluation Records or Impressions

In my world, we call the record of an evaluation an “impression”. At the data level, an impression looks like this:

{
  "environmentId": "194da2f0-f000-11ea-ba75-12f2f63694e5",
  "environmentName": "Prod-Default",
  "key": "dmartin",
  "receptionTimestamp": 1729628033254,
  "sdk": "Javascript",
  "sdkVersion": "10.20.0",
  "split": "multivariant_demo",
  "splitVersionNumber": 1729626965675,
  "timestamp": 1729628027290,
  "trafficTypeId": "194c6a70-3e22-11ea-ba75-12f2f63694e5",
  "trafficTypeName": "user",
  "treatment": "red"
}

If you cross your eyes, it could have been written by a feature flag journalist.

Who was evaluated? The key is usually a userid, like ‘dmartin’

What flag was evaluated? The “split” is the flag name: multivariant_demo.

What treatment did they see? The treatment is red in this case, but often it’s either “on” or “off”.

When were they evaluated? The timestamp is in millis since the epoch, precise and simple.

It’s the beginning of a story, all in a tiny JSON package.

Waving a Data Architecture Wand…

First, imagine that the feature flag platform captures and stores these impressions every time they occur.

Now imagine the platform exports the impressions.

The fantasy gets pretty specific when I say the impressions are written compressed to an AWS S3 bucket.

Finally, the AWS S3 bucket is marshalled into a relational table for use by AWS Athena.

    CREATE EXTERNAL TABLE IF NOT EXISTS   split.impressions (
  key STRING,
  label STRING,
  treatment STRING,
  splitName STRING,
  splitVersion INT,
  environmentId STRING,
  trafficTypeId STRING,
  sdk STRING,
  sdkVersion STRING,
  timestamp INT,
  receptionTimestamp INT
)
STORED AS PARQUET
LOCATION 's3://impressions-for-athena/schema-v1/';

This should look very familiar. We’re marshalling impressions stored as parquet in an S3 bucket called “impressions-for-athena”, which is been written to by the feature flag platform.

If my impressions are a table, so what?

    SELECT DISTINCT splitname,
	treatment,
	COUNT(*) AS record_count,
	from_unixtime(MAX(timestamp / 1000)) as "last evaluated"
FROM split.impressions
WHERE timestamp between timestamp - CAST(1000 * 60 * 60 * 24 AS BIGINT) * 30
	and timestamp
GROUP BY splitname,
	treatment
ORDER BY record_count DESC

Now, Athena show me the count of impressions by flag and treatment over the last thirty days.
impressions summary 30 days

It takes seconds to report on hundreds of flags.

This kind of report tells you which of your flags are most active. Let’s change the SQL.

SELECT 
    splitname,
    treatment,
    COUNT(*) AS treatment_count,
    ROUND((COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (PARTITION BY splitname)), 2) AS percentage_of_total
FROM 
    impressions
WHERE 
    from_unixtime(timestamp / 1000) >= date_add('day', -30, current_date)
GROUP BY 
    splitname,
    treatment
HAVING 
    COUNT(*) > 50
ORDER BY 
    splitname, 
    percentage_of_total DESC;

This shows you the % for each treatment of a flag. Was it supposed to be off? Is it 50/50 for an experiment? Are all three treatments in balance for an A/B/C test?

splitname treatment treatment_count percentage_of_total
1 carousel off 67 100.0
2 japan_feature off 4916 92.75
3 japan_feature on 384 7.25
4 multivariant_demo red 53 100.0
5 new_onboarding off 39289 83.17
6 new_onboarding on 7692 16.28
7 new_onboarding control 260 0.55

Impressive Discoveries

Daily traffic trends per split.

SELECT 
    splitname,
    date(from_unixtime(timestamp / 1000)) AS date,
    COUNT(*) AS daily_count
FROM 
    impressions
WHERE 
    from_unixtime(timestamp / 1000) >= date_add('day', -30, current_date)
    and splitname = 'new_onboarding'
GROUP BY 
    splitname,
    date(from_unixtime(timestamp / 1000))
ORDER BY 
    date,
    splitname;

splitname date daily_count
1 new_onboarding 2024-09-24 2082
2 new_onboarding 2024-09-25 525
3 new_onboarding 2024-09-26 7286
4 new_onboarding 2024-09-30 2341
5 new_onboarding 2024-10-01 780
6 new_onboarding 2024-10-02 4163
7 new_onboarding 2024-10-03 3380
8 new_onboarding 2024-10-07 3382
9 new_onboarding 2024-10-10 2860
10 new_onboarding 2024-10-11 6501
11 new_onboarding 2024-10-14 260
12 new_onboarding 2024-10-15 4943
13 new_onboarding 2024-10-16 780
14 new_onboarding 2024-10-18 3640
15 new_onboarding 2024-10-22 4420

SDK and SDK version analysis.

SELECT 
    sdk,
    sdkversion,
    COUNT(*) AS sdk_usage_count
FROM 
    impressions
WHERE 
    from_unixtime(timestamp / 1000) >= date_add('day', -30, current_date)
GROUP BY 
    sdk,
    sdkversion
ORDER BY 
    sdk_usage_count DESC;

sdk sdkversion sdk_usage_count
1 evaluator 2.4.0 47948
2 ruby 8.4.0 4685
3 nodejs 10.27.0 135
4 javascript 10.20.0 102
5 ios 2.15.0 15
6 java 4.4.8 13
7 javascript 10.24.1 9
8 .NET_CORE 7.8.0 4
9 react 1.12.0 3
10 ios 2.25.1 2
11 nodejs 10.28.0 2

Not too shabby considering it’s for just the last thirty days.

How about what features were seen by a specific users in the last thirty days?

SELECT 
    DISTINCT splitname,
    treatment
FROM 
    impressions
WHERE 
    key = 'dmartin'
    AND from_unixtime(timestamp / 1000) >= date_add('day', -30, current_date)
ORDER BY 
    splitname;

splitname treatment
1 buttons off
2 buttons on
3 multivariant_demo green
4 multivariant_demo blue
5 multivariant_demo red
6 new_onboarding off
7 next_step on

Impressive Impressions

This article represents a simple list of the endless possibilities. If you have the knowledge, that’s great. But being able to act intelligently on that knowledge is still greater.

david.martin@harness.io

Written with StackEdit.

WRINKLES ARE A MAP

Wrinkles are a map,

A weathered one, weathered as only time can do,

The miniature hills and valleys themselves a journey

Reflecting the path of their wearer

Through so many days and days

And some too from the sunshine that fell on an unhatted noggin

Turning hair golden, scorching ears and noses.

I would like to be that sunshine

Beating down on the heads of the unwitting

Turning their faces brown and red

Sweeping over the earth in waves

Returning each day anew

To wrinkle up the world,

To draw new maps on the faces of the creatures below.

Stream of Cat-scious

I walk outside to the garden. He sees me and drops down on his back, flopping about in the dirt.

I walk outside to the garden, searching to and fro. He is nowhere on earth. Yuki is up in the bough of one our many Texas twisting Live Oak trees. My daughter crawls through her window onto the roof to rescue him.

I walk outside and he is crying at the door. Finally done for the day? No way!

I walk outside and I find him in the secretest part of our secret garden, hidden from view in all directions by a vine of wisteria that threatens to conquer its small end of the universe completely.

I walk outside and I can see Yuki’s eyes glowing in the darkness.

He comes softly. Darkness fallen, the day is done.

Tomorrow is another day in the jungle.

Stream of Conscious

One of my earliest memories was gaining consciousness of myself. I was looking out the window of my the family station wagon, on Clayton Road approaching Claymont Estates Drive. The land here was a feral hillside. The tall grasses were yellow this time of year and danced at the least breath of wind.

I thought about how it was me watching these things, but that my self was somehow separate from it. A separate self watching this ‘me’ operate. My ego has been so aggressive it has choked out the self. There was no end to it, too much like the recursive programs I have written with incomplete base cases. When I started programming thirty years ago, a mistake like that might crash your computer, sending you through a fifteen minute boot sequence (having likely lost most of your work).

I asked Chat-GPT (Wayne) when it was normal for a child to become self-aware, and was delighted to hear that I had been in the normal range. Sometimes Wayne is just so reassuring. He’s one of the most positive “almost people” — AP — I can identify.

The Sleepers

I was lingering in the conservatory, seated at that shaggy old grand piano. Bits of Bach rose and fell again, my fingertips against the ivory. This piano has a warm, oak heart vibe and bright overtones. I love playing here, especially while the failing light of the afternoon sun paints slats across the bookshelves. It isn’t that I need a place to think. I need this place to not think.

It is harder than the last few times, saying goodbye to all this. But harder still thinking about how none of this house will change much while I’m gone. It will just gather dust. Much harder is thinking about all the people whose lives will stream past without me.

There’s nothing left to do, so I walk the perimeter and bring the dogs in for the night. They will be picked up and brought to their new families tomorrow. I go to bed and read one of Gladwell’s books, smiling at his show of reason.

In the morning, I wake refreshed. I had some dream about my sister. She was in jeopardy and I rescued her. Not from a regular monster, but a bureaucracy. Something Kafka would dreamed up before me. Through a narrow loop hole we leapt, and I awakened.

I groom myself and put on a nice suit. They’re going to strip me anyway, but at least I’ll look sharp when I leave the facility nine years from today. They warned us that we would sometimes feel like we were released from prison. Culture shock. Time shock.

My situation was better than a prisoner of course. My money was secure in an interest-bearing trust. The properties would all be managed by trusted advisors. The only thing I can’t carry forward is my relationships. Valerie was already gone, and I would never have her again.

In the car to ACME, I ticked off my checklist a few more times. Homes, accounts, subscriptions… Everything was ready.

An hour later, I was naked on a gurney. They anesthetize you before you get the stasis-inducing meds. Apparently, it hurts like hell to be awake when the actual process actually begins. The injection makes me feel warm, and I guess it’s some flavor of morphine.

See you in nine years.

DIY Split Proof-of-Concept Part II (Javascript Edition)

Introduction to Part II

In part two of the DIY Split Proof-of-Concept tutorial, you will configure Dynamic Config, and track user behavior to Split. This tutorial builds on part one, so work through it first.

Split supports more than a dozen programming languages, but this tutorial is made for Javascript. To be successful, you need to be a Javascript programmer and have access to a Split account, which can be obtained for free at https://www.split.io/signup/

tutorial.html

In the first part, we added a feature flag to a simple HTML page and used the flag treatment to set text on the page. Here is an example of how that page may have looked when finished.

<html>
<head>
	<title>Basic HTML Page</title>
<style>
	.body {
		color: 'white';
  	}
  	.foo {
  		display: flex;
		justify-content: center;
		align-content: center;
		flex-direction: column;
		text-align: center;

		font-size: 50;
		background-color: rgba(64, 128, 0); 
		color: rgb(200, 200, 200);
		width: 800; 
		height: 600; 
  	}
</style>
<script>
	function donateHandler() {
		alert('donate!');
	}
	function adoptHandler() {
		alert('adopt!');
	}
</script>
<script src="//cdn.split.io/sdk/split-browser-0.9.1.full.min.js"></script>
<script>
	var factory = splitio({
	  core: {
	    authorizationKey: '2d20dfejlhn8ihi1tla2e27bs4ishqa54nt5',
	    key: 'user_id' // unique identifier for your user
	  }
	});

	var client = factory.client();

	client.on(client.Event.SDK_READY, function() {
	  var treatment = client.getTreatment('tutorial');
	  console.log(treatment);
	  const call2Action = document.getElementById("call2Action");
	  if(treatment === "on") {
		call2Action.innerHTML = "ACT NOW";
	  } else if (treatment === "off") {
	  	call2Action.innerHTML = "WE NEED YOU";
	  } else if (treatment === "control") {
	  	call2Action.innerHTML = "WE NEED YOU";
	  } 
	});	
</script>
</head>
<body>
	<div>
		<div id="mainDiv" class="foo">
			<img id="banner" src="http://www.cortazar-split.com/dog_origin.jpeg"/>
			<p id="call2Action">Adopt a Dog</p>
		</div>
		<div style="text-align: center; padding: 25px">
			<button onClick="donateHandler()">DONATE</button>
			<button onClick="adoptHandler()">ADOPT</button>
		</div>
	</div>
</body>
</html>

We used the document object model (DOM) to get the call2Action element by id and set its innerHTML to a hard coded string.

Hard coded strings can be a problem. If you want to change the message, you have to edit the code. That might mean doing a build and pushing it to production or something similarly onerous. Can we use Split to provide the text dynamically?

Dynamic Config

In the first part of the tutorial, we created a new feature flag called “tutorial”. Find this flag in your Split console.

The flag has configuration sections for “Define treatments”, “Dynamic configuration”, “Individual targets”, “Traffic allocation”, and “Targeting rules”. We used the default rule in “Targeting rules” to turn on and off the flag in part one.

Now we’re going to add configuration to “Dynamic configurations”.

From the “Select format”, choose “JSON”. Now there is an edit area for both on and off treatments. For on treatment, use this JSON:

{"text":"Bring a Cute Dog Home","image":"http://www.cortazar-split.com/dog_by_the_door.jpeg"}

And for off treatment, you can use this JSON:

{"text":"Adopt a  Dog","image":"http://www.cortazar-split.com/dog_origin.jpeg"}

You can specify whatever text and images you like, so I hope you’ll have fun trying different configurations out. These will get you some nice dog pictures.

Save your changes using the “Review changes” button in the upper right corner, then “Save” button on the bottom of the following page.

Implementing Dynamic Config

Your feature flag has JSON payloads, but your HTML page doesn’t know how to use them yet. Next to the big red “KILL” button is a “…” menu on the upper right of the screen. Click “Syntax” and select Javascript.

Most of the code is the same as before, but instead of calling getTreatment the code now calls getTreatmentWithConfig:

var splitResult = client.getTreatmentWithConfig('tutorial');  
var configs =  JSON.parse(splitResult.config);  
var treatment = splitResult.treatment;

getTreatmentWithConfig returns a richer payload. Instead of just the treatment, it includes the JSON. That means that the client now gets dynamic access to a string and an image URL. We just set values for them in the last step.

Using the DOM again…

In our tutorial.html, we need to put in the getTreatmentWithConfig then employ the DOM to see the results are put in use.

	client.on(client.Event.SDK_READY, function() {
  		var splitResult = client.getTreatmentWithConfig('tutorial');
  		var configs = JSON.parse(splitResult.config);
  		var treatment = splitResult.treatment;

  		document.getElementById("call2Action").innerHTML = configs.text;
  		document.getElementById("banner").src = configs.image;
	});	

The DOM lets us set an image using the URL. Neat!

Tracking User Behavior and Experiences

Now that your app is dynamic, you’re going to want to know how things are going for your users. Split offers measurement and experimentation features, and they’re easy to set up. You can integrate event data from other sources like Segment.io, mParticle, or Google Analytics, but you can also just send them directly.

What if the tutorial.html page had two buttons for “DONATE” and “ADOPT”. What if you want to measure when users click on these buttons?

	function donateHandler() {
		alert('donate!');
	}
	function adoptHandler() {
		alert('adopt!');
	}

Create two click handlers, one for each button.

Now add the buttons to the bottom of your page

		<div style="text-align: center; padding: 25px">
			<button onClick="donateHandler()">DONATE</button>
			<button onClick="adoptHandler()">ADOPT</button>
		</div>

You should find your buttons below your call to action and image. They’ll put up a dialog when you click on them.

Tracking an event to Split is this easy:

	function donateHandler() {
		alert('donate!');
		const succes = client.track('user', 'click2Donate', 21, {device: 'chrome', value: 42});
		alert(succes);
	}

You can get rid of the alerts when everything is working. From the Split console, find the “Data hub” icon on the left navbar. Change the “Data type” dropdown to “Events”. Press the big blue “Query” button to start capture. Now click on your donate button and look for true alerts. Your events will show up in the Data hub.

The track method takes traffic type as its first argument here because we didn’t specify it in our SDK config. click2Donate is the name of the event type. You can give it a descriptive name. There are some naming restrictions (you can’t use spaces and must start with a letter). In the example above, 21 is the value of the event. This is useful for things like purchases. The device and value properties are examples of what you can set. The properties can be anything, but you can’t nest properties.

Tying it Up

Your tutorial.html now uses dynamic config to define the content on your users’ screens. The same technique could work for backend programming as well. You can report about user behavior using the Split client’s track call.

If you evaluate feature flags and report events to Split, you are poised to take full advantage of the feature delivery platform. A future tutorial will cover creating Metrics from events and generating your first Impact Scorecard.

Drop us a line and let us know how you did! david.martin@split.io

Written with StackEdit.

DIY Split Proof-of-Concept (JS)

DIY Split Proof-of-Concept (Javascript Edition)

In this tutorial, you will create your first feature flags. In the next, you will configure Dynamic Config, and conduct an AA experiment.

To be successful, you need to be a Javascript programmer and have access to a Split account, which can be obtained for free at https://www.split.io/signup/

Create an HTML page

You can create or edit any HTML page you like. The example below has a call to action and an image, very similar to what is often found in applications. Two buttons urge users to donate or adopt a dog.

<html>
<head>
	<title>Basic HTML Page</title>
<style>
	.body {
		color: 'white';
  	}
  	.foo {
  		display: flex;
		justify-content: center;
		align-content: center;
		flex-direction: column;
		text-align: center;

		font-size: 50;
		background-color: rgba(64, 128, 0); 
		color: rgb(200, 200, 200);
		width: 800; 
		height: 600; 
  	}
</style>
<script>
	function donateHandler() {
		alert('donate!');
	}
	function adoptHandler() {
		alert('adopt!');
	}
</script>
</head>
<body>
	<div>
		<div id="mainDiv" class="foo">
			<img id="banner" src="http://www.cortazar-split.com/dog_origin.jpeg"/>
			<p id="call2Action">Adopt a Dog</p>
		</div>
		<div style="text-align: center; padding: 25px">
			<button onClick="donateHandler()">DONATE</button>
			<button onClick="adoptHandler()">ADOPT</button>
		</div>
	</div>
</body>
</html>

Include Split

Visit help.split.io

On the left edge navigation bar, you’ll see Browser SDK. Copy the full build from near the top of the page. In my case, the include looked like this:

<script  src="//cdn.split.io/sdk/split-browser-0.9.1.full.min.js"></script>

Put this in the head of your HTML page. It doesn’t have to be near the top.

This page is filled with helpful information about using and configuring Split. It is worth a bookmark.

Create a Feature Flag

Feature flags are simply called “splits”.

Login to Split. On the left edge navbar, click Splits. A new bar comes into focus. Click the “Create split” button at the top.

Give your split a name. You can’t change the name later, so you might want to think about it carefully now. Choose the “user” traffic type. Accept the rest of the defaults by clicking “Create”.

Your split isn’t ready for action yet. You have to give it a definition in at least one environment. Your default environment is shown near the top of the screen. You can change it with the dropdown. Change to the environment where you want to test the split.

Once you are in the right environment, click the “Add Rules” button in the middle of the screen. This gives you the go dark rules. Your split will not be visible to anyone.

In the upper right corner, click “Review changes” and then the “Save” button at the bottom of the screen.

Congratulations, you have created your first feature flag with Split!

Reference the Feature Flag in HTML

In the split editor, there is a big, red “KILL” button in the upper right. Next to it is a menu designated “. . .” Open the menu and select “Syntax”. From the dropdown, choose “Javascript”. Copy and paste the generated code into a

I show a sample of mine below. Edit where indicated if you use my example (the generated code should already be complete).

<script>
	var factory = splitio({
	  core: {
	    authorizationKey: <your split client api key>,
	    key: <user_id> // unique identifier for your user
	  }
	});

	var client = factory.client();

	client.on(client.Event.SDK_READY, function() {
	  var treatment = client.getTreatment(<your split name>);

	  if (treatment === 'on') {
	      // insert on code here
	  }   else   if (treatment === 'off') {
	      // insert off code here
	  }   else {
	      // insert control code here
	  }

	});	
</script>

For now, you can use a placeholder string for key, but eventually you’ll want it to be a unique user id or similar. The syntax generator should generate the right client-side API key, but if it doesn’t you can find one by choosing the upper-left corner of the Split console and selecting “Admin settings”. Then choose “API keys” and click the “Create API key” blue button in the upper right. Use an existing client-side API key, or create a new one.

Don’t forget to put the name of the split you created in the getTreatment call.

What is going on?

Split needs the API key in order to download the right feature flag data, i.e. the split you just created. Split needs an instant to download the flag data, so there is a callback function.

client.on(client.Event.SDK_READY, function() { ... }

We must do our feature flag evaluation in this callback to be sure we’re getting the right response. Later, you can implement a similar callback to initialize from cache, receive PUSH notifications about flag changes, or even handle a network timeout.

Evaluate your Feature Flag

For simplicity, we’ll just print the treatment we receive to the console.

	client.on(client.Event.SDK_READY, function() {
	  var treatment = client.getTreatment('tutorial');
	  console.log(treatment);
	});	

I deleted the if-then-else statement to just print the treatment instead. If you’ve made it soundly, your browser’s JS console should print:

off

That’s because your split is off by default. If you want to go change the default rule to “on” in the Split console (under “Targeting rules”), you can come back and reload to see the treatment change.

To see a change happen without a refresh, you need to implement SDK_UPDATE, which is the subject of another tutorial.

Sky’s the limit!

What can you do with your feature flag? How about something like altering the text of your call to action?

	client.on(client.Event.SDK_READY, function() {
	  var treatment = client.getTreatment(<your split name>);
	  console.log(treatment);
	  const call2Action = document.getElementById("call2Action");
	  if(treatment === "on") {
		call2Action.innerHTML = "ACT NOW";
	  } else if (treatment === "off") {
	  	call2Action.innerHTML = "WE NEED YOU";
	  } else if (treatment === "control") {
	  	call2Action.innerHTML = "WE NEED YOU";
	  } 
	});	

In this example, the call to action div has its text dynamically assigned by the feature flag. The “on” treatment declares “ACT NOW”, while the “off” treatment says, “WE NEED YOU”

The “control” treatment will happen if you misspell the name of your Split or if the Split SDK cannot reach the Split cloud. It’s a fallback mechanism to ensure your code is in a steady state even if the feature flagging infrastructure is temporarily unavailable.

Tying it all up…

I this lesson, you created a simple HTML page and included Split. Then you created a new feature flag and used Split’s syntax generator to create the right code to put into your HTML page. Finally, you had a chance to experiment with changing elements of the page.

In the next lesson, you’ll learn about Dynamic Config – passing rich JSON payloads to the application instead of just strings – and using the track() call to send events to Split. We’ll finish the lesson with an AA test.

Written with StackEdit.

Bearded Beggarticks and Such

Spying a Harbinger of Spring, I step out in my Pink Lady’s Slipper

Onto a Lizard Tail.  Up I go, climbing Jabob’s Ladder

Until The rays of dawn lift the mist like Prairie Smoke through the forest.

The Swamp Candles wink out.  I breakfast on Butter and Eggs.


A Hound’s Tongue is like a Dragon’s Mouth here.

The Bleeding Hearts on Yellow Bedstraw beat without rhythm,

Hung up in Slender Ladies’ Tresses. 

I peer through Venus’ Looking Glass and see naught but dew.


My Goat’s Beard is wiry and stout, the admiration of even Indian Paintbrush

Which stands proud and stiff for the Queen Anne’s Lace.

Double, double, toil and trouble the Enchanter’s nightshade,

It makes a Marsh Mallow of a Bull Elephant’s Head


And once caught a Dutchman without his Britches.

Blog at WordPress.com.

Up ↑