White Labels
Can we do better?
Scalability
Will it hurt If tomorrow we asked to make 10 new white labels?
Problems:
- if (IS_BRAND_NAME) {...}
- BPF_FEATURE_ON(BMA_USE_TABBAR_MENU). Is it on?
- Ambiguous hierarchy of application classes
- Responsibilities and hierarchy of .xcconfigs
- Same vs separate repositories
How do we check brand?
- IS_HUGGLE macro - used 116 times
- [BPFApplication isHuggleBrand] - used 3 times
- BMAGlobals.isHuggle - used 2 times
Let's agree on one!
Styling
- string constants
- color constants
- images
Behaviour
- additional/restricted behavior
- navigation differences
- brand specific bug fixes
- location permissions differences.
What we use it for?
if (IS_HUGGLE) {
self.loadingView = [[HUGLoadingScreenView alloc] initWithFrame:self.view.bounds videoLoadingPreferred:self.videoLoadingPreferred];
} else {
self.loadingView = [[BMALoadingScreenView alloc] initWithFrame:self.view.bounds];
}
Brand specific implementation
Instead, check for feature:
if (BMA_FEATURE_ON(USING_DOTS_SPASH_SCREEN)) {
self.loadingView = [[BMADotsLoadingScreenView alloc] initWithFrame:self.view.bounds videoLoadingPreferred:self.videoLoadingPreferred];
} else {
self.loadingView = [[BMALoadingScreenView alloc] initWithFrame:self.view.bounds];
}
Check for brand:
if (IS_HUGGLE) {
styleInfo = @{
kBMAFlatSegmentedControlSelectionColor : [BMAStyleSheet colorForHuggleBlueColor],
kBMAFlatSegmentedControlTitleSelectedColor : [BMAStyleSheet colorForHuggleBlueColor],
kBMAFlatSegmentedControlUnderscoreLineColor : [BMAStyleSheet colorForHuggleSeparator],
};
} else {
...
}
Brand styling
Instead, private BMAStyleSheet subclasses:
Brand hardcoded into method signature:
styleInfo = @{
kBMAFlatSegmentedControlSelectionColor : [BMAStyleSheet segmentedControlSelectionColor],
kBMAFlatSegmentedControlTitleSelectedColor : [BMAStyleSheet segmentedControlTitleSelectedColor],
kBMAFlatSegmentedControlUnderscoreLineColor : [BMAStyleSheet segmentedControlUnderscoreLineColor],
};
if (IS_HUGGLE) {
return @[
@(BMAUserCollectionViewCellBadgeTypeNewPerson),
@(BMAUserCollectionViewCellBadgeTypeMatched),
@(BMAUserCollectionViewCellBadgeTypeCommonPlace),
];
} else {
return @[
@(BMAUserCollectionViewCellBadgeTypeMatched),
@(BMAUserCollectionViewCellBadgeTypeBumpedInto),
@(BMAUserCollectionViewCellBadgeTypeCommonPlace),
];
}
Exceptional brand specific logic
Still convertible to feature based:
Brand based badge priorities:
if (BMA_FEATURE_ON(NEW_PEOPLE)) {
[priorities addObject:@(BMAUserCollectionViewCellBadgeTypeNewPerson)];
}
[priorities addObject:@(BMAUserCollectionViewCellBadgeTypeMatched)];
if (BMA_FEATURE_ON(BUMPED_INTO)) {
[priorities addObject:@(BMAUserCollectionViewCellBadgeTypeBumpedInto)];
}
[priorities addObject:@(BMAUserCollectionViewCellBadgeTypeCommonPlace)];
BPF_FEATURE_ON(BMA_USE_TABBAR_MENU)
How do we check that a feature is on?
Suggestion: define static feature instead
let tabBarMenuFeature: BPFFeature = {
let feature = BPFFeature(title: "Using Tab Bar Menu",
group: "UI",
key: "com.bma.using.tab.menu")
feature.onByDefault = BPFApplication.isHuggleBrand()
return feature
}()
public extension BPFFeature {
public class func tabBarMenu() -> BPFFeature {
return tabBarMenuFeature
}
}
[brandBasedFeatures addObject:[BPFFeature tabBarMenu]];
BMA_FEATURE_ON([BPFFeature tabBarMenu].key);
Ambiguous hierarchy of application classes
@protocol BPFApplicationInterface <NSObject>
...
@end
@interface BPFApplication : NSObject <BPFApplicationInterface>
...
@end
@interface BMABaseApplication : BPFApplication // most of the things here
@end
@interface HUGApplication : BPFApplication
@end
@interface BMABadooApplication : BMABaseApplication // empty implementation
@end
@interface HONApplication : BMABaseApplication
@end
Does white label require application subclass?
Huggle derives all features from Badoo by default, but why it is different in the code?
Suggestion: move Badoo only code, fix Huggle superclass
Responsibilities and hierarchy of .xcconfigs
NSString *const BCFileUtilsTestFairyAppID = @"BPFTestFairyIdentifier";
NSString *testFairyAppIdentifier = [BCFileUtils infoEntryForKey:BCFileUtilsTestFairyAppID];
"
Unsafe usage of base configuration
FACEBOOK_APPID | |
---|---|
base.xcconfig | 12312312323 |
hon.xcconfig | 54645645645 |
FACEBOOK_APPID | |
---|---|
base.xcconfig | N/A |
badoo.xcconfig | 12312312323 |
hon.xcconfig | 54645645645 |
Suggestion: use .xcconfigs for required keys, move rest into the code
Same
Pros:
+ all code is shared by default
+ separate workspaces available if needed
Separate
Pros:
+ no one brakes white label code
+ release whenever we want
Repositories for white labels
Cons:
- no code is shared by default
- versioning system needed for using shared code
Cons:
- base app changes brakes white labels
- the release process is not ready for multiple release branches
Take out:
- use features instead of is_brand_name
- make white labeling process safer, faster and cleaner by:
- improving discoverability of checking if a feature is enabled for a brand. [BPFeature usingTabBarMenu]?
- sorting out BMAStyleSheet. Class cluster?
- sorting out base classes.
- sorting out .xcconfigs (extracting configuration code)
Extra points: get rid of CocoaPods for platform code?
White Labels
By borlov
White Labels
- 1,342