<commit_before># Feature API

Etsy's Feature flagging API used for operational rampups and A/B
testing.

The Feature API is how we selectively enable and disable features at a
very fine grain as well as enabling features for a percentage of users
for operational ramp-ups and for A/B tests. A feature can be
completely enabled, completely disabled, or something in between and
can comprise a number of related variants.

For features that are not completely enabled or disabled, we log every
time we check whether a feature is enabled and include the result,
including what variant was selected, in the events we fire.

The two main API entry points are:

    Feature::isEnabled('my_feature')

which returns true when `my_feature` is enabled and, for multi-variant
features:

    Feature::variant('my_feature')

which returns the name of the particular variant which should be used.

The single argument to each of these methods is the name of the
feature to test.

A typical use of `Feature::isEnabled` for a single-variant feature
would look something like this:

    if (Feature::isEnabled('my_feature')) {
        // do stuff
    }

For a multi-variant feature, within the block guarded by the
`Feature::isEnabled` check, we can determine the appropriate code to
run for each variant with something like this:

    if (Feature::isEnabled('my_feature')) {

        switch (Feature::variant('my_feature')) {
          case 'foo':
              // do stuff appropriate for the foo variant
              break;
          case 'bar':
              // do stuff appropriate for the bar variant
              break;
        }
    }

It is an error (and will be logged as such) to ask for the variant of
a feature that is not enabled. So the calls to variant should always
be guarded by an `Feature::isEnabled` check.

The API also provides another pair of methods that will be used much
less frequently:

    Feature::isEnabledFor('my_feature', $user)

    Feature::variantFor('my_feature', $user)

These methods exist only to support a very specific use-case: when we
want to enable or disable a feature based not on the user making the
request but on some other user. The canonical case is if we wanted to
change something about how we deal with listings and instead of
enabling the feature for only some users but for all listings those
users see, but instead we want to enable it for all users but for only
some of the listings. Then we could use `isEnabledFor` and
`variantFor` and pass in the user object representing the owner of the
listing. In general it is much more likely you want to use the plain
old `isEnabled` and `variant` methods.

For Smarty templates, where static methods can’t readily be called,
there is an object, `$feature`, wired up in Tpl.php that exposes the
same four methods as the Feature API but as instance methods, for
instance:

    {% if $feature->isEnabled("my_feature") %}<commit_msg>Adding documentation of bucketingBy methods.<commit_after># Feature API

Etsy's Feature flagging API used for operational rampups and A/B
testing.

The Feature API is how we selectively enable and disable features at a
very fine grain as well as enabling features for a percentage of users
for operational ramp-ups and for A/B tests. A feature can be
completely enabled, completely disabled, or something in between and
can comprise a number of related variants.

For features that are not completely enabled or disabled, we log every
time we check whether a feature is enabled and include the result,
including what variant was selected, in the events we fire.

The two main API entry points are:

    Feature::isEnabled('my_feature')

which returns true when `my_feature` is enabled and, for multi-variant
features:

    Feature::variant('my_feature')

which returns the name of the particular variant which should be used.

The single argument to each of these methods is the name of the
feature to test.

A typical use of `Feature::isEnabled` for a single-variant feature
would look something like this:

    if (Feature::isEnabled('my_feature')) {
        // do stuff
    }

For a multi-variant feature, within the block guarded by the
`Feature::isEnabled` check, we can determine the appropriate code to
run for each variant with something like this:

    if (Feature::isEnabled('my_feature')) {

        switch (Feature::variant('my_feature')) {
          case 'foo':
              // do stuff appropriate for the foo variant
              break;
          case 'bar':
              // do stuff appropriate for the bar variant
              break;
        }
    }

It is an error (and will be logged as such) to ask for the variant of
a feature that is not enabled. So the calls to variant should always
be guarded by an `Feature::isEnabled` check.

The API also provides two other pairs of methods that will be used
much less frequently:

    Feature::isEnabledFor('my_feature', $user)

    Feature::variantFor('my_feature', $user)

and

    Feature::isEnabledBucketingBy('my_feature', $bucketingID)

    Feature::variantBucketingBy('my_feature', $bucketingID)

These methods exist only to support a couple very specific use-cases:
when we want to enable or disable a feature based not on the user
making the request but on some other user or when we want to bucket a
percentage of executions based on something entirely other than a
user.) The canonical case for the former, at Etsy, is if we wanted to
change something about how we deal with listings and instead of
enabling the feature for only some users but for all listings those
users see, but instead we want to enable it for all users but for only
some of the listings. Then we could use `isEnabledFor` and
`variantFor` and pass in the user object representing the owner of the
listing. That would also allow us to enable the feature for specific
listing owners. The `bucketingBy` methods serve a similar purpose
except when there either is no relevant user or where we don't want to
always put the same user in the same bucket. Thus if we wanted to
enable a certain feature for 10% of all listings displayed,
independent of both the user making the request and the user who owned
the listing, we could use `isEnabledBucketingBy` with the listing id
as the bucketing ID.

In general it is much more likely you want to use the plain old
`isEnabled` and `variant` methods.

For Smarty templates, where static methods can’t readily be called,
there is an object, `$feature`, wired up in Tpl.php that exposes the
same four methods as the Feature API but as instance methods, for
instance:

    {% if $feature->isEnabled("my_feature") %}
{'fraction_non_alphanumeric': 0.05213843131328397, 'fraction_numerical': 0.0003022517757291824, 'mean_word_length': 3.7956521739130435, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4343579', 'n_tokens_mistral': 1672, 'n_tokens_neox': 1605, 'n_words': 975}