Pachinko
is a feature toggle library for iOS & OSX that aims to keep the technical debt associated with feature switching to a minimum whilst leaving you plenty of flexibility.
Pachinko
is still very much an experiment and a work in progress. Please feel free to contribute and help make it better.
- Add feature toggles to your app using the provided
BaseFeature
class or extend and define your own - Create toggles with binary on/off switching or add bespoke conditional logic with one or more
FeaturePredicate
closures - Encapsulate your feature predicates and group them in a
ToggleCondition<T>
- Optionally group feature toggles into a
FeatureContext
you define that is meaningful to your app to make them easier to manage - Implement your own
FeatureSource
to provideFeatureToggle
status. - You can use a PLIST, a remote API call to your app's server backend, CoreData, Realm or all of the above.
FeatureSource
is source-agnostic and defers to you on how best to implement toggle status information.
Pachinko
is provided as a Swift 2.0 dynamic framework which you embed in your app project. Embedded frameworks are supported only from iOS8 onwards.
- iOS 8.0+ | Mac OSX 10.9+
- Xcode 7.0+
To integrate Pachinko
into your Xcode project using Carthage, add the following to your local Cartfile
:
github "cloudofpoints/pachinko" ~> 1.0.2
Stay tuned - CocoaPods support to follow soon 😳
- Optionally define a
FeatureContext
to group your feature toggles together for easier lifecycle management and general admin :
let myLoginContext = FeatureContext(name: "UserLogin",
synopsis: "Features related to user login")
-
Instantiate a unique
FeatureSignature
for eachFeature
. This signature will act as the link between theFeature
and the matchingFeatureToggle
.FeatureSignature
conforms to the SwiftHashable
protocol -
Note that each
FeatureSignature
is versioned to make it easier to manage updates to deployedFeatures
let myNewUserLoginSignature = FeatureSignature(id: "FA8F9F0A-5BDA-4105-A177-E7992A22D643",
versionId: FeatureVersion("1.0.0"),
name: "NewUserLoginFeature",
synopsis: "A/B testing for new user greeting")
-
Implement a
FeatureSource
that will return aConditionalFeature
for a specifiedFeatureContext
andFeatureSignature
. -
A
FeatureSource
could encapsulate device local resources such as a JSON file, a PLIST,NSUserDefaults
, CoreData, a Realm file or payloads from a remote API or indeed a composite of any or all of the above. -
Instantiate a
FeatureToggle
corresponding to eachFeature
you wish to execute conditionally. Compose eachFeatureToggle
with yourFeatureSource
implementation.
let myNewUserLoginToggle = FeatureToggle(context: myLoginContext,
signature: myNewUserLoginSignature,
featureSource: myStubFeatureSource)
-
Optionally bind one or more
ToggleCondition<T>
instances to yourFeatureToggle
to inject the evaluation of an added layer of conditional logic over and above determining whether or not theFeatureStatus
of your toggle isActive
. -
The array of
FeaturePredicate
closures for any individualToggleCondition<T>
instance are reduced to a singleBoolean
output by applying a logicalAND
operation across the entire array. -
If you choose not to bind any
ToggleCondition<T>
instances, yourFeatureToggle
becomes a simple on/off switch driven by theFeatureStatus
value.
myNewUserLoginToggle.bindFeaturePredicates([ToggleCondition<UserProfile>(sampleUserProfile)
{userProfile in userProfile.isNewUser() && userProfile.location == UserLocation.EU}
])
-
Apply your
FeatureToggle
instance to wrap the relevant feature in your app. -
Combine
FeatureToggle
instances to support A/B feature logic
if myNewUserLoginToggle.shouldExecuteFeature() {
print("Executing new user login feature --> A Feature")
// Your A/B testing 'A' feature code
} else if myOtherNewUserLoginToggle.shouldExecuteFeature() {
print("Executing new user login feature --> B Feature")
// Your A/B testing 'B' feature code
} else {
print("Neither the A or the B test feature were executed")
}
This project is licensed under the terms of the BSD-3 license. See the LICENSE file.