Golos.io: Рефакторинг и редизайн
Друзья, мы с вами поговорили о проблемах существующей кодовой базы Golos.io и обозначили дальнейший путь развития; обсудили новую архитектуру клиента по части: скорости работы сайта и производительности, а также инфраструктурных сервисов.
И теперь можем поднять вопрос редизайна Golos.io, который неразрывно связан с рефакторингом, так как невозможен без переработки текущего кода.
Рефакторинг и редизайн
Относительно недавно мы приступили к редизайну сайта Golos.io. В первую очередь попытались изменить стили, без изменения основного кода компонентов. Однако, вскоре поняли, что такой подход не приносит удовлетворительных результатов. Дело в том, что в текущем клиенте используется Foundation Framework, и имеется достаточно большой массив css кода, разработанного командой steemit. Пойдя по пути каскадного переопределения стилей, без рефакторинга логики компонентов, стало очевидно, что такой подход нежизнеспособен, из-за огромного количества возникающих коллизий и сайд эффектов. В связи с этим мы приняли решение написать компоненты заново и реструктуризировать проект.
Роутинг страниц
В текущей реализации роутинга, пришедшей от steem, есть, как минимум, две проблемы:
- Определение открытой страницы происходит с использованием регулярных выражений, и без использования возможностей пакета react-router. Вследствии чего сложно понять, какой компонент страницы сейчас просматривается пользователем.
- Вопреки redux практикам, в приложении существует единое место сбора данных. Из-за этого трудно определить, как и где были сформированы данные
Отсюда вытекают сложности в реализации нового функционала и интуитивного понимания кода.
Требования
Мы делаем SPA-приложение, которое работает со сложными структурами данных, требующими дополнительной обработки на клиенте после получения ответа от api.
К тому же, основным требованием для нас является оптимизация страниц под работу поисковых ботов, поэтому мы должны реализовывать серверный рендеринг страниц (SSR).
Нам необходимо сохранить возможность обработки данных и SSR, но избавиться от текущих проблем за счет последовательного рефакторинга, без масштабной переделки проекта в течении долгого времени, а в рамках реализации новых страниц.
Стратегия улучшения
- Работая над новой страницей, в app/RootRoute.js нужно описать новый роут (маршрут) с path и component (loadable контейнер) в самом нижнем условии (после else).
- Каждый контейнер, которому требуются данные для SSR, должен реализовывать статичный async метод getInitialProps с вызовами экшенов (например, выполняющих запросы к api).
- Сервер должен искать текущий роут и вызывать метод getInitialProps у относящегося к нему компонента.
После того, как каждый контейнер будет вызывать экшены для загрузки необходимых ему данных, мы сможем отказаться от регулярных выражений для определения роута, пришедших от steem.
Данные
В существующем варианте приложения данные поступают через redux-saga, исходя из роута, определенного с помощью регулярных выражений. Следуя redux way, такая реализация некорректна, и требует рефакторинга.
Идеальным вариантом заполнения необходимыми данными redux хранилища, является вызов экшена в момент mount (монтирования) контейнера (на клиенте) и вызова специального метода контейнера (при серверном рендеринге).
Специально написанный redux middleware должен слушать экшен определенной структуры и выполнять необходимые манипуляции для выполнения запроса, обработки полученных данных и выполнять действие в случае ответа с ошибкой.
Обновленная структура проекта
Папка src является основной папкой, в которой мы храним:
- app - SPA-приложение;
- server - SSR приложение и api для него (перенесем в ближайшее время).
В свою очередь папка app имеет следующие вложенности:
├── components
│ ├── common
│ ├── golos-ui
│ └── папки с именами папок контейнеров
├── containers
├── helpers
├── redux
│ ├── actions
│ ├── constants
│ ├── reducers
│ ├── sagas
│ └── selectors
└── themes
Разделение логики проекта
Приложение имеет следующие слои распределения логики:
- store - папка redux;
- selectors - папка redux/selectors;
- containers - папка containers;
- presentational components - папка components/(имя контейнера или страницы);
- dumb components - папка components/golos-ui, components/common и styled-components в presentational components.
Store
- entities - хранит результат работы redux-entities-immutable, после нормализации;
- status - хранит статусы запросов, ошибки, данные, которые нельзя вынести в entities из-за неподходящей реализации api;
- ui - хранит изменение интерфейса, сгруппированные по страницам;
- и остальная структура хранения данных, пришедшая от steemit.
Selectors
Селекторы - это функции, задача которых получить данные из стора (хранилища данных), трансформировать и агрегировать их для дальнейшей передачи по следующим слоям.
Containers
Контейнеры - это компоненты верхнего уровня, задачи которых получить данные и экшены через props, и описать основные методы, которые понадобятся в presentational components.
Пример: containers/userProfile/settings/SettingsContent
Presentational components
Это компоненты, которые лежат в папке components, сгруппированные по папкам на основе принадлежности к конкретным контейнерам. Их задача получить props и методы от контейнера, описать рендеринг dumb components и передать им конечные данные.
В рамках этого слоя, в идеальном варианте, должен быть компонент, который является основным presentational component для конкретного контейнера. Он должен описывать рендеринг других presentational components для разделения логики по выполняемым задачам и отображаемым сущностям.
Пример: components/userProfile/SettingsShow
Dumb components
Это компоненты, которые не реализуют логику, не описывают экшены, а вызывают переданные методы и рендерят конечные данные.
Примеры: components/golos-ui, components/common и styled-components в presentational components.
Переход на styled-components
Препроцессоры, такие как SASS и LESS, добавляют много полезных функций, но они не решают проблем, приводящих к анархии CSS. Поэтому работа по организации кода остается для таких методологий, как BEM, которые хотя и полезны, но не являются обязательными и не могут применяться на уровне языка или инструментов.
Основная идея styled-components заключается в том, чтобы применять лучшие практики, удаляя сопоставление между стилями и компонентами.
Так же, styled-components хорошо поддерживают темы, то есть, в будущем можно будет легко использовать библиотеки компонентов на базе styled-components без необходимости использовать что-то кроме документации, чтобы адаптировать их внешний вид, согласно общему стилю сайта.
Итак, после реализации описанных ранее сервисов, усовершения инфраструктуры клиента, улучшения его юзабилити, обновления внутренней структуры и внешнего вида, мы получим современное, производительное и дружелюбное по отношению к пользователям приложение.
Иллюстрация к посту - Yandex
—
Подписывайтесь на официальный аккаунт блог-платформы Golos.io @golosio, чтобы быть в курсе развития проекта! Телеграм для ваших вопросов — https://t.me/golos_support. Лучшее на Голосе — https://t.me/golos_best
Есть предложения, как сделать Golos.io лучше? Пишите в Issues на нашем Github, в наш Телеграм-канал или в чат разработчиков Golos.io в Телеграм!
—
С уважением, команда Golos.io @golosio: @alex-firsov, @bacher, @b1acksun, @chinpu, @dan-kinescop, @dekol, @devall, @format-x22, @insider, @jevgenika, @kucinskaya.alla, @muhazokotuha, @msm72, @nickshtefan, @yulia.rodnikova, @yuri-vlad.