SlideShare a Scribd company logo
1 of 78
Download to read offline
SOSUiComponents
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Alternative titles:
Lessons learned from UiComponents
or
My own best practices for UiComponents
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
I'm assuming you have at least a (very)
basic understanding of
— require.js
— Knockout.js
— jQuery UI Widgets
— UiComponents
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
UiComponents
So what is the problem?
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
For me grokking UiComponents was one
of the hardest things
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
It still takes me a long time to do some
things that I expect to be quick
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
I try to understand UiComponents mainly
by reading code
Reading Code > Reading Docs
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
So I try to optimize code for reading
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
This talk
1. A little bit of whining
2. General advice on readable code
3. View state management
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Three issues I frequently encounter:
1. High cognitive load
2. Duplication of knowledge
3. State is coupled to the DOM
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
If it was my job...
..to fix UiComponents
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Cognitive load
Super verbose declaration
(no sane defaults)
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Cognitive load
Mixing of concepts
(Knockout.js and jQuery UI Widgets)
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Cognitive load
Inconsistent use in core
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Self
Documenting
CodeSOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Rules I try to apply to code I write.
When working with the core code...
well, it is what it is.
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
4 Rules of simple design by Kent Beck:
1. Passes all tests
2. Reveals intent
3. No duplication
4. Fewest elements
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Passes all tests
The code has to work.
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Reveals intent
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Reveals intent
Good naming
— Descriptive base class names
— Intent of functions, not
implementation
— Descriptive properties and variables
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Reveals intent
bad:
interface ButtonProviderInterface
{
/**
* Retrieve button-specified settings
*
* @return array
*/
public function getButtonData();
}
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Reveals intent
because:
public function getButtonData()
{
// ...
return [
'label' => __('Save'),
'class' => 'save primary',
'data_attribute' => [
'mage-init' => [
'buttonAdapter' => [
'actions' => [
[
'targetName' => 'product_form.product_form',
'actionName' => 'save',
'params' => [false]
]
]
]
]
],
'class_name' => Container::SPLIT_BUTTON,
'options' => $this->getOptions(),
];
}
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Reveals intent
better:
interface ButtonProviderInterface
{
public function getLabel();
public function getCssClassNames();
public function getActions();
...
}
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Reveals intent
bad:
{
getSortOrder: function () {
return this.order;
}
}
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Reveals intent
good:
{
isDescending: function() {
return this.order === SORT_DESC;
},
isAscending: function() {
return this.order === SORT_ASC;
}
}
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Reveals intent
Try to use a style familiar to
the most likely reader
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Reveals intent
Favor UiComponent JSON over XML
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Reveals intent
<item name="progressBar" xsi:type="array">
<item name="sortOrder" xsi:type="string">0</item>
<item name="component" xsi:type="string">Magento_Checkout/js/view/progress-bar</item>
<item name="displayArea" xsi:type="string">progressBar</item>
<item name="config" xsi:type="array">
<item name="deps" xsi:type="array">
<item name="0" xsi:type="string">checkout.steps.shipping-step.shippingAddress</item>
<item name="1" xsi:type="string">checkout.steps.billing-step.payment</item>
</item>
</item>
</item>
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Reveals intent
{
"progressBar": {
"component": "Magento_Checkout/js/view/progress-bar",
"sortOrder": 0,
"displayArea": "progressBar",
"config": {
"deps": [
"checkout.steps.shipping-step.shippingAddress",
"checkout.steps.billing-step.payment"
]
}
}
}
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
Keep knowledge in one place
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
Duplication is a common problem in M2
EAV, DataInterfaces, UiComponents,
GraphQL, ...
How does it apply in the view layer?
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
Avoid selectors in view models
loginFormSelector = 'form[data-role=email-with-possible-login]',
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
:'-(
miniCart.sidebar({
'targetElement': 'div.block.block-minicart',
'button': {
'checkout': '#top-cart-btn-checkout',
'remove': '#mini-cart a.action.delete',
'close': '#btn-minicart-close'
},
'showcart': {
'parent': 'span.counter',
'qty': 'span.counter-number',
'label': 'span.counter-label'
},
'minicart': {
'list': '#mini-cart',
'content': '#minicart-content-wrapper',
'qty': 'div.items-total',
'subtotal': 'div.subtotal span.price'
},
'item': {
'qty': ':input.cart-item-qty',
'button': ':button.update-cart-item'
}
});
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
If selectors are required?
Keep the definition and the configuration
as close as possible,
ideally in the same file
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
DOM selector declaration and config
<div data-bind="scope: 'foo'">
<div data-role="message-container">...</div>
</div>
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app": {
"components": {
"foo": {
"component": "MyCompany_MyModule/js/view/foo",
"containerSelector": "div[data-role=message-container]"
}
}
}
}
}
</script>
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
UiComponent selector declaration and config
<div data-bind="scope: 'messages'">
...
</div>
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app": {
"components": {
"messages": {
"component": "Magento_Theme/js/view/messages"
}
}
}
}
}
</script>
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
Keep knowledge in one file and close together.
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app": {
"components": {
"appRoot": {
"component": "My_Module/js/root"
"children": {
"thingA": {
"component: "My_Module/js/thing-a"
},
"thingB": {
"component: "My_Module/js/thing-b",
"sibling":" "thingA"
}
}
}
}
}
}
}
</script>
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
Injecting DOM-Nodes is better
E.g. with a custom binding:
<div data-bind="scope: 'myViewModel', bindDomNode: true">
</div>
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
Custom binding handler declaration:
define(['ko'], function(ko) {
'use strict';
ko.bindingHandlers.bindDomNode = {
init: function(element, valueAccessor, _a, _b, bindingContext) {
if (valueAccessor()) {
bindingContext.$data.domNode = element;
}
}
};
});
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
No duplication
Example access of injected DOM node the view model:
this.domNode.getBoundingClientRect();
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Fewest elements
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Fewest elements
If something works,
expresses intent
and contains no duplicate knowledge,
don't split it further
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Fewest elements
The Single Responsibility Principle is not
the Single Public Method Principle.
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Fewest elements
If things are related, keep them together.
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Managing
State
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Context: Magento <= 2.2.2
Not a SPA/PWA
SRP with several frontend "components",
each with its own more or less
independent state.
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
We have three options.
1. Keep state in the DOM or
UiComponents
2. Pass state from root down to children
3. Keep state outside of the view
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Example TicTacToe
https://github.com/Vinai/example-module-tictactoe
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Example TicTacToe
Shamelessly stolen from https://reactjs.org/tutorial/tutorial.html
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Example TicTacToe
Simple example for each approach to
managing shared state:
https://github.com/Vinai/example-module-tictactoe
$ git branch
* 0-in-component-state
1-pass-to-children
2-external-state
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
1. Keep state in the DOM or
UiComponents
E.g. jQuery or pure Knockout.js
Only for simplest, single component cases
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
1. State in the DOM
How is state stored in the DOM?
— Form element values
— CSS classes (e.g. "active" or "invalid")
— Inline styles (e.g. "display: none")
— Element attributes (e.g. disabled)
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
1. State in the DOM
DOM state storage is common with jQuery
self.element.off('submit');
// disable 'Add to Cart' button
addToCartButton = $(form).find(this.options.addToCartButtonSelector);
addToCartButton.prop('disabled', true);
addToCartButton.addClass(this.options.addToCartButtonDisabledClass);
form.submit();
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
1. State in UiComponents
Properties on the knockout view model
Shared state: imports, exports, links
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
1. State in UiComponents
Component.extend({
defaults: {
links: {
squares: '${ $.provider }:squares'
},
imports: {
xIsNext: '${ $.provider }:xIsNext',
winner: '${ $.provider }:winner'
}
},
square: function () {
return this.squares[this.squareIndex];
}
handleClick: function () {
const square = this.square();
if ('' === square() && !this.winner) {
square(this.xIsNext ? 'X' : 'O');
}
}
});
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
1. Shared state in DOM or UiComponents
Strong coupling through
cross-component dependencies
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
1. Derived state
In this approach state derived from one
model is o!en stored in another model
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
1. Derived State
updateFoo: function() {
this.foo = this.other.bar * this.other.bar;
}
// vs.
foo: function() {
return this.other.bar * this.other.bar;
}
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
2. Pass state from root down to children
E.g. pure react components
Works within one component hierarchy
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
2. Example from React TicTacToe
<Board
squares={current.squares}
onClick={i => this.handleClick(i)}
/>
class Board extends React.Component {
renderSquare(i) {
return (
<Square
value={this.props.squares[i]}
onClick={() => this.props.onClick(i)}
/>
);
}
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
2. Pass state from root down to children
Problem when state is required outside
one hierarchy
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
2. Pass state from root down to children
Not common in Magento 2
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
2. Pass state from root down to children
No callback on parent, only on child
Component.extend({
initContainer: function (parent) {
const state = parent.state;
this.cells = [...state.squares.keys()].map(function (i) {
return new Square({index: i, state: state});
});
return this._super(parent);
}
...
}
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
3. Keep state outside the view
E.g. Elm architecture, flux, redux/vuex
Most versatile but needs more plumbing
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
3. Keep state outside the view
There are differences:
Naming, (im)mutability, 1 or 2 way data
flow, (F)RP, effects handling, amount of
architecture...
But there always is a single state storage
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
3. Separate state with UiComponents
State object with observable properties
define(['ko'], function (ko) {
'use strict';
return ko.track({
moves: [],
squares: [...Array(9).keys()].map(() => ko.observable('')),
xIsNext: true,
winner: false
});
});
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
3. Separate state with UiComponents
Require and use state container object
define(
['uiComponent', 'ticTacToeState'],
function (Component, state) {
'use strict';
return Component.extend({
...
handleClick: function () {
if ('' === this.value() && !state.winner) {
state.squares[this.index](state.xIsNext ? 'X' : 'O');
}
},
});
}
);
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Example Breakout
https://github.com/Vinai/example-module-breakout
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
3. Multiple state storage objects
define(
['gameComponent', 'ballState', 'frameState', 'gameState'],
function (GameComponent, ball, frame, game) {
'use strict';
return GameComponent.extend({
initialize: function () {
this._super();
this.initDimensions(frame);
frame.width = function () {
return game.width * .98;
};
frame.height = function () {
return game.height * .80;
};
frame.left = function () {
return game.width * .01;
};
frame.top = function () {
return game.height * .19;
};
},
...
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
3. State outside the view
Benefits:
— State is simple to share
— View models contain mostly only logic
— Less code
— Easier to understand
— More maintainable
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Recommendations
for maintainable UiComponents...
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
The code needs to...
1. Pass all tests
2. Reveal intent
3. Contain no duplication
4. Have the fewest possible elements
5. Separate shared state from the view
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
Thanks to Kent Beck for his timeless
4 rules of simple design.
Thank you for your attention!
SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018

More Related Content

Similar to SOS UiComponents

Magento 2 TDD Code Kata Intro
Magento 2 TDD Code Kata IntroMagento 2 TDD Code Kata Intro
Magento 2 TDD Code Kata Introvinaikopp
 
Funnel Analysis with Apache Spark and Druid
Funnel Analysis with Apache Spark and DruidFunnel Analysis with Apache Spark and Druid
Funnel Analysis with Apache Spark and DruidDatabricks
 
Becoming Certified - MageTitansMCR 2018
Becoming Certified - MageTitansMCR 2018Becoming Certified - MageTitansMCR 2018
Becoming Certified - MageTitansMCR 2018vinaikopp
 
Strategies for the seamless deployment of travel diary collection systems to ...
Strategies for the seamless deployment of travel diary collection systems to ...Strategies for the seamless deployment of travel diary collection systems to ...
Strategies for the seamless deployment of travel diary collection systems to ...Adrian C. Prelipcean
 
Let's understand Data Science
Let's understand Data Science Let's understand Data Science
Let's understand Data Science Sachin Rastogi
 
Preserving a Web of Linked Data: Lessons and challenges from a fading web
Preserving a Web of Linked Data: Lessons and challenges from a fading webPreserving a Web of Linked Data: Lessons and challenges from a fading web
Preserving a Web of Linked Data: Lessons and challenges from a fading webMiel Vander Sande
 
Developing web applications in 2010
Developing web applications in 2010Developing web applications in 2010
Developing web applications in 2010Ignacio Coloma
 
Digital cultural heritage spring 2015 day 3
Digital cultural heritage spring 2015 day 3Digital cultural heritage spring 2015 day 3
Digital cultural heritage spring 2015 day 3Stefano A Gazziano
 
Debugging - things your senior hasn't told you about
Debugging - things your senior hasn't told you aboutDebugging - things your senior hasn't told you about
Debugging - things your senior hasn't told you aboutCarola Nitz
 
Contribution day guide. MM19ES 2019
Contribution day guide. MM19ES 2019Contribution day guide. MM19ES 2019
Contribution day guide. MM19ES 2019Oleksii Korshenko
 
App Indexing & Mobile SEO - Friends of Search 2016
App Indexing & Mobile SEO - Friends of Search 2016App Indexing & Mobile SEO - Friends of Search 2016
App Indexing & Mobile SEO - Friends of Search 2016MobileMoxie
 
Architecture in-the-small-slides
Architecture in-the-small-slidesArchitecture in-the-small-slides
Architecture in-the-small-slidesvinaikopp
 
Geek Moot '09 -- Multilang Implemenatation
Geek Moot '09 -- Multilang ImplemenatationGeek Moot '09 -- Multilang Implemenatation
Geek Moot '09 -- Multilang ImplemenatationTed Kulp
 
Optimizing Spark-based data pipelines - are you up for it?
Optimizing Spark-based data pipelines - are you up for it?Optimizing Spark-based data pipelines - are you up for it?
Optimizing Spark-based data pipelines - are you up for it?Itai Yaffe
 
Get Into Open Source
Get Into Open SourceGet Into Open Source
Get Into Open SourceJoe Sepi
 
Single page applications & SharePoint
Single page applications & SharePointSingle page applications & SharePoint
Single page applications & SharePointFabio Franzini
 
INRA @ Scilab Conference 2018
INRA @ Scilab Conference 2018INRA @ Scilab Conference 2018
INRA @ Scilab Conference 2018Scilab
 
Writing Testable Code (for Magento 1 and 2) 2016 Romaina
Writing Testable Code (for Magento 1 and 2)  2016 RomainaWriting Testable Code (for Magento 1 and 2)  2016 Romaina
Writing Testable Code (for Magento 1 and 2) 2016 Romainavinaikopp
 
UXDX Berlin - Test & Deploy, by Quentin Berder, President, WiredCraft
UXDX Berlin - Test & Deploy, by Quentin Berder, President, WiredCraftUXDX Berlin - Test & Deploy, by Quentin Berder, President, WiredCraft
UXDX Berlin - Test & Deploy, by Quentin Berder, President, WiredCraftUXDXConf
 

Similar to SOS UiComponents (20)

Magento 2 TDD Code Kata Intro
Magento 2 TDD Code Kata IntroMagento 2 TDD Code Kata Intro
Magento 2 TDD Code Kata Intro
 
Funnel Analysis with Apache Spark and Druid
Funnel Analysis with Apache Spark and DruidFunnel Analysis with Apache Spark and Druid
Funnel Analysis with Apache Spark and Druid
 
Becoming Certified - MageTitansMCR 2018
Becoming Certified - MageTitansMCR 2018Becoming Certified - MageTitansMCR 2018
Becoming Certified - MageTitansMCR 2018
 
Strategies for the seamless deployment of travel diary collection systems to ...
Strategies for the seamless deployment of travel diary collection systems to ...Strategies for the seamless deployment of travel diary collection systems to ...
Strategies for the seamless deployment of travel diary collection systems to ...
 
Let's understand Data Science
Let's understand Data Science Let's understand Data Science
Let's understand Data Science
 
Preserving a Web of Linked Data: Lessons and challenges from a fading web
Preserving a Web of Linked Data: Lessons and challenges from a fading webPreserving a Web of Linked Data: Lessons and challenges from a fading web
Preserving a Web of Linked Data: Lessons and challenges from a fading web
 
Developing web applications in 2010
Developing web applications in 2010Developing web applications in 2010
Developing web applications in 2010
 
Digital cultural heritage spring 2015 day 3
Digital cultural heritage spring 2015 day 3Digital cultural heritage spring 2015 day 3
Digital cultural heritage spring 2015 day 3
 
Debugging - things your senior hasn't told you about
Debugging - things your senior hasn't told you aboutDebugging - things your senior hasn't told you about
Debugging - things your senior hasn't told you about
 
Contribution day guide. MM19ES 2019
Contribution day guide. MM19ES 2019Contribution day guide. MM19ES 2019
Contribution day guide. MM19ES 2019
 
Real_World_0days.pdf
Real_World_0days.pdfReal_World_0days.pdf
Real_World_0days.pdf
 
App Indexing & Mobile SEO - Friends of Search 2016
App Indexing & Mobile SEO - Friends of Search 2016App Indexing & Mobile SEO - Friends of Search 2016
App Indexing & Mobile SEO - Friends of Search 2016
 
Architecture in-the-small-slides
Architecture in-the-small-slidesArchitecture in-the-small-slides
Architecture in-the-small-slides
 
Geek Moot '09 -- Multilang Implemenatation
Geek Moot '09 -- Multilang ImplemenatationGeek Moot '09 -- Multilang Implemenatation
Geek Moot '09 -- Multilang Implemenatation
 
Optimizing Spark-based data pipelines - are you up for it?
Optimizing Spark-based data pipelines - are you up for it?Optimizing Spark-based data pipelines - are you up for it?
Optimizing Spark-based data pipelines - are you up for it?
 
Get Into Open Source
Get Into Open SourceGet Into Open Source
Get Into Open Source
 
Single page applications & SharePoint
Single page applications & SharePointSingle page applications & SharePoint
Single page applications & SharePoint
 
INRA @ Scilab Conference 2018
INRA @ Scilab Conference 2018INRA @ Scilab Conference 2018
INRA @ Scilab Conference 2018
 
Writing Testable Code (for Magento 1 and 2) 2016 Romaina
Writing Testable Code (for Magento 1 and 2)  2016 RomainaWriting Testable Code (for Magento 1 and 2)  2016 Romaina
Writing Testable Code (for Magento 1 and 2) 2016 Romaina
 
UXDX Berlin - Test & Deploy, by Quentin Berder, President, WiredCraft
UXDX Berlin - Test & Deploy, by Quentin Berder, President, WiredCraftUXDX Berlin - Test & Deploy, by Quentin Berder, President, WiredCraft
UXDX Berlin - Test & Deploy, by Quentin Berder, President, WiredCraft
 

More from vinaikopp

Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023vinaikopp
 
Hyvä: Compatibility Modules
Hyvä: Compatibility ModulesHyvä: Compatibility Modules
Hyvä: Compatibility Modulesvinaikopp
 
Hyvä from a developer perspective
Hyvä from a developer perspectiveHyvä from a developer perspective
Hyvä from a developer perspectivevinaikopp
 
Property Based Testing in PHP
Property Based Testing in PHPProperty Based Testing in PHP
Property Based Testing in PHPvinaikopp
 
Property based testing - MageTestFest 2019
Property based testing - MageTestFest 2019Property based testing - MageTestFest 2019
Property based testing - MageTestFest 2019vinaikopp
 
ClojureScript in Magento 2 - PHPUGMRN
ClojureScript in Magento 2 - PHPUGMRNClojureScript in Magento 2 - PHPUGMRN
ClojureScript in Magento 2 - PHPUGMRNvinaikopp
 
Magento 2 TDD Code Kata
Magento 2 TDD Code KataMagento 2 TDD Code Kata
Magento 2 TDD Code Katavinaikopp
 
Testing Magento 2
Testing Magento 2Testing Magento 2
Testing Magento 2vinaikopp
 
ClojureScript in Magento 2 - MageTitansMCR 2017
ClojureScript in Magento 2 - MageTitansMCR 2017ClojureScript in Magento 2 - MageTitansMCR 2017
ClojureScript in Magento 2 - MageTitansMCR 2017vinaikopp
 
Lizards & Pumpkins Catalog Replacement at mm17de
Lizards & Pumpkins Catalog Replacement at mm17deLizards & Pumpkins Catalog Replacement at mm17de
Lizards & Pumpkins Catalog Replacement at mm17devinaikopp
 
Stories from the other side
Stories from the other sideStories from the other side
Stories from the other sidevinaikopp
 
Writing Testable Code (for Magento 1 and 2)
Writing Testable Code (for Magento 1 and 2)Writing Testable Code (for Magento 1 and 2)
Writing Testable Code (for Magento 1 and 2)vinaikopp
 
Writing testable Code (MageTitans Mini 2016)
Writing testable Code (MageTitans Mini 2016)Writing testable Code (MageTitans Mini 2016)
Writing testable Code (MageTitans Mini 2016)vinaikopp
 
Getting your Hands Dirty Testing Magento 2 (at London Meetup)
Getting your Hands Dirty Testing Magento 2 (at London Meetup)Getting your Hands Dirty Testing Magento 2 (at London Meetup)
Getting your Hands Dirty Testing Magento 2 (at London Meetup)vinaikopp
 
Getting your hands dirty testing Magento 2 (at MageTitansIT)
Getting your hands dirty testing Magento 2 (at MageTitansIT)Getting your hands dirty testing Magento 2 (at MageTitansIT)
Getting your hands dirty testing Magento 2 (at MageTitansIT)vinaikopp
 
Modern Module Architecture
Modern Module ArchitectureModern Module Architecture
Modern Module Architecturevinaikopp
 
The beautiful Magento module - MageTitans 2014
The beautiful Magento module - MageTitans 2014The beautiful Magento module - MageTitans 2014
The beautiful Magento module - MageTitans 2014vinaikopp
 

More from vinaikopp (17)

Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023
 
Hyvä: Compatibility Modules
Hyvä: Compatibility ModulesHyvä: Compatibility Modules
Hyvä: Compatibility Modules
 
Hyvä from a developer perspective
Hyvä from a developer perspectiveHyvä from a developer perspective
Hyvä from a developer perspective
 
Property Based Testing in PHP
Property Based Testing in PHPProperty Based Testing in PHP
Property Based Testing in PHP
 
Property based testing - MageTestFest 2019
Property based testing - MageTestFest 2019Property based testing - MageTestFest 2019
Property based testing - MageTestFest 2019
 
ClojureScript in Magento 2 - PHPUGMRN
ClojureScript in Magento 2 - PHPUGMRNClojureScript in Magento 2 - PHPUGMRN
ClojureScript in Magento 2 - PHPUGMRN
 
Magento 2 TDD Code Kata
Magento 2 TDD Code KataMagento 2 TDD Code Kata
Magento 2 TDD Code Kata
 
Testing Magento 2
Testing Magento 2Testing Magento 2
Testing Magento 2
 
ClojureScript in Magento 2 - MageTitansMCR 2017
ClojureScript in Magento 2 - MageTitansMCR 2017ClojureScript in Magento 2 - MageTitansMCR 2017
ClojureScript in Magento 2 - MageTitansMCR 2017
 
Lizards & Pumpkins Catalog Replacement at mm17de
Lizards & Pumpkins Catalog Replacement at mm17deLizards & Pumpkins Catalog Replacement at mm17de
Lizards & Pumpkins Catalog Replacement at mm17de
 
Stories from the other side
Stories from the other sideStories from the other side
Stories from the other side
 
Writing Testable Code (for Magento 1 and 2)
Writing Testable Code (for Magento 1 and 2)Writing Testable Code (for Magento 1 and 2)
Writing Testable Code (for Magento 1 and 2)
 
Writing testable Code (MageTitans Mini 2016)
Writing testable Code (MageTitans Mini 2016)Writing testable Code (MageTitans Mini 2016)
Writing testable Code (MageTitans Mini 2016)
 
Getting your Hands Dirty Testing Magento 2 (at London Meetup)
Getting your Hands Dirty Testing Magento 2 (at London Meetup)Getting your Hands Dirty Testing Magento 2 (at London Meetup)
Getting your Hands Dirty Testing Magento 2 (at London Meetup)
 
Getting your hands dirty testing Magento 2 (at MageTitansIT)
Getting your hands dirty testing Magento 2 (at MageTitansIT)Getting your hands dirty testing Magento 2 (at MageTitansIT)
Getting your hands dirty testing Magento 2 (at MageTitansIT)
 
Modern Module Architecture
Modern Module ArchitectureModern Module Architecture
Modern Module Architecture
 
The beautiful Magento module - MageTitans 2014
The beautiful Magento module - MageTitans 2014The beautiful Magento module - MageTitans 2014
The beautiful Magento module - MageTitans 2014
 

Recently uploaded

Strategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsStrategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsJean Silva
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...Bert Jan Schrijver
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesVictoriaMetrics
 
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...kalichargn70th171
 
Osi security architecture in network.pptx
Osi security architecture in network.pptxOsi security architecture in network.pptx
Osi security architecture in network.pptxVinzoCenzo
 
SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?Alexandre Beguel
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shardsChristopher Curtin
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...OnePlan Solutions
 
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogueitservices996
 
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfPros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfkalichargn70th171
 
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jGraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jNeo4j
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingShane Coughlan
 
Mastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxMastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxAS Design & AST.
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolsosttopstonverter
 
Zer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfZer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfmaor17
 
Best Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITBest Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITmanoharjgpsolutions
 
Advantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptxAdvantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptxRTS corp
 
Introduction to Firebase Workshop Slides
Introduction to Firebase Workshop SlidesIntroduction to Firebase Workshop Slides
Introduction to Firebase Workshop Slidesvaideheekore1
 
Key Steps in Agile Software Delivery Roadmap
Key Steps in Agile Software Delivery RoadmapKey Steps in Agile Software Delivery Roadmap
Key Steps in Agile Software Delivery RoadmapIshara Amarasekera
 

Recently uploaded (20)

Strategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsStrategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero results
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 Updates
 
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
 
Osi security architecture in network.pptx
Osi security architecture in network.pptxOsi security architecture in network.pptx
Osi security architecture in network.pptx
 
SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
 
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogue
 
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfPros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
 
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jGraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
 
Mastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxMastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptx
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration tools
 
Zer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfZer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdf
 
Best Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITBest Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh IT
 
Advantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptxAdvantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptx
 
Introduction to Firebase Workshop Slides
Introduction to Firebase Workshop SlidesIntroduction to Firebase Workshop Slides
Introduction to Firebase Workshop Slides
 
Key Steps in Agile Software Delivery Roadmap
Key Steps in Agile Software Delivery RoadmapKey Steps in Agile Software Delivery Roadmap
Key Steps in Agile Software Delivery Roadmap
 

SOS UiComponents

  • 1. SOSUiComponents SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 2. SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 3. Alternative titles: Lessons learned from UiComponents or My own best practices for UiComponents SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 4. I'm assuming you have at least a (very) basic understanding of — require.js — Knockout.js — jQuery UI Widgets — UiComponents SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 5. SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 6. SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 7. SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 8. UiComponents So what is the problem? SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 9. For me grokking UiComponents was one of the hardest things SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 10. It still takes me a long time to do some things that I expect to be quick SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 11. I try to understand UiComponents mainly by reading code Reading Code > Reading Docs SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 12. So I try to optimize code for reading SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 13. This talk 1. A little bit of whining 2. General advice on readable code 3. View state management SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 14. Three issues I frequently encounter: 1. High cognitive load 2. Duplication of knowledge 3. State is coupled to the DOM SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 15. If it was my job... ..to fix UiComponents SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 16. Cognitive load Super verbose declaration (no sane defaults) SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 17. Cognitive load Mixing of concepts (Knockout.js and jQuery UI Widgets) SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 18. Cognitive load Inconsistent use in core SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 19. Self Documenting CodeSOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 20. Rules I try to apply to code I write. When working with the core code... well, it is what it is. SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 21. 4 Rules of simple design by Kent Beck: 1. Passes all tests 2. Reveals intent 3. No duplication 4. Fewest elements SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 22. Passes all tests The code has to work. SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 23. Reveals intent SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 24. Reveals intent Good naming — Descriptive base class names — Intent of functions, not implementation — Descriptive properties and variables SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 25. Reveals intent bad: interface ButtonProviderInterface { /** * Retrieve button-specified settings * * @return array */ public function getButtonData(); } SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 26. Reveals intent because: public function getButtonData() { // ... return [ 'label' => __('Save'), 'class' => 'save primary', 'data_attribute' => [ 'mage-init' => [ 'buttonAdapter' => [ 'actions' => [ [ 'targetName' => 'product_form.product_form', 'actionName' => 'save', 'params' => [false] ] ] ] ] ], 'class_name' => Container::SPLIT_BUTTON, 'options' => $this->getOptions(), ]; } SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 27. Reveals intent better: interface ButtonProviderInterface { public function getLabel(); public function getCssClassNames(); public function getActions(); ... } SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 28. Reveals intent bad: { getSortOrder: function () { return this.order; } } SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 29. Reveals intent good: { isDescending: function() { return this.order === SORT_DESC; }, isAscending: function() { return this.order === SORT_ASC; } } SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 30. Reveals intent Try to use a style familiar to the most likely reader SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 31. Reveals intent Favor UiComponent JSON over XML SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 32. Reveals intent <item name="progressBar" xsi:type="array"> <item name="sortOrder" xsi:type="string">0</item> <item name="component" xsi:type="string">Magento_Checkout/js/view/progress-bar</item> <item name="displayArea" xsi:type="string">progressBar</item> <item name="config" xsi:type="array"> <item name="deps" xsi:type="array"> <item name="0" xsi:type="string">checkout.steps.shipping-step.shippingAddress</item> <item name="1" xsi:type="string">checkout.steps.billing-step.payment</item> </item> </item> </item> SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 33. Reveals intent { "progressBar": { "component": "Magento_Checkout/js/view/progress-bar", "sortOrder": 0, "displayArea": "progressBar", "config": { "deps": [ "checkout.steps.shipping-step.shippingAddress", "checkout.steps.billing-step.payment" ] } } } SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 34. No duplication SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 35. No duplication Keep knowledge in one place SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 36. No duplication Duplication is a common problem in M2 EAV, DataInterfaces, UiComponents, GraphQL, ... How does it apply in the view layer? SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 37. No duplication Avoid selectors in view models loginFormSelector = 'form[data-role=email-with-possible-login]', SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 38. No duplication :'-( miniCart.sidebar({ 'targetElement': 'div.block.block-minicart', 'button': { 'checkout': '#top-cart-btn-checkout', 'remove': '#mini-cart a.action.delete', 'close': '#btn-minicart-close' }, 'showcart': { 'parent': 'span.counter', 'qty': 'span.counter-number', 'label': 'span.counter-label' }, 'minicart': { 'list': '#mini-cart', 'content': '#minicart-content-wrapper', 'qty': 'div.items-total', 'subtotal': 'div.subtotal span.price' }, 'item': { 'qty': ':input.cart-item-qty', 'button': ':button.update-cart-item' } }); SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 39. No duplication If selectors are required? Keep the definition and the configuration as close as possible, ideally in the same file SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 40. No duplication DOM selector declaration and config <div data-bind="scope: 'foo'"> <div data-role="message-container">...</div> </div> <script type="text/x-magento-init"> { "*": { "Magento_Ui/js/core/app": { "components": { "foo": { "component": "MyCompany_MyModule/js/view/foo", "containerSelector": "div[data-role=message-container]" } } } } } </script> SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 41. No duplication UiComponent selector declaration and config <div data-bind="scope: 'messages'"> ... </div> <script type="text/x-magento-init"> { "*": { "Magento_Ui/js/core/app": { "components": { "messages": { "component": "Magento_Theme/js/view/messages" } } } } } </script> SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 42. No duplication Keep knowledge in one file and close together. <script type="text/x-magento-init"> { "*": { "Magento_Ui/js/core/app": { "components": { "appRoot": { "component": "My_Module/js/root" "children": { "thingA": { "component: "My_Module/js/thing-a" }, "thingB": { "component: "My_Module/js/thing-b", "sibling":" "thingA" } } } } } } } </script> SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 43. No duplication Injecting DOM-Nodes is better E.g. with a custom binding: <div data-bind="scope: 'myViewModel', bindDomNode: true"> </div> SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 44. No duplication Custom binding handler declaration: define(['ko'], function(ko) { 'use strict'; ko.bindingHandlers.bindDomNode = { init: function(element, valueAccessor, _a, _b, bindingContext) { if (valueAccessor()) { bindingContext.$data.domNode = element; } } }; }); SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 45. No duplication Example access of injected DOM node the view model: this.domNode.getBoundingClientRect(); SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 46. Fewest elements SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 47. Fewest elements If something works, expresses intent and contains no duplicate knowledge, don't split it further SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 48. Fewest elements The Single Responsibility Principle is not the Single Public Method Principle. SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 49. Fewest elements If things are related, keep them together. SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 50. Managing State SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 51. Context: Magento <= 2.2.2 Not a SPA/PWA SRP with several frontend "components", each with its own more or less independent state. SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 52. We have three options. 1. Keep state in the DOM or UiComponents 2. Pass state from root down to children 3. Keep state outside of the view SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 53. Example TicTacToe https://github.com/Vinai/example-module-tictactoe SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 54. Example TicTacToe Shamelessly stolen from https://reactjs.org/tutorial/tutorial.html SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 55. Example TicTacToe Simple example for each approach to managing shared state: https://github.com/Vinai/example-module-tictactoe $ git branch * 0-in-component-state 1-pass-to-children 2-external-state SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 56. 1. Keep state in the DOM or UiComponents E.g. jQuery or pure Knockout.js Only for simplest, single component cases SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 57. 1. State in the DOM How is state stored in the DOM? — Form element values — CSS classes (e.g. "active" or "invalid") — Inline styles (e.g. "display: none") — Element attributes (e.g. disabled) SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 58. 1. State in the DOM DOM state storage is common with jQuery self.element.off('submit'); // disable 'Add to Cart' button addToCartButton = $(form).find(this.options.addToCartButtonSelector); addToCartButton.prop('disabled', true); addToCartButton.addClass(this.options.addToCartButtonDisabledClass); form.submit(); SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 59. 1. State in UiComponents Properties on the knockout view model Shared state: imports, exports, links SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 60. 1. State in UiComponents Component.extend({ defaults: { links: { squares: '${ $.provider }:squares' }, imports: { xIsNext: '${ $.provider }:xIsNext', winner: '${ $.provider }:winner' } }, square: function () { return this.squares[this.squareIndex]; } handleClick: function () { const square = this.square(); if ('' === square() && !this.winner) { square(this.xIsNext ? 'X' : 'O'); } } }); SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 61. 1. Shared state in DOM or UiComponents Strong coupling through cross-component dependencies SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 62. 1. Derived state In this approach state derived from one model is o!en stored in another model SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 63. 1. Derived State updateFoo: function() { this.foo = this.other.bar * this.other.bar; } // vs. foo: function() { return this.other.bar * this.other.bar; } SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 64. 2. Pass state from root down to children E.g. pure react components Works within one component hierarchy SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 65. 2. Example from React TicTacToe <Board squares={current.squares} onClick={i => this.handleClick(i)} /> class Board extends React.Component { renderSquare(i) { return ( <Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} /> ); } SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 66. 2. Pass state from root down to children Problem when state is required outside one hierarchy SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 67. 2. Pass state from root down to children Not common in Magento 2 SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 68. 2. Pass state from root down to children No callback on parent, only on child Component.extend({ initContainer: function (parent) { const state = parent.state; this.cells = [...state.squares.keys()].map(function (i) { return new Square({index: i, state: state}); }); return this._super(parent); } ... } SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 69. 3. Keep state outside the view E.g. Elm architecture, flux, redux/vuex Most versatile but needs more plumbing SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 70. 3. Keep state outside the view There are differences: Naming, (im)mutability, 1 or 2 way data flow, (F)RP, effects handling, amount of architecture... But there always is a single state storage SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 71. 3. Separate state with UiComponents State object with observable properties define(['ko'], function (ko) { 'use strict'; return ko.track({ moves: [], squares: [...Array(9).keys()].map(() => ko.observable('')), xIsNext: true, winner: false }); }); SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 72. 3. Separate state with UiComponents Require and use state container object define( ['uiComponent', 'ticTacToeState'], function (Component, state) { 'use strict'; return Component.extend({ ... handleClick: function () { if ('' === this.value() && !state.winner) { state.squares[this.index](state.xIsNext ? 'X' : 'O'); } }, }); } ); SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 73. Example Breakout https://github.com/Vinai/example-module-breakout SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 74. 3. Multiple state storage objects define( ['gameComponent', 'ballState', 'frameState', 'gameState'], function (GameComponent, ball, frame, game) { 'use strict'; return GameComponent.extend({ initialize: function () { this._super(); this.initDimensions(frame); frame.width = function () { return game.width * .98; }; frame.height = function () { return game.height * .80; }; frame.left = function () { return game.width * .01; }; frame.top = function () { return game.height * .19; }; }, ... SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 75. 3. State outside the view Benefits: — State is simple to share — View models contain mostly only logic — Less code — Easier to understand — More maintainable SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 76. Recommendations for maintainable UiComponents... SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 77. The code needs to... 1. Pass all tests 2. Reveal intent 3. Contain no duplication 4. Have the fewest possible elements 5. Separate shared state from the view SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018
  • 78. Thanks to Kent Beck for his timeless 4 rules of simple design. Thank you for your attention! SOS UiComponents - (c) @VinaiKopp - for #MageTitansIT, Milano, 06. April 2018