Pull to refresh
47
0
Дмитрий Казаков @DmitryKazakov8

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

Send message
Подобные ошибки характерны, если в приложении нет тщательных валидаций, а это подавляющее большинство проектов. В типах может быть все прекрасно, а АПИ бэкенда отдало 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 всегда в топе и в обильных количествах. Сам постараюсь по мере свободного времени развивать именно техническую область, но больше на хайповые темы — раз уж и так большая часть проектов на известных фреймворках, то хоть пусть разработчики закладывают перспективу, а не просто собирают «франкенштейна» из готовых кусков.
Благодарю за статью и хорошо структурированный код. Сам незримо участвовал для получения опыта — за пару дней собрал рабочий прототип (тоже canvas), определил моменты в которых был слаб и точечно прокачал. Отдавая себе отчет, что первое-второе место для javascript-разработчика (а участвовало их много) взять будет неоправданно сложно, а поощрительные призы экономически невыгодны, дальше дорабатывать не стал. А пара дней на то, чтобы расшевелить мозг новыми задачами — это удовольствие.
Поддерживаю, статья вообще ни о чем, конкретики никакой. Хранить утилиты в отдельной папке, использовать чистые функции, думать перед тем как писать код… Для кого это все
Видимо, напишет еще одну часть, в которой будут новые глупые ошибки
Спасибо, вы правы, подход createProxy(store).registration.email.toString() / toString(createProxy(store).registration.email) может облегчить рефакторинг, если совпадут факторы: в проекте используется типизация, она сделана корректно, IDE ее понимает и корректно меняет параметры при рефакторинге.

В остальных случаях строка подходит отлично — findAndReplace 'store.registration.email' справится с той же скоростью и надежностью, пожалуй я перебдел в данном случае.
Хотя если проект на MobX то лучше storePath все же строкой, чтобы компонент формы не подписывался на обновление значения конкретных полей.
Стараюсь не вписываться в такие проекты — жизнь одна, и если оглядываешься и видишь что полгода не развивался вообще, а писал бизнес-логику и правил баги, в постоянной спешке и стрессе, то должны быть мощнейшие другие мотивирующие факторы. В госкомпаниях и их подрядчиках таких факторов как правило немного. Благо живем в мире, переживающем глобализацию, и найти интересный и хорошо оплачиваемый проект вполне возможно
Для сервиса шаблонизированных темплейтов на node.js я использовал Marko — он на порядок быстрее Pug, кстати, так как преобразует все в чистые функции. Выдерживал прессинг танка с коронными 4мс скоростью ответа (вход-выход по nginx). Возможно, пригодится

Реакт да, тормоз в этом смысле, но у него ssr это побочная фича, которая мало кому нужна
Полностью согласен про «лучшее из возможного» — все эти презентации, встречи и т.п. нужны для того, чтобы согласовать разумные сроки. Мне встречались такие кейсы:
— сроки назначены сверху (или клиентами), часто уже просрочены, и абсолютно оторваны от реальности. Здесь обучение руководства с помощью презентаций и маппинг их радужных представлений с реальностью необходимы, иначе проект просто умрет. Например, от сильного прессинга, под которым невозможно станет работать.
— сроки сильно приуменьшены, но реальны — как принято говорить, «минимально необходимы». В этом случае нужно донести, что бизнес-задача будет выполнена, но образуется техдолг, который будет замедлять и замедлять развитие проекта, до состояния когда простейшая задача будет выполняться полдня или целый день и приводить к непредсказуемым багам. На моем опыте в такое состояние проект приходит в среднем за полтора года, при подобной схеме управления.
— сроки адекватные, техдолг минимальный
— сроки раздутые — тут уже работу нужно проводить с командой, чтобы не распалялась на «а давайте все перепишем на новую хайповую технологию» и другие бесполезные в основном затеи.

Если работаю в компаниях с первыми двумя «управленческими схемами», и при этом «предоставьте Ваше видение мы им подотремся», варианта два — проверить себя, как долго сможешь там отсидеть, либо найти более адекватных ребят.
Достаточно классический разговор — в молодости по максимализму не раз вел такие, отстаивая идеализированный мир, где важны не деньги, а самореализация и позитивный след в истории, способствующий развитию. Со временем баланс выровнялся, и примерно ["деньги", "реализация и развитие", "польза для общества"].test(benefit => weight(benefit) === "33.3%") === true. Для меня этот баланс поддерживает гармонию компонентов в системе «личность».

Я не могу сказать, что что-то здесь для меня вторично. Вполне реально найти компанию, отвечающую такому соотношению, как, в общем, и любому другому. У вас деньги занимают 90%? Найдете и такую компанию. Хотя куда проще было бы для подобной цели работать чиновником.

К слову, достижение корректного соотношения в целях работает не только параллельно, но и последовательно — я могу устроиться на проектную работу ради денег на 2 месяца, а после его завершения — заняться обучением и творчеством, волонтерством на 2 месяца. В случае, если предложений от гармоничных компаний (на мой взгляд) в данный момент нет.
Пока (?) не перекупили, делюсь опытом для тех, кого тоже пока (?) не перекупили. Мне довелось пока (?) не превратиться в разработчика-мебель, за бонусы готового не раздражать начальство своим мнением и опытом, и исправно создающим сотни багов и мучений пользователям своим быстрокодом.
А про все то что вы описываете я уже сказал — «Не с первого раза, так с десятого», зависит от того, зачем вы вообще занимаетесь программированием, и если только за деньги — возможно, это не ваше.
react-router ну очень многого не умеет, тоже думаю о том, чтобы написать статью про проектирование качественного роутера. И про ssr на этом стеке тоже тема актуальная, хотя его, по моим прикидкам, сделать намного проще.
Хорошая практика — везде использовать именованные экспорты / импорты. Вместе import Field from './field' лучше использовать import { Field } from './Field'. Иначе готовьтесь к Fild / Feld и т.п. переменным по недосмотру.

Information

Rating
6,593-rd
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity