AttributeLuke Smith@ls_n
You know this stuffmodel.get(“id”);overlay.set(“visible”, true);var drag = new Y.DD.Drag({    node: “#dragme”});
You know this stuffBakery.ATTRS = {     flour: {         value: “pastry”     },     ...};
What is an attribute? Encapsulation of a value state and set of feature configurations for customizing logic associated wit...
What is an attribute?      Object property + magic
The magic• What it is• Why we need it• Where it comes from• How it works• What it costs• Is it worth it?
The magic• What it is• Why we need it• Where it comes from• How it works• What it costs• “Should I use a property or an at...
What is the magic?
What is the magic?• getters• setters• default values• change events
ES5 has magicObject.defineProperties(this, {   flour: {     value: “pastry”,     getter: ...     setter: ...     ...
ES5 has magic ... exceptIE6 IE7 IE8
ES5 has magic ... exceptIE6 IE7 IE8          * Dear old IE, please die in a fire.
So, here we areobj.get(“attr”);obj.set(“attr”, “I’m needed, thanks IE!”);
Why do we want magic?
Why do we want magic?  Properties are dumb
Why do we want magic?1. Properties are dumb2. Maintenance
Where is the magic?
The Classes         (all the things)           Y.Base
The Classes                 (all the things)                   Y.Base    Y.BaseCore              Y.BaseObservable   Y.AE
The Classes                     (all the things)                       Y.Base     Y.BaseCore                 Y.BaseObserva...
The Classes                     (all the things)                       Y.Base     Y.BaseCore                 Y.BaseObserva...
The Modules                     (all the things)                         base    base-core                  base-observabl...
The Modules                      (all the things)                          base     base-core                  base-observ...
The Modules Y.AttributeCore    Y.AttributeObservable   attribute-core    attribute-observable
Y.AttributeCoreobj.get(name);obj.set(name, value);obj.getAttrs(); // see docsobj.setAttrs({ vals });
Y.AttributeCoreClass.ATTRS = { configs }; // sort ofobj.addAttr(name, { config }, lazy?);obj.addAttrs({ configs }, { values }...
Y.AttributeObservablebakery.on(“flourChange”, callback);bakery.after(“flourChange”, callback);bakery.once(...);bakery.addTar...
Creating attributesOne at a time bakery.addAttr(“flour”, {       setter: “_setFlour”,       value: “whole wheat” });
Creating attributesA bunch at a timebakery.addAttrs({      flour: {           setter: “_setFlour”,           value: “whole ...
Creating attributesStatically for a class Bakery.ATTRS = {       flour: {         setter: “_setFlour”,         value: “whol...
How does the magic work?
Configurations• value        • valueFn• getter       • validator• setter       • readOnly               • writeOnce        ...
Configurations• value        • valueFn                • broadcast• getter       • validator              •   cloneDefaultVa...
value and valueFn• Most expensive• lazyAdd = true to defer cost• valueFn always called at instantiation
lazyAdd• Minimal setup, no set()• Full setup on first call to get() or set()• Some might never get fully setup (good)• Y.Ba...
setter for robustness• Use for  a) Input normalization, or  b) Tightly coupled state related logic• Not for side effects (...
setter vs validator• validator is called before setter• If you have a setter, validate inline_setFlour: function (val) {  ...
getter, setter, etc• Pass string values to late bind handlersflour: {   setter : “_setFlour” // this._setFlour(val)   gette...
cloneDefaultValue• {undefined, true, “deep”}, “shallow”, false• Y.Base defaults Y.clone() behavior• Always set or use a val...
Change events•   For decoupling systems•   Why custom events have on() and after()•   Assigning initial value does NOT fire...
Ad hoc attributes•   From Y.BaseCore•   Create dynamic objects with Attribute API•   prototype._allowAdHocAttrs = true•   ...
Ad hoc attributesBakery.prototype._allowAdHocAttrs = true;var llamaBakery = new Bakery({    flour: “pastry”,    llamas: “sh...
What does the magic cost?
Magic taxes1. Attribute setup cost2. get()/set() cost     *Many Bothans died to bring us this information
Attribute setup
Attribute setup1. Creates State object
Attribute setup1. Creates State object2. Depth 2 copy of configs
Attribute setup1. Creates State object2. Depth 2 copy of configs3. Gets value from construction values,   valueFn, or value
Attribute setup1. Creates State object2. Depth 2 copy of configs3. Gets value from construction values,   valueFn, or value...
Attribute setup1. Creates State object2. Depth 2 copy of configs3. Gets value from construction values,   valueFn, or value...
Attribute setup                 LOC   fn calls no attributes   34       9  +lazy attr     +46    +14 +empty attr     +56  ...
Base setup
Base setup1. Creates State object
Base setup1. Creates State object2. Aggregates ATTRS up superclass chain
Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call...
Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call...  1. class extension cons...
Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call...  1. class extension cons...
Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call...  1. class extension cons...
Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call...  1. class extension cons...
Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call...  1. class extension cons...
get()1. Checks if attribute is lazy, inits if necessary2. Gets the value and getter from State3. Returns value or result o...
get()                 LOC    fn calls   get(attr)      10       6 get(sub.attr)   +3       +5   +getter       +2       +1 ...
set()  http://yuilibrary.com/yui/docs/attribute/setflow.html
set() - just attribute                 LOC    fn calls   set(attr)      80      20 set(sub.attr)   +27      +4  +lazy init...
set() - events                  LOC    fn calls   set(attr)       80      20 set(sub.attr)    +27      +4+change event    ...
Avoid Subattributesobj.set(“nested.sub.attribute”, false);• Triggered by . in attribute name• A lot of extra work, most is...
Is the magic worth it?Should you use a property or an attribute?
Property           PROs                CONs•   Fast                 •   Dumb•   Terse                •   Can’t migrate to ...
Attribute          PROs                   CONs•   Stable abstraction    •   Slow•   Code organization     •   Nested struc...
Property or Attribute?• Will it be accessed a lot? Like, really A LOT.• Will there be lots of instances? (see #1)• Will it...
Property or Attribute?   Justify the use of properties             rather than  justifying the use of attributes    (It’s ...
The Future
Attribute          PROs                   CONs•   Stable abstraction    •   Slow•   Code organization     •   Nested struc...
Faster; no new features
Faster; no new features• Replace State with ES5 objects or shim
Faster; no new features• Replace State with ES5 objects or shim• Compile configs once for all instances
Faster; no new features• Replace State with ES5 objects or shim• Compile configs once for all instances• Event optimizations
kittens + pancakes = future
The End.             Thanks!Luke Smith@ls_n
Attribute
Attribute
Upcoming SlideShare
Loading in …5
×

Attribute

1,798 views

Published on

Demystifying the magic behind YUI 3 Attributes. A look at what's there, how it's broken down, what you can do, what you should and shouldn't do, and some help in answering the question "should I use a property or an attribute?"

0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,798
On SlideShare
0
From Embeds
0
Number of Embeds
37
Actions
Shares
0
Downloads
13
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • modeling DOM\n
  • modeling DOM\n
  • modeling DOM\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • AttributeCore ATTRS less restrictive than Base\n
  • \n
  • \n
  • \n
  • \n
  • You can also use obj.set(‘unknown’, val) and setAttrs({ ... }); but they will be magicless\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • “Be conservative in what you send, liberal in what you accept”\nsetter code creep = serving multiple masters\n
  • \n
  • You can find this in the API docs, but I want to strongly recommend\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • cloneDefaultValue for obj values during aggregation\naddAttrs() called with the aggregated configs for that class\naddAttrs() applies user values - Attribute ignores user values for unknown attrs\naddAttrs() calls Y.merge() on user value hash, so once for each level\n
  • cloneDefaultValue for obj values during aggregation\naddAttrs() called with the aggregated configs for that class\naddAttrs() applies user values - Attribute ignores user values for unknown attrs\naddAttrs() calls Y.merge() on user value hash, so once for each level\n
  • cloneDefaultValue for obj values during aggregation\naddAttrs() called with the aggregated configs for that class\naddAttrs() applies user values - Attribute ignores user values for unknown attrs\naddAttrs() calls Y.merge() on user value hash, so once for each level\n
  • cloneDefaultValue for obj values during aggregation\naddAttrs() called with the aggregated configs for that class\naddAttrs() applies user values - Attribute ignores user values for unknown attrs\naddAttrs() calls Y.merge() on user value hash, so once for each level\n
  • cloneDefaultValue for obj values during aggregation\naddAttrs() called with the aggregated configs for that class\naddAttrs() applies user values - Attribute ignores user values for unknown attrs\naddAttrs() calls Y.merge() on user value hash, so once for each level\n
  • cloneDefaultValue for obj values during aggregation\naddAttrs() called with the aggregated configs for that class\naddAttrs() applies user values - Attribute ignores user values for unknown attrs\naddAttrs() calls Y.merge() on user value hash, so once for each level\n
  • cloneDefaultValue for obj values during aggregation\naddAttrs() called with the aggregated configs for that class\naddAttrs() applies user values - Attribute ignores user values for unknown attrs\naddAttrs() calls Y.merge() on user value hash, so once for each level\n
  • cloneDefaultValue for obj values during aggregation\naddAttrs() called with the aggregated configs for that class\naddAttrs() applies user values - Attribute ignores user values for unknown attrs\naddAttrs() calls Y.merge() on user value hash, so once for each level\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Similarly, if you capture the object returned from get(‘nested’), you can set its properties whenever.\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • It’s not just a numbers game - maintenance, future proofing\n
  • \n
  • and remember, you’re talking about giving up all those yummy features\n
  • \n
  • \n
  • result in the cost being replaced by kittens making you pancakes\n
  • result in the cost being replaced by kittens making you pancakes\n
  • result in the cost being replaced by kittens making you pancakes\n
  • result in the cost being replaced by kittens making you pancakes\n
  • \n
  • \n
  • Attribute

    1. 1. AttributeLuke Smith@ls_n
    2. 2. You know this stuffmodel.get(“id”);overlay.set(“visible”, true);var drag = new Y.DD.Drag({ node: “#dragme”});
    3. 3. You know this stuffBakery.ATTRS = { flour: { value: “pastry” }, ...};
    4. 4. What is an attribute? Encapsulation of a value state and set of feature configurations for customizing logic associated with the mutation and storage of that state, while providing opportunities to monitor changes.
    5. 5. What is an attribute? Object property + magic
    6. 6. The magic• What it is• Why we need it• Where it comes from• How it works• What it costs• Is it worth it?
    7. 7. The magic• What it is• Why we need it• Where it comes from• How it works• What it costs• “Should I use a property or an attribute?”
    8. 8. What is the magic?
    9. 9. What is the magic?• getters• setters• default values• change events
    10. 10. ES5 has magicObject.defineProperties(this, { flour: { value: “pastry”, getter: ... setter: ... ...
    11. 11. ES5 has magic ... exceptIE6 IE7 IE8
    12. 12. ES5 has magic ... exceptIE6 IE7 IE8 * Dear old IE, please die in a fire.
    13. 13. So, here we areobj.get(“attr”);obj.set(“attr”, “I’m needed, thanks IE!”);
    14. 14. Why do we want magic?
    15. 15. Why do we want magic? Properties are dumb
    16. 16. Why do we want magic?1. Properties are dumb2. Maintenance
    17. 17. Where is the magic?
    18. 18. The Classes (all the things) Y.Base
    19. 19. The Classes (all the things) Y.Base Y.BaseCore Y.BaseObservable Y.AE
    20. 20. The Classes (all the things) Y.Base Y.BaseCore Y.BaseObservable Y.AE Y.AttributeCore Y.AttributeObservable
    21. 21. The Classes (all the things) Y.Base Y.BaseCore Y.BaseObservable Y.AE Y.AttributeCore Y.AttributeObservable Y.State Y.EventTarget
    22. 22. The Modules (all the things) base base-core base-observable a-extras attribute-core attribute-observable (attribute-core) event-custom-complex
    23. 23. The Modules (all the things) base base-core base-observable a-extras Y.AttributeCore attribute-core Y.AttributeObservable attribute-observable (attribute-core) event-custom-complex
    24. 24. The Modules Y.AttributeCore Y.AttributeObservable attribute-core attribute-observable
    25. 25. Y.AttributeCoreobj.get(name);obj.set(name, value);obj.getAttrs(); // see docsobj.setAttrs({ vals });
    26. 26. Y.AttributeCoreClass.ATTRS = { configs }; // sort ofobj.addAttr(name, { config }, lazy?);obj.addAttrs({ configs }, { values }, lazy?);obj.attrAdded(name);
    27. 27. Y.AttributeObservablebakery.on(“flourChange”, callback);bakery.after(“flourChange”, callback);bakery.once(...);bakery.addTarget(...); // etc.
    28. 28. Creating attributesOne at a time bakery.addAttr(“flour”, { setter: “_setFlour”, value: “whole wheat” });
    29. 29. Creating attributesA bunch at a timebakery.addAttrs({ flour: { setter: “_setFlour”, value: “whole wheat” }, ...});
    30. 30. Creating attributesStatically for a class Bakery.ATTRS = { flour: { setter: “_setFlour”, value: “whole wheat” } });
    31. 31. How does the magic work?
    32. 32. Configurations• value • valueFn• getter • validator• setter • readOnly • writeOnce • lazyAdd http://yuilibrary.com/yui/docs/attribute/#configuration
    33. 33. Configurations• value • valueFn • broadcast• getter • validator • cloneDefaultValue• setter • readOnly • writeOnce • lazyAdd http://yuilibrary.com/yui/docs/attribute/#configuration
    34. 34. value and valueFn• Most expensive• lazyAdd = true to defer cost• valueFn always called at instantiation
    35. 35. lazyAdd• Minimal setup, no set()• Full setup on first call to get() or set()• Some might never get fully setup (good)• Y.BaseCore defaults lazyAdd = true for all (override with prototype._lazyAddAttrs)• Beware lazyAdd + setter
    36. 36. setter for robustness• Use for a) Input normalization, or b) Tightly coupled state related logic• Not for side effects (use events)• setter + lazyAdd gotcha
    37. 37. setter vs validator• validator is called before setter• If you have a setter, validate inline_setFlour: function (val) { return (typeof val === “string”) ? val.toLowerCase() : Y.Attribute.INVALID_VALUE;
    38. 38. getter, setter, etc• Pass string values to late bind handlersflour: { setter : “_setFlour” // this._setFlour(val) getter : “_getFlour”, validator: “_validateFlour”, valueFn : “_initFlour”,
    39. 39. cloneDefaultValue• {undefined, true, “deep”}, “shallow”, false• Y.Base defaults Y.clone() behavior• Always set or use a valueFn insteadflour: { value: { grain: ‘fine’, gluten: false, ... }, cloneDefaultValue: true,
    40. 40. Change events• For decoupling systems• Why custom events have on() and after()• Assigning initial value does NOT fire event• Change event published on first set()
    41. 41. Ad hoc attributes• From Y.BaseCore• Create dynamic objects with Attribute API• prototype._allowAdHocAttrs = true• static _NON_ATTRS_CFG to blacklist
    42. 42. Ad hoc attributesBakery.prototype._allowAdHocAttrs = true;var llamaBakery = new Bakery({ flour: “pastry”, llamas: “sheared” // unknown, but added});
    43. 43. What does the magic cost?
    44. 44. Magic taxes1. Attribute setup cost2. get()/set() cost *Many Bothans died to bring us this information
    45. 45. Attribute setup
    46. 46. Attribute setup1. Creates State object
    47. 47. Attribute setup1. Creates State object2. Depth 2 copy of configs
    48. 48. Attribute setup1. Creates State object2. Depth 2 copy of configs3. Gets value from construction values, valueFn, or value
    49. 49. Attribute setup1. Creates State object2. Depth 2 copy of configs3. Gets value from construction values, valueFn, or value4. lazyAdd attributes are stowed in State
    50. 50. Attribute setup1. Creates State object2. Depth 2 copy of configs3. Gets value from construction values, valueFn, or value4. lazyAdd attributes are stowed in State5. non-lazy populate State and set(value)
    51. 51. Attribute setup LOC fn calls no attributes 34 9 +lazy attr +46 +14 +empty attr +56 +16+attr property +7 +0 +value +80 +20 +valueFn +3 +1
    52. 52. Base setup
    53. 53. Base setup1. Creates State object
    54. 54. Base setup1. Creates State object2. Aggregates ATTRS up superclass chain
    55. 55. Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call...
    56. 56. Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call... 1. class extension constructors
    57. 57. Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call... 1. class extension constructors 2. addAttrs with filtered list from ATTRS aggregate
    58. 58. Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call... 1. class extension constructors 2. addAttrs with filtered list from ATTRS aggregate 3. initializer
    59. 59. Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call... 1. class extension constructors 2. addAttrs with filtered list from ATTRS aggregate 3. initializer 4. class extension initializers
    60. 60. Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call... 1. class extension constructors 2. addAttrs with filtered list from ATTRS aggregate 3. initializer 2.5. addAttrs(ad-hocs) 4. class extension initializers
    61. 61. get()1. Checks if attribute is lazy, inits if necessary2. Gets the value and getter from State3. Returns value or result of calling getter
    62. 62. get() LOC fn calls get(attr) 10 6 get(sub.attr) +3 +5 +getter +2 +1 +lazy init +100 +20
    63. 63. set() http://yuilibrary.com/yui/docs/attribute/setflow.html
    64. 64. set() - just attribute LOC fn calls set(attr) 80 20 set(sub.attr) +27 +4 +lazy init +100 +20 +validator +5 +1 +setter +6 +1
    65. 65. set() - events LOC fn calls set(attr) 80 20 set(sub.attr) +27 +4+change event +151 +24 +first event +100 +12+per subscriber +27 +5 +per bubble +205 +21
    66. 66. Avoid Subattributesobj.set(“nested.sub.attribute”, false);• Triggered by . in attribute name• A lot of extra work, most is wasted• Confusing relationship with getter/setter * sorry about this
    67. 67. Is the magic worth it?Should you use a property or an attribute?
    68. 68. Property PROs CONs• Fast • Dumb• Terse • Can’t migrate to attribute w/o API• Nested structs are breakage the same• Magic allowed if environment mandated
    69. 69. Attribute PROs CONs• Stable abstraction • Slow• Code organization • Nested structs are awkward• Consistent API (subattributes--)• Easy loose coupling • More typing with events• Abstraction performance can improve invisibly
    70. 70. Property or Attribute?• Will it be accessed a lot? Like, really A LOT.• Will there be lots of instances? (see #1)• Will it be public, or interesting outside the object?• Might the class be extended? Plugged?• Would it amount to a micro-optimization?
    71. 71. Property or Attribute? Justify the use of properties rather than justifying the use of attributes (It’s less likely to bite you in the ass)
    72. 72. The Future
    73. 73. Attribute PROs CONs• Stable abstraction • Slow• Code organization • Nested structs are awkward• Consistent API (subattributes--)• Easy loose coupling • More typing with events• Abstraction performance can improve invisibly
    74. 74. Faster; no new features
    75. 75. Faster; no new features• Replace State with ES5 objects or shim
    76. 76. Faster; no new features• Replace State with ES5 objects or shim• Compile configs once for all instances
    77. 77. Faster; no new features• Replace State with ES5 objects or shim• Compile configs once for all instances• Event optimizations
    78. 78. kittens + pancakes = future
    79. 79. The End. Thanks!Luke Smith@ls_n

    ×