Дима Коваленко

Дима Коваленко

Темы
Неделя
Apr 6, 2020 → Apr 12, 2020

Архив недели @dmtrKovalenko

Понедельник


Карантин карантином, а jsunderhood по расписанию. Меня зовут Дима Коваленко (@dmtrKovalenko), я работаю фулл-тайм над @MaterialUI, ex @Cypress_io На этой неделе будем говорить про тесты (много говорить про тесты), дизайн системы и если силушки останутся – про ReasonML.
notion image

Да, я создаю мемы на непонятных сайтах и не удаляю их подпись. И не стыжусь этого!

Сегодня будем говорить про надежность наших тестов. И в связи с этим хочу спросить: А вас вообще устраивают ваши тесты и надежность покрытия вашей системы?
🤔 6.6% Да, все устраивает
🤔 24.8% Скорее да, чем нет
🤔 54.7% Скорее нет, чем да
🤔 14.0% Нет, лучше б их не было

Сегодня будем говорить про надежность наших тестов. И в связи с этим хочу спросить: А вас вообще устраивают ваши тесты и надежность покрытия вашей системы?
Собственно, что и требовалось доказать. Результаты опроса абсолютно совпадают с моей картиной мира, поэтому встречайте тред про надежность 👇 twitter.com/jsunderhood/st…

Для начала давайте разберемся, что же такое та самая надежность в контексте тестирования? Ваша система на 100% защищена тестами, если:

Вы можете внести любое изменение в бизнес логику и ваши тесты упадут. Или по-другому: изменения в бизнес-логике требуют изменения тестов.

Вы можете произвести ЛЮБОЙ рефакторинг и хотя бы не переписывать тесты заново, а в идеале вообще не менять тесты И конечно когда тесты пройдут – быть уверены что приложение действительно работает.

Вы можете обновить любую зависимость в вашей системе, даже на мажорную версию, и если тесты прошли – быть уверены что система работает.

Ваши тесты не падают на каждый чих, так что красный билд превращается в белый шум (привет jest -u на каждом коммите). На самом деле крайне важный пункт. Если фиксить тесты после любого изменения входит в привычку, то даже действительно серьезная ошибка может быть пропущена.

Возможно, звучит как что-то невозможное. Если бы можно было легко писать такие тесты, то а каких багах и тестировщиках может идти речь? Но мы хотя бы избегать того, что напрочь гробит надежность и делает тесты бесполезными:

И первое, самое очевидное – это недостаточное покрытие приложения тестами. Даже внимание уделять этому не буду. > Но хочу отметить, что нужно опираться не на CODE coverage, а на USE CASE coverage. Если захотите можем сделать отдельный тред о покрытиях.

Итак продолжаем. Поговорим за use case coverage: автоматически высчитать его невозможно, потому что 1 строкой кода может обрабатываться несколько сценариев. Это хорошо описано в статье kentcdodds.com/blog/how-to-kn…

Именно по причине отсутствия метрики тут можно полагаться только на сознательность разработчика, который не поленился и описал все возможные сценарии ручками. В принципе, такие вещи возможно поймать на код ревью, но только при условии реально хорошего погружения в ПР.

Но и code coverage выбрасывать не стоит. Просто важно понимать что написать 100% coverage можно с абсолютно отвратительными и бесполезными тестами. То есть, если коверейджа мало – это однозначно плохо, но если его много – это не значит что все хорошо.

Собственно дальше о том что гробит надежность. И первое что приходит на ум — неправильное и слишком частое использование моков. Например, часто вижу проблему когда начинается замокивание частей бизнес логики внутри тестов, а интеграция модулей остается непокрытой.

В принципе использование юнит-тестов ведет к проблемам надежности. Чем выше мы взбираемся по пирамиде, тем более надежные у нас тесты. На этой неделе мы к этому еще вернемся, но в данном контексте: Чем меньше у вас юнит-тестов, тем надежнее и устойчивее к изменениям ваша система

Моки в тестах это вообще довольно опасная вещь, потому что мы сознательно вырезаем кусок кода нашего приложения в тестах.
 Это примерно тоже самое что писать any в ts. Если можно без них обойтись - лучше обойтись.

И вообще! Хватит мокать функции только потому что они находится в другом файле или потому что это внешняя зависимость. Кто вам сказал что эта зависимость или этот код будет работать правильно через 2/3/10 лет?

Вот собственно классическая проблема юнит-тестов и overmocking-а.
 С таким тестом мы не можем ни изменить название роута, ни способ которым мы делаем запрос (например на axios) – в любом случае придется переписывать тест.
notion image

Собственно, а что мы вообще проверяем в этом тесте? То, что наш код дергает fetch и возвращает промис? Зачем нам это тестировать? Что нам это дает? - нипанятна

!! Вообще эту проблему можно описать одной фразой – “Тестирование реализации”. Тесты должны проверять не то как наш код НАПИСАН, а то как наш код РАБОТАЕТ - и будет вам счастье :)

Для всех – будет отдельный тред про пирамиду тестирования. Затравочка: Кто вам сказал что e2e тесты сломать проще чем юниты? Кто вам сказал что писать e2e тесты сложнее и дольше чем юниты?

Продолжаем эппопею. Не только моки делают тесты ненадежными. Зачастую просто лень разработчиков, которым лень писать чуть-более низкоуровневые условия assert-ов. 
Это очень хорошо видно именно во фронтовых тестах.

К примеру тесты на компоненты можно сделать практически независимыми от фреймворка. Звучит странно, согласен. И самое главное – абсолютно независимыми от реализации компонента/фреймворка/ui kit-a/дизайна.

Все наши тесты состоят из 3 частей: Preparation, action & assertion. 
И если можете взять любой тест на компонент, сделать его точную копию на другом фреймворке и изменить только первую preparation часть и тесты будут работать — мое почтение!

Вот собственно пример такого теста, который абсолютно никак не дергает ни React-specific ручки, ни там названия css-классов. Этот тест придётся менять только при изменении бизнес логики или при изменении внешнего API — собственно чего мы и ожидаем от тестов.
notion image

А вот пример не очень хорошего теста: Завязываемся на названии компонента Day Почему-то дергаем именно 10 день 🤦‍♂️ Завязываемся на название Popover-a и название пропса вместо того чтобы просто проверить что 'div[role="dialog"]' отрисован в html
notion image

И последний пример: Недавно смотрел доклад про рефакторинг. Ссылки не будет, бо вы меня загрызете 🙃 И дело зашло за тесты, спикер рассказывал как он целый месяц рефакторил 1 компонент, потому что ему пришлось переписать все тесты в системе, которые были завязаны на него.

@jsunderhood Расскажи, пожалуйста, что думаешь о фразе "Не мокай, что не твое" или как она в оригинале звучит "Don't mock what you don't own".
Очень разумно. Когда это наш код – у нас есть хотя бы толика контроля над его изменениями. Но когда у тебя есть какой-то внешний модуль и ты его полностью мокаешь. Вдруг брейкинг ченж, и как у нас любят поменяли абсолютно ВСЕ. Как будем проверять что система работает? twitter.com/Oleg75113370/s…

Причина банальная. Все тесты были завязаны на классах нашего компонента и в итоге при попытке заизолировать стили внутри компонента – все пошло по одному месту. И автор решил переписать тесты:
notion image

И действительно – стало лучше. Вот только никто не подумал о том, что избавляясь от одних деталей реализации (названия классов) тесты теперь знают о других (названиях компонентов и пропсов).

Автор сам говорил о том, что проект изначально был написан на jquery. Тогда никто не мог подумать о том что кому-то когда-то понадобится изолироваться от классов. И опять не подумали, что например через 5 лет веб-компоненты захватят мир и опять надо будет все переписать.
notion image

Приближаемся к выводу. Тесты, даже банальные юнит тесты имеют свои подводные камни, свои "бед" и "бест" практики. Помочь писать хорошие тесты могут утилиты для тестов с правильным и строгим API которое запрещает делать всякую грязь. Например testing-library.com

Итак вывод: Если вы уважаете себя и ваш продукт, хотите чтобы он цвел и пах (и например уволить тестировщиков), а вы не чинили тесты на каждый чих – вам заранее необходимо думать о том как обеспечить “Антихрупкость” тестам и надежное покрытие пользовательских сценариев.

🔥Тред (Дима Коваленко)
@jsunderhood Чем плохо всё переписывать с нуля через 5 лет?
Кстати очень интересный вопрос. Казалось бы, у бизнеса деньги есть – поделится :) Но во-первых из-за некачественного продукта они могут и закончится, а во-вторых есть такая штука, как эффект второй системы: ru.wikipedia.org/wiki/%D0%AD%D1… twitter.com/taujavarob/sta…

Ночное обсуждение! Что думаете по-поводу кризиса в IT? Пронесет или нет? Вот лично мне очень ссыкотно что скоро деньги на саппорт опен сорса у компаний закончятся и останется material-ui у разбитого корыта 😱

Вторник


@jsunderhood @xanf_ua Для меня идеал тестов компонента - это что-то типа сторибук: - компонент рендерится в отдельном приложении - работает во всех состояниях - с чистым изолированым стором - с моканым или реальным апи - всё конечно работает в браузере Насколько сложно такое настроить?
Вот если бы помержили мой ПР в cypress (github.com/cypress-io/cyp…) - то это стало бы супер легко. Тестирование компонента в сайпрессе требовало бы от тебя соблюдение всех этих правил twitter.com/davert/status/…

@jsunderhood @davert Потому что иначе тесты слишком много знают про компоненты "под низом". Сегодня иконка это font awesome, завтра встроенное svg, послезавтра с svg use. Мы сейчас в процессе большой миграции компонентов
Хороший вопрос. Как писать тесты на UI в условиях постоянных изменений в UI?- Не стоит вообще КОДОМ пытаться проверить как ВЫГЛЯДИТ наш компонент. Для этого существует обалденная штука - Visual Regression. Которая вам покажет что конкретно меняется в UI. twitter.com/xanf_ua/status…

Вот как это выглядит: percy.io/mui-org/materi… Делается полный снэпшот дома, запускается в разных браузерах и попиксльно проверятеся что изменилось. И вообще не надо вот этого вот всего: expect(el).to.have.class("button")

Есть много сервисов, я юзаю percy.io потому что там есть 5000 халявных снэпшотов в месяц. Этого хватит с головой для небольшого проекта, ну а если проект растет – не надо жлобиться :)

Интересный факт: JS фронтендеры – единственные, кто додумались тестировать UI без собственно UI (Да, сегодня будет вброс по поводу jsdom-a)
notion image

Прошу заметить! Я не занимаюсь рекламой перси) Мне лично, вообще до лампочки что вы будете использовать – главное не пытаться забивать гвозди микроскопом. Есть например еще argos-ci.com (юзается дл я кор компнентов material-ui) и много других инструментов.

🔥Тред (Дима Коваленко)
JSDom. Абсолютно банальный пример – пройдет тест или нет?
notion image

У меня интеллекта не хватило, чтобы в codesandbox-e замокать window.alert :) Поэтому пришлось немного переписать тест, но логика осталась той же: codesandbox.io/s/serene-torva… (Справа есть вкладки browser/test чтобы переключится)

Как заметил @asaenko, такой тест действительно не пройдет! По простой причине – браузер делает проверку на то что элемент задизейблен ДО того как происходит срабатывание ивента. И это на самом деле настолько неочевидная вещь, что вот даже тут многие не ожидали такого поворота.

И самое забавное, если вы возьмете Карму и будете запускать тесты в браузере – они опять пройдут! Потому что посути из js мы можем сделать document.querySelector("button").click()

Существует огромное количество ограничений в браузере, которые ограничивают интерактивность елемента, вот неполный список: pointer-events: 'none' из css перекрыт другим элементом с большим z-index не находится в области видимости readonly ...

Еще например есть проблема c обработкой фокусов (codesandbox.io/s/eager-dust-z…) Долгое время вообще document.activeElement не сетился, а теперь остается на body

Основная проблема не в том, что это так работает. Основная проблема – это то, что никто об этом не говорит, тоесть многие разработчики просто не знают о том что их тесты не ведут себя как приложение в настоящем браузере.

Настоящих нативных ивентов можно добится только с помощью реальных e2e тестов (webdriver, puppeteer). Потому что они симулируют ивенты на уровне общения браузера с ОС. Ну либо пытаться симулировать поведение, как делает cypress и github.com/testing-librar… (что тоже не кайф)

Да, кстати Cypress ближе к вот таким тестам (которые просто запускаются в браузере с симуляцией ивентов), чем к webdriver-ам

🔥Тред (Дима Коваленко)
@lionskape @jsunderhood @davert @xanf_ua Без мокирования зависимостей. shallow - это фактически автомоки.
Этот твит заслуживает внимания: shallow тесты действительно это моки на моках К примеру в React – shallow тесты по сути автомокают все вызовы React.createElement кроме первого. Такие тесты нужны крайне неустойчивы к изменениям реализации компонента. И нужны крайне редко. twitter.com/jin_nin/stat…

А вы трекаете ререндеры вашего SPA? Оптимизируете компоненты? А вот @Facebook с новым дизайном – нет P.S. Я конечно понимаю что вы трекаете все мои движения мышкой, но зачем перерисовывать интерфейс?
notion image

Спрашивается, чего я заладил за эту надежность? Разве все так плохо? - Да, недавно мы в material-ui скрапили репозитории, которые используют наши unstable компоненты. Результат: > 20 000 репозиториев и 1 самый интересный: Система контроля аппаратами ИВЛ для больных Covid-19.
notion image

И конечно же там не было ни 1 теста! К счастью этот проект похоже был каким-то прототипом. И разрабатывался в каком-то институте. И вообще большинству можно выдохнуть, до наших стран аппараты с интерфейсом на реакте просто не доедут :)

Просто в такие моменты отчетливо понимаешь НАСКОЛЬКО ВАЖНА может быть надежность наших тестов. Для нас баг/дефект – это так, рутина. Но вот когда ты понимаешь что твоя ошибка может стоить кому-то жизни – ууух, дело набирает совершенно другой оборот.

Я конечно головой ручаюсь за наши компоненты :) Всем бы такие stable компоненты, как у нас unstable. Но все же, а вдруг там какой-нибудь автокомплит выдаст не тот результат. И всьо.

Как часто вы проверяете что вы устанавливаете из помойки (или по-русски npm)? Как часто вы смотрите код который написан в либе, есть ли у этой зависимости тесты? Какие они? Как они реагируют на issue? Или по-старинке: Звезды, загрузки, дата последнего коммита и в продакшн.

Понятно, что хочется взять самое крутое, самое новое, что-то попробовать. Что уж говорить, есть люди которые в продакшн тянут, например, новый pipeline operator. Который блин в stage-1! То eсть его только-только начали обсуждать, даже эдиторы толком его не поддерживают.

🔥Тред (Дима Коваленко)
Ну и продолжаем наши ночно-кризисные обсуждения! А что вы предпринимаете для того чтобы не потерять работу, или даже заработать во время кризиса? > Я вот например веду @jsunderhood

(очень сомневаюсь что мне это как-то поможет, но а вдруг XD)

Среда


Я тут потихоньку срусь с людьми в тредах (кстати присоединяйтесь). И у меня возникает ощущение что многие не до конца понимают термин "рефакторинг". Немного об этом 👇

Рефа́кторинг (англ. refactoring), или перепроектирование кода, переработка кода, равносильное преобразование алгоритмов — процесс изменения внутренней структуры программы, не затрагивающий её внешнего поведения и имеющий целью облегчить понимание её работы.


То есть к примеру, я работая в Cypress частично был задействован в переписывании системы с Rest Api на Graphql. И это чистейшего рода рефакторинг! Потому что на выходе мы должно получить тот же продукт, что и был.

И это было ужасно! Но не так ужасно, как могло быть :) Потому что у нас была хренова гора cypress тестов, которые помогали. Но как всегда дьявол кроется в деталях. Наши тесты мокали бек-енд, и поэтому мне все равно приходилось переписывать тесты по одному.

Но все же сами (вспоминаем тред понедельника) assertion и action части остались точно такими же. Это позволило КРАЙНЕ СИЛЬНО ускорить переписывание системы. Но могло быть еще лучше, если бы все не было так завязано на моках бек-енда. И да, у нас не было ни одного QA :)

Вывод этого треда: Переписали всю системы с нуля, но исходный интерфейс остался тот же = рефакторинг. Поменяли aria-label, изменили модалку на поповер = изменение бизнес логики. Ровно, как и изменение алгоритмов или расчетов внутри системы.

🔥Тред (Дима Коваленко)
Да, и кстати я не говорю переписывать все assert-ы на проверку html. Это зачастую действительно не нужно и не удобно. Но для этого придумали божественную штуку = data-test-id атрибут. Который используется исключительно в тестах и его можно использовать как абстракцию над html.

Хотя гораздо более правильно отталкиваться от текста который видит пользователь. В том числе и пользователь с ограниченными возможностями. Так называемое a11y-first тестирование. Если вы не можете идентифицировать кнопку без индекса, id или селектора - у вас проблема с a11y.

А если вы переживаете по-поводу бандл-сайза ил по-поводу того, что ваше приложение легче будет проскраппить, то за нас уже все придумали: npmjs.com/package/babel-…

@jsunderhood Не всем сайтам нужен a11y
Уууух, го похоливарим! Раз такое дело, не всем сайтам нужен хороший интерфейс, не всем сайтам нужна надежность, не всем сайтам нужна устойчивость к нагрузкам, и так далее... Но тогда получается, что и не всем сайтам нужны хорошие программисты с большим рейтом? twitter.com/lionskape/stat…

Проблема в том, что когда 'жареный петух клюнул' – это уже поздно. Значит что все сломалось и срочно нужно чинить. Там пришли пользователи с огран. возможностями и не смогли купить продукт. И вы ж сразу не узнали об этом – узнали спустя год.

И кто в этом виноват? PM который не завел тикет a11y? Заказчик который этого не предусмотрел? Или программист который не написал такой код? - У меня нет ответа на этот вопрос.

Итак, мы дошли до обсуждения пирамиды! И начать предлагаю с обсуждения терминов. Я с недавнего времени стараюсь избегать названий "юнит", "интеграционные" и "e2e". Понятия настолько расплывчаты, что каждый подразумевает что-то свое под каждым из них.
notion image

Наибольшие проблемы возникают с интеграционными. Вот например в яндексе считают что selenium тесты которые ходят и тестируют их продакшн – интеграционные 🤷‍♂️ youtube.com/watch?v=dflmpq…

Интеграцио́нное тести́рование (англ. Integration testing, иногда называется англ. Integration and Testing, аббревиатура англ. I&T) — одна из фаз тестирования программного обеспечения, при которой отдельные программные модули объединяются и тестируются в группе. (wikipedia)

А юнит тесты — процесс в программировании, позволяющий проверить на корректность отдельные модули исходного кода программы, наборы из одного или более программных модулей вместе с соответствующими управляющими данными, процедурами использования и обработки.

И вот тут уже возникает коллизия. Юнит тесты могут тестировать группу модулей (> наборы из одного или более программных модулей ) – но все еще не превращаются в интеграционные. То есть нету четкого разграничения когда юнит тест стал интеграционным.

Тоже самое происходит и с e2e. Ведь по-сути все наше приложение это тоже группа модулей. Соответственно любой e2e тест это интеграционный, но не наоборот.

Пример! Мы пишем библиотеку которая наверх вываливает функции. Например date-fns (кстати вообще не понимаю почему все писяют кипятком от нее). Наши e2e тесты это будет просто вызов функции. Потому что мы в тестах работаем с кодом точно так же как наши пользователи.

Но абсолютно точно такой же тест на точно такой же код в любом приложении – уже никак нельзя назвать e2e. Тоже самое происходит с UI тестами. Для вас покрыть фронтенд через selenium это e2e, а для какого-то огромного сервиса у которого таких фронтов 86 – уже нет.

У каждого продукта (или каждой команды) есть своя зона ответственности. Например для меня в material-ui это будут тесты на компоненты. И для меня же, когда я пишу свой стартапчик (а я пишу) – уже нет. Хотя в теории у меня может быть точно такой же компонент и точно такой же тест

И внутри каждой зоны ответственности мы можем писать 3 вида тестов: black box, grey box и white box. То есть когда наши тесты знают все про реализацию, не знают ничего или знают чучуть. Так вот white box тесты в моей картине мира приносят только проблемы.

И кстати, попробуйте какому-нибудь не js-программисту сказать что вы покрываете юнит тестами UI. Он вам посмеется в лицо. Ни в android, ни в ios ни в wpf (то что я хотя бы отчасти знаю) – никто вообще не представляет что UI можно тестировать юнит тестами.

И поэтому "UI тесты" со временем стали синонимом e2e или функционального тестирования. Опять же, потому что изолировано тестировать UI в нормальных (ох, зря я это пишу) платформах – невозможно.

И да, компонентный подход в js реализовали очень круто. Вот например я думаю SwiftUI очень вдохновлялся именно современным js. Но концепция UI от этого не изменилась, а люди все равно пытаются тащить unit тесты – наверное потому что привыкли так писать.

Ой, я ж забыл написать самое важное! Если говорите со своей командой о тестах, обязательно убедитесь что вы говорите об одном и том же.

🔥Тред (Дима Коваленко)
Время пришло! Тот самый тред о том, почему пирамида это пережиток прошлого. Вот только важно: Под юнит тестами тут я подразумеваю white-box тесты на самые маленькие части нашей системы (компонент, функция, и т.д.)
notion image

Немного истории. Пирамида начинает свое начало примерно в 2008 году. Вот пруф benhutchison.wordpress.com/2008/03/20/aut…

И если вы ознакомитесь со статейчками о том почему же все таки именно так необходимо писать тесты. Например от Мартина Фоулера (martinfowler.com/articles/pract…) То вы увидите только 2 аргумента: Юнит тесты писать проще Юнит тесты бегают быстрее

Действительно писать юнит тесты проще? Ха-ха-ха, не смешите мои тапочки. Если мы говорим про тот тест, где у вас 2 строчки самого теста и 50 строк кода на то чтобы замокать зависимости? Серьезно?

Современные e2e раннеры для фронтенда типа cypress от вас требуют просто запустить ваше приложение. И все, больше ничего не надо. У вас открывается браузер, дебажьте тесты, используйте дев тулзы. Вам тут и тайм-тревелинг и все что угодно. vimeo.com/237527670

Помимо всего прочего, юнит тесты от вас требуют определенной инфраструктуры. Типо DI, которые разработчики начинают использовать только ради тестов. Но не спешите полыхать, я все объясню. Мой поинт: попробуйте написать юнит тесты в продукте где никто не готовился к этому :)

Юнит тесты бегают быстрее Ну как бы хрен поспоришь. Вот только вспоминаем 2008 – никакого докера, из CI только jenkins. А у вас тесты бегут 2 часа. Вполне логично что таких ситуаций следует избегать. Но мы же не в 2008! 21 век надворе – очнитесь.

В cypress у нас было 2000 cypress тестов. C покрытием >95%. И эти тесты бежали 2 минуты на 15 машинах в параллели. Да, на локали не запустить – но просто пушиш коммит и ждешь CI. Ну а если вам жалко 1000 долларов на нормальный CI – извините это диагноз. Нанимайте 5 manual QA.

Окей, но что же там по поводу фокусности тестов. Я абсолютно не отрицаю необходимости покрытия бизнес логики отдельно. То есть юнит-тесты на вашу кор бизнес логику написать необходимо. Почему и не противоречу ли я сам себе? - отвечаю дальше:

Я сегодня уже делал твит про зоны ответственности. Итак вашу бизнес логику вы должны изолировать от UI. И не для того чтобы тестировать проще было, а чтобы ее можно было переиспользовать в будущем. То есть для того чтобы не менять ее когда будет рефакториться UI

И соответственно на уровне бизнес логики вы пишите тесты. Вы пишите опять e2e тесты, как бы представляя что ваша бизнес логика – это отдельный проект. Но по-факту это могут быть jest тесты которые вы привыкли называть юнитами. Хотя по-сути это e2e на другом уровне.

Тоже самое с переиспользуемыми компоненты. Какие-нибудь части UI (кнопка, таблица), которые в теории могут быть вынесены в отдельный проект и зашарены. Вы их покрываете с учетом того, что они будут использованы абсолютно в разных контекстах. Но это опять e2e на другом уровне.

Да тесты будут пересекаться. И это нормально, на 1 уровне вы проверяете работоспособность БЛ. На другом проверяете что итоговый продукт правильно работает с БЛ.

Но возникает интересный вопрос: А сколько собственно чистой бизнес-логики вы пишите? Я очень сомневаюсь что у вас наберется и 20% такого кода в проекте. В основном мы просто берем готовые компоненты и как-то их комбинируем между собой.

Так на кой ляд нам писать юнит-тесты, если 80% нашего кода – это чистого рода интеграции. (спорное утверждение согласен, смотрите срач в ответах)

Если вы думаете что e2e тесты, которые запускаются в браузере ненадежные – вас возможно покусали xpath-ы. Это ужасный антипаттерн который юзают автоматизаторы, короче эта штука которая ищет элементы в доме через дерево.

И это реально бред, потому что любое изменение структуры дома, даже которое не влияет на внешний UI приводит к поломке. Как это решить мы уже обсуждали. Использовать a11y теги, текст или data-test-id для доступа к элементам. И ваааау – ничего не падает.
notion image

И кстати это касается и бекенда. Вообще представить не могу как писать бек без полноценного тестирования API. Но это уже совсем другая история.

Вообще я уже задолбался тут писюкать. Вывод из этого такой: выше забираться по пирамиде вообще не сложно. Но добавляет капец как много надежности нашим тестам. Жду срачей C:

🔥Тред (Дима Коваленко)
@jsunderhood Проблема тестов на сайпрес, что с усложнением приложения они начинают дольше ранится. нельзя собирать каверейдж по компонентам если есть много тестов то надо мощная машинка что бы они не таймаутились нельзя применить подходы с path тестингом
Знаете, Cypress – это как демократия. Худший из тест раннеров. Но лучше человечество пока не придумало. twitter.com/zmitriy/status…

О и кстати, коверейдж собирать уже давно можно :)

Вот еще немного в продолжении надежности, а потом я спать. Скрин из статьи про пирамиду тестирования за 2008 год. benhutchison.wordpress.com/2008/03/20/aut… Подписываюсь под каждым словом. Вот что будет если следовать пирамиде:
notion image

Четверг


TDD. Используете ли вы реально на практике TDD?

@jsunderhood это как геи — ты точно знаешь, что они есть, но ни с одним не знаком. так же и тдд
А лучше и не скажешь :) Вот я например, латентный ТДД-шер. И не потому что я там такой крутой программист, а исключительно из прагматичных побуждений. ТДД экономит время. Немного об этом в треде 👇 twitter.com/cuz_you_love/s…

Лучше всего это можно проиллюстрировать на примере бека. Представьте ситуацию: Ваня получает тикет на создание контроллера в АПИ Ваня садится кодить Открывает свой Rest API клиент и начинает мануально проверять свой контроллер.

Впадает в истерику потому что его авторизационный токен экспайрится каждые 10 минут (например) Доделывает контроллера Открывает ПР Ему дают по башке за то что он забыл написать тесты Героически отправляется писать тесты, допустим используя supertest

И собственно проблема в чем: Его тесты делают абсолютно тоже самое, что Ваня делал в 3 пункте попутно страдая. Они ходят на реальный API, делают запрос и получают ответ. И ко всему прочему вся инфраструктура необходимая для авторизации – уже написана и работает автоматически.

Так не было бы логично избавится от мануальной проверки, и проверить свой контроллер сразу с помощью тестов?

Мне кажется, что в ТДД главное это не факт написания тестов до кода. Можно написать и после кода, главное что вы свой код СРАЗУ проверяли тестами. А если вы начнете делать хотя бы так, то сразу окажется что писать тесты до кода – не так уж сложно.

!! Вообще эту проблему можно описать одной фразой – “Тестирование реализации”. Тесты должны проверять не то как наш код НАПИСАН, а то как наш код РАБОТАЕТ - и будет вам счастье :)
И в таком случае у вас просто не получится писать плохие тесты. Потому что вашей задачей станет проверить что код РАБОТАЕТ. twitter.com/jsunderhood/st…

И кстати, мои ненавистные white-box тесты очень сложно писать именно с помощью TDD. Так как white-box тесты много знают про реализацию – такие тесты невозможно написать до того как собственно эта реализация появилась. И это круто.

Кстати еще многие переживают по поводу отладки. Мол как я буду отлаживать приложение, если проверяю его с помощью тестов? Запросто. В vscode можно настроить дебаггер для jest-овых тестов. И тогда просто ставите .only не тест, нажимаете F5 и дебажите. github.com/microsoft/vsco…

🔥Тред (Дима Коваленко)
А как вы боретесь с гигантскими PR-ами? Это моя извечная проблема. Каждый раз обещаю себе что буду дробить большие пр-ы. А потом через 2 месяца начинаю пилить большую фичу и:
notion image

А на сегодняшний вечер я вам предлагаю увеселительный тред про всякие странные штуки в имплементации Cypress-а. Я его конечно очень люблю, но откровенно странных вещей под капотом у него ой как много. А если вы его используете, возможно вам будет даже полезно :)
notion image

Итак, приступаем! Для начала разберемся как Cypress работает. Очевидно что есть iframe, туда загружается ваше приложение и сайпресс лазит в этот iframe во время тестов.
notion image

Но! Попробуйте сделать iframe с урлой facebook.com и потом из javascript-a лазить туда и получать доступ к дому. Звучит как-то не очень нормально, согласитесь? Звучит как дыра в безопасности и так должно быть невозможно...

Да. Сайпресс это вообще по-сути одна большая война с веб-секьюрити C: Чтобы обойти это ограничение сайпресс проксирует первый запрос на ваше приложение, подменяет в ответе ему domain и ставит специальную куку. Звучит костыльненько, не так ли?

Да, и из этого следует одно из ограничений сайпресса: нельзя менять домен на лету. И теперь вы понимаете почему. Когда домен меняется изнутри страницы – мы уже не можем запроксировать запрос и увы хром блокирует доступ к тестируемому айфрейму.

Но все будет окей, если origin-ы совпадают :) То-есть если все ваши проекты находятся на одном origin-e (*.google.com) например – тесты будут работать. Кстати по этому же принципу тестируются айфреймы внутри вашего приложения.

А на самом деле у сайпресса 2 айфрейма. Во-втором загружается собранный код вашей спеки. Именно поэтому если внутри тестов вы обратитесь к document – вы не получите document приложения, а document вот этого спековского айфрейма.
notion image

Зачем так сделано? Я сам толком не знаю – не задавался вопросом :) Скорее всего чтобы изнутри тестов нельзя было взаимодействовать с самым интерфейсом сайпресса.

А еще многих интересует как работает тот самый тайм-тревелинг. На самом деле самым топорным из всех возможных способов. После каждой команды собирается снэпшот дома. Технически просто делается querySelector("*:not:(iframe)") и сохраняется в массив.

А потом когда вы кликаете на команду этот снэпшот собирается обратно в дерево дома. И тут возникает еще 1 большая проблема – сайпресс выжирает просто НЕРЕАЛЬНОЕ количество оперативной памяти.

И соответственно этой памяти есть лимит. Чем больше у вас будет тестов (а соответственно команд) – тем быстрее у вас вылетит out of memory exception. И тут совет – старайтесь делать как можно меньше тестов в 1 файле. Максимум 10-20.

Дело в том, что даже если у вас эксепшн не вылетает вы все равно от этого будете страдать. Чем больше оперативки жрет ваше приложение тем медленнее оно работает. Потому что каждый цикл GC становится все труднее и труднее. Ну и работать с маленькими спеками гораздо приятнее.

Кстати в сайпрессе у нас были спеки по 900 строк кода. В этот момент я понял что создатели инструмента не обязаны уметь идеально им пользоватся XD

Еще например в сайпрессе мне одновременно нравится и не нравится его API. Дело в том, что оно действительно выразительное и писать код в основном легко. Но этот код синхронный, а выполняется асинхронно.
notion image

Сайпресс использует собственный враппер над bluebird промисами. Если кто знаком с ФП – то работает это примерно по принципу монады Future. И все классно, но до поры до времени. Пока вам не нужно писать переиспользуемые куски кода и цепочка чейна отваливается.

И возникает вот такие магические конструкции как cy.then. Я честно сам не до конца понимаю как эта байда работает. Но короче она ожидает все пендинг чейнинги и отрабатывает в следующем тике. Но выглядит если честно как 💩
notion image

А еще очень важно понимать все технические ограничения сайпресса, обусловленные тем что он исполняется из javascript. Например команды cy.hover не существует. Потому что ховер мышкой обрабатывается на уровне ОС и запускает хренову тучу разных эффектов.

Я конечно понимаю, что после этого треда в Cypress опять мне уже не вернутся 🤓 Моя идея не разубедить вас использовать Cypress. Просто у каждой технологии есть свои недостатки – и в первую очередь вы должны узнать о них. А про плюшки вам и так расскажут в первую очередь :)

О и еще маленькая штука. Вы знали что fetch и xml http request – это АБСЛЮТНО разные вещи в браузере и хендлятся абсолютно по-разному даже на уровне ОС? Вот и я об этом узнал только из сайпресса XD

🔥Тред (Дима Коваленко)

Пятница


Сегодня ближе к вечеру поговорим про дизайн системы. Хотелось бы узнать, а вы вообще используете их и каким образом?
🤔 36.8% Да, пишем с нуля сами.
🤔 26.9% Да, на базе UI кита
🤔 36.3% Нет, я омлет

Окей, разбираймся с дизайн системами. И сначала поговорим про полностью самописные дизайн системы.

Понятное дело что это действительно самый эффективный способ сделать собственную дизайн систему. При чем хочу уточнить что дизайн система !== набор компонентов для дизайна. Это очень важно – сделать дизайн систему это работа дизайнеров.

По сути дизайн система это набор правил для построения вашего уникального дизайна. Эти правила обычно собираются в гайды и потом реализовываются для различных платформ. Самая популярная дизайн система – material design (material.io)

Кстати очень хочу заметить что то что делаем мы в @MaterialUI – это всего лишь реализация этой дизайн системы. Точно такими же (токо хуже 😉) реализациями материал дизайна являются Vuetify, Angular material, MDL и так далее

Отвлекся. Возвращаемся к правилам –> хорошим примером правила дизайн системы является: В материал дизайне все размеры/отступы кратны 8 пикселям. (8, 24, 32, или даже 4). Это все идет из правил золотого сечения, короче когда все размеры кратны – людям так больше нравится.

И вот в самописной дизайн системе гораздо проще создавать и заставлять итоговые продукты следовать этим правилам. Помимо всего прочего ваша кастомная имплементация системы будет решать только вашу проблему и поэтому будет делать это наиболее эффективно.

Теперь по проблемам. И основная проблема самописной имплементации дизайн системы (собственно как и всего самописного) – это ресурсы. Очевидно, что бизнесу необходимо выделить деньги и время на создание такой системы.

Но неочевидная вещь заключается в том что вы 100% недооцените необходимое время на создание. Просто потому что создание компонентов требует довольно много знаний не очень востребованных в обычной разработке фронтенда.

Например - тришейкинг. Вы должны понимать что такое esm/cjs модули, как билдить библиотеку компонентов, освоить какой-нибудь rollup. Но этого вам не хватит чтобы сделать esm. Дело в том, что тришейкинг в вебпаке работает только по файлам.

Помимо этого вам нужно будет сделать UMD билд, потому что кто-то захочет использовать дизайн систему через CDN, сделать cjs потому что кому-то понадобится SSR. Кстати о SSR – ваши компоненты должны уметь вытаскивать critical css, иначе перформанса на сервере вам не видать.

Дальше идет accessibility, которое должно внедряться на уровне именно компонентов. А это тянет за собой такие вещи как TrapFocus – штука которая не даст вам вытабаться из модалки, вам нужно будет уметь работать с регионами, live-announcements и еще кучей всего.

И еще кучи всего того, что уже есть в UI kit-ax. И понятное дело, что сразу всего этого не сделать. Помимо этого нужно сделать нормальную документацию, запилить нормальные дефинишены для ts, flow или чего вы там используете.

Основная проблема заключается в том что каждый новый проект будет приходить со своей хотелкой и вы должны будете его удовлетворить. А это на первых порах будет постоянно тратить ресурсы, тормозить запуск продуктов и вообще не хорошо :)

🔥Тред (Дима Коваленко)
Теперь немного про то как реализовывать дизайн систему на базе UI кита. Технически это когда вы создаете отдельный пакет, и внутри него делаете export * from '@materail-ui/core' и меняете стили и тему UI kit-а на те, которые вам нужны.

Плюсами такого подхода будут все минусы создания с нуля. Но мы говорим о проблемах: Вам гораздо сложнее заставлять разработчиков следовать правилам вашего дизайна. Потому что API вашего кита абсолютно ничего не знает про ваши правила. Так что придется подстраиваться.

Вы ни в коем случае не должны расширять или переопределять готовое АПИ. То есть если в ките есть только 3 варианта кнопки – вы можете либо использовать эти 3, либо оставить только 2. Объясняю почему:

Во-первых возникает диссонанс между готовой документацией и тем как ведет себя ваша дизайн система. А во-вторых если вы пытаетесь манки-патчить готовый кит то вам будет нереально сложно его поддерживать и обновлять в дальнейшем.

Немного объясню что имею ввиду под расширением API: попытка изменить уже готовое поведение к примеру кнопки. Вместо этого просто сделайте свой собственный новый компонент и используйте его.

Помимо этого вы должны быть готовы к тому что за глобальный оверрайд стилей вы поплатитесь дополнительным бандл-сайзом, потому что стили компонентов никуда не деваются.

@jsunderhood Было бы здорово, если расскажешь как вы работаете с breaking changes при такой кастомизируемости компонентов. Интересно какая стратегия, если у людей после апдейта что-то ломается из-за самих оверрайдов.
Готовьтесь к проблемам с апдейтами twitter.com/blvdmitry/stat… Это реально огромная проблема, и вас тут не спасут даже codemod скрипты. Я знаю 2 компании которые используют бутстрап как базу для своих дизайн систем. И не одна из них так и не смогла обновится на 4 версию.

Ну вот собственно и все что мне пришло на ум :) И кстати мы как раз этот вопрос постараемся порешать в 5 версии material-ui. Мы хотим предоставлять unstyled версию всех компонентов. В двух словах расскажу об этом:

Это API пока в обсуждении, но мы хотим сделать что-то наподобии Angular Material CDK, только для всех компонентов. Как-бы база для построения собственных дизайн систем на базе material-ui.

В идеале было бы отдавать на каждый компонент: - react hook со всей логикой компонента, который отдает наверх только пропсы для html - готовые компоненты без стилей, для того чтобы их руками глобально задизайнить без оверрайдов - ну и как сейчас готовые компоненты к использованию

Такой подход, как по мне, был бы идеален для построения абсолютно любой дизайн системы за вменяемое количество времени и денег :) Ну а если у вас есть идеи – я с удовольствием их послушаю!

🔥Тред (Дима Коваленко)
I glad to announce documentation for Hegel (a new static type checker). We have come a long way, but the path ahead is a longer one. There is a lot of work but, I hope, today I have become closer to my dream about JavaScript with a good Type System. jsmonk.github.io/hegel/
Hegel вот-вот уже будет готов✌️как говорится can't wait > P.S. А я напоминаю что мы на этой неделе еще вернемся к теме нормально типизированного js. twitter.com/rage_monk/stat…

И предлагаю продолжить коронакризисное обсуждение. По результатам 2 прошлых обсуждений стало понятно что все ужасно боятся кризиса, но никто не хочет ничего в связи с этим делать. Ну что сказать, классика. А что думаете насчет увеличения своей ценности как профессионала?

Наверное уже поздно пить боржоми, но однозначно что самых важных людей не уволят. Ну пока бизнес вообще не развалится. Соответственно стать таким человек = спасти свою родимую задницу 😎

@jsunderhood А подскажешь как эту ценность увеличить? Просто учить новые технологии? Я вот вроде учу, но по факту все равно запоминается только то, что используется на регулярной основе.
Вот кстати еще интересный вопрос на обсуждение. > Лично мое мнение: хоть все технологии выучить или знать любую технологию досконально, если дядя бизнесмен не видит в тебе практичной ценности – то гаплык. А в чем измеряется ценность – в деньгах которые делают твой код. twitter.com/palamar/stat…

Абстрактный пример: Ваня пришел и сказал дяде бизнесмену "Смотри, вот тут надо подшаманить и клиент пойдет" – Ване дали денег на фичу – И таки да, продажи увеличились и стало хорошо Ну а если такое повторяется, то такого Ваню потом будут держать до потери пульса.

@jsunderhood Не раз наблюдала картиру, когда человек не может объяснить какую пользу он нанес организации. Например, говорит так: Я покрыл тестами такой-то сервис. И пилил фичи из беклога. Бизнесу от тестов ни холодно, ни горячо.
twitter.com/Travieso_nasty… Вот кстати спасибо @Travieso_nastya. Помимо реальной ценности вы должны уметь доказать что именно ВЫ принесли ценность. Иначе это сделала "команда", а в команде как говорится незаменимых нет :) Эгоистично? Да.

Суббота


Сегодня речь зайдет за типизированный javascript. Я надеюсь не нужно объяснять почему flow и typescript – это не совсем нормальная типизация?
notion image

Окей, так уж и быть накидаю тайпскрипту. P.S. У меня вообще какая-то дурацкая привычка обсирать то, чем я пользуюсь :)

Ну во-первых typescript себя не позиционирует как СТРОГОСТЬ. Это скорее такой баланс между типизацией и продуктивностью. Чего только стоит это долбанное any или оператор (или это не оператор) ! которые просто отключают любые проверки.

Во-вторых огромное количество конструкций не требует реального доказательства, например is
notion image

При чем , что если убрать функцию check он понимает что у переменной не может быть состояния number
notion image

@jsunderhood так ну все приличные люди банят any и ! на уровне линтера иначе же весь смысл теряется
Вот поступил комментарий что все нормальные люди банят any twitter.com/t1tvs/status/1…. А вы знаете что происходит внутри дефинишенов, которые вы используете?

notion image

Или например generic-и, ну это если честно вообще боль. Описание дженериков в тайпскрипте це боль. А все потому что ты должен все описывать руками. И это работает неплохо на простых примерах. Но потом ты сталкиваешься с реальностью
notion image

Ну либо потом к тебе заходит ПР github.com/cypress-io/cyp…
notion image

Really love writing complex typescript generics. Because other devs looking at your code like at the black magic 🙄
twitter.com/dmtrKovalenko/… Как-то запостил такую фигню и меня закидали помидорами, но это реально так – вот такую байду понять нужно как минимум долго сидеть и вчитываться в код. А по-другому и не напишешь.

А еще можно накидать за структурную типизацию. То есть любые объекты с совпадающей структурой будут равнозначными. А на этом можно сильно напоротся. Вот из жизни пример с системами координат. P.S. функция будет неправильно работать
notion image

Но это может быть пофикшено вот этим ПР-ом github.com/microsoft/Type…

Ну или вот, потеря типов на тюплах на абсолютно любых взаимодействиях с массивом
notion image

Короче еще куча всего, тайпскрипт это скорее штука для ускорения разработки, чем для действительно строгих проверок на работоспособность кода.

🔥Тред (Дима Коваленко)
Где же найти ту самую СТРОГУЮ типизацию в мире js? Ну пока @rage_monk не закончит свой Hegel, то пока только в язык компилирующихся в JS. И сегодня хочу рассказать об одном, на мой взгляд, наиболее перспективном из такого рода языков – @reasonml
notion image

И как у любого ДРУГОГО языка отличного от js у него есть огромная проблема – вам крайне сложно будет найти людей которые будут уметь на нем писать. Именно поэтому я сегодня буду рассказывать только про плюшки ризона. Но это не отменяет что у него есть много своих проблем.

Ризон является диалектом функционального языка OCaml и компилируется через специальную тулзу (bucklescript) в javascript. Почему не использовать просто окамль? Потому что он выглядит еще более страшнее для js разработчиков ;)

Ризон как и окамл является языком семейства ML. А значит там есть тот самый вывод типов по Хиндли-Милнеру (вот больше инфы нормальным языком habr.com/ru/post/125250/) Но если коротко то типы выводятся по-красоте! То-есть на основании использования:
notion image

Тут ризон знает, что оператор + работает только с числами, а соответственно он может точно вывести типы аргументов. Но он тоже самое может сделать с внешними функциями:
notion image

Да, и тут в принципе нет аналога any. Поэтому reasonml имеет всегда 100% корректное покрытие типами вашего приложения. А если вы думаете что это слишком: Допустим ваше приложение имеет 100 типов. И корректность составляет 99.9%, то общая корректность кода -> 99.9% ^ 100 = 90.4

Похоливарилили сегодня за вывод типов из рантайма, aka IO. Запросы на сервер, чтение из файла, ну там то что мы не можем предсказать – вот на этом моменте ризон заставляет вас доказать что вы получили именно то, что и ожидали. Вот пример, я конечно понимаю что выглядит мерзко
notion image

Да, вот такую байду вам нужно написать чтобы спарсить ответ пришедший с сервера. И да я понимаю насколько это ужасно в реальной жизни. И да – это можно описать более компактно и системно с помощью контракта. Но факт в том что вы на 100% уверены что парсинг вернет вам именно то.

Следующее. Ризон функциональный язык, то есть у него есть готовая поддержка на уровне языка для композиции функций. Из коробки есть каррирование, pipeline оператор, pipe-first оператор и выглядит это вот так.
notion image

@jsunderhood А как он работает с коллекциями? Например в подобном кейсе какое будет его поведение: const a = [] // какой тип? a.push(1) // новый тип (какой?) или ошибка a.push("2") // и тд
twitter.com/i_kabirov/stat… Про коллекции. Ризон предостовляет возможность использовать js-овские массивы, но не приветствуется. Стандартная библотека тебе дает list (который является по-сути связным списком) который иммутабельный из коробки. (но медленее чем массив из js)
notion image

Еще одна фишка которая мне нравится именно в отдельных языках – это ограничения. JS сам по себе ужасно динамический язык который в принципе очень сложно статически анализировать. Например динамическое количество аргументов у функций - wtf. В ризоне такого нет

Это конечно иногда бывает крайне удобно, но зачастую приводит к таким странностям и в принципе отсутствием возможности покрыть типами конкретное API
notion image

Ну и основная плюха ризона это их варианты и паттерн-матчинг. Собственно это имплементация алгебраических типов данных – и очень удобная я вам скажу. Тут можно увидеть тонкую отсылку к flux и вообще тем как работает реакт под капотом.
notion image

И это действительно так, потому что первая версия реакта была написана на языке StandardML, и потом уже переписана на js и flow. А ризон делали собственно те люди, которые когда-то давно проектировали АПИ реакта. Именно это апи и стало прообразом редьюсеров:
notion image

И эта штука кстати отлично работает с константами, списками и массивами
notion image

Объекты типизируются с помощью самых обычных деклараций типов, единственное что явно указывать типы не обязательно, ризон сам попытается найти подходящий тип и выведет аргумент. Но я предпочитаю именно объекты (в ризоне - рекорды) явно декларировать.
notion image

Хмм ну не буду я же вам всю документацию тут пересказывать. Короче ReasonML – имеет очень мощный вывод типов на основании использования. Офигенную поддержку функциональшины (даже монадический синтаксис как в хаскле есть), иммутабельность и полную поддержку React.

Ох и самое важное забыл! Это же полноценный язык, поэтому он может билдится в нативный код как и окамл. В том числе и запускаться через wasm. Вот проект на который я ставлю ставку – кросс платформенные приложения на ризоне (без электрона github.com/revery-ui/reve…)

🔥Тред (Дима Коваленко)
Почитал я свой тред про ризон и понял шо то туфта. Поэтому вдохновившись @_bravit хочу сделать онлайн трансляцию: вводный доклад в ReasonML для js-еров. Там расскажу не только про плюшки, но еще и про недостатки и покажу его в реальном продукте. Ставьте 👍 если посмотрели бы.

Воскресенье


@ArturasLapinsk @goodhoopoe @while_infinite @jsunderhood Да бля , на хуй как попало , зато мне сцуко не надо писать тип ебаный , если я переменной задал значение , а потом его поменял потому, что я так решил , значит мне так нужно ! Если при отсутствии типизации ты пишишь дерьмо 💩, то это твои проблемы а не языка
Прошу прощения за такие репосты, но этот твит сделал мое утро! Побольше бы таких ответов, которые действительно поднимают настроение 😁 twitter.com/AntonKulibyaki…

Короче я заболел. Да это стремно 😱. Сегодня тредов не будет, а взамен предлагаю вам просто обсуждение некоторых, на мой взгляд, важных и интересных вопросов.

Первый вопрос на холиварное обсуждение: Вы за конвейерную разработку или против? То есть нужен ли отдельный бекендщик, фронтендщик, тестировщик, автоматизатор, верстальщик и попу-подтиральщик? Или каждый должен уметь всего по чуть-чуть? Обсуждаем ⬇️

@jin_nin @ArturasLapinsk @goodhoopoe @while_infinite @jsunderhood Так это время твоей проверки а не языка ! Пиши на пайтоне в чем проблема , пиши бек на c , тока вы толпами используете js и его же и критикуете .
Этот человек не перестает меня радовать! Прямо предвосхищение обсуждения которое я хотел устроить. Почему вы продолжаете сидеть в javascript а не уходите в другой язык? Вам нравится веб? Много вакансий? Что будет если их станет меньше? Действительно интересно. Обсуждаем⬇️ twitter.com/AntonKulibyaki…

И чисто опрос для меня. Скажите используете ли вы русскую документацию если доступен перевод? Или вас бесит и вы переключаете всегда на английский? Мне как опенсорсеру очень важно понимать – стоит ли инвестировать время в перевод именно на русский язык.
🤔 29.4% Да, использую русский
🤔 48.7% Нет, только английский
🤔 21.8% Мне без разницы

Кстати это заблуждение что переведенная документация 100% устаревшая. Устаревание – это топ 1 проблема переводов, которую уже порешали. Например в material-ui мы переводим доку по 1 абзацу, а когда это предложение меняется то юзер увидит английский текст, пока не переведем опять
notion image

Кстати если есть желание поконтрибьютить в опен сорс не напрягаясь – приглашаю помочь нам с переводом! crowdin.com/project/materi… Просто заходите сюда и переводите 🙂

Я тронут количество лайков 😳😳 стриму быть! Встречайте анонс трансляции "ReasonML для javascript-еров и гусей" – следующее воскресенье, 19 апреля в 18:00 Заходите, нажимайте на кнопку "напомнить" чтобы ничего не пропустить! youtube.com/watch?v=hHzdxO…

Ну что котики, моя неделя подошла к концу! Не знаю как вам, а мне понравилось. Надеюсь я смог хоть чутка затронуть ваше сердечко :) Спасибо за активное обсуждение, пишите антихрупкие тесты и залетайте на стрим про ризон. А с вами был @dmtrKovalenko, не болейте и всем бобра!
notion image

Ссылки