Как фронтендеры изобретали чистые функции и 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
    • Проблемы подхода

Использованные материалы

Использованные материалы

Дополнительные материалы

Made with Slides.com