A talk by Leonid Shevtsov.
?
for help,
p
for notes.
Talks catalog
::
Back to site
.
<p style="margin: -1em -4em -1em -4em;background:black"> <img src="/uploads/images/react_kharkivjs/title_slide.png" /> </p> ??? (приветствие) (подсчет рук) Здравствуйте, меня зовут Леонид Шевцов. Я работаю в компании Railsware. Я люблю React! Ну, скажете, это очевидно, раз уж я пришел сюда делать доклад. Скажу что-то менее очевидное. Три года назад я считал Javascript и фронтенд-программирование делом пропащим, и предпочитал в него не лезть. Вообще я чем только не занимаюсь. Потом я открыл для себя React, и с тех пор я начал любить Javascript. Понятно, что полюбить что-то гораздо проще, чем объяснить, за что ты его любишь. Я долго пытался выразить, что же привлекает меня в Реакте. И, наконец, поэтому я и стою на этой сцене. Есть академические причины любить React - за какие-нибудь "чистые функции" и "иммутабельные данные" и "однонаправленный поток данных". Это все круто. --- class: center, middle <img src="/uploads/images/react_kharkivjs/engineer.png" /> _Тот, кто умело и расчетливо управляет некоторым предприятием._ ??? Но для меня, причина кроется в том, что я инженер. Помните эту шутку про счет на 1000 за удар молотком? Где сам удар стоит 1 доллар, а 999 долларов стоит знать, где ударить? В этой шутке есть зерно истины. Инженер должен иметь четкую ментальную модель проекта, с которым работает. Это необходимо, чтобы уверенно и четко делать изменения в проекте. На фронтенде с этим туго, поэтому я обычно вижу наслоение кода в проекте, а о тестах и о рефакторинге вообще не вспоминают, надеясь только на "ну ведь сроки были, писали на коленке, а вот когда-нибудь перепишем". Дело не в сроках и не в коленках, а в отсутствии хорошей модели. Поэтому советую в следующий раз переписывать на Реакте - и он будет последним. --- class: center, middle ## Структура приложения <img src="/uploads/images/react_kharkivjs/cycle.png" style="width:90%" /> ??? Реакт/Редакс - имеют очень четкую и простую модель приложения. Приложение React/Redux реализует модель бесконечного круговорота данных. Данные начинают свой путь внутри _состояния приложения_. Потом данные превращаются _деревом компонент_ в DOM для браузера. Любой обработчик события, требующий изменения состояния, выпускает _объект действия_. Далее _редюсер_ - чистая функция - принимает на вход текущее состояние и объект действия и возвращает новое состояние. И круговорот замыкается отрисовкой нового состояния DOM. Эта модель - функциональная, и она радикально отличается от объектно-ориентированных фреймворков, поэтому ее и сложно оценить сходу. и я не буду уговаривать вас, что она хорошая из каких-то абстрактных соображений. Перейдем к конкретным штукам. --- class: center, middle ## React использует простой Javascript <img src="/uploads/images/react_kharkivjs/good_parts.jpg" style="width:90%" /> ??? Одна из причин любить React - он использует простой Javascript. Никаких особенных механизмов зависимостей. Никакого ООП. Никакой эзотерики. Названия компонент в JSX - это просто имена функций, реализующих эти компоненты. Атрибуты JSX - ключи в аргументе такой функции. Нам, конечно, ничего не мешает использовать современные (и будущие) возможности языка. Но и не заставляет. --- class: center, middle ## Тесты <img src="/uploads/images/react_kharkivjs/unit_testing.png" /> ??? Я буду много говорить про юнит-тесты. Что может быть непривычно для фронтенд-разработчика. Я понимаю, что если ты работал только с фронтендом, то может, никогда их и не писал. Для меня самая важная причина писать юнит-тесты - они показывают, что о модулях твоей системы можно думать по отдельности. Если юнит-тесты не пишут, обычно это говорит о плохой архитектуре, сложной в понимании. Баги в ней будут не потому, что не протестировали. А потому, что отловить баги в непонятной системе сложнее на порядки. Так вот, недавно меня спросили, а что мы тестируем в приложении, написанном на React/Redux. В тот момент я не нашел лучшего ответа, чем "...все?" Но на самом деле, так и есть. --- ## Тесты компонент <img src="/uploads/images/react_kharkivjs/unit_test_for_component.png" /> ??? - Мы пишем юнит-тесты на каждую компоненту. --- ## Тесты редюсеров ### Редюсер <img src="/uploads/images/react_kharkivjs/reducer_example.png" /> ??? Мы пишем юнит-тесты на каждый редюсер. Что важно, потому что в редюсерах сидит бизнес-логика приложения. Очень круто, что редюсеры можно легко тестировать и компоновать. --- ## Тесты редюсеров <img src="/uploads/images/react_kharkivjs/reducer_test.png" style="width: 80%" /> --- ## Все покрыто тестами - Каждый компонент - Каждый редюсер - Каждая вспомогательная функция - Каждый модуль ??? - Естественно, мы покрываем тестами и мелкие вспомогательные функции. Тесты с React - это не редкость, это норма. Возле каждого исходного файла лежит файл с тестами. Мы смотрим на тесты во время PR review. --- # Избавление от асинхронности <img src="/uploads/images/react_kharkivjs/complex_async.jpg" /> _Диаграмма путешествий во времени в фильме Primer_ ??? ## Весь асинхронный код спрятан за абстракцией А вот асинхронный код это для фронтенда близко. Его не любит никто. Мы придумали кучу абстракций вокруг отложенного выполнения функций. Некоторые абстракции лучше, некоторые хуже. Но все они оставляют на нас _бремя_ асинхронности. Писать асинхронный код - все равно, что смотреть фильм про путешествия во времени. Приходится больше напрягать мозги. Последовательность действий не очевидна. Сценарии багов воссоздаются по рассказам очевидцев. --- class: middle ```javascript nextState = reduce(previousState, action); nextDOM = render(nextState); ``` ??? React, а затем Redux, очень круто решили эту проблему. Логика приложения делится на функции, каждая из которых синхронна и имеет четкий вход и выход. Каждую из них можно понять и протестировать отдельно. --- # Скрытие асинхронности ### В компоненте: ```javascript <form onSubmit={props.onSubmitForm}> ``` ### В контейнере: ```javascript const mapDispatchToProps = dispatch => { return { onSubmitForm: () => { dispatch({type: 'ADD_TODO'}}) } } } ``` ??? Когда нам все же приходится обрабатывать асинхронное событие - такое, как нажатие на кнопку, или ответ от сервера - мы сводим асинхронный код к созданию объекта действия. А потом даже намек на код, выполняемый асинхронно, скрываем за абстракцией. Получается, все что нужно протестировать в компоненте - это то, что она вызывает переданную ей функцию-обработчик при нужном событии. --- class: middle ## Редюсер ```javascript function newTodoReducer(state, action) { switch (action.type) { case "ADD_TODO": return Object.assign({}, state, { newTodo: { title: "" }, todos: state.todos.concat(state.newTodo), }); default: return state; } } ``` ??? А потребители действий (то есть редюсер) полностью отвязаны от причины события. Даже от самого понятия _асинхронности_. --- ## Отладка путешествием во времени <p class="center"> <img src="/uploads/images/react_kharkivjs/redux_devtools.png" style="width:60%"/> </p> https://github.com/gaearon/redux-devtools ??? Раз все действия мы передаем в видет данных, и состояние приложения - тоже данные, мы можем сохранить предыдущие состояния и действия в журнал, а потом при надобности вернуться в прошлое состояние, и проиграть заново все последующие действия, уже без вызова кода, который к ним привел. Теперь проблемное место в приложении можно перематывать сколько угодно раз. Кроме того, мы можем этот журнал просмотреть и понять, что произошло в приложении. Что привело к багу. Кроме того, мы можем _дописывать_ действия в журнал, вызывать изменения в приложении просто из консоли. --- class: center, middle # Live Reload ??? ## Перегружать код - проще простого Раз код нашего приложения так хорошо отсоединен от состояния, то весь код приложения можно, в принципе, выбросить и загрузить заново. Поэтому приложения на React/Redux отлично поддаются живой перезагрузке кода - это когда страница не перегружается и состояние приложения не теряется. Только катастрофические ошибки или рефакторинг состояния потребуют перезагрузки. Поэтому так мы и работаем - перегружая код без страницы. --- class: middle # JSX <p class="center"> <img src="/uploads/images/react_kharkivjs/jsx.png" /> </p> https://facebook.github.io/jsx/ _Задача JSX - определить выразительный и знакомый синтаксис для задания древовидных структур с атрибутами._ ??? Итак, связка Реакт/Редакс дает нам четкую модель работы нашего приложения. Когда что-то ломается, мы знаем, куда смотреть. Мы знаем, как отследить, что привело к нежелаемому поведению. Наша бизнес-логика выражена в красивых чистых функциях, протестирована и верна. Однако все это мало что значит. если сверху налеплен конгломерат презентационного кода. Ведь бизнес-логика в наших приложениях обычно не очень сложная. В основном трудности вызывает организацич слаженной работы вьюхи. Поговорим про React и JSX. JSX может выглядеть, как старые добрые текстовые шаблоны, известные с незапамятных времен. Но. Обычно системы-шаблонизаторы начинают с текста (или HTML) и дополняют его синтаксисом для описания логики, без которой все-таки никак. --- class: center, middle <img src="/uploads/images/react_kharkivjs/javascript_vs_jsx.png" style="width: 90%" /> ??? JSX же начал свою жизнь как обычный код Javascript. Не очень красивый код. Поэтому для него придумали, а точнее, адаптировали, более удобный синтаксис - благо мы живем в эпоху транспайлеров. Так что JSX транслируется в Javascript во время компиляции. Синтаксис естественно тоже проверяется. Поэтому никакого tag soup в JSX быть не может. Когда в JSX атрибутом компоненты назначается объект, по сути мы просто передаем этот объект аргументом в обыкновенную функцию Javascript. Он не переводится в строку, например. Когда в JSX нужно задать условие, или цикл, для этого можно использовать обыкновенные структуры Javascript, а не какой-то особенный эзотерический синтаксис. Который к тому же не проверяется во время компиляции. --- class: center, middle <img src="/uploads/images/react_kharkivjs/jsx_logic.png" /> ??? ## JSX - это код Всегда шаблоны были диким западом приложения. Их нельзя было с легкостью разбить на мелкие куски - всегда с этим были какие-то особенные для шаблонов нюансы. Их нельзя было протестировать. Мы успокаивали себя тем, что когда они сломаются, это по крайней мере будет заметно. Когда напишешь достаточно компонент-функций с JSX внутри, приходит озарение: **ты работаешь с кодом!** Не второсортным кодом - а просто. Кодом. На. Языке. Javascript! В JSX можно использовать все средства Javascript (об этом позже). Нет никакого полу-программирования в шаблонах. --- class: center, middle <img src="/uploads/images/react_kharkivjs/unit_test_for_component.png" /> ??? На компоненты в React можно писать обыкновенные юнит-тесты - задаешь ввод, проверяешь вывод, изолированно от всего окружающего мира. --- class: center, middle <img src="/uploads/images/react_kharkivjs/errors.png" /> ??? С JSX работает ESLint - и очень полезно, кстати. --- ### До Prettier <img src="/uploads/images/react_kharkivjs/before_prettier.png" /> ### После Prettier <img src="/uploads/images/react_kharkivjs/after_prettier.png" /> https://github.com/prettier/prettier --- class: center, middle <img src="/uploads/images/react_kharkivjs/jsx_before_extracting_component.png" /> ??? Но самое крутое, это то, что **JSX можно рефакторить!** Буквально! Увидел повторяющийся кусок - вытянул в функцию. Слишком сложная разметка - разбил ее! Можно обобщить и параметризовать? Сделано! И все это под защитой тестов. И если с другими фреймворками шаблон в 50 или в 100 строк выглядел совершенно нормально, то теперь на PR Review я оставляю комментарий - "порефакторить". --- class: center, middle <img src="/uploads/images/react_kharkivjs/jsx_after_extracting_component.png" /> ??? Ну и благодаря тому, что презентация уже отвязана от бизнес-логики, из простых компоненты можно легко строить библиотеку и использовать во всем проекте. --- <img src="/uploads/images/react_kharkivjs/react_devtools.png" /> ??? ## JSX - мечта верстальщика Люди, не работающие с React, любят говорить, что верстальщикам (профессионалы HTML/CSS) будет нереально работать с JSX, что они будут совсем отсоединены от рабочего процесса. На практике оказывается совсем не так. Верстальщики в восторге от всегда корректного синтаксиса. От того, что они могут влезть в проект и что-нибудь поменять в живом коде самостоятельно. (сообщаю, дерево компонент .реакт можно инспектить в Хроме). --- class: center, middle <img src="/uploads/images/react_kharkivjs/ford_assembly.jpg" /> ??? Для меня React сделал то, чего не сделал ни один другой фреймворк: превратил фронтенд-программирование в настоящее программирование. - Где есть модель приложения, которая укладывается в голову - Где нет второсортного кода в шаблонах - Где можно писать тесты - Где можно по-человечески рефакторить любую часть системы К сожалению, остальные знакомые мне фреймворки следуют более очевидному курсу. Они продолжают развивать модель MVC, хотя ясно, что состояние веб-страниц слишком взаимосвязано, чтобы инкапсулировать его в аккуратные объекты. Они продолжают использовать текстовые шаблоны, хотя они всегда будут содержать логику, написанную на недоязыке. Как по мне, они все еще строят "более быструю лошадь". Я приглашаю вас пересаживаться на Форд Модель Т. --- class: center, middle # Спасибо! ## http://L-S.me