Attribute

  • 1,149 views
Uploaded 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 …

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?"

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,149
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
10
Comments
0
Likes
6

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    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

Transcript

  • 1. AttributeLuke Smith@ls_n
  • 2. You know this stuffmodel.get(“id”);overlay.set(“visible”, true);var drag = new Y.DD.Drag({ node: “#dragme”});
  • 3. You know this stuffBakery.ATTRS = { flour: { value: “pastry” }, ...};
  • 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. What is an attribute? Object property + magic
  • 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. 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. What is the magic?
  • 9. What is the magic?• getters• setters• default values• change events
  • 10. ES5 has magicObject.defineProperties(this, { flour: { value: “pastry”, getter: ... setter: ... ...
  • 11. ES5 has magic ... exceptIE6 IE7 IE8
  • 12. ES5 has magic ... exceptIE6 IE7 IE8 * Dear old IE, please die in a fire.
  • 13. So, here we areobj.get(“attr”);obj.set(“attr”, “I’m needed, thanks IE!”);
  • 14. Why do we want magic?
  • 15. Why do we want magic? Properties are dumb
  • 16. Why do we want magic?1. Properties are dumb2. Maintenance
  • 17. Where is the magic?
  • 18. The Classes (all the things) Y.Base
  • 19. The Classes (all the things) Y.Base Y.BaseCore Y.BaseObservable Y.AE
  • 20. The Classes (all the things) Y.Base Y.BaseCore Y.BaseObservable Y.AE Y.AttributeCore Y.AttributeObservable
  • 21. The Classes (all the things) Y.Base Y.BaseCore Y.BaseObservable Y.AE Y.AttributeCore Y.AttributeObservable Y.State Y.EventTarget
  • 22. The Modules (all the things) base base-core base-observable a-extras attribute-core attribute-observable (attribute-core) event-custom-complex
  • 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. The Modules Y.AttributeCore Y.AttributeObservable attribute-core attribute-observable
  • 25. Y.AttributeCoreobj.get(name);obj.set(name, value);obj.getAttrs(); // see docsobj.setAttrs({ vals });
  • 26. Y.AttributeCoreClass.ATTRS = { configs }; // sort ofobj.addAttr(name, { config }, lazy?);obj.addAttrs({ configs }, { values }, lazy?);obj.attrAdded(name);
  • 27. Y.AttributeObservablebakery.on(“flourChange”, callback);bakery.after(“flourChange”, callback);bakery.once(...);bakery.addTarget(...); // etc.
  • 28. Creating attributesOne at a time bakery.addAttr(“flour”, { setter: “_setFlour”, value: “whole wheat” });
  • 29. Creating attributesA bunch at a timebakery.addAttrs({ flour: { setter: “_setFlour”, value: “whole wheat” }, ...});
  • 30. Creating attributesStatically for a class Bakery.ATTRS = { flour: { setter: “_setFlour”, value: “whole wheat” } });
  • 31. How does the magic work?
  • 32. Configurations• value • valueFn• getter • validator• setter • readOnly • writeOnce • lazyAdd http://yuilibrary.com/yui/docs/attribute/#configuration
  • 33. Configurations• value • valueFn • broadcast• getter • validator • cloneDefaultValue• setter • readOnly • writeOnce • lazyAdd http://yuilibrary.com/yui/docs/attribute/#configuration
  • 34. value and valueFn• Most expensive• lazyAdd = true to defer cost• valueFn always called at instantiation
  • 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. 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. 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. getter, setter, etc• Pass string values to late bind handlersflour: { setter : “_setFlour” // this._setFlour(val) getter : “_getFlour”, validator: “_validateFlour”, valueFn : “_initFlour”,
  • 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. 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. Ad hoc attributes• From Y.BaseCore• Create dynamic objects with Attribute API• prototype._allowAdHocAttrs = true• static _NON_ATTRS_CFG to blacklist
  • 42. Ad hoc attributesBakery.prototype._allowAdHocAttrs = true;var llamaBakery = new Bakery({ flour: “pastry”, llamas: “sheared” // unknown, but added});
  • 43. What does the magic cost?
  • 44. Magic taxes1. Attribute setup cost2. get()/set() cost *Many Bothans died to bring us this information
  • 45. Attribute setup
  • 46. Attribute setup1. Creates State object
  • 47. Attribute setup1. Creates State object2. Depth 2 copy of configs
  • 48. Attribute setup1. Creates State object2. Depth 2 copy of configs3. Gets value from construction values, valueFn, or value
  • 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. 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. 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. Base setup
  • 53. Base setup1. Creates State object
  • 54. Base setup1. Creates State object2. Aggregates ATTRS up superclass chain
  • 55. Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call...
  • 56. Base setup1. Creates State object2. Aggregates ATTRS up superclass chain3. for each class call... 1. class extension constructors
  • 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. 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. 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. 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. 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. get() LOC fn calls get(attr) 10 6 get(sub.attr) +3 +5 +getter +2 +1 +lazy init +100 +20
  • 63. set() http://yuilibrary.com/yui/docs/attribute/setflow.html
  • 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. 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. 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. Is the magic worth it?Should you use a property or an attribute?
  • 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. 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. 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. 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. The Future
  • 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. Faster; no new features
  • 75. Faster; no new features• Replace State with ES5 objects or shim
  • 76. Faster; no new features• Replace State with ES5 objects or shim• Compile configs once for all instances
  • 77. Faster; no new features• Replace State with ES5 objects or shim• Compile configs once for all instances• Event optimizations
  • 78. kittens + pancakes = future
  • 79. The End. Thanks!Luke Smith@ls_n