МРТ для данных / Анастасия Горячева (avito)
TRANSCRIPT
МРТ для данныхКак увидеть внутренние процессы
и состояния веб-приложения
Анастасия Горячева, Avito
Настя Горячева
Работаю в Avito
Делаю SPA
Пишу на basis.js
Почта [email protected]
twitter @tyanasgo
1
Инструменты для профи – SPA на basis.js2
3
4
5
6
Потоки данных Как они устроены?7
Мировыепрактики
Devtoolsв браузере
9
console.log
10
console.log??
11
twitter.com/JavaScriptDaily/status/718471086246072320
12
14
Мировыеэксперименты
17
twitter.com/andrestaltz/status/729742864561917953
19
streams... channels...
callback chains...
20
Как "чиним"человека?
Сначала диагностика
• Гастроскоп :?
• Рентген
• Компьютерная томография: 3D-рентген
• МРТ – Магнитно-резонансный томограф
• ...
22
Как работает МРТ?
Водород в тканях
+ Магнитное поле
=> Фиксируем их взаимодействие
23
Как диагностироватьсостояние
приложения?
24
Чиним шаблоны
0:50
28
Подробнее про инспектор шаблонов
Доклад Романа Дворнова (февраль 2015)
Слайды slideshare.net/basisjs/spa-45289195Видео youtu.be/IUtbbN9aevU
Адаптация для backbone, react, "white label"github.com/lahmatiy/component-inspector
29
component-inspector для React
Отзывы: Константин Кривленя доклад на FrontendDevConf, Минск, апрель 2016
30
Словари l10n
31
Локализация, строки в интерфейсе32
Demo
33
34
l10n-МРТ никуда без ast-парсера для json
npmjs.com/package/json-to-ast
35
Вернемся к примеру с кнопкой36
Заглянем ненадолго
под капот
37
Dataset
Value
disabled
Состояние кнопкиvar feeds = new ( ... ); // ~observableArray
var hasMoney = .from(profile, 'data.hasMoney');
var = new Expression( // computed
count(feeds.selection),
hasMoney, // observable
function(feedsCount, hasMoney) {
return feedsCount && hasMoney;
}
);
38
Value – скаляр
Object – модель
Dataset – набор моделей (коллекция)
39
Value, Object, Dataset
• Состояния
• Подписка на изменения
• Синхронизация с подписчиками
Разные модели хранения данных
40
Трансформациязначений
41
square
square
Value → Value (RP)
var number = new Value({ value: 5 });
var = number.as(function(n) {
return n * n;
});
.value
// 25
42
sumTwo
sumTwo
Value&Value → Value (RP)
var a = new Value({ value: 4 });
var b = new Value({ value: 6 });
var = new Expression(a, b, function(a, b) {
return a + b;
});
.value
// 10
43
Трансформациянаборов
44
oddA
oddA
Dataset → Dataset (RP)
var A = new Dataset({ items: [1, 2, 3, 4] });
var = new Filter({ // нечетные
source: A,
rule: basis.getter('data.value % 2')
});
.getValues() // [1, 3]
45
46
common
common
Dataset&Dataset → Dataset (RP)
var A = new Dataset({ items: [1, 2, 3, 4] });
var B = new Dataset({ items: [2, 4, 8] });
var = new Merge({
sources: [A, B],
rule: Merge.INTERSECTION
});
.getValues() // [2, 4]
47
48
Значениепо набору
49
sumA
sumA
Dataset → Value (RP)
var A = new Dataset({
items: [1, 2, 4]
});
var = sum(A, function(item) {
return item.data.value;
});
.value // 7
50
51
Все виды трансформаций52
Та же кнопка53
Та же кнопка54
new
disabled new
function
return
Код кнопки Button({
caption: 'Опубликовать',
: Expression(
count(classifieds.selection),
count(feeds.selection),
(countClassifieds, countFeeds) {
!(countClassifieds || countFeeds);
}
)
});
55
Как получить цельноепредставление?
56
Инспекторданных
0:33
58
Demo data flow
59
В чём же магия?60
Формируем мета-информацию
(devinfo)
61
1. Локация (инструментирование)
github.com/restrry/babel-plugin-source-wrapper
62
Подробнее про инструментирование
Доклад Романа Дворнова
Слайды slideshare.net/basisjs/ss-52963081
Видео youtu.be/watch?v=UPtDcAbg6EI&t=2h41m12s
ноябрь 2015, WSD в Минске
63
2. Детали трансформации данных64
devInfo
'path/to/file.js:2:8:5:3'
1. + 2. = то, что нужно (devinfo)Исходный объект остается без изменений (WeakMap: объект → мета-данные)
.get(value) →
{
loc: , // Итог инструментирования.
// Описание трансформации.
source: ..., // Добавляется
transform: ... // в библиотеке.
}
65
Распаковываемdevinfo
66
Мета-данные – в дерево (JSON)67
Дерево (JSON) – в картинку68
Победа!
69
Победа?
70
Сложности
71
Фабрики
Паттерн фабрика: производим функции, создающие значения
Проблемы:
№1 Локация конструктора
vs. локация результата
№2 Кэш значений портит локации
72
value
value :(
№1. Локацииvar = createFactory( ... ); // app.js
...
function createFactory( ... ){ // lib.js
return function factory( ... ) {
return { ... };
}
}
devInfo.get( ).loc // 'lib.js:2:12:4:5'
01.
02.
03.
04.
05.
73
factory
factory
factory
value :D
№1. Решение – подмена локацииfunction createFactory( ... ){ // lib.js
return function ( ... ) {
var x = { ... };
setInfo(x, 'loc', getInfo( ).loc); // dev only
return x;
}
}
devInfo.get( ).loc // 'lib.js:1:1:7:1' (blackboxed)
devInfo.get( ).loc // 'app.js:1:21:1:41'
01.
02.
03.
04.
05.
06.
07.
74
A
B
A B
A B
:(
№2. Кэшvar = createFactory(address, 'data.city'); // profile.js
var = createFactory(address, 'data.city'); // action.js
===
devInfo.get().loc == devInfo.get().loc
== devInfo.get(cachedAorB).loc
'action.js' ? 'profile.js'
75
res
res
res
res
res :(
function cacheFactory(x) {
var ;
if (x in cache) { // где-то выше var cache = {...}
= cache[x];
} else {
= cache[x] = {...}
}
return ;
}
devInfo.get( ).loc // 'action.js' ? 'profile.js'
01.
02.
03.
04.
05.
06.
07.
08.
09.
76
:D
:D
№2. Решение – PROXYfunction cacheFactory(...) {
...
return new Proxy(res, {}):
}
A !== B
devInfo.get(A).loc // profile.js
devInfo.get(B).loc // action.js
77
proxyToOriginal
proxyToOriginal
Как теперь сравнивать?var = new WeakMap();
function compare(x, y) {
return resolveOriginal(x) === resolveOriginal(y);
}
function resolveOriginal(x) {
return .get(x);
}
78
• Значения по-прежнему считаются идентичными
• ...кроме момента, когда хотим узнать локацию создания
Добавляется только в dev-режиме
79
Итоги
Есть ли жизнь без basis.js?81
Адаптация дляknockout.js
82
83
Главное – идея
Специфика для %ваш фреймворк%
там, где происходят
трансформации данных
84
Точки трансформации данных85
Точки трансформации данных86
Точки трансформации данных87
Точки трансформации данных88
Ключи к успеху
1. Инструментирование
2. Описание трансформаций
3. Сборка мета-данных в дерево
4. Визуализация дерева
90
Сложно, но можно91
ВопросыНастя Горячева
твиттер @tyanasgo
92