GithubHelp home page GithubHelp logo

skylab's Introduction

This library is no longer being maintained. You can continue to use SkyLab in your projects, but we recommend switching another solution whenever you have the opportunity.

SkyLab

Multivariate & A/B Testing for iOS and Mac

SkyLab is a backend-agnostic framework for multivariate and A/B testing.

Test conditions are persisted across sessions and launches using NSUserDefaults, ensuring that every user will have a consistent experience, no matter which testing bucket they end up in.

SkyLab integrates easily into any existing statistics web service. Depending on your particular needs, this may include posting to an endpoint in test blocks, or perhaps setting an HTTP header for a shared API client.

Requests for integration with any particular backend are heartily encouraged.

This project is part of a series of open source libraries covering the mission-critical aspects of an iOS app's infrastructure. Be sure to check out its sister projects: GroundControl, CargoBay, houston, and Orbiter.

Usage

Check out the included example project to see everything in action.

Simple A/B Test

[SkyLab abTestWithName:@"Title" A:^{
    self.titleLabel.text = NSLocalizedString(@"Hello, World!", nil);
} B:^{
    self.titleLabel.text = NSLocalizedString(@"Greetings, Planet!", nil);
}];

Split Test with Weighted Probabilities

You can pass either an NSDictionary (with values representing the weighted probability of their corresponding key) or an NSArray (with each value having an equal chance of being chosen) into the choices parameter.

[SkyLab splitTestWithName:@"Subtitle" conditions:@{
    @"Red" : @(0.15),
    @"Green" : @(0.10),
    @"Blue" : @(0.50),
    @"Purple" : @(0.25)
} block:^(id choice) {
    self.subtitleLabel.text = NSLocalizedString(@"Please Enjoy This Colorful Message", nil);

    if ([choice isEqualToString:@"Red"]) {
        self.subtitleLabel.textColor = [UIColor redColor];
    } else if ([choice isEqualToString:@"Green"]) {
        self.subtitleLabel.textColor = [UIColor greenColor];
    } else if ([choice isEqualToString:@"Blue"]) {
        self.subtitleLabel.textColor = [UIColor blueColor];
    } else if ([choice isEqualToString:@"Purple"]) {
        self.subtitleLabel.textColor = [UIColor purpleColor];
    }
}];

Multivariate Test

[SkyLab multivariateTestWithName:@"Switches" variables:@{
    @"Left" : @(0.5),
    @"Center" : @(0.5),
    @"Right" : @(0.5)
 } block:^(NSSet *activeVariables) {
     self.leftSwitch.on = [activeVariables containsObject:@"Left"];
     self.centerSwitch.on = [activeVariables containsObject:@"Center"];
     self.rightSwitch.on = [activeVariables containsObject:@"Right"];
}];

License

SkyLab is available under the MIT license. See the LICENSE file for more info.

skylab's People

Contributors

abrahamvegh avatar aburgel avatar alistra avatar gregkrsak avatar mattt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

skylab's Issues

splitTestWithName triggers NSUserDefaultsDidChangeNotification every time it's called

It looks like:

    if ([choices isKindOfClass:[NSArray class]]) {
        if (!choice || ![choices containsObject:choice]) {
            choice = SLRandomValueFromArray(choices);
        }
    } else if ([choices isKindOfClass:[NSDictionary class]]) {
        if (!choice || ![[choices allKeys] containsObject:choice]) {
            choice = SLRandomKeyFromDictionaryWithWeightedValues(choices);
        }
    } else {
        @throw [NSException exceptionWithName:NSInvalidArgumentException reason:NSLocalizedString(@"Parameter `choices` must be either array or dictionary", nil) userInfo:nil];
    }

    [[NSUserDefaults standardUserDefaults] setObject:choice forKey:SLUserDefaultsKeyForTestName(name)];
    [[NSUserDefaults standardUserDefaults] synchronize];

should change to:

    if ([choices isKindOfClass:[NSArray class]]) {
        if (!choice || ![choices containsObject:choice]) {
            choice = SLRandomValueFromArray(choices);
        }
        [[NSUserDefaults standardUserDefaults] setObject:choice forKey:SLUserDefaultsKeyForTestName(name)];
        [[NSUserDefaults standardUserDefaults] synchronize];
    } else if ([choices isKindOfClass:[NSDictionary class]]) {
        if (!choice || ![[choices allKeys] containsObject:choice]) {
            choice = SLRandomKeyFromDictionaryWithWeightedValues(choices);
        }
        [[NSUserDefaults standardUserDefaults] setObject:choice forKey:SLUserDefaultsKeyForTestName(name)];
        [[NSUserDefaults standardUserDefaults] synchronize];
    } else {
        @throw [NSException exceptionWithName:NSInvalidArgumentException reason:NSLocalizedString(@"Parameter `choices` must be either array or dictionary", nil) userInfo:nil];
    }

It looks like the same pattern is used in multivariateTestWithName:variables:block as well.

We ran across this because we were calling splitTestWithName:choices:block: from inside tableView:cellForRowAtIndexPath: and noticed repeated NSUserDefaultsDidChangeNotifications in the logs. Granted, that's not a great way to use it and we've refactored.

Please let me know if you'd rather have a pull request.

Add documentation about backend integration

It would be nice to hear thoughts on how to integration with a backend. Not about how to do network requests, but things like should I just read keys out of NSUserDefaults, what should I do with them to make a meaningful conclusion?

I also didn't see an API for recording outcomes (positive/negative). How do you handle that?

Thanks

Synchronous AB tests with SkyLab

All of SkyLab's methods rely on blocks -- which is a great structure for control-flow between tests. Things look a little strange, though, once you want something synchronously. ie,

- (BOOL)showNewFancyButton 
{
     BOOL showNewFancyButton;
    [SkyLab abTestWithName:@"ShowNewFancyButton" A:^{
        showNewFancyButton = YES;
    } B:^{
        showNewFancyButton = NO;
    }]

    return showNewFancyButton;
}

Looking at the implementation of SkyLab, the above code will work just fine, but we thought it's a little weird to rely on blocks to run synchronously (even though we know the implementation does).

Do you think it'd be cool for SkyLabs to have non-block counterparts to its block-based methods? Or would you just suggest doing synchronous operations like above?

about @[ @"A", @"B" ]

Thank first. I am already using SkyLab and GroundControl.

It makes life easy to init a array or dictionary using @[] or @{}. But it will be a problem for those whose XCode is still under 4.2. I encountered this problem.

In the code you init a array using this:

@[ @"A", @"B" ]

would you please change it to [NSArray arrayWithObjects:@"A", @"B", nil]?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.