erichoracek / Motif

Lightweight and customizable stylesheets for iOS

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Naming

erichoracek opened this issue · comments

/cc @fcanas

I'm trying to think of the best naming scheme for the project. Right now it's the following:

  • AUTTheme Container of:
    • AUTThemeConstant - Named constant mapped to values
    • AUTThemeClass - Named container that maps named properties to values (The property → value mappings are internally instances of AUTThemeConstant)
  • AUTThemeApplier Responsible for applying a theme to objects, via the applyClassWithName:toObject: method
  • <AUTThemeClassApplicable> Protocol defining a generic interface for applying a AUTThemeClass to an object. A set of these are used internally by AUTThemeApplier to apply a theme to an object
    • AUTThemeClassApplier Applier invoked when a class is applied to an object
    • AUTThemeClassPropertyApplier Applier invoked with a specific property is applied to an object
    • AUTThemeClassPropertiesApplier Applier invoked when a set of properties are applied to an object

I'm also somewhat unhappy about the naming of the blocks that are executed to actually perform the mapping of a property/class onto a object. Right now they're named AUTTheme...ApplierBlock. However, in my mind, the "Applier" is the object responsible for applying the theme, but there also needs to be a word that corresponds to the function that performs the mapping of the theme class/properties onto an object, which is what the applierBlock is right now. Do you have any ideas of what they should be named? I'm thinking maybe:

  • ThemeApplier (performs the application of a theme onto a object from a specified class name)
  • ThemeClassApplication (performs the application of a instance of a theme class onto an object)
  • Application (a function that maps a property value / class value onto an object)

The syntax would then be:

typedef void (^AUTThemePropertyApplication)(id propertyValue, id applicant);

+ (id <AUTThemeClassApplicable>)aut_registerThemeProperty:(NSString *)property application:(AUTThemePropertyApplication)application;

Starting from the top: I think AUTTheme, AUTThemeConstant, and AUTThemeClass make sense together. I question "constant". I get that it's constant, but I'm not sure that's the most salient feature of that entity. I'll offer up "value", "symbol", "namedValue" -- I think it'll work as is, but something to think about. It may even change the API a bit if it turns out to better-represent something else...

AUTThemeApplier is hard to swallow. I think having this broken out into its own object is the kind of thing I love to do and some people will pick on as over-engineering. When making an API, and wanting to do more of what Apple does vs. what Sun did to Java, it might make sense to keep its implementation separate, but the interface consolidated with AUTTheme.

Another (drastically different) approach to AUTThemeApplier is a bit more drastic and take a functional approach. Make the type a block signature, and you ask a theme for an applier for class:

self.buttonApplier = self.theme;
buttonApplier(button);

... maybe I've been writing too much Swift.

In either case, "Applier" is an awkward word, and "Theme" doesn't carry any meaning here. Maybe things would be simplified by introducing the word "Style".

Before reading the rest of this, think about how you might use "Style" before polluting your mind with my rough proposal of terms below.


A Theme is loosely a collection of Styles. A Style (noun) can style (verb) things (that's pretty weird). Or possibly that a style can be applied to objects. Meaning that we could be left with a AUTStyle, or a AUTStyler, or a StyleApplier, of which I favor the first if it's going to be a class not a type of function.

So you might say

AUTTheme *buttonTheme = [self.theme styleForClass:@"somethingThatsProbablyASymbolSomewhere"];
[buttonTheme applyToObject:button];

Which then leads me to wonder : Should Classes apply themselves?

AUTClass *primaryButtonClass = [self.theme classNamed:@"primaryButton"];
[primaryButtonClass applyToObject:button];

If we can get the word "Applier" to no longer be so overloaded, then maybe applierBlock becomes more comfortable because it's not competing with all the other "Applier" concepts.

Totally agreed on the overuse and contradictions of "applier"/"apply" in the API. It just smells off, and I think you've nicely summed the underlying reasons that make it feel that way. According to the Apple dictionary, "applier" isn't actually even a word! However, "Styler" isn't much better either, but I think is is technically a word.. The question is how to reconcile this...

One thing I am quite partial to is the concept of a "class applier" object being returned by the +[NSObject aut_registerApplier... set of APIs, as that nicely encompasses the transactionality of the API. I modeled this off of the + (id<AspectToken>)aspect_hookSelector... APIs in Aspects. In my opinion, this theming API is very similar in style to the aspect-oriented paradigm that that project is enabling (adding an additional behavior that is represented by an object that conforms to a protocol, and can later be deregistered). However, this API isn't really something that most people would use—the standard use case is just to throw away the value—it just makes for a nice API design.

As for "style"—I actually previously used "style" in the previous implementation of this framework as a verb (applyStyle...), but decided to go against it in this incarnation as it doesn't feel like the correct word to encompass an entire set of styles (AUTStyle feels like a single component's style, vs. AUTTheme, which feels like a proper theme for the entire interface on an app). Following from that, it felt strange to have "style" in the project in addition to "theme", as it creates some ambiguity for first-time API consumer when trying to figure out the difference.

I really like the idea of having an AUTThemeClass being responsible for applying itself. Unfortunately, this results in an API issue when you want to have the same theme application API able to enable dynamic theming. If the AUTThemeClass were responsible for dynamic theming, it would have to become mutable to be able to re-apply a different theme to the same object (or you'd have to pass around multiple themes). Either situation feels strange to me. Can you think of a solution to this?

As it is now, the reason that the AUTThemeApplier class exists is three-fold:

  • The sole interface with which you apply a theme class to an object.
  • The object that must be passed around when initializing view controllers (which I believe is the correct way to propagate styles through an app)
  • Enabling dynamic theming. A consumer is able to change its theme property, which results the objects that had a previous theme class applied to them subsequently have the identically-named classes re-applied to them from the new theme (what happens in the dynamic theming project when you hit the "refresh" icon in the upper right).

As is, I feel like this is a really solid abstraction and simple-enough API to enable dynamic theming. IMO, it's enough to remain separated out into a separate class. I'm struggling to find something that makes dynamic theming simpler than this now:

NSURL *themeURL =  [[NSBundle mainBundle] URLForResource:@"Theme" withExtension:@"json"];
AUTTheme *theme = [[AUTTheme alloc] initWithURL:themeURL];
AUTThemeApplier *applier = [[AUTThemeApplier alloc] initWithTheme:theme];
[applier applyClassWithName:@"button" toObject:self.button];

// Sometime later...

AUTTheme *newTheme = [AUTTheme new];
applier.theme = newTheme;
// This re-applies the "button" class from the new theme to self.button

Perhaps just a better verb/noun cluster is needed than "to apply"/"applier"? "to map"/"mapper" is the correct operation in my mind, but I'm not sure a "mapper" is an improvement whatsoever from an understandability perspective (nor an existence perspective!). "to paint"/"painter" makes sense, but isn't the correct concept for theme (you don't paint a theme!) "to set"/"setter" kind of works, but doesn't evoke the correct image in my mind (setting a theme doesn't feel like it will apply it). This is why I landed on "apply", but it's not the best—the big question in my mind is if there is anything better... thoughts?