All streams
Search
Write a publication
Pull to refresh
47
0
Дмитрий Казаков @DmitryKazakov8

Front-end архитектор

Send message
Не использую VUEX в работе, так как в целом не нравится добавление дополнительного слоя в виде «мутаций». Можно вполне упростить этот код, который еще и в строках передает названия функций (facepalm)

const actions = {
  fetchVariable1({ commit }) {
    return asyncAction().then(data => commit('SET_VARIABLE_1', data))
  },
}
const mutations = {
    SET_VARIABLE_1(state, data) {
       state.variable1 = data;
    },
}

до

const actions = {
  fetchVariable1(state) {
    return asyncAction().then(data => (state.variable1 = data))
  },
}

Экшены — уже часть экосистемы стора, и если в них не проводить изменения данных, то смысла в них нет. Логично было бы оставить либо actions, либо mutations. Разработчики данной библиотеки аргументируют таким вот странным способом:

Запомните, причина, по которой мы вызываем мутацию вместо изменения store.state.count напрямую, в том, что мы хотим явным образом отслеживать её. Это простое соглашение делает наше намерение более явным, что упрощает понимание происходящих изменений состояния приложения при чтении кода. Кроме того, это позволяет использовать инструменты для отслеживания каждой мутации, создания снимков состояния или даже использования «машины времени» для отладки.

Делает явным? Ничуть, лишь удлиняет путь и размазывает логику по нескольким сущностям. Отслеживание каждой мутации, то есть вызовов мутирующих функций? В реальных приложениях это не нужно — могут быть задачи отследить, что изменился определенный параметр в сторе и предпринять соответствующие действия, а вот знать, что его изменила функция SET_VARIABLE_1 или SET_VARIABLE_ALL бывает нужно только для дебага очень запутанных приложений и можно так же быстро отловить обычным console.log. Тайм тревелинг — маркетинговая фича, добравшаяся до умов разработчиков, но реального применения у нее нет, так как если нужно сделать к примеру историю редактирования документа, то никто в здравом уме не будет полагаться на «историю действий» вместо «истории состояний». А к созданию «снимка состояний» добавление дополнительного слоя в виде mutations не имеет никакого отношения, в общем, очень слабая аргументация, берущая лишь продающим стилем изложения.

По статье — решение использовать require.context не лучшее, особенно с преобразованием имен. Таким образом ни IDE, ни человек не сможет понять, что же сейчас находится в export default modules — поможет только console.log + чтение документации к архитектуре, если она написана, а это дополнительные затраты времени. Лучше генерировать классический реэкспортный файл.

Ну и пол-статьи про то, как заменить один объект другим объектом, создав для этого функцию — как скучно, наверно, было заниматься переводом)
Кроме подхода «использовать технологию, чтобы решить проблему» разработчики используют еще «потому что привыкли», «потому что где-то прочитали, что так хорошо», «потому что могут» — не менее распространенные подходы, чем первый) Думаю, стоит узнать у тех разработчиков — для чего вместо
.form { .input { & .red {} } }
писать
.form { .form__input {} .form__input_red {} }
так как никакого практического смысла это не несет.
Согласен с Named — в статье явно верстальщику приписываются компетенции от другой профессии — «веб-мастер», а надо бы их разделять.

Так что я бы оставил в списке целевых технологий: адаптивная верстка, препроцессоры, Git, работа с готовыми javascript-библиотеками (уметь подключить и кое-что подправить на упрощенном js типа jQuery), несколько графических редакторов, работа с изображениями и svg-масками, шрифтами, особенности верстки писем, владение вставкой переменных в каком-либо шаблонизаторе (предпочтительно JSX+Pug), принципы SEO и оптимизации для поисковиков. Зарплата как я могу судить по мониторингу рынка с 2000-х будет в районе 1000$ за такой набор, а при отличном владении и высокой производительности — до 1500$. Обучаться ремеслу придется в районе года-полутора.

А вот для веб-мастера плюсом к этому нужно знание нескольких CMS-движков, уметь настраивать большое количество модулей к ним и темы, заказать хостинг и выложить это дело на сервер, базово раскрутить в поисковиках, написать кастомные js-компоненты на базовом уровне, поправить серверный код на php, написать документацию по пользованию системой и терпеливо поддерживать клиентов. Продвинутые веб-мастера могут делать сложные интернет-магазины. Зарплата тут будет зависеть от конторы, но можно рассчитывать при достаточном опыте на 2000-2500$, я вот мог в бородатое время и больше «наработать» — например, за месяц успевал сделать по 3 проекта по типу такого полностью «под ключ», с кастомной админкой под каждый проект и инлайн-редактированием. Обучаться этому ремеслу придется + 1-2 года от становления хорошим верстальщиком.

Ну, а Node.js и Webpack — это уже от третьей профессии, javascript-разработчик. Это альтернативный веб-мастерингу путь, который приведет к становлению frontend-разработчиком (комбо верстка+js на крутом уровне), тут и так все понятно)
Читаю ветку, слова вроде знакомые, но в общую картинку как-то не складываются) Попробую распутать.

Отправная точка как проблема — коллизия имен стилевых классов, так как все они находятся на глобальном уровне. Решается тремя основными подходами:
— уникальное именование (в том числе по БЭМ). Недостатки — длинные имена классов, ручное именование, соответственно высока возможность ошибки, нет автодополнения в IDE — в общем, пригодится только для маленьких проектов.
— большая специфичность (`.landing-block.list-item{}` вместо просто `.list-item{}`) — подход, гармонично воплощенный во всех препроцессорах методом вложенности классов. То есть подобная склейка происходит автоматически, что дает на выходе АНБ (абсолютно независимый блок) «из коробки». Недостатки — у родительских классов все равно приходится вручную поддерживать уникальность, нет автодополнения.
— добавление уникального ключа к каждому классу либо какой-либо человекопонятной переменной вроде названия папки (CSS Modules). Наиболее прогрессивный метод, когда все файлы стилей подключаются непосредственно в js-файлах компонентов и проходят через специальный обработчик (например, css-loader Webpack). Присутствуют все «бонусы» — модульность, автодополнение, уникальность, ну и если еще используется препроцессор — то и все его возможности.

Смутили в ветке обсуждения такие выражения, как
— «локальные стили» — это как? CSS классы в любом случае будут глобальными. Условно «локальными стилями» можно считать только те, которые указаны в атрибутах типа <div style=""/>, но так сейчас делают только письма ввиду отсутствия поддержки отдельных CSS-файлов, либо CSS-in-JS — ужасный паттерн, который я намеренно не стал перечислять выше, пусть он уже совсем уйдет в небытие.
— «А какой шаблонизатор поддерживает css модули?» — их поддерживает не шаблонизатор, а сборщик, но только при импорте в js-файлах. То есть el.innerHTML = '<div class="${styles.myClass}"/>' можно сделать на «ванильном шаблонизаторе»)
— «Использовать фреймворк только ради того...» — вместо БЭМ и лучше него — препроцессоры с вложенностью классов, но и css модули тоже можно использовать, как писал выше, никакие фреймворки не требуются.

Так что вроде понимаю слова — типа локальные стили, шаблонизатор, модули, фреймворк… Но как будто они накиданы наобум
Статья популяризует MobX, что не может не радовать, это отличный инструмент, на мой взгляд. Хотя описаны довольно простые сценарии, уверен, этот опыт пригодится разработчикам.

Из недостатков вижу следующее:

1. "@action.bound… Не используйте его, если внутри коллбека нет изменения наблюдаемых полей" — тут сразу ряд вопросов.
— Подразумевает ли это, что @action использовать в подобном случае можно?
— Чем мешает использование @action или @action.bound на методах, не изменяющих параметры стора?
— Чем @action.bound такой особенный?

Вот моя версия ответов.
Если параметры стора данным методом не изменяются — то лучше и не использовать на них эти декораторы (@action или @action.bound), так как они навешивают довольно большое количество логики и будут зазря отъедать процессорное время. Но в большинстве случаев это означает, что данный метод — не часть экосистемы MobX store и может быть вынесен как отдельная функция в утилиты.
Различие между @action.bound и @action минимальное, первый отличается лишь биндингом стора. Смотрим реализацию. Сокращенно:

action = createAction(fn.name, fn)
boundAction = createAction(fn.name, fn.bind(target))

Таким образом, это по факту сокращенная форма классического способа биндинга контекста в классах (пятый стандартный способ в дополнение к четырем из статьи):

class Store {
  constructor() { 
    this.myMethod = this.myMethod.bind(this) 
  }
  
  @action myMethod()
}

Так что ничем @action.bound не особенный, и подходит для всех методов стора в экосистеме MobX, и удобнее эти декораторы навешивать автоматически, если придерживаться паттерна actions-inside-classes. Например, таким декоратором.

2. Конвертация кода в другую структуру (из промисов в генераторы) — сомнительное решение. Вопрос недоверия к преобразованному коду в целом уже не возникает, за последний год я не сталкивался с тем, что babel при трансформации создает нерабочий или не так как нужно работающий код, хотя раньше такие случаи не были редкостью. Но вопрос кроссбраузерности стоит. caniuse.com/#feat=es6-generators говорит, что некоторым проектам с широкой поддержкой браузеров такой вариант не подойдет, так как генераторы используют новые синтаксические конструкции, не поддающиеся полифиллингу.
Я бы однозначно выбрал «придется выносить функцию обратного вызова в отдельный метод», подавив в себе желание «иметь возможность передавать анонимную функцию». Получив анонимный стектрейс… Нет, не замечал за собой такого желания)

3. По поводу ререндеринга всего компонента, когда меняются нужные только одному из дочерних элементов параметры, могу предложить такую схему в данном случае (там кстати ошибочка в коде — константа называется то PlayerComp, то AudioComponent):

const AudioComponent = withVisible({
  Component: PlayerComponent,
  condition: state => !state.hasAudio && !state.hasErrors
});

function Player({ model }) {
  return <AudioComponent conditionState={model} />;
}

function withVisible({ Component, condition }) {
  function Visible({ conditionState, ...otherProps }) {
    return !condition(conditionState) ? null : <Component {...otherProps} />;
  }

  return observer(Visible);
}

Тут нужно обратить внимание на то, что так как в этот декоратор передается observable-объект, то нужно добавить observer(Visible) для того, чтобы MobX reaction связал изменения в нем с необходимостью заререндерить этот Visible HOC. Код не проверял, но логических ошибок не вижу)

Другой вариант — передавать <AudioComponent visible="model.showAudio" /> строкой либо годящимся для TS прокси с конвертацией в строку <AudioComponent visible={proxy(model).showAudio.toString()} />, а в декораторе уже подключать соответствующий стор исходя из этой строки и осуществлять MobX observed-наблюдение. Вариант, кстати, годный, но в случае со строками нужна внимательность — при рефакторинге названий параметров подсказок изменить строку не будет, а в случае с линзой получается довольно многословно и нельзя переиспользовать один прокси несколько раз, нужно пересоздавать. Так что недостатки есть, но это в любом случае лучше, чем ререндеры или ручной SCU.

***

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

const obj = { method() { console.log(this) } }
obj.method();
const fn = obj.method;
fn();

А в целом — палец вверх за статью!
Вот согласен, если 1-2 разработчика на проекте, то ручное форматирование действительно развивает внимательность и концентрацию, учит уделять внимание каждому символу, вырабатывает самодисциплину. Первые 8 лет в разработке писал код исключительно в блокноте, без IDE и линтеров, и научился делать это достаточно красиво… А потом изобрели Eslint, и постепенно начал понимать его удобство, особенно при расширении команды. А уж в последние годы, когда появился Prettier, больше и не думаю об этом. Но опыт был полезный, сформированные тогда навыки помогают и в рефакторинге, и в код-ревью.
Думаю, рекомендовал бы юниорам тоже практиковаться без IDE с форматтерами и подсказками — это также заставляет думать о грамотной организации кода по файлам, сокращении схем нормализации и минимальном пути по пробросу данных (в те времена мне встречалось много кода на php, где приходилось открывать более 10 файлов, чтобы понять, что именно передано в функцию). Сейчас с господством IDE это снова почти становится проблемой, так как при наличии интеллектуальных подсказок можно фактически не уделять времени грамотному проектированию. Но не нужно.
Кстати, музыкант, и играю гаммы — это действительно полезно)
Спасибо за перевод, когда-то тоже основывал решение по выбору react-like-библиотеки для проектов на основе синтетических тестов. Однако, после нескольких сравнений в реальных проектах (заменой react с помощью webpack-алиасов на preact / inferno и тщательным исследованием профилировщика), пришел к выводу, что разница в производительности близка к нулю, как и разница в размере production-бандла. Тем не менее, регулярно стараюсь проверять этот вывод на новых версиях библиотек и новых проектах, вдруг действительно обнаружится заметный выигрыш? Но пока он заметен только на «добавить тысячи строк — обновить тысячи строк», что в реальном приложении не встречается, так как подобные задачи разбиваются по lazy-паттерну. А вот несовместимость некоторых пакетов с «неканонической» react-like библиотекой и разное поведение встречаются довольно часто.
Да, в классовых компонентах есть композиционная проблема — если на componentDid(Mount|Update) нужно выполнить несколько разнородных операций (поставить несколько обработчиков, вызвать асинхронную логику), то они указываются одноуровнево, что приводит к раздуванию самого класса. Предлагаемые вами behaviors, как понимаю, позволяют задавать эту логику в отдельных сущностях, которые затем «склеиваются» в основном компоненте, при этом учитывается логика Реакта и проброс в render, что удобнее композиции отдельных классов. Идея, в целом, очевидная, и мне тоже странно, что разработчики Реакта предпочли создать хуки вместо упрощения работы с классами.

Согласен с faiwer, что у хуков множество ловушек, и написать низкопроизводительное некрасивое кодом приложение стало намного проще. То, за что я любил Реакт — отсутствие своего мета-языка и строгих правил, очевидность жизненного цикла, простота в целом, с хуками начало уходить и библиотека превращается в «ни туда — ни сюда» — не фреймворк и не библиотека рендеринга.

«Месиво в классах»? Вы, наверное, еще не повидали «месиво в хуках», см. скоро в каждом втором проекте. Решается прямыми руками)
Избегайте описывания ваших форм с помощью конфигов

Вот не согласен максимально. В итоговом варианте с портянкой в разметке получилось, что компонент — черная коробка <Form /> с неизвестным набором полей и полностью скрытой логикой, хранящейся во внутреннем стейте. И вот навскидку то, с чем придется столкнуться при таком подходе:

  • Для проброса initialValues в форму придется копаться в реализации и передавать объект с согласованными с именами полей параметрами. Если добавятся propTypes / TS Interface, то это будет дубляж
  • Типы передаваемых initalValues, опять же, нужно согласовывать (для селектов / чекбоксов)
  • При добавлении влияющей на пропы конкретного поля логики (включение / выключение отображения, disabled, optional, смена label) придется внутри писать массу if-конструкций
  • Динамическую раскладку придется поддерживать вручную (чтобы если поле пропало, то следующее встало рядом с ним)
  • Хотелось бы посмотреть, как будут реализованы валидации и синхронизация их с backend (когда в ответ присылается к примеру { email: «INVALID»} в слое-контроллере, и нужно вставить эту валидацию в поле в добавление к имеющимся, подсветить его с указанием локализованной ошибки, прокрутить страницу к нему)
  • Как будут исключаться поля с пометкой optional из валидаций, а с disabled из отправляемых данных на бэк
  • Как будут контролироваться динамически добавляемые поля
  • Как сторонние компоненты и другие формы смогут влиять на эту (получать значение, проставлять, менять конфигурацию полей)


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

В общем, я бы не использовал описанный в статье подход даже для таких казалось бы маленьких и супер-простых форм, потому что в продакшене будет совсем другая история, и следовало бы начать с проектирования грамотного конфига. Фичи в него можно добавлять постепенно и обрабатывать централизованно с минимальным вмешательством непосредственно в компоненты уже сделанных форм. Кроме того, убежден, что грамотно спроектированный «скелет» (с глобальным стейтом, механизмом валидаций, конфигом полей, оптимизацией рендеринга) не является оверинжинирингом, а служит базой для масштабирования, под какими бы yarniенками ни маскировался подход «слепить по минималке и перекопировать по сотне раз с разной реализацией», в будущем все равно кому-то придется сделать нормально.

Накипело, столько уже проектов повидал с такими вот формами. Не надо так. Но и превращать конфиг в json-схему генерируемую в cms по созданию форм, разумеется, тоже не надо — это как раз оверинжиниринг, а не создание дополнительного объекта.
Согласен, хуки — не только перемешивание логики и разметки, но еще и мешанина асинхронно выполняемых функций и синхронного рендеринга. Хуки — по факту обычные setTimeout:

let prevMyProp = null;
function Component({ myProp }) {
  setTimeout(() => {
    // запрет выполнения при совпадении параметров, как в хуках [myProp]
    if (prevMyProp === myProp) return;
    // логика
    1 + 1;
    // для будущей проверки на совпадение
     prevMyProp = myProp;
  }, Component.didRenderTimeout)

  React.useEffect(() => {
    1 + 1;
  }, [myProp])

  return <div />
}


Но так как Component.didRenderTimeout — динамический параметр, а проверка на изменение пропов — довольно распространенная операция, разработчики сделали хелперы для этого, названные «хуками». Этот шаг по сути небольшой, но он вызвал неоправданный ажиотаж у людей со складом ума «вышло позже — значит надо использовать, все остальное легаси!», которые еще и толпы создают на премьерах новых айфонов) Но у functional components + hooks масса недостатков:

  • раздувание чистой функции рендера
  • создание функций, интенсивно использующих замыкания и друг друга (один хук получает информацию из другого хука, который вытаскивает ее из ref, сохраненного в стейте компонента и вызывает setState). Одна-две композиции не принесли бы ощутимого вреда, но я вижу в проектах по пять-десять тесно связанных функций, походит на характерный для jquery клубок-пятисотстрочник.
  • синтаксис, основанный на «соглашениях». Вместо понятного жизненного цикла (до рождение, после рождения, после обновления и т.п.) с именованными названиями пришли useEffect (использовать эффект?) с неименованными параметрами (первый — асинхронный колбэк, второй — массив с управляющими вызовом асинхронного колбэка элементами), useState (это название годное), который возвращает массив с первым элементом = значение, вторым = функцией для проставления значения...
  • ухудшение производительности и проблемы с утечками памяти (когда функции создаются непосредственно в рендере и работают с внешними данными)
  • оформление в functional components и отдельных функциях привело к неструктурированности компонентов и обилию ручных пробросов (контекста и других функций)


Таким образом, React сделал шаг в сторону «фреймворкоризации», предложив определенные синтаксические конструкции со своими хелперами (т.е. «соглашения») вместо бытия библиотекой по согласованию переданных данных и DOM-представления. Не смотря на уже 3 довольно объемных проекта, с которыми поработал на хуках+FC, вернулся к классовым компонентам и радуюсь преимуществам:

  • инкапсулированная логика с методами, в которых уже есть доступ к props, context и другим методам
  • чистые render-функции
  • человекопонятный жизненный цикл
  • простота установки переменных (ref / не ref)
  • одинаковые функции типа this.handleChange без оборачивания в дополнительный useCallback (бонус — легкость удаления обработчиков вроде addEventListener)
  • возможность применения декораторов в @-синтаксисе как глобально к классу, так и к методам


Вот теперь думаю, что если бы классы вышли после хуков — то побежали ли бы все с криком «о как круто столько преимущество долой эту всю кашу!» переписывать проекты на классы? Почему-то кажется, что да
Здравые идеи, лаконичный синтаксис, достойный вклад в опенсорс.
Единственное что как вижу слово «велосипед», так сразу в голове что-то скрипит и негодует. Абсолютно любую библиотеку или фреймворк, да и язык программирования можно назвать «велосипедом», как и большую часть кода проектов — у этого слова просто отсутствует значимый смысл. А если бы решения (именно это слово лучше употреблять) не совершенствовать, не создавать более удобные, логичные, производительные кодовые базы и паттерны — тогда о чем вообще слово «разработка»?
За собой наблюдал неприязнь к кастомным решениям только в период юниорства, когда сам не мог ничего толкового создать, и умел только компоновать чьи-то решения. А так как юниоров всегда пруд пруди, видимо они и распространяют везде это словечко
Но в этот плагин же все равно нужно руками вбивать нужные полифиллы? Не использовать ли анализатор кода, который в каждый файл будет сам вставлять полифиллы исходя из того, что в этом файле используется, и затем конкатенировать в отдельный polyfill.js?
Благо на дворе 2020 и такой инструмент есть: browserslist + Can I Use как источник данных, какие технологии поддерживаются в целевых браузерах; @babel/preset-env c useBuiltIns: 'usage' в качестве анализатора кода и инсертера полифиллов; core-js как источник полифиллов; Webpack optimization.splitChunks для вынесения в отдельный кешируемый файл вроде polyfill.somecontenthash.js. Про год шучу, было доступно и раньше.
Этот способ позволяет точно определять необходимые полифиллы для конкретного проекта и соответствует требованиям информационной безопасности. Альтернатива — polyfill.io, внешний скрипт, в который передается вручную набор необходимых фич (например, https://polyfill.io/v3/polyfill.min.js?features=es2017), и их сервер в зависимости от User Agent включит в отдаваемый файл только те полифиллы, которые требуются конкретному браузеру. Так, современным будет отдан с размером менее 1кб, а стареньким — соответствующей возрасту толщиной. Соответственно, как внешний скрипт, на непредсказуемое время может блокировать загрузку страницы и отдавать любой код, крадущий ваши данные (даже доверяя конкретным разработчикам, надо учитывать что и Гугл раз в год бывает взломан). Но многие выбирают именно это решение, да и вообще пользуются опенсорс-пакетами, не валидируют поступающие данные, и… в общем, дело каждого.

В любом случае, думаю что оба решения получше, чем ручной подбор полифиллов (когда я подбирал вручную, ан-нет, а всегда что-то да забывалось, то Date.now забудешь, то .trim(), то Object.assign).

А статья будто из родных 00-х, удивительно сейчас такое читать, как и видеть подобный стиль кода с использованием
// startHere Make some forEach
arr.forEach(function() { someLogic; })
// endHere Make some forEach

Эх, сколько можно переписывать одни и те же статьи, причем делая хуже и хуже… Ну вот чем отличается от Prettier, ESLint, Husky, Lint-Staged и EditorConfig: инструменты для написания аккуратного кода, кроме в несколько раз урезанных объяснений и функционала? Или может это начало клона Стартуем библиотеку компонентов на React и TypeScript? Только не говорите, что автора посетила мысль, что за 3 года все уже забыли React.js: собираем с нуля изоморфное / универсальное приложение. Часть 1: собираем стек. Могу еще let me google for you.

Ну правда, не стыдно одно и то же переписывать у других авторов? В чем польза именно вашего цикла статей? Я пока вижу только базовые конфиги плохого качества и объяснения из разряда «Я думаю тут все понятно» (а если нет — читайте доку), в приведенных выше статьях получше будет.
Подобные ошибки характерны, если в приложении нет тщательных валидаций, а это подавляющее большинство проектов. В типах может быть все прекрасно, а АПИ бэкенда отдало null в обязательном параметре, или number в id одного из элементов массива вместо строки, либо со стороннего сайта прилетел параметр с некорректным типом, либо непредсказуемо (а в JS такое частенько) сработало приведение типов — и вот в хранилище совсем не то, с чем может справиться статический анализ.

Во фронтенде много источников данных, а большинство архитектур построено таким образом, что возникающие непредсказуемые ошибки не изолированы в отдельных контекстах, а выскакивают в глобальный unhandled exception и рушат приложение полностью. Спасает от этого архитектура с тщательной валидацией + изоляцией сред выполнения со стратегиями отказоустойчивости + проверкой типов в рантайме непосредственно в функциях. Статический анализ тут абсолютно бесполезен, он оперирует «вероятными» типами и никак не освобождает от того, что писал выше.

При этом и не мешает сделать все хорошо. Я написал в недостатки, что типизация иногда расхолаживает разработчиков, которым становится лень описывать типы 4 раза: в TS, в рантайме, в валидации, в названии переменной (я сторонник более явных названий переменных, например не list, в котором может быть что угодно — array, collection, map, set и т.п., а listArray, listObservableMap). Конечно, забота старших разрабов следить за исполнением стандартов кодирования и качества в конкретных проектах, но тенденцию к расхолаживанию я замечал.

Благодарю за карму, настроение улучшилось!

P.S. По поводу масштабирования — гарантом единообразия кода и его качества являются стандарты + контроль их соблюдения. Сам язык или наличие типов никак не влияют на то, что 10 разработчиков будут писать непонятный друг другу код разного уровня качества. На памяти уже два случая, когда после увольнения разработчика остальным приходилось переписывать его код, так как он был им непонятен, и один из этих случаев как раз в TS-проекте. Но это камень в огород тимлида (эх...), который тогда не уделял должного внимания стандартам и приведению навыков команды к общему уровню методом публичного обсуждения проектируемых каждым решений.
Если человек привык именно к типизированным языкам — разумеется, он привыкает и к дополнительным источникам получения информации, и к синтаксису, нарабатывает удобные методы прототипирования в условиях 99% типизированного кода, учится полагаться на предупреждения компилятора, а не изучение кода и собственную внимательность.
Я же полтора десятка лет работаю с нетипизированными языками, и описал, с какими сложностями столкнулся вместе с командами фронтенд-разработчиков при попытке создавать SPA на TS. К сожалению, не вижу возможности провести достаточно достоверное исследование по параллельной разработке одинакового приложения на JS/TS, чтобы замерить скорость выполнения задач и качество итогового продукта — здесь практически все зависит от опыта разработчиков, а не используемых языков.
Поэтому в холиваре на заданную тему участвую редко, и опираюсь только собственный опыт, в котором внедрение типизации принесло намного больше вреда, чем пользы. Удивляет, что когда достаточно аргументированно делюсь опытом, стоившим не один миллион денег компании в виде увеличения сроков поставки, расходов на разработчиков и техсап, а также репутационные потери, почему-то получаю минусы в карму. Нет коллеги, я не покушаюсь на вашу веру, а вношу посильный вклад в развитие сообщества, которое вполне вероятно придет к выводам, схожим с моими. Либо научится преодолевать те сложности, которые я описал.
Несмотря на то, что штат поддерживающих TS разработчиков в последние 2 года значительно разросся и окреп, и еще более массово минусует посты и комментарии «не уверовавших», продолжаю оставаться в теперь уже непопулярном лагере сторонников написания кода без статического анализа типов. Не подумайте, что не имею опыта работы с этим языком, или что мало читаю нахваливающих его статей и комментариев — вовсе нет, и крупные проекты были, и аргументы из сотен комментариев аккуратно сложены на весы. Но в сухом остатке TS лично в моем понимании — гирька на пару кило пользы, а вреда тащит на пуд.

Вот значимая польза:
— при наличии сложных моделей данных TS справляется лучше, чем JSDoc — типы занимают меньше места, могут быть многосоставными и более гибкими
— при использовании паттернов, скрывающих промежуточные результаты (ФП), либо функций, допускающих передачу параметров разного типа и возвращающих разнородные значения, TS определенно поможет предсказать результат
— при доработке легаси-проекта, в написании которого участвовали разного уровня разработчики, а качеству кода и стандартизации уделялось мало времени (таких проектов, к сожалению, подавляющее количество...), TS поможет быстрее понять, на что повлияют вносимые изменения.

А вот и значимый вред (тут буду чуть более подробным):
— увеличивается время до достижения качественного результата.
Разработка — процесс творческий, и от поступления задачи до качественного кода может быть множество этапов (проектирование, черновик-mvp, оптимизированный черновик, отрефакторенный условно-качественный код, качественный код после ревью). Бывает и такое, что «сразу идеал», а иногда приходится придумывать и тестировать на производительность несколько версий. А часто — еще затрагивать довольно много окружающего кода. TS заставляет в каждой из версий описывать типы, сочетать их с окружающими, и переписывать при рефакторинге. Иногда спасает «any». А еще чаще надоедает эта возня и пушится код, не доведенный до идеала.
— увеличивается кодовая база, которую нужно поддерживать
— ухудшается читаемость. Это личное, но мне действительно сложно интерпретировать TS-код, когда к привычным источникам информации (название переменной, название функции которая преобразует данные, проверка данных в рантайме, комментарии) добавляются еще источники (предполагаемый тип переменной, предполагаемое возвращаемое значение, ссылки на сложные типы, дженерики) и вместе с ними дополнительные символы (:<>). То, на что без TS тратил условный X времени, становится как минимум 1.5X, пока все разложишь в голове, отделишь кодовые символы от типовых, научишь мозг сосредотачиваться на полезной составляющей кода. В итоге от этой пестроты намного быстрее охватывает усталость. Со временем просто стал фильтровать это все, как «неизбежный шлак», стало чуть попроще, но не особо.
— разработчики, у которых «скомпилировалось», менее тщательно относятся к проверкам в рантайме. Поэтому при реальной работе, когда есть множество источников данных, количество багов из разряда «cannot read smth of undefined», «toLowerCase is not a function» и т.п. возрастает. Возможно, в ваших проектах было по-другому, в тех, где участвовал я, их было неприлично много (нет, не мной допущенных ;)
— комплексный рефакторинг усложняется на порядок.
Я не об «изменении нескольких параметров в объекте» или «изменении параметров в паре функций» говорю, а о многосоставных изменениях кодовой базы на несколько тысяч строк. Сам за карьеру программиста таких рефакторингов очень плохо спроектированных частей приложений осуществил не один десяток раз, и если без TS это занимало Y времени, то с ним по субъективной оценке — минимум 3Y. На каждый чих приходится переписывать кучу типов (а то ведь не соберется), и уже после сотни чихов подумываешь о долгосрочном отдыхе на Бали. Вообще за крупные архитектурные изменения берутся очень мало специалистов, дело это сродни разгребанию Авгиевых конюшен, но что-то мне подсказывает что плохо написанные TS-проекты останутся помойками навечно, потому что даже глубоко верующий в мощь тщательно описанных типов скорее всего разочаруется в них, когда нужно будет делать что-то крупное и желательно быстро, т.к. затрагиваемый код может ежедневно наращивать конфликты с другими задачами.
— для корректной работы весь код, включая подключаемые библиотеки, должен быть типизирован, иначе получается «лоскутное одеяло» — в одних файлах все в TS, в других много мест с «any». Да, многие библиотеки имеют типы или для них сделаны пакеты с типами (версии которых нужно вручную синхронизировать), но это только в последнее время, и то далеко не везде. А чтобы было везде — приходится создавать себе «работу на пустом месте», форкая библиотеки, либо создавая для них типы и дорабатывая по мере обновления этих внешних зависимостей.
— дополнительное время на обучение коллектива, составление правил кодирования типов и ревью их грамотного использования.

Что касается «значимой пользы» — я лично стараюсь писать код «прямым как топор»; без паттернов с неявными промежуточными результатами вроде `pipeRight(toLowerCase, first, getUserEmails)`, в которых где-то объект, где-то массив, а в итоге наверное строка; без многочисленных этапов преобразования данных; без длинных функций, которые разве что кофе не сварят; с проверками всех нужных типов в рантайме и обязательной валидацией поступающих извне данных. Возможно, у вас совсем по-другому, и плюсы перевешивают, но этот язык — абсолютно точно не для всех проектов, скорее для выборочных.
Пишу статейку про формы на React+MobX, думаю пригодится — иногда нужно именно свои механизмы пилить, а не компоновать из готовых, но не подходящих под задачи

Очевидно — описанная в статье схема работы подойдет, если приложение простое, отсутствие коннекта кратковременное, не подразумевается разбиение на чанки со своей бизнес-логикой и если CI настроен на релизную схему, например раз в неделю или на схожий период.
В другом случае: то, что пользователь "накликал" может быть завязано на права доступа и конкретные ответы сервера, так что пайплайн событий будет сломан; редиректы и открытие новых страниц при разбиении на чанки не будет работать — если не загружать их всех к кэш, а тогда их смысл теряется наполовину; в подавляющем большинстве случаев "оптимистичное обновление" будет обманывать юзера, и он получит негатив, когда "делал-делал и вдруг все сломалось", т.к. возникнет реальный коннект; если приложение имеет несколько релизов в день например по Kanban CI, то количество поломанных действий возрастет, ошибки в логгер будут сыпаться тоннами, а причина одна — полный рассинхрон реальности и оффлайнового кэша, и в этой каше будет сложно разобраться.
При длительном дисконнекте данные будут приходить старые, например отсутствовать ответы техподдержки или не обновляться статус услуги, что повысит нагрузку на техсап, которые будут разводить руками — опять что-то с сайтом нахимичили разрабы. При перезагрузке страницы нужно будет восстанавливать "виртуальный" стейт, который разойдется с серверным, если используется server side rendering, что приведет к непредсказуемым последствиям.
Вывод: если чуть сложней todo листа — лучше выбирать стратегию показа нотификации "у вас отвалился инет" и проверять раз в секунду, не появился ли он, сохраняя по возможности стейт приложения, либо по лайтсу пытаясь его частично восстановить при долгом отсутствии коннекта.

Интернет-магазины делаются на готовых CMS вроде Битрикса, с адским фронтендом и общей тормознутостью, но громадным бизнес-функционалом, который «под ключ» писать очень дорого. В кастомной разработке сложных продуктов (SPA), как правило, все лишние десктопные компоненты исключаются из бандла. В идеале и стили бы, конечно, исключать — но они в основном не съедают много трафика и на производительность влияют слабо.

Я тоже помню текстовые сайты на заре развития Интернета, когда модем 32кб/с по карточкам, но сами приложения были с постоянной перезагрузкой, ужасным дизайном, и пользоваться было неудобней. Сейчас благо инет в основном быстрый, и можно делать красивые, удобные и быстрые в работе веб-приложения, увеличив размер файлов при первичной загрузке (при повторной — они возьмутся из кэша и откроются быстро). Ваши претензии надо перенаправить к создателям громоздких CMS-систем из 2000-х.
Подобная ситуация во многих областях, по количеству подписчиков считать что Бузова — крутая певица и пример для подражания, тоже такое себе.

История из практики — для создания продвинутого ci наняли человека, написавшего много статей на Хабр, более-менее технически грамотных, с положительной оценкой сообщества (на личности переходить не буду). Каждый месяц он обильно рассказывал, какой строит космолет, и советовался с лидами разработки по поводу архитектурных решений на нарисованных схемах. Через полгода выдал базовый нерабочий MVP, на который и две недели-то жалко было бы потратить. А все это время проект вполне себе корректно собирался на системе, созданной разработчиками, и за эти полгода основательно развившейся. Так что еще один кейс в копилку недостатков медийных личностей — вам может попасться чукча-«теоретик», а не «практик».

Не перестаю так же как и вы удивляться малому количеству продвинутых технических статей, а если и есть — то с небольшим количеством просмотров. В то время как болтология и hello world всегда в топе и в обильных количествах. Сам постараюсь по мере свободного времени развивать именно техническую область, но больше на хайповые темы — раз уж и так большая часть проектов на известных фреймворках, то хоть пусть разработчики закладывают перспективу, а не просто собирают «франкенштейна» из готовых кусков.

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity