n_gafarov

18 января 2021

# Понедельник 24 твита

Всем привет. Меня зовут Гафаров Назим @n_gafarov
Вы могли видеть меня в качестве докладчика на Яндексовых мероприят… twitter.com/i/web/status/1…

8:38

Короткий рассказ о себе.

В 2015 году я работал в стартапе, который делал "убийцу" Amazon Kindle для школьников. Ст… twitter.com/i/web/status/1…

8:57

В Яндекс.Маркете я начал работу над "убийцей" Amazon - маркетплейсом "Беру", а точнее, над админкой для партнеров.… twitter.com/i/web/status/1…

8:58

Слова благодарности друзьям за поддержку pic.twitter.com/B8kw7Hh7BG

9:40

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

9:40

Как и при старте нового проекта, начнем с особенностей package.json
⬇️ Начнем

10:31

В блоке скриптов package.json не должно быть никаких платформо-зависимых команд. Например, оператор & в Windows Cmd… twitter.com/i/web/status/1…

10:31

Кроме того, npm-run-all позволяет одной командой запускать несколько сценариев. Вместо:
npm run build:css && npm ru… twitter.com/i/web/status/1…

10:32

"test": "npm-run-all --parallel test:*"
"test:lint": "eslint '**/*.{ts,tsx}'"
"test:types": "tsc"
"test:unit": "rea… twitter.com/i/web/status/1…

10:38

Аудит безопасности пакетов должен стать частью CI/CD. Органично впишем в наш список команд:

"test:audit": "npm aud… twitter.com/i/web/status/1…

10:44

Также имеет смысл добавить package.json свойство:
"private": true

Чтобы случайный npm publish не выкатил ваш код в… twitter.com/i/web/status/1…

14:38

В старых проектах еще бывает полезно время от времени проверять package.json на неиспользуемые пакеты. В этом помог… twitter.com/i/web/status/1…

14:39

package-lock.json
⬇️

14:54

Во-первых, имеет смысл приучить всех в команде пользоваться командой "npm ci" при установке зависимостей, а не "npm… twitter.com/i/web/status/1…

14:54

В итоге npm install нужно использовать только при добавлении новых пакетов в проект.
Если вам надоели пул-реки с +2… twitter.com/i/web/status/1…

14:55

Чтобы npm install у всех разработчиков резолвил пакеты одинаково, нужно договориться, чтобы все сидели на одной вер… twitter.com/i/web/status/1…

14:56

А так как лучше доверять машинам, а не людям, то есть смысл декларативно описать окружение с помощью… twitter.com/i/web/status/1…

14:57

В package.json всегда имеет смысл указывать конкретные версии, особенно в dependencies секции. Указывая примерные ~… twitter.com/i/web/status/1…

15:17

И, пожалуйста, никогда не используйте yarn в продакшене.
Yarn - это песочница, в которой тестируются самые безумные… twitter.com/i/web/status/1…

15:40

Yarn крутой, кто ж спорит. Но это не стандарт.
Возьмем например выборочное разрешение зависимостей:… twitter.com/i/web/status/1…

22:37

Во-первых, непонятно как resolutions работает для вложенных зависимостей? Никак: github.com/yarnpkg/yarn/i…
Во-вторых,… twitter.com/i/web/status/1…

22:38

Пока нормальные ребята думают над import-maps, чтобы механизм резовалва был единый для всех платформ: неважно брауз… twitter.com/i/web/status/1…

22:39

Я достаточно старый, чтобы помнить времена, когда вокруг Io.js был такой же хайп, как вокруг yarn сейчас.
Io.js был… twitter.com/i/web/status/1…

22:40

Но используя yarn сегодня вы подписываетесь на то, чтобы быть вечным бета-тестером. В этом нет ничего плохого, но с… twitter.com/i/web/status/1…

22:41

# Вторник 24 твита

Новый день - новая тема. Сегодня обсудим вопросы взаимодействия с бэкендом.

10:11

Добрые слова поддержки от друзей на сегодня. pic.twitter.com/TcRSkTLTk9

10:12

Начнем с BFF.
⬇️

10:22

  • BFF - это адаптер к внешним API, который агрегирует запросы из разных источников и отдает на фронт в удобном для… twitter.com/i/web/status/1…
  • 10:22

  • BFF - это отличное решение, но только если у вас очень сильная команда инфры. Деплоить, мониторить, балансироват… twitter.com/i/web/status/1…
  • 10:22

  • Соло фронтэнд-команда может затащить BFF только в публичное облако. Взять какой-нибудь Serverless Framework и за… twitter.com/i/web/status/1…
  • 10:22

    4. Однако даже в этом случае вам, скорее всего, нужен будет Cloud DevOps.

    10:22

  • Из РФ-провайдеров поддержку Serverless.com я знаю только от Yandex Cloud Functions (… twitter.com/i/web/status/1…
  • 11:05

  • И последнее про serverless. В 2020 году хорошо выстрелил workers.cloudflare.com
    За 5$ вы получаете 10 млн. запр… twitter.com/i/web/status/1…
  • 11:05

  • В итоге, если у вас нет выделенной инфра-команды или вы не чувствуете в себе силы заехать на serverless, разумне… twitter.com/i/web/status/1…
  • 11:05

  • Отсутствие серверного приложения под фронтом дает кучу преимуществ. Например, mcs.mail.ru - это "гол… twitter.com/i/web/status/1…
  • 11:05

    Идем дальше. Расскажу, что делать, если физрук оставлял вас после уроков и не давал пользоваться GraphQL.
    ⬇️

    15:29

  • GraphQL крут тем, что из коробки дает тебе документацию, валидацию запросов/ответов и TS-типы. Об этом подробно… twitter.com/i/web/status/1…
  • 15:29

  • Но проблема в том, что бэкендеров, которые только вчера отказались от SOAP или RPC в пользу JSON REST API, довол… twitter.com/i/web/status/1…
  • 15:29

  • Первая мысль, которая в такой ситуации приходит в голову, - а давайте сами поднимем GraphQL-сервер и напишем рез… twitter.com/i/web/status/1…
  • 15:53

  • Но лично я в таких случаях практикую другой подход. Первым делом нужно попросить от бэкендеров машиночитаемую до… twitter.com/i/web/status/1…
  • 15:53

  • Если бэкендеры сопротивляются, то мы сами начинаем писать Swagger внутри фронтовой команды. То есть буквально вр… twitter.com/i/web/status/1…
  • 15:53

  • Из этой схемы дальше мы генерируем TypeScript-типы. Я пробовал разные библиотеки, но остановился на… twitter.com/i/web/status/1…
  • 15:53

  • Но что гораздо круче – это то, что, помимо типов, можно сгенерировать и полноценный клиент с помощью… twitter.com/i/web/status/1…
  • 15:53

  • Качество генераторов (openapi-generator.tech/docs/generators) очень разное. Возьмем, например, typescript-fetch и попробуем сге… twitter.com/i/web/status/1…
  • 16:12

  • Не знаю как оно работает для Swagger v2, но на третьей версии я получаю нормальный тип:
    loginMethod(): Promise<L… twitter.com/i/web/status/1…
  • 16:12

  • Ну а что вы хотели? Это вам не GraphQL.
    Подобная проблема описана в ишьюсе github.com/OpenAPITools/o…. Я так поним… twitter.com/i/web/status/1…
  • 16:12

    В итоге из Swagger-схемы вы получаете красивую документацию, типизированный сервисный слой для запросов к API и опц… twitter.com/i/web/status/1…

    17:14

    GraphQL отлично зайдет если вы начинаете проект с нуля. В этом случае вы просто берете hasura.io и ув… twitter.com/i/web/status/1…

    17:14

    # Среда 16 твитов

    Прекрасный день, чтобы покинуть свой дворец и окунуться в пучину JavaScript-разработки.

    9:56

    Сегодня обсудим управление состоянием. Если вы думали, что в предыдущие дни были неаргументированные набросы, то вы… twitter.com/i/web/status/1…

    9:57

    Традиционные слова поддержки. На этот раз от благодарных подписчиков. pic.twitter.com/gdlSFkupsL

    10:07

    Если серьезно, то преимущество редакса это иммутабельность. K.O.
    Но вы платите огромную цену ради нее - бойлерплейт… twitter.com/i/web/status/1…

    10:43

  • В какой ситуации вообще вам может понадобиться иммутабельность на фронте? Мне в голову приходит какой-нибудь тек… twitter.com/i/web/status/1…
  • 10:43

  • Но в реальном мире вам для текстового редактора скорее всего понадобится режим совместного редактирования и там… twitter.com/i/web/status/1…
  • 10:43

  • Говоря о преимуществах иммутабельности, часто упоминают простоту логирования и возможность "поднять" приложение… twitter.com/i/web/status/1…
  • 11:20

  • Почему нельзя просто повесить new Proxy() и логировать вообще все что угодно, хоть каждое обращение к объекту?
    А… twitter.com/i/web/status/1…
  • 11:20

  • По правде говоря, редакс-фанбоям не нужна иммутабельность сама по себе. Их просто привлекает "ореол крутости" ФП… twitter.com/i/web/status/1…
  • 11:20

  • Конечно большинство фанбоев ничего не слышали про идемпотентность, но "крутость" этого слова заставляет их успок… twitter.com/i/web/status/1…
  • 11:20

    Второе преимущество Redux - его дикая популярность. Расскажу, что делать, если в детстве трудовик оставался с вами… twitter.com/i/web/status/1…

    12:01

    Благодаря повальной чипизации населения общий интеллектуальный уровень людей растет. Поэтому каждый год удовлетворе… twitter.com/i/web/status/1…

    12:01

    Если же в 2021 году вы начинаете новый проект с Redux, то имеет смысл задуматься о своем предназначении в жизни. Ра… twitter.com/i/web/status/1…

    12:01

    Ну а если вы начали новый проект с Redux-Saga, то имеет смысл сменить профессию.

    12:01

    Так какой способ работы со слоем данных мне выбрать? Если посмотреть на stateofjs, то у вас всего два варианта:
    1)… twitter.com/i/web/status/1…

    12:18

    С первым вариантом мы вчера определились, что GraphQL-бэкенд вам никто не даст. Поэтому остается один единственный… twitter.com/i/web/status/1…

    12:18

    # Четверг 21 твит

    Отличная вчера была аквадискотека, но во всем важна умеренность. Сегодня не будет никакой провокации. Давайте вместе определим темы:

    9:30

    Традиционный обзор сентимента. Наблюдаем сильную поляризацию в обществе. pic.twitter.com/k0USMYIQwG

    10:12

    Победило тестирование. Начнем с обсуждения того, из-за чего чаще всего возникают баги на фронте.
    ⬇️

    10:18

  • 99% багов возникают на стыке систем. Условно говоря , на фронте все ок, на бэке все ок, а баги возникают в проце… twitter.com/i/web/status/1…
  • 10:18

  • Научите бэкендеров версионировать API и расширять ручки без ломающих изменений. Естественно, доверять на слово н… twitter.com/i/web/status/1…
  • 10:18

  • Если же у вас Swagger, то можно взять любой JSON-валидатор, т.к. формат ответа Swagger это обычная JSON Schema и… twitter.com/i/web/status/1…
  • 10:18

    С бэкендом определились. Идем дальше по пирамиде тестирования.
    ⬇️

    11:19

  • В основе пирамиды на мой взгляд должны стоять не Unit-тесты, а строгая типизация и строгие линтеры. Помимо станд… twitter.com/i/web/status/1…
  • 11:19

  • Готовые конфиги (типа eslint-config-airbnb) мне не нравятся тем, что они смешивают стилистические и логические п… twitter.com/i/web/status/1…
  • 11:19

  • В погоне за высоким покрытием, многие фронты упарываются по jestjs.io/docs/ru/snapsh… (не путать с тестированием с… twitter.com/i/web/status/1…
  • 11:19

  • В теории звучит классно: кидаем в пропсы {isLoading: true} и в снапшоте мы увидим что срендерился какой-нибудь <… twitter.com/i/web/status/1…
  • 11:47

  • Секрет в том, что никто никогда не смотрит что там в снапшоте. Потому что они огромные и постоянно меняются.
    Но… twitter.com/i/web/status/1…
  • 11:47

  • Нормальный тест в этом случае должен быть примерно таким: рендерим компонент с { isLoading: true }, а в теле ком… twitter.com/i/web/status/1…
  • 11:56

    Что взять для UI/E2e-тестов?
    ⬇️

    12:57

  • Используя Selenium-библиотеки вы получаете кучу очень хрупких абстракций. Возьмем, например,… twitter.com/i/web/status/1…
  • 12:57

  • Поэтому лучше взять решения, которые базируются на родных API браузеров, например github.com/puppeteer/pupp… или github.com/microsoft/play…
  • 12:57

  • Можно, конечно, писать тесты напрямую в Puppeteer, но вам точно понадобится удобная работа с локаторами, Page Ob… twitter.com/i/web/status/1…
  • 13:37

  • Крутость CodeceptJS в том, что вы можете взять любой раннер, не важно WebDriver или TestCafe, Puppeteer или Play… twitter.com/i/web/status/1…
  • 13:37

  • Если Puppeteer завтра умрет, как умер WebDriver, то вам не нужно будет переписывать свои тесты.
    Окей, а может лу… twitter.com/i/web/status/1…
  • 13:37

  • Звучит заманчиво, но я никогда не видел чтобы менеджеры или аналитики писали E2e-тесты. А для программистов, Ghe… twitter.com/i/web/status/1…
  • 13:37

    В итоге идеальное тестирование это:

    13:56

    # Пятница 32 твита

    В продолжение вчерашней темы про тестирование. Есть вариант почти полностью отказаться от unit- и E2e-тестов, чтобы… twitter.com/i/web/status/1…

    10:15

  • Обмазаться кучей технических и бизнесовых метрик
  • Мониторить ошибки (Sentry и т.п.)
  • Практиковать Blue-green… twitter.com/i/web/status/1…
  • 10:15

    Если все это использовать на максимум, то можно отказаться от кучи тестов и релизиться хоть по 20 раз в день. О люб… twitter.com/i/web/status/1…

    10:15

    Новая тема - идеальное собеседование.
    В Яндексе я был собеседующим программистом, т.е. проводил интервью и ставил о… twitter.com/i/web/status/1…

    13:05

  • В Мейле я уже сам нанимал людей в свою команду и принимал решение самостоятельно (вместе с руком группы). Обычно… twitter.com/i/web/status/1…
  • 13:05

  • Я не вижу смысла спрашивать WTF-вопросы, типа typeof null или [] * {} - 0 + "", т.к. практического смысла от них… twitter.com/i/web/status/1…
  • 13:05

  • В качестве троллинга, чтобы разрядить обстановку, можно спросить typeof(typeof)
    Именно в таком написании. Но мне… twitter.com/i/web/status/1…
  • 13:05

  • Желательно, чтобы человек знал еще какой-нибудь язык, помимо JS. TypeScript подходит, т.к. считаю его отдельным… twitter.com/i/web/status/1…
  • 13:05

    Конечно от теоретических вопросов на собеседованиях не очень много пользы. Ведь продуктом жизнедеятельности програм… twitter.com/i/web/status/1…

    13:28

  • Пример плохой задачи - leetcode.com/problems/powx-…
    Это плохая задача, т.к. она проверяет знание… twitter.com/i/web/status/1…
  • 13:28

  • Пример хорошей задачи: напишите функцию, которая на вход принимает массив типа:
    [ {name: "a", value: 1}, {name:… twitter.com/i/web/status/1…
  • 13:41

  • Что может быть проще? Любым перебором прошлись по массиву и заполнили объект. Проблемы начинаются как раз с пер… twitter.com/i/web/status/1…
  • 13:41

  • Дальше начинаются проблемы со скобочной записью в property accessors. Если бы мне платили по 1$ каждый раз, когд… twitter.com/i/web/status/1…
  • 13:41

  • А как правильно? Можно было бы просто взять reduce, но если тебе сегодня ко второму уроку, то вот моё решение:… twitter.com/i/web/status/1…
  • 14:03

    Ночной JS-TS-Flow срач?

    17:15

    Чтобы понять насколько Flow превосходит TS достаточно взглянуть на этот код:
    type User = string | undefined
    const u… twitter.com/i/web/status/1…

    18:28

  • На этом преимущества Flow заканчиваются. Раньше многие выбирали Flow, т.к. у него была лучше поддержка Реакта. У… twitter.com/i/web/status/1…
  • 18:39
    i recently discovered the JSDoc comment form of TypeScript (typescriptlang.org/docs/handbook/…) and it is a goddamn revelation… twitter.com/i/web/status/1…

  • Подробнее про это см. typescriptlang.org/docs/handbook/…
    Даже сегодня такой подход находит сторонников среди лидеров мнений… twitter.com/i/web/status/1…
  • 18:39

  • Но потом Microsoft напряглись и бросили все силы на поддержку React. И у них отлично получилось.
    В итоге, выбира… twitter.com/i/web/status/1…
  • 18:50

  • Проблема в «Embrace, Extend, and Extinguish».
    «Поддержать, надстроить и уничтожить» — фраза, которая, как было… twitter.com/i/web/status/1…
  • 18:50

    ... чтобы описать их стратегию внедрения в отрасли программного обеспечения, использующего широко распространённые… twitter.com/i/web/status/1…

    18:50

    5. Заиграл ли новыми красками TypeScript-слоган «TS это всего лишь надстройка над JS»?
    Поддержать, надстроить и уничтожить.

    18:50

  • Я понимаю, что это звучит как «покайтесь, ибо грядет», но если оставить Microsoft без конкуренции, то JS-сообщес… twitter.com/i/web/status/1…
  • 19:00

    Поехали дальше. Как вы думаете, какой тип прописан в TS для аргумента val в Number.isFinite(val)?
    Прежде чем ответи… twitter.com/i/web/status/1…

    19:25

  • Разумно было бы предположить, что сигнатура будет такой:
    isFinite(val: unknown): boolean
  • 19:25

  • Тут можно возразить, типа "передай намбер, чтобы узнать инфинити это или нет". Но у нас нет метода isInteger, а… twitter.com/i/web/status/1…
  • 19:25

  • У TS была другая мотивация на самом деле github.com/Microsoft/Type…
    Это для твой безопасности, сынок. Чтобы ты вмес… twitter.com/i/web/status/1…
  • 19:25

    Следующий пример чуть сложнее:
    const robots = ["R2-D2", "BB-8"]
    const isRobot = robots.includes(790)

    TS запрещает… twitter.com/i/web/status/1…

    19:55

  • Моя логика такая: у меня в справочнике есть список фруктов и я хочу узнать, является ли арбуз фруктом или нет. Я… twitter.com/i/web/status/1…
  • 19:55

    Ясно понятно. pic.twitter.com/KcgOm9XDKS

    20:02

  • А как там у нормальных пацанов? В C# нет includes, но есть indexOf:
    string[] robots = { "R2-D2", "BB-8" };
    int l… twitter.com/i/web/status/1…
  • 20:08

  • Если же вы посмотрите на includes как на Boolean(Array.find()), то все встанет на свои места.
    Но я все равно не… twitter.com/i/web/status/1…
  • 20:20

    # Суббота 8 твитов

    Идея для исследования. Обучить нейронку, которая по твоим взрослым фоткам определяет - ты это на детской фотография… twitter.com/i/web/status/1…

    11:35

    Сложно придумать какую-нибудь тему на сегодня, помимо политики. По политике в РФ каждый может сделать собственные в… twitter.com/i/web/status/1…

    14:55

  • Многие не знают, что большая часть разработчиков Zoom находятся в Китае и поэтому они открыты для давления китай… twitter.com/i/web/status/1…
  • 14:55

  • В 2020 году выяснилось, что сотрудник Zoom сливал китайскому правительству данные пользователей, которые критико… twitter.com/i/web/status/1…
  • 14:55

  • Кроме простого отключения таких конференций, сотрудник Zoom создавал поддельные учетные записи на имена полит. д… twitter.com/i/web/status/1…
  • 14:55

  • То есть он буквально подделывал скриншоты, на которых неугодные властям люди стоят на фоне флагов запрещенных бл… twitter.com/i/web/status/1…
  • 14:55

  • Мораль тут простая:
  • 14:55

  • Надо быть очень отважным, чтобы отправить компартии скан своего паспорта при регистрации в Huawei AppGallery
  • 14:55

    # Воскресенье 1 твит

    Неделя подходит к концу. Надеюсь вам понравилось.
    Если да, то подписывайтесь на меня тут @n_gafarov или пишите на… twitter.com/i/web/status/1…

    18:57

    github.com

    other