Как фронтендеры изобретали чистые функции и TDD
История меня

Дима Богер
Python Backend Lead, Cindicator
- Организатор PiterPy Meetup
- Тимлид
- Иногда преподаю
Люблю Python и Vue.js неосознанной любовью
Я был тимлидом фулл-стек команды

Я был бекенд-лидом

А теперь я здесь

Почему мне нельзя верить

История функций
Математические отображения
Математики придумали отображение — абстракцию, которая каждому числу ставит в соответствие другое число

Математические функции
Математики придумали функции — абстракции, которые что-то получают на вход, и что-то выдают на выход

Свойства функции

Полная определенность
Что не скорми — всё прожует
На самом деле секрет в том, чтобы не кормить лишним

Детерминированность
Всегда возвращает одинаковый результат на одинаковые значения аргументов
Например, пусть и неявно, функция random в Python детерминирована

Отсутствие побочных эффектов
Не лезет куда не надо
Математики такого явно не говорили, но мы такое придумали: взять что-то не из аргументов, сходить в API, мутировать аргумент

История чистых функций
(у программистов)
Идеальная чистая функция
- работает для любых входных аргументов
- возвращает одинаковый результат на одинаковые вызовы
- не лезет наружу и не мутирует (отсутствие побочных эффектов)


Что такое побочные эффекты?

Так зачем нужны чистые функции?
Интерактивность

Отладка

Тестирование

easy.py
def divide(a: float, b: float) -> float:
return a/b
assert divide(6.0, 2.0) == 3.0
assert divide(1.0, 0.0) exception raised
hard.py
import coeff
import external_api
def divide(a: float, b: float) -> float:
return external_api.call(a, b, coeff)
assert divide(6.0, 2.0) == ???
assert divide(1.0, 0.0) ???
Почему нельзя писать только чистые функции?

Постоянно нужно делать грязные вещи
Test Driven Development
(кто-то вообще этим пользуется?)
TDD

А иногда и так

История компонентного подхода
(у строителей пользовательских интерфейсов)
Эволюция

Блоки вёрстки
Сначала мы писали страницу модулями — блоками вёрстки, которую кусочно генерировали на сервере

Переиспользование
Потом мы поняли, что блоки одни и те же, и вынесли их в компоненты
Которые зависели только от данных

Данные для блоков
Если такие блоки зависят только от данных, то можно придумывать разную магию:
- способы передачи этих данных;
- хранилища;
- способы синхронизации;

А в чём проблема?
(данные есть компоненты есть)
Побочные эффекты!

Пример
(входим и выходим)
Как быть?

Глупые и умные компоненты
(представительные и контейнеры)
Разделяй и властвуй
Глупые — не делают побочных эффектов
Умные — делают побочные эффекты (API, хранилище, мутирование)








Visual TDD и CDD
визуальное тестирование и разработка через компоненты
TDD

Visual TDD и связь с заказчиком

Задача — источник состояний

Пишем заглушку компонента

Пишем "визуальный тест"

Вторая итерация

Пишем реализацию

Повторяем

Storybook
и другие component workshop
Storybook
- У каждого компонента есть состояния
- На каждое состояние — историю
- Истории — по папкам
- Плагины для логирования
- Плагины для песочницы

Как это пишется
export const Default = () =>
<TaskList tasks={defaultTasksData} {...actionsData} />;
export const WithPinnedTasks = () =>
<TaskList tasks={withPinnedTasksData} {...actionsData} />;
export const Loading = () =>
<TaskList loading tasks={[]} {...actionsData} />;
export const Empty = () =>
<TaskList tasks={[]} {...actionsData} />;
Как это выглядит

Плюшки

Теперь у вас есть дизайн-система!
У всех разработчиков, менеджеров и дизайнеров есть реальный интерактивный набор компонентов

Граничные случаи
Историями легко показать как компонент ведёт себя в граничных случаях, как выводит ошибки и как ведёт себя на тёмном фоне

Документация
Истории, как и обычные тесты, могут работать как документация к вашей библиотеке компонентов

Песочница
Можно дёргать ручки и смотреть что поменяется.

Снепшот-тесты
Можно фиксировать поведение ваших компонентов между релизами
(см chromaticqa)

Ура!
Красивая сказка

Поддержка языка
Ни язык, ни фреймворк не поддерживает деление на "чистые" и на "грязные" функции/компоненты
Нет никакой возможности не отстрелить себе случайно ногу

Реальная жизнь сложнее
Не всегда получится написать чистый компонент, особенно при большом зацеплении компонентов.
Иногда нужно императивно взаимодействовать с браузером или получать одну маленькую переменную из общего стора.

Большие деревья и прослойки
Иногда событие нажатия на кнопку придётся прокидывать через много уровней.
Не всегда понятно где делать прослойки из умных компонентов.

Изучайте новое
не будьте занудами
Спасибо, Олег

Вопросы?
- Меня зовут Дима
- Я рассказывал про
- свойства математических функций
- свойства чистых функций
- TDD
- глупые и умные компоненты
- Visual TDD
- Storybook
- Проблемы подхода
Использованные материалы
Использованные материалы
Дополнительные материалы
[piterjs] Storybook или Как фронтендеры изобретали чистые функции
By b0g3r
[piterjs] Storybook или Как фронтендеры изобретали чистые функции
Запись доклада: https://youtu.be/j83p7mCr7h0?t=1347. Небольшой экскурс в историю математических функций, как это связано с Visual TDD и причём тут Storybook
- 128