Непрофессиональный цикл статей, на мой взгляд. Даже в простейших примерах явные ошибки. То setState как будто синхронный, то текстовые пропы от руки каждый раз пишутся вместо констант, то вот label здесь без htmlFor. Если кто-то все же читает, лучше используйте такой паттерн:
<Input.Text
label="Name"
storePath="forms.registration.email"
/>
// и внутри компонента
const id = generateId(props.storePath);
return (
<div>
<label htmlFor={id}>{props.label}</label>
<input type="text" id={id} value={getValueFromStore(props.storePath)}/>
</div>
)
Акцент на автоматической генерации id, удобстве получения данных из стора, и фокусировании инпута при клике на label.
В примере storePath строкой задано, что при рефакторинге может вылезти в баг, поэтому тоже лучше генерировать storePath={pathToString(forms.registration.email)}
Дипломатические методы — обсуждение, убеждение, презентации для руководства разного уровня — могут принести достаточно ресурсов, чтобы сделать большую часть проекта качественно. Я в нескольких компаниях на цифрах показывал, сколько убытков в деньгах и времени приносит некачественный быстрокод и засилье «дешевых» разработчиков в проекте — и если для руководства важен бизнес и результат, а не распил, то непременно пойдут навстречу. Не с первого раза, так с десятого.
«Извращение», «все неправильно» и особенно «все уже поняли что всем нужна типизация», как модно было говорить в докладах на недавних конференциях, для меня не аргументы использовать эту технологию.
Если бы я знал о явных преимуществах и они стоили всех мучений и долгого обучения — как вы правильно заметили, за полгода команда довольно сильных специалистов не научилась «правильно работать со строгой типизацией», хотя в основном проблемы зависели не от команды, то можно было бы дальше возиться с этим и обильно осваивать бюджет компании. Но нет. Предпочитаю делать продуманные качественные продукты и приносить пользу, а не возиться с почти бесполезными инструментами, не двигающими к этой цели.
Я не говорю за всех разработчиков и за все проекты — как я писал выше, в отдельных библиотеках использование типизации скорее оправдано, а в сложных многосоставных системах вроде SPA явно негативный эффект — замедление разработки без видимых профитов. IMHO
Я описал только малую часть проблем — каждый день несколько часов работы команды уходило на типизацию и борьбу с негативными эффектами. Разумеется, все можно победить — вопрос зачем? Пользу от типизации в SPA я до сих пор не увидел.
Ошибки в типах в рантайме только увеличились. Рефакторинг стал сложнее — в ES6 проекте 90% рефакторинга выполняется findAndReplace с помощью регулярок, с типизацией работа удваивается. Переменные как были с опечатками или не отражающие назначения, так и остались. В опенсорс-зависимостях очень часто выходят версии с некорректными типами, ломающими сборку, и приходится форкать и вручную исправлять. Перечислять минусы могу еще долго.
Я действительно хочу понять, что именно сподвигает некоторых людей топить за Typescript в SPA.
Проигрывание этой истории и логирование последних действий при возникновении глобальной ошибки, полагаю, тоже сделать несложно — мне не пригождалось, так как стараюсь решать проблему поиска причины залогированного бага с помощью именованного stackTrace, типизированного error.name и человекопонятного error.message.
Поэтому я бы не рассматривал встроенный в Redux механизм истории как серьезный аргумент в его пользу — если он действительно нужен, реализовать его довольно просто.
По теме гонок и каскадных обновлений Redux, как вы правильно заметили, своим диспетчером решает проблему «частично», и мне, к сожалению, приходилось работать в приложениях, где «все остальные части» не решались, и они очень страдали от нагромождения бойлерплейтов и дополнительных библиотек и мидлвар, в которых крайне сложно было создать стабильный флоу. Это не камень в огород Redux, я скорее о том, что проектирование архитектуры никто не отменяет.
import React from 'react';
import { observer } from 'utils';
import { useStore } from 'hooks';
function TestComponent() {
const store = useStore();
const { currentTP: { executions } } = store;
return <div>{executions.fetchSymbol ? 'Загружается...' : 'Загружен'}</div>;
}
export const TestComponentConnected = observer(TestComponent);
Вроде полностью соответствует вашему описанию, только в виде объекта с ключами выполняемых асинхронных действий. Это выгоднее, так как позволяет обновлять компонент только при обновлении стейта конкретного действия — если же использовать массив (loaders.indexOf('fetchSymbol') !== -1), компонент будет обновляться и при попадании в этот массив всех других, ненужных для данного компонента стейтов. Хотя в Redux можно сделать селектор для этого. Глобальный лоадер можно завязать на Object.entries(executions).some(([key, value]) => value === true).
Разумеется, на любом движке или ванильном JS можно сделать то же самое, просто на MobX это очень просто и удобно.
Присоединяюсь к «выводу что react + mobx серебряная пуля для задач и проектов любой сложности» — задачи, стоящие перед frontend-разработкой решаются насколько элегантно, что не приходится раскручивать цепочки вида компонент-родительский компонент-контейнер-селектор-экшен-тип экшена-поиск затрагиваемых сторов-обработчик АПИ запросов-нормализатор, которые присутствуют в более-менее сложных проектах на Redux. Практически ничто не мешает свободному полету мысли и созданию качественного приложения. Разве что Typescript я бы все же не прикручивал — мороки намного больше, чем профита, по моему опыту.
JSX — просто калька с того, как написаны php-сайты 2000х
Я бы не был так категоричен, по моему мнению это лучший на сегодня шаблонизатор, максимально приближенный к html. В отличие от Vue и Angular, где в кастомных атрибутах в виде строк описывается логика работы — подход, с которым сообщество борется десятки лет, но он почему-то жив и приобретает новые формы.
В последнее время в среде тимлидов мелькает мысль, что можно написать инструменты, которые будут ограничивать программиста и заставлять его писать хороший код
На моей практике стандарты кодирования и стандарты качества (неинструментальные, но все же ограничения) способствуют формированию общности в среде разработчиков, если создаются демократическими методами. ESLint туда же. Не в одном проекте видел достаточно образованных разработчиков, которые в одной кодовой базе использовали кардинально разные подходы — с типизацией/без, функциональный стиль/ООП, thunk/saga, даже различные методы именования переменных. Нельзя сказать, что код каждого был плохой — но при уходе разработчика другим приходилось переписывать то, что он делал, так как не понимали его код.
В остальном согласен, разве что только не MobX обновляет UI, а все же React в данном случае, просто эффективней (хотя крайне мало проектов, в которых важно — обновилось 10 компонентов или 1)
Исправил в апдейте на кроссплатформенный, только \/ будет недостаточно, а [\\/] покроет оба написания слэшей. Папка dist коммитится для демо — так работают Github Pages, они показывают контент одной из папок в репозитории. Другие хеши в первоначальном варианте получились скорее всего потому, что скрин с ними я сделал до финальной версии кода — так что если бы и сам пересобрал, то были бы другие. С yarn.lock разобрался в апдейте, действительно было ошибкой не использовать его для основных зависимостей
При проработке названия искал слово, которым можно емко объединить сразу много сфер — контроль качества и форматирования кода, сборку, оптимизацию, работу со стилями, метод организации файлов, создание связки store+view, локализацию, практический обзор работы с React Hooks, принципы работы с АПИ, проектирование роутинга, конечное тестирование. Можно это было бы назвать «Основа для полноценного SPA-приложения», но тоже можно найти недостатки.
Так как «архитектура ПО» — размытое понятие, у которого сотни определений с разным охватом тем, можно взять например такое от Екатерины Головановой: «это процесс превращения таких характеристик программного обеспечения, как: гибкость, масштабируемость, возможность реализации, многократность использования и безопасность — в структурированное решение, которое соответствует как техническим, так и бизнес требованиям». По большей части подходит, на мой взгляд.
Понимаю, что тем, кто хотел увидеть в статье архитектуру «в узком смысле» — как «выбор структурных элементов, интерфейсов и их поведения в рамках системы» — здесь информации не много, так что для них это выглядит кликбейтом.
Boilerplate — «шаблонный код, который должен быть написан во многих местах практически без изменений», в статье встречается только в виде
Сейчас пришла идея, что если потребуется изменить в одной транзакции сразу много сторов, можно это красиво сделать через реализованный в статье autorun. Таким образом, сторы потеряют тесную связь, что снизит сложность программы. Да, так всегда — по мере «выращивания» кода приходят идеи, как его улучшить. Сразу идеально спроектировать у меня никогда не получалось
У меня скорее негативный опыт взаимодействия с TypeScript. Понимаю, что тема спорная, и зависит от принципов, которых придерживается сам разработчик. Знаю сильных специалистов, которым комфортно работать в стиле «тише едешь — дальше будешь», и проекты они выполняют с полной тщательной типизацией и за тройной, на мой взгляд, срок, при сравнимом качестве итогового продукта.
Видел проекты с типизацией и сотнями зарегистрированных багов по части фронтенда, в том числе касательно некорректных типов (т.к. разработчики полагались на типизацию, а не проверяли данные в рантайме, применяя стратегии отказоустойчивости). Также часто возникали ситуации, когда в репозиторий коммитился не проходящий сборку код — проблема встает остро, когда проект разбит на несколько репозиториев (например, на библиотеку компонентов, валидационные схемы).
Сам код, на мой взгляд, становится сложнее читаемым, в миддлварах и сложных функциях и декораторах приходится писать многотомные типы ценой дополнительных часов, не получая профита (автодополнение? JSDoc в помощь), а ввиду того, что работал в проектах, где важна скорость разработки, приходилось «скатываться» в any. Еще помню большие затраты времени на обучение корректному использованию типизации всех разработчиков. Для динамической типизации в ряде случаев приходилось использовать хаки со StackOverflow, также было несколько проблем касательно утечек памяти при сборке (watch-режим падал, какие бы лоадеры и ухищрения не пробовали, через 2-3 часа работы), увеличении времени на сборку, и баги, специфичные для Linux / Windows систем.
В итоге польза была катастрофически не совместима с затрачиваемыми усилиями. Эти минусы касаются именно SPA-разработки. Для отдельных библиотек (к примеру, для графиков) и онлайн-игр, думаю, типизация была бы очень кстати. А в разработке сайтов минимизирую количество багов тщательными интеграционными тестами и проверкой данных в рантайме.
Опыт работы с TypeScript — 6 месяцев. Итоговое впечатление — сырой продукт, не приносящий ощутимой пользы, при этом значительно увеличивающий время на разработку, при этом расхолаживая коллег, которые вместо заботы над реальным user experience начинают полагаться на «скомпилировалось — значит все будет работать».
Корневой стор передается, чтобы MobX-сторы имели доступ друг к другу и могли напрямую получать данные друг от друга. Всегда будут методы, которые должны изменить сразу несколько сторов — это просто решение проблемы. Диспетчер как в Redux здесь будет скорее неэффективен, так как желательно единомоментно в одной транзакции менять все параметры. А вы как решаете эту задачу?
Чтобы продемонстрировать принципы, которыми руководствуюсь, полезней и понятней написать свою реализацию, хотя можно было бы и сделать на базе готового инструмента, основательно обработав напильником.
Раньше использовал вышеуказанные библиотеки, но в большинстве проектов приходилось их клонировать и дорабатывать, либо использовать сложные конструкции, для соответствия тем принципам, которых я придерживаюсь при разработке.
react-intl, к примеру, работает через свой провайдер, требует в каждом сообщении передавать уникальный id (который, конечно, можно сгенерировать через _filename), не всегда подходит его шаблонизатор. Если можно сделать намного проще и удобней — то стараюсь избегать сторонних зависимостей.
react-router использовал 2-4 версии, каждый раз приходилось писать много лишнего кода, чтобы добиться тесной интеграции с приложением, вплоть до нескольких миддлвар на каждый onEnter / onLeave, а правами на просмотр управлять через Prompt… Работало хорошо, но код совсем не элегантный.
Create React App все же для небольших приложений, так как накладывает жесткие ограничения, в которые проект неминуемо упрется. Придется делать npm run eject и основательно перерабатывать конфиги (проходил, не удовольствие).
Уверен, что можно так обернуть готовые библиотеки, чтобы соответствовали всем предъявляемым требованиям — просто времени и усилий лично у меня займет больше, чем написать с чистого листа.
Верно, глубокие зависимости без lock-файла не будут зафиксированы. По всей видимости я сам себе противоречу в статье — выступаю за стабильные зависимости без ^, при этом допускаю возможность поломки из-за глубоких зависимостей.
Проблема, которую я решал — чтобы зависимости, указанные с помощью «file:./webpack-custom» обновлялись, так как с lock-файлом при изменении их package.json они не обновляются. Выходом вижу использовать yarn install --force. Возможно есть другие варианты?
Непрофессиональный цикл статей, на мой взгляд. Даже в простейших примерах явные ошибки. То setState как будто синхронный, то текстовые пропы от руки каждый раз пишутся вместо констант, то вот label здесь без htmlFor. Если кто-то все же читает, лучше используйте такой паттерн:
Акцент на автоматической генерации id, удобстве получения данных из стора, и фокусировании инпута при клике на label.
В примере storePath строкой задано, что при рефакторинге может вылезти в баг, поэтому тоже лучше генерировать
storePath={pathToString(forms.registration.email)}Удобнее было бы не контролировать с помощью PropTypes постфактум, а дать сразу набор возможных значений
Если бы я знал о явных преимуществах и они стоили всех мучений и долгого обучения — как вы правильно заметили, за полгода команда довольно сильных специалистов не научилась «правильно работать со строгой типизацией», хотя в основном проблемы зависели не от команды, то можно было бы дальше возиться с этим и обильно осваивать бюджет компании. Но нет. Предпочитаю делать продуманные качественные продукты и приносить пользу, а не возиться с почти бесполезными инструментами, не двигающими к этой цели.
Я не говорю за всех разработчиков и за все проекты — как я писал выше, в отдельных библиотеках использование типизации скорее оправдано, а в сложных многосоставных системах вроде SPA явно негативный эффект — замедление разработки без видимых профитов. IMHO
Ошибки в типах в рантайме только увеличились. Рефакторинг стал сложнее — в ES6 проекте 90% рефакторинга выполняется findAndReplace с помощью регулярок, с типизацией работа удваивается. Переменные как были с опечатками или не отражающие назначения, так и остались. В опенсорс-зависимостях очень часто выходят версии с некорректными типами, ломающими сборку, и приходится форкать и вручную исправлять. Перечислять минусы могу еще долго.
Я действительно хочу понять, что именно сподвигает некоторых людей топить за Typescript в SPA.
Доброго дня.
тривиально реализуется через autorun. Можно делать глобальные слепки -
очищая от функций и ненужных данных, разумеется, либо пушить только изменения конкретных данных
Проигрывание этой истории и логирование последних действий при возникновении глобальной ошибки, полагаю, тоже сделать несложно — мне не пригождалось, так как стараюсь решать проблему поиска причины залогированного бага с помощью именованного stackTrace, типизированного
error.nameи человекопонятногоerror.message.Поэтому я бы не рассматривал встроенный в Redux механизм истории как серьезный аргумент в его пользу — если он действительно нужен, реализовать его довольно просто.
По теме гонок и каскадных обновлений Redux, как вы правильно заметили, своим диспетчером решает проблему «частично», и мне, к сожалению, приходилось работать в приложениях, где «все остальные части» не решались, и они очень страдали от нагромождения бойлерплейтов и дополнительных библиотек и мидлвар, в которых крайне сложно было создать стабильный флоу. Это не камень в огород Redux, я скорее о том, что проектирование архитектуры никто не отменяет.
Вроде полностью соответствует вашему описанию, только в виде объекта с ключами выполняемых асинхронных действий. Это выгоднее, так как позволяет обновлять компонент только при обновлении стейта конкретного действия — если же использовать массив (
loaders.indexOf('fetchSymbol') !== -1), компонент будет обновляться и при попадании в этот массив всех других, ненужных для данного компонента стейтов. Хотя в Redux можно сделать селектор для этого. Глобальный лоадер можно завязать наObject.entries(executions).some(([key, value]) => value === true).Разумеется, на любом движке или ванильном JS можно сделать то же самое, просто на MobX это очень просто и удобно.
Я бы не был так категоричен, по моему мнению это лучший на сегодня шаблонизатор, максимально приближенный к html. В отличие от Vue и Angular, где в кастомных атрибутах в виде строк описывается логика работы — подход, с которым сообщество борется десятки лет, но он почему-то жив и приобретает новые формы.
На моей практике стандарты кодирования и стандарты качества (неинструментальные, но все же ограничения) способствуют формированию общности в среде разработчиков, если создаются демократическими методами. ESLint туда же. Не в одном проекте видел достаточно образованных разработчиков, которые в одной кодовой базе использовали кардинально разные подходы — с типизацией/без, функциональный стиль/ООП, thunk/saga, даже различные методы именования переменных. Нельзя сказать, что код каждого был плохой — но при уходе разработчика другим приходилось переписывать то, что он делал, так как не понимали его код.
В остальном согласен, разве что только не MobX обновляет UI, а все же React в данном случае, просто эффективней (хотя крайне мало проектов, в которых важно — обновилось 10 компонентов или 1)
\/будет недостаточно, а[\\/]покроет оба написания слэшей. Папка dist коммитится для демо — так работают Github Pages, они показывают контент одной из папок в репозитории. Другие хеши в первоначальном варианте получились скорее всего потому, что скрин с ними я сделал до финальной версии кода — так что если бы и сам пересобрал, то были бы другие. С yarn.lock разобрался в апдейте, действительно было ошибкой не использовать его для основных зависимостейТак как «архитектура ПО» — размытое понятие, у которого сотни определений с разным охватом тем, можно взять например такое от Екатерины Головановой: «это процесс превращения таких характеристик программного обеспечения, как: гибкость, масштабируемость, возможность реализации, многократность использования и безопасность — в структурированное решение, которое соответствует как техническим, так и бизнес требованиям». По большей части подходит, на мой взгляд.
Понимаю, что тем, кто хотел увидеть в статье архитектуру «в узком смысле» — как «выбор структурных элементов, интерфейсов и их поведения в рамках системы» — здесь информации не много, так что для них это выглядит кликбейтом.
Boilerplate — «шаблонный код, который должен быть написан во многих местах практически без изменений», в статье встречается только в виде
и параметров вроде «name», «version» в *.json файлах. А как тогда назвать все остальное? Архитектура вроде как подходит
Видел проекты с типизацией и сотнями зарегистрированных багов по части фронтенда, в том числе касательно некорректных типов (т.к. разработчики полагались на типизацию, а не проверяли данные в рантайме, применяя стратегии отказоустойчивости). Также часто возникали ситуации, когда в репозиторий коммитился не проходящий сборку код — проблема встает остро, когда проект разбит на несколько репозиториев (например, на библиотеку компонентов, валидационные схемы).
Сам код, на мой взгляд, становится сложнее читаемым, в миддлварах и сложных функциях и декораторах приходится писать многотомные типы ценой дополнительных часов, не получая профита (автодополнение? JSDoc в помощь), а ввиду того, что работал в проектах, где важна скорость разработки, приходилось «скатываться» в any. Еще помню большие затраты времени на обучение корректному использованию типизации всех разработчиков. Для динамической типизации в ряде случаев приходилось использовать хаки со StackOverflow, также было несколько проблем касательно утечек памяти при сборке (watch-режим падал, какие бы лоадеры и ухищрения не пробовали, через 2-3 часа работы), увеличении времени на сборку, и баги, специфичные для Linux / Windows систем.
В итоге польза была катастрофически не совместима с затрачиваемыми усилиями. Эти минусы касаются именно SPA-разработки. Для отдельных библиотек (к примеру, для графиков) и онлайн-игр, думаю, типизация была бы очень кстати. А в разработке сайтов минимизирую количество багов тщательными интеграционными тестами и проверкой данных в рантайме.
Опыт работы с TypeScript — 6 месяцев. Итоговое впечатление — сырой продукт, не приносящий ощутимой пользы, при этом значительно увеличивающий время на разработку, при этом расхолаживая коллег, которые вместо заботы над реальным user experience начинают полагаться на «скомпилировалось — значит все будет работать».
Чтобы продемонстрировать принципы, которыми руководствуюсь, полезней и понятней написать свою реализацию, хотя можно было бы и сделать на базе готового инструмента, основательно обработав напильником.
react-intl, к примеру, работает через свой провайдер, требует в каждом сообщении передавать уникальный id (который, конечно, можно сгенерировать через _filename), не всегда подходит его шаблонизатор. Если можно сделать намного проще и удобней — то стараюсь избегать сторонних зависимостей.
react-router использовал 2-4 версии, каждый раз приходилось писать много лишнего кода, чтобы добиться тесной интеграции с приложением, вплоть до нескольких миддлвар на каждый onEnter / onLeave, а правами на просмотр управлять через Prompt… Работало хорошо, но код совсем не элегантный.
Create React App все же для небольших приложений, так как накладывает жесткие ограничения, в которые проект неминуемо упрется. Придется делать npm run eject и основательно перерабатывать конфиги (проходил, не удовольствие).
Уверен, что можно так обернуть готовые библиотеки, чтобы соответствовали всем предъявляемым требованиям — просто времени и усилий лично у меня займет больше, чем написать с чистого листа.
Проблема, которую я решал — чтобы зависимости, указанные с помощью «file:./webpack-custom» обновлялись, так как с lock-файлом при изменении их package.json они не обновляются. Выходом вижу использовать yarn install --force. Возможно есть другие варианты?