Home

Awesome

shoutout

A clojure library that's a direct port of jamesgolick's rollout

Usage

Available from clojars

Initialize a shoutout (just a bundle of storage and group definitions):

(shoutout my-storage)

You'll need to provide shoutout with your own storage, but that part is relatively simple. See the relevant readme section

Check if a feature is active for a particular user:

(active? my-shoutout my-user)

You can activate features using three different mechanisms: percentages, groups and by the user's id

Groups

Your users might fit into different categories. A project management site might, for example, have admin users and normal users for individual projects.

You can activate the all group for the chat feature like this:

(activate-group shoutout "chat" "all")

(note that group and feature names are both always strings)

To define your own groups, pass group definitions to shoutout when initializing it:

(shoutout storage
  {"admin" (fn [user] (contains (:roles user) "admin"))})

You can activate multiple groups per feature

Deactivate groups like this:

(deactivate-group shoutout "chat" "all")

Specific Users

You might want to let a specific user into a beta or something, even if they aren't in your formal beta testers group:

(activate-user shoutout "chat" user)

Deactivate them like this:

(deactivate-user shoutout "chat" user)

Note that user-specific stuff relies on the HasUserId protocol, see below for more on that.

User Percentages

If you're rolling out a new feature, you might want to test the waters by slowly enabling it for a percentage of your users:

(activate-percentage shoutout "chat" 20)

The algorith for determining which users get let in is this:

(< (mod (crc32 (user-id user)) 100) percentage)

So for 20%, roughly 20% of your users should be let in

This again relies on HasUserId

Deactivate percentages like this:

(activate-percentage shoutout "chat" 0)

Feature is broken

If a feature is broken, you can deactivate it for everybody at once:

(deactivate shoutout "chat")

Storage

Unlike rollout, shoutout is completely storage agnostic. You'll have to implement your own storage backend, which implements ShoutoutStorage. The storage protocol has two functions, read-from-storage, and write-to-storage, both of which should be simple enough to implement. Both deal purely with serialized strings, and string keys, shoutout does the serialization logic itself.

The library provides an in memory store (used for testing) that you could look at for an example.

There is also an example store that uses apache curator's zookeeper NodeCache as a storage backend - so feature checks are purely in memory lookups, but backed by persistent, CP storage. That's located here for now: shoutout zookeeper store

Namespacing

Shoutout separates its keys from other keys in the data store by prefixing all keys with shoutout_feature

Various storages have namespacing faciltiies for prefixing keys as well - if you need further namespacing, be sure to use those.

HasUserId

HasUserId is a protocol that solves the following problem:

When checking if a user is a member of a group, we often want a full database record, or a map, or something domain specific. But when it comes to checking if a user should be active in a percentage, or if the specific user is active, we really just want a string.

Likely you will need to implement this protocol for whatever type your application uses for "users". Your user-id function has to return a string, and that string shout be unique for each "user" (otherwise you'll likely end up turning on features for more users than you think you should be).

Here's a rough implementation for datomic's Entity class, as an example:

(extend-type datomic.Entity HasUserId
  (user-id [entity] (:db/id entity)))

Things this libary doesn't handle, and won't ever deal with

In larger organizations, you'll likely want some kind of audit trail for your feature flags. Shoutout doesn't provide this kind of facility, it's designed for smaller places. You can start to get somewhere like that by using a storage (datomic for example) that keeps history for you, but that won't help you identify who changed which feature flags.

Modification is (potentially) very racy. It depends on the backing store. In many many places this likely won't matter (I've never been bitten by it), but it's something to be aware of if you're likely to have more than a few folk modifying shoutout storage at once.

License

Copyright © 2014 Tom Crayford

Distributed under the Eclipse Public License version 1.0