Мозговой штурм
В статье описывается методика мозгового штурма и ее проблемы, а также доказывается ее общая неэффективность. Прямых ссылок на исследования не приводится, но я склонен согласиться с описываемыми утверждениями, правда с парой оговорок.
1. Мозговой штурм, как любая метододика, не универсальное средство, и лучше всего его применять при желании получить результат быстро, а не самый качественный.
2. Ключевая сила методики - обработка невероятных вариантов. Смысл не в том что бы перебрать больше вариантов и попробовать найти правильный. Смысл в озвучивании каждым самых безумных теорий, которые помогут другим участникам сассоциировать что-то оригинальное и продуктивное. При таком фокусе проблемы изначального направления и лидера мнений вносят коррективы в наименьшей степени.
Я часто применял эту методику в творческих и инженерных задачах и она мне здорово помогала. Эффективнее всего она работает в тупиковых случаях, а не как точка отчёта.
#soft
В статье описывается методика мозгового штурма и ее проблемы, а также доказывается ее общая неэффективность. Прямых ссылок на исследования не приводится, но я склонен согласиться с описываемыми утверждениями, правда с парой оговорок.
1. Мозговой штурм, как любая метододика, не универсальное средство, и лучше всего его применять при желании получить результат быстро, а не самый качественный.
2. Ключевая сила методики - обработка невероятных вариантов. Смысл не в том что бы перебрать больше вариантов и попробовать найти правильный. Смысл в озвучивании каждым самых безумных теорий, которые помогут другим участникам сассоциировать что-то оригинальное и продуктивное. При таком фокусе проблемы изначального направления и лидера мнений вносят коррективы в наименьшей степени.
Я часто применял эту методику в творческих и инженерных задачах и она мне здорово помогала. Эффективнее всего она работает в тупиковых случаях, а не как точка отчёта.
#soft
Хабр
Мозговой штурм не работает. Почему его до сих пор используют?
Давайте представим себе ситуацию: группе экспертов нужно решить сложную задачу. Она необычная и не решается стандартными способами. Одна из самых распространённых методик поиска решения таких задач —...
usePureCallback
Опубликовал свои мысли и пример кода на счет мемоизации функций в реакте. Пакета нет в НМП, потому что вся реализация занимает чуть больше ста байтов. Без гзипа 🙂
Проблема в том что в реакте нет апи для ленивого чтения данных.
Пример (даю эту задачку на интервью): есть тяжелый компонент таблицы с пропом функцией `
Идея простая: зачем пересоздавать функцию на каждое изменение зависимых данных и ломать этим нижележащую мемоизацию, если можно отделить функцию от зависимостей, сделав ее чистой и получить неизменяемую ссылку.
Проблема в таком подходе в том что данные в мутабельной структуре храняться всегда от последнего рендера, и если рендер будет выброшен ошибкой в нижележащем рендере или данные изменяться параллельным рендером, а функция будет вызвана из старого поддерева с расчетом на старые зависимости, то что-то может пойти не так. Обнадеживает то что такая ситуация не очень часто может встретиться еще и потому что данные в зависимостях не обязательно меняются при новом ререндере, да и нужны нам старые данные не всегда - если старое поддерево будет работать с новыми данными, может оно так и надо.
Конечно, описанные проблемы, при их проявлении, будет очень не приятно дебажить, но на моей практике это какие-то совсем редкие случаи, а профит от постоянных ссылок на функции заметен сильно (у меня с этим постоянно проблемы).
Материалы по теме:
- ссылочная прозрачность
#perf #immutable
Опубликовал свои мысли и пример кода на счет мемоизации функций в реакте. Пакета нет в НМП, потому что вся реализация занимает чуть больше ста байтов. Без гзипа 🙂
Проблема в том что в реакте нет апи для ленивого чтения данных.
Пример (даю эту задачку на интервью): есть тяжелый компонент таблицы с пропом функцией `
getData`, которая дергается по таймауту / инпуту или еще чему. Есть отдельно фильтры, которые нужно учитывать при запросе в getData. Как менять фильтры, что бы не ререндерить таблицу? Идея простая: зачем пересоздавать функцию на каждое изменение зависимых данных и ломать этим нижележащую мемоизацию, если можно отделить функцию от зависимостей, сделав ее чистой и получить неизменяемую ссылку.
Проблема в таком подходе в том что данные в мутабельной структуре храняться всегда от последнего рендера, и если рендер будет выброшен ошибкой в нижележащем рендере или данные изменяться параллельным рендером, а функция будет вызвана из старого поддерева с расчетом на старые зависимости, то что-то может пойти не так. Обнадеживает то что такая ситуация не очень часто может встретиться еще и потому что данные в зависимостях не обязательно меняются при новом ререндере, да и нужны нам старые данные не всегда - если старое поддерево будет работать с новыми данными, может оно так и надо.
Конечно, описанные проблемы, при их проявлении, будет очень не приятно дебажить, но на моей практике это какие-то совсем редкие случаи, а профит от постоянных ссылок на функции заметен сильно (у меня с этим постоянно проблемы).
Материалы по теме:
- ссылочная прозрачность
#perf #immutable
GitHub
GitHub - artalar/usePureCallback: useCallback doing right
useCallback doing right. Contribute to artalar/usePureCallback development by creating an account on GitHub.
👍5
Производительность вам не подконтрольна
Разработчики постоянно переоценивают производительность своего продукта и недооценивают тормознутость пользовательского устройства. Понятно, что средняя машина программиста скорее всего мощнее среднего устройства пользователя, но от незнания количественного соотношения значимость этого факта стремится к нулю. Т.к. продукты и ЦА у всех разные, невозможно вывести какой-то средний и понятный коэффициент, но вы можете попытаться прикинуть его сами на основе следующих пунктов.
Разработчик не имеет задержки в доступах к ресурсам, т.к. большая их часть чаще всего находится на том же localhost. Если же вы используете пару CDN'ок, пару сервисов аналитики ну и собственный домен, то около четверти секунды уйдет только на обращение к DNS и еще больше на handshake. Хотелось бы понадеяться на то что запросы будут обрабатываться параллельно, но у браузеров лимит на это дело (около 6 запросов одновременно), который быстро забивается загрузкой собственных ресурсов.
Кстати, про аналитику, вы же не грузите ее в дев режиме, но сколько требуется клиентскому устройству времени что бы скачать, распарсить и запустить какие-нибудь 100KB GTM? Google Tag Manager vs Page Speed: The Impact and How to Improve.
Некоторые пользователи имеют блокировщики рекламы и аналитики и таким образом за разработчика ускоряют его сайт, но в браузере могут быть установлены и другие расширения, которые на секунды могут увеличивать появление, а в дальнейшем и отзывчивость сайта.
У пользователя могут быть запущены программы кроме браузера или может быть просто большой износ системы (накопленные кеши от долгого аптайма, фрагментированный диск замедляет своп и тп). Естественно, и само устройство может быть малопроизводительным.
Разные браузеры могут иметь различия в реализации разных фич и иметь разницу в их исполнении в десятки раз. Особенно, это касается новых возможностей.
#perf #soft
Разработчики постоянно переоценивают производительность своего продукта и недооценивают тормознутость пользовательского устройства. Понятно, что средняя машина программиста скорее всего мощнее среднего устройства пользователя, но от незнания количественного соотношения значимость этого факта стремится к нулю. Т.к. продукты и ЦА у всех разные, невозможно вывести какой-то средний и понятный коэффициент, но вы можете попытаться прикинуть его сами на основе следующих пунктов.
Разработчик не имеет задержки в доступах к ресурсам, т.к. большая их часть чаще всего находится на том же localhost. Если же вы используете пару CDN'ок, пару сервисов аналитики ну и собственный домен, то около четверти секунды уйдет только на обращение к DNS и еще больше на handshake. Хотелось бы понадеяться на то что запросы будут обрабатываться параллельно, но у браузеров лимит на это дело (около 6 запросов одновременно), который быстро забивается загрузкой собственных ресурсов.
Кстати, про аналитику, вы же не грузите ее в дев режиме, но сколько требуется клиентскому устройству времени что бы скачать, распарсить и запустить какие-нибудь 100KB GTM? Google Tag Manager vs Page Speed: The Impact and How to Improve.
Некоторые пользователи имеют блокировщики рекламы и аналитики и таким образом за разработчика ускоряют его сайт, но в браузере могут быть установлены и другие расширения, которые на секунды могут увеличивать появление, а в дальнейшем и отзывчивость сайта.
У пользователя могут быть запущены программы кроме браузера или может быть просто большой износ системы (накопленные кеши от долгого аптайма, фрагментированный диск замедляет своп и тп). Естественно, и само устройство может быть малопроизводительным.
Разные браузеры могут иметь различия в реализации разных фич и иметь разницу в их исполнении в десятки раз. Особенно, это касается новых возможностей.
#perf #soft
👍6
valueOf
В моем личном списке, “что должен сделать успешный программист за свою карьеру”, есть два пункта: найти уязвимость в чужом ПО и исправить такую уязвимость. Я никогда не надеялся их реализовать т.к. предметная область мне кажется достаточно сложной. Но вчера, совершенно случайно, при регулярном использовании nanoid у меня что-то стрельнуло в голове, и я пошел копать исходники.
Через несколько минут у меня в голове уже созрел план как сломать библиотеку, а через 20 минут был код воспроизведения ошибки, он позволял получить предыдущий сгенерированный идентификатор. Фактически, это воспроизводимые коллизии, что плохо для подобного рода библиотеки, но т.к. условия эксплуатации подразумевают прямой доступ к ссылке инстанс библиотеки, проблема не выглядит серьезной.
Для нетерпеливых вот ПР с кодом воспроизведения проблемы и ее фиксом.
Детали. В вызов генератора идентификатора можно передать число для указания его длины. Чаще всего его не указывают и используется значение по умолчанию -
Проанализировав код библиотеки, я понял, что переданный параметр длинны идентификатора передается по ссылке и в какой-то момент участвует в трех математических операциях с условиями, в которых можно создать логическую ошибку, если значение переменной будет меняться для каждого условия. В ПРе есть наглядный пример реализации.
В итоге, можно было создать такую логическую последовательность работы valueOf, при которой внутреннее состояние библиотеки не менялось бы и генерация идентификатора производилась бы на старом значении, условно говоря, сгенерированным под предыдущий идентификатор.
Интересно было и придумать исправление для этой ошибки. Не хотелось вносить большой оверхед в нано библиотеку, я сам увлекаюсь микрооптимизациями производительности и бандлсайза и для меня это был отдельный челендж. Несколько часов я экспериментировал. Первая реализация добавляла 4 байта, последующая
Библиотека разрешает передавать число строкой в аргумент, поэтому необходимо было использовать именно минус, который конвертирует строку в число, а не плюс, который для строк имеет приоритет как операция конкатенации.
В течении дня я нашел уязвимость, связался с автором, сделал фикс, отрепортил все это в snyk, который завел CVE-2021-23566. Андрей со всем помогал и сразу же зарелизил новую версию 3.1.31, за что ему отдельно спасибо.
В общем, опыт был интересный, наконец удалось получить фан от слабой динамической типизации ЖСа 🙂
#security
В моем личном списке, “что должен сделать успешный программист за свою карьеру”, есть два пункта: найти уязвимость в чужом ПО и исправить такую уязвимость. Я никогда не надеялся их реализовать т.к. предметная область мне кажется достаточно сложной. Но вчера, совершенно случайно, при регулярном использовании nanoid у меня что-то стрельнуло в голове, и я пошел копать исходники.
Через несколько минут у меня в голове уже созрел план как сломать библиотеку, а через 20 минут был код воспроизведения ошибки, он позволял получить предыдущий сгенерированный идентификатор. Фактически, это воспроизводимые коллизии, что плохо для подобного рода библиотеки, но т.к. условия эксплуатации подразумевают прямой доступ к ссылке инстанс библиотеки, проблема не выглядит серьезной.
Для нетерпеливых вот ПР с кодом воспроизведения проблемы и ее фиксом.
Детали. В вызов генератора идентификатора можно передать число для указания его длины. Чаще всего его не указывают и используется значение по умолчанию -
21. Одна из особенностей JS заключается в том что для математических операций над значениями вызывается их метод valueOf, который для Number возвращает само число, но для любых других объектов мы можем его переопределить. И возвращать разные числа по условию!Проанализировав код библиотеки, я понял, что переданный параметр длинны идентификатора передается по ссылке и в какой-то момент участвует в трех математических операциях с условиями, в которых можно создать логическую ошибку, если значение переменной будет меняться для каждого условия. В ПРе есть наглядный пример реализации.
В итоге, можно было создать такую логическую последовательность работы valueOf, при которой внутреннее состояние библиотеки не менялось бы и генерация идентификатора производилась бы на старом значении, условно говоря, сгенерированным под предыдущий идентификатор.
Интересно было и придумать исправление для этой ошибки. Не хотелось вносить большой оверхед в нано библиотеку, я сам увлекаюсь микрооптимизациями производительности и бандлсайза и для меня это был отдельный челендж. Несколько часов я экспериментировал. Первая реализация добавляла 4 байта, последующая
size += size добавляла 2 байта. В итоговой версии я добавил всего 3 символа -=0, а магия минификатора и архиватора смогла нивелировать это до ничего - бандлсайз не изменился!Библиотека разрешает передавать число строкой в аргумент, поэтому необходимо было использовать именно минус, который конвертирует строку в число, а не плюс, который для строк имеет приоритет как операция конкатенации.
В течении дня я нашел уязвимость, связался с автором, сделал фикс, отрепортил все это в snyk, который завел CVE-2021-23566. Андрей со всем помогал и сразу же зарелизил новую версию 3.1.31, за что ему отдельно спасибо.
В общем, опыт был интересный, наконец удалось получить фан от слабой динамической типизации ЖСа 🙂
#security
👍25
Небольшой статус по каналу. Отправляю без нотификации 🙂
(lofi трек, который играл пока я писал этот пост)
За два месяца количество подписчиков увеличилось в четыре раза, если подбирать красивые цифры. Это круто, я это очень ценю, правда. Для меня важен этот канал и каждый подписчик, потому что мне нужно общаться и делиться всем тем хаусом, что происходит в моей голове. Канал помогает структурировать информацию и подводить какой-то итог мыслей - завершать их, хоть на какой-то стадии, переставать о них беспокоиться.
Сейчас комментарии отключены. Их включение точно будет негативно сказываться на моих повседневных обязанностях, буду что-то не успевать. Но мы можем устраивать войсы по следам постов и я буду вносить в них правки или писать новые итоги. Чуть позже.
Если сильно хочется дать / получить доп комментарии - пишите в личку.
Ключевой приоритет для меня - @reatom_ru. Планов очень много, и они даже как-то движутся. За прошедшие полгода накопилось много продуктового фидбека, и я пилю новые крутые фичи. Скоро будут анонсы.
А пока, буду понемногу выкладывать в текстовом виде, в этот канал, расшифровку доклада уже годовалой давности про архитектуру менеджера состояния.
Конечно, будут посты и на другие темы. Не так насыщенно, как на этой неделе 😊 Но мыслей и экспериментов у меня еще много как на работе, так и в петах, так что ждите.
(lofi трек, который играл пока я писал этот пост)
За два месяца количество подписчиков увеличилось в четыре раза, если подбирать красивые цифры. Это круто, я это очень ценю, правда. Для меня важен этот канал и каждый подписчик, потому что мне нужно общаться и делиться всем тем хаусом, что происходит в моей голове. Канал помогает структурировать информацию и подводить какой-то итог мыслей - завершать их, хоть на какой-то стадии, переставать о них беспокоиться.
Сейчас комментарии отключены. Их включение точно будет негативно сказываться на моих повседневных обязанностях, буду что-то не успевать. Но мы можем устраивать войсы по следам постов и я буду вносить в них правки или писать новые итоги. Чуть позже.
Если сильно хочется дать / получить доп комментарии - пишите в личку.
Ключевой приоритет для меня - @reatom_ru. Планов очень много, и они даже как-то движутся. За прошедшие полгода накопилось много продуктового фидбека, и я пилю новые крутые фичи. Скоро будут анонсы.
А пока, буду понемногу выкладывать в текстовом виде, в этот канал, расшифровку доклада уже годовалой давности про архитектуру менеджера состояния.
Конечно, будут посты и на другие темы. Не так насыщенно, как на этой неделе 😊 Но мыслей и экспериментов у меня еще много как на работе, так и в петах, так что ждите.
👍14
Слоты в реакте
Я уже писал про исправление мемоизации, которое не является стандартным паттерном работы с реактом. Сегодня продолжим эту тему и поговорим о слотах.
Слот — это специальный аргумент / атрибут / проп компонента, который подразумевает передачу другого компонента, для его отрисовки ниже по дереву. Это актуальный паттерн для компонентов высшего порядка и часто встречается в любом приложении.
В реакт экосистеме ошибочно считается что любой проп может быть слотом, т.к. children это такой же проп. Проблема, которая уже описывалась в канале “Горшочек варит” (классный канал, рекомендую), заключается в том, что JSX тег отдает всегда новый иммутабельный объект, который будет ломать мемоизацию компонента контейнера.
Из моей практики очевидно, что изменение children происходит внутри компонента очень редко, практически всегда они просто перепрокидываются и вызывают избыточный ререндер, даже если остальные пропы не поменялись.
Правильные слоты прокидывают некий “портал” к передающимся чилдренам и не трогают сам рендер компонента. В этом примере можно посмотреть подобную реализацию на контексте.
Но и у реализации на контексте есть проблема с тем, как это работает под капотом - реакт проходиться по всему VDOM под провайдером контекста при каждом изменении его значения в поисках подписчиков. Это не может вызвать лишние ререндеры, но все равно провоцирует избыточную работу, которая тем больше, чем больше детей у провайдера.
Рома Дворнов делился более оптимальным и рабочим решением, но с ним реакт выкидывает варнинги в консоль, хотя я не знаю какую проблему оно может повлечь.
Мне не понятно, почему в реакте нет встроенного нормального решения для слотов, хотя о них упоминается в документации.
#perf
Я уже писал про исправление мемоизации, которое не является стандартным паттерном работы с реактом. Сегодня продолжим эту тему и поговорим о слотах.
Слот — это специальный аргумент / атрибут / проп компонента, который подразумевает передачу другого компонента, для его отрисовки ниже по дереву. Это актуальный паттерн для компонентов высшего порядка и часто встречается в любом приложении.
В реакт экосистеме ошибочно считается что любой проп может быть слотом, т.к. children это такой же проп. Проблема, которая уже описывалась в канале “Горшочек варит” (классный канал, рекомендую), заключается в том, что JSX тег отдает всегда новый иммутабельный объект, который будет ломать мемоизацию компонента контейнера.
Из моей практики очевидно, что изменение children происходит внутри компонента очень редко, практически всегда они просто перепрокидываются и вызывают избыточный ререндер, даже если остальные пропы не поменялись.
Правильные слоты прокидывают некий “портал” к передающимся чилдренам и не трогают сам рендер компонента. В этом примере можно посмотреть подобную реализацию на контексте.
Но и у реализации на контексте есть проблема с тем, как это работает под капотом - реакт проходиться по всему VDOM под провайдером контекста при каждом изменении его значения в поисках подписчиков. Это не может вызвать лишние ререндеры, но все равно провоцирует избыточную работу, которая тем больше, чем больше детей у провайдера.
Рома Дворнов делился более оптимальным и рабочим решением, но с ним реакт выкидывает варнинги в консоль, хотя я не знаю какую проблему оно может повлечь.
Мне не понятно, почему в реакте нет встроенного нормального решения для слотов, хотя о них упоминается в документации.
#perf
👍18🔥1
Перформанс и память
В популярном бенчмарке фронтенд фреймворков используется достаточно тупой пример, а код примеров каждого фреймворка может содержать какие-то хаки или стилистику далекую от реального написания в продакшене. Но оценка потребляемой памяти, по моим прикидкам, там более или менее адекватная. И вот просто прикиньте как много можно потерять выбирая реакт как слой отображения по умолчанию. А ведь это практически невозможно оптимизировать.
#perf
В популярном бенчмарке фронтенд фреймворков используется достаточно тупой пример, а код примеров каждого фреймворка может содержать какие-то хаки или стилистику далекую от реального написания в продакшене. Но оценка потребляемой памяти, по моим прикидкам, там более или менее адекватная. И вот просто прикиньте как много можно потерять выбирая реакт как слой отображения по умолчанию. А ведь это практически невозможно оптимизировать.
#perf
👍8👎1
Мысли фоном
Первая работа "на дядю" у меня случилась лет 16 назад и с тех пор я много чего перепробовал. Много работал руками (грузчик), ногами (курьер), языком (продавец) и ещё кучей ролей, но ничто так не убивало мою индивидуальность как работа за компьютером дома.
Когда я ездил в офис у меня было время подумать о чем угодно: оценить недавние события, вспомнить что-то, помечтать, подумать о Боге. Просто порассуждать о мелочах и вселенной, о своей жизни и своих близких.
При короне я и в магазины перестал ходить, только доставка. Бывает, выбираешься куда-то с семьей или гуляешь с ребенком, но время на одиночество стало заметно меньше. Небольшие промежутки умственного не напряжения я добиваю прослушиванием подкастов, хочется же побольше успеть.
Сегодня проснулся ночью и пошел немного прогуляться, а по дороге понял как ценно время на едине с самим собой и как много и регулярно оно нужно, чтобы не плыть по накатанной как робот и не перегорать, а жить.
—
Этим постом, видимо, я открываю цикл про #soft скилы и связанное. Хочется рассказать про свой опыт работы в разных сферах и компаниях и почему я хейчу (это так выглядит, но это не так) тех. спецов, которые ведут публичную деятельность.
Первая работа "на дядю" у меня случилась лет 16 назад и с тех пор я много чего перепробовал. Много работал руками (грузчик), ногами (курьер), языком (продавец) и ещё кучей ролей, но ничто так не убивало мою индивидуальность как работа за компьютером дома.
Когда я ездил в офис у меня было время подумать о чем угодно: оценить недавние события, вспомнить что-то, помечтать, подумать о Боге. Просто порассуждать о мелочах и вселенной, о своей жизни и своих близких.
При короне я и в магазины перестал ходить, только доставка. Бывает, выбираешься куда-то с семьей или гуляешь с ребенком, но время на одиночество стало заметно меньше. Небольшие промежутки умственного не напряжения я добиваю прослушиванием подкастов, хочется же побольше успеть.
Сегодня проснулся ночью и пошел немного прогуляться, а по дороге понял как ценно время на едине с самим собой и как много и регулярно оно нужно, чтобы не плыть по накатанной как робот и не перегорать, а жить.
—
Этим постом, видимо, я открываю цикл про #soft скилы и связанное. Хочется рассказать про свой опыт работы в разных сферах и компаниях и почему я хейчу (это так выглядит, но это не так) тех. спецов, которые ведут публичную деятельность.
👍36
Хакатон
Я не знаю, что это точно, термин скорее обобщает, чем конкретизирует. Расскажу сегодня про свой успешный опыт какой-то формы хакатона.
Наша команда: пара фулстеков, фронт и несколько аналитиков и представителей бизнеса, делала продукт уже около полугода. Мы уже пропустили плато налаженного, не до конца, стека и архитектуры, и начали медленно спускаться в яму техдолга. Все было не плохо, но технического драйва было все меньше, требования все еще менялись, а до стабильного релиза было еще далеко.
Как раз под раздумья о том, как бы подбодрить разработку прилетела новая задачка от бизнеса с точными целями и совершенно не понятной реализацией. Проблема была в том, что лишь прототип решения мы оценили в неделю и это было долго, другие таски тоже щемили, хотя профит от этой фичи подразумевался большой.
Дело было в пятницу, и я предложил в понедельник разработчикам полностью игнорировать контакты с бизнесом, а начать день с брейншторма фичи и попробовать сделать прототип за день. С бизнесом тоже согласовали.
В понедельник, отдохнувшие и готовые на заряженный день мы сразу созвонились и быстро придумали простые и эффективные решения, и разошлись на пару часов их реализовывать. Было ощущение свободы и легкости, потому что мы знали, что могли делать что угодно и, в крайнем случае, это будет не жалко выбросить.
Во второй половине дня мы уже поняли, что идея полетит, на следующий день утром презентовали реализацию, бизнес одобрил и до конца дня мы доделали базовую версию. До конца недели один разработчик еще допиливал мелочи.
Честно говоря, было это год назад и что-то я уже не помню, да и ощущения описал свои, хоть и писал “мы”. Но мне правда очень понравился такой формат. В некоторых компаниях бывает “день тишины” раз в неделю, когда разработчиков не приглашают на митинги и не дергают в личке — это тоже, кажется, классным форматом.
Сегодня пятница, может и вы запланируете что-то подобное на следующую неделю 😉
#soft
Я не знаю, что это точно, термин скорее обобщает, чем конкретизирует. Расскажу сегодня про свой успешный опыт какой-то формы хакатона.
Наша команда: пара фулстеков, фронт и несколько аналитиков и представителей бизнеса, делала продукт уже около полугода. Мы уже пропустили плато налаженного, не до конца, стека и архитектуры, и начали медленно спускаться в яму техдолга. Все было не плохо, но технического драйва было все меньше, требования все еще менялись, а до стабильного релиза было еще далеко.
Как раз под раздумья о том, как бы подбодрить разработку прилетела новая задачка от бизнеса с точными целями и совершенно не понятной реализацией. Проблема была в том, что лишь прототип решения мы оценили в неделю и это было долго, другие таски тоже щемили, хотя профит от этой фичи подразумевался большой.
Дело было в пятницу, и я предложил в понедельник разработчикам полностью игнорировать контакты с бизнесом, а начать день с брейншторма фичи и попробовать сделать прототип за день. С бизнесом тоже согласовали.
В понедельник, отдохнувшие и готовые на заряженный день мы сразу созвонились и быстро придумали простые и эффективные решения, и разошлись на пару часов их реализовывать. Было ощущение свободы и легкости, потому что мы знали, что могли делать что угодно и, в крайнем случае, это будет не жалко выбросить.
Во второй половине дня мы уже поняли, что идея полетит, на следующий день утром презентовали реализацию, бизнес одобрил и до конца дня мы доделали базовую версию. До конца недели один разработчик еще допиливал мелочи.
Честно говоря, было это год назад и что-то я уже не помню, да и ощущения описал свои, хоть и писал “мы”. Но мне правда очень понравился такой формат. В некоторых компаниях бывает “день тишины” раз в неделю, когда разработчиков не приглашают на митинги и не дергают в личке — это тоже, кажется, классным форматом.
Сегодня пятница, может и вы запланируете что-то подобное на следующую неделю 😉
#soft
👍9👎2
artalog
Хакатон Я не знаю, что это точно, термин скорее обобщает, чем конкретизирует. Расскажу сегодня про свой успешный опыт какой-то формы хакатона. Наша команда: пара фулстеков, фронт и несколько аналитиков и представителей бизнеса, делала продукт уже около…
Кто-нибудь попробовал?) Отпишите в личу, пожалуйста.
Сегодня должен был быть пост про гитпод, но день был тяжелый и я не успел его доделать, ждите завтра.
А ещё, скоро запущу новый подкаст, о котором давно мечтал. Надеюсь все получится.
Сегодня должен был быть пост про гитпод, но день был тяжелый и я не успел его доделать, ждите завтра.
А ещё, скоро запущу новый подкаст, о котором давно мечтал. Надеюсь все получится.
👍3
Gitpod
Я уже два года пользуюсь этим крутым сервисом для OSS, а осенью затащил селфхост на работу для нашего гитлаба. Вот список основных фич и особенностей, которые я тогда презентовал команде:
- Запуск ВМ (виртуальной машины) в облаке с vscode сервером для указанного git репозитория. Там можно запускать любые скрипты: дев сервер, тесты сборка, линтинг, есть полноценный терминал с рут доступом.
- Открытый порт на сервере может быть доступен по публичному урлу (прощай ngrok).
- Доступ разработчика к серверу осуществляется через браузер или десктопный vscode. Там же можно открыть терминал.
- Доступна полная кастомизация vscode: user, repo, vm instance.
- Есть собственный магазин расширений для vscode, в котором есть почти все.
- Есть поддержка IDE от JetBrains.
- Под каждый бранч каждого репо можно запустить отдельный инстанс.
- Можно загрузить свои дотфайлы (для глобальной настройки терминала)
- Из коробки итеграции с: Github (public or enterprise), Gitlab (public and selfhosted), Bitbucket.
- По умолчанию гитпод запускается из этого докерфайла, который часто обновляется и в какой-то момент может что-то сломаться (у нас так в очередной день ничего не запустилось из-за обновления версии ноды).
- В корне репозитория может быть файл конфигурации для описания скриптов лайфтайма: before, init, command.
- В файле конфигурации можно указать путь к своему докеробразу, который будет использоваться для запуска гитпод контейнера.
- В CI гит системы на каждый коммит можно пребилдить гитпод контейнер, который будет выполнять init скрипт. Например, на каждый ПР.
- Если клиент отключается от контейнера на 3 минуты или не активен (mouse / keyboard interactions) 30 минут, он останавливается.
- Только папка
- Стоимость, по моему мнению, не высокая, тем более что каждый месяц доступно 50 бесплатных часов для публичных репозиториев.
- Базовые сервера в облаке гитпода достаточно мощные.
- Запущенный гитпод контейнер можно шарить по ссылке. Например, это полезно при сложной последовательности воспроизведения проблемы, которой хочется поделиться. Или для парного программирования (по DX хуже live share).
- Можно и наоборот, подключаться сервисом в гитподе к локалхосту компьютера разработчика через Local Companion.
Когда я начинал пользоваться гитподом и половины этих фич не было, а вместо vscode была своя IDE без расширений. Но даже тогда это было очень полезный сервис, поэтому я не могу не рекомендовать попробовать его всем и каждому. Способов применений у него масса.
Советую поставить вот это расширение для браузера, которое добавить каждому репозиторию кнопки открытия онлайн IDE, среди которых есть и гитпод.
#tools
Я уже два года пользуюсь этим крутым сервисом для OSS, а осенью затащил селфхост на работу для нашего гитлаба. Вот список основных фич и особенностей, которые я тогда презентовал команде:
- Запуск ВМ (виртуальной машины) в облаке с vscode сервером для указанного git репозитория. Там можно запускать любые скрипты: дев сервер, тесты сборка, линтинг, есть полноценный терминал с рут доступом.
- Открытый порт на сервере может быть доступен по публичному урлу (прощай ngrok).
- Доступ разработчика к серверу осуществляется через браузер или десктопный vscode. Там же можно открыть терминал.
- Доступна полная кастомизация vscode: user, repo, vm instance.
- Есть собственный магазин расширений для vscode, в котором есть почти все.
- Есть поддержка IDE от JetBrains.
- Под каждый бранч каждого репо можно запустить отдельный инстанс.
- Можно загрузить свои дотфайлы (для глобальной настройки терминала)
- Из коробки итеграции с: Github (public or enterprise), Gitlab (public and selfhosted), Bitbucket.
- По умолчанию гитпод запускается из этого докерфайла, который часто обновляется и в какой-то момент может что-то сломаться (у нас так в очередной день ничего не запустилось из-за обновления версии ноды).
- В корне репозитория может быть файл конфигурации для описания скриптов лайфтайма: before, init, command.
- В файле конфигурации можно указать путь к своему докеробразу, который будет использоваться для запуска гитпод контейнера.
- В CI гит системы на каждый коммит можно пребилдить гитпод контейнер, который будет выполнять init скрипт. Например, на каждый ПР.
- Если клиент отключается от контейнера на 3 минуты или не активен (mouse / keyboard interactions) 30 минут, он останавливается.
- Только папка
/workspace сохраняется между перезапусками контейнера.- Стоимость, по моему мнению, не высокая, тем более что каждый месяц доступно 50 бесплатных часов для публичных репозиториев.
- Базовые сервера в облаке гитпода достаточно мощные.
- Запущенный гитпод контейнер можно шарить по ссылке. Например, это полезно при сложной последовательности воспроизведения проблемы, которой хочется поделиться. Или для парного программирования (по DX хуже live share).
- Можно и наоборот, подключаться сервисом в гитподе к локалхосту компьютера разработчика через Local Companion.
Когда я начинал пользоваться гитподом и половины этих фич не было, а вместо vscode была своя IDE без расширений. Но даже тогда это было очень полезный сервис, поэтому я не могу не рекомендовать попробовать его всем и каждому. Способов применений у него масса.
Советую поставить вот это расширение для браузера, которое добавить каждому репозиторию кнопки открытия онлайн IDE, среди которых есть и гитпод.
#tools
Ona
Ona (formerly Gitpod) | AI software engineers
Enterprise AI software engineers that work with and for your teams.
👍10
Реактивное программирование - парадигма программирования, предполагающая передачу ответственности за инициализацию обработки информации источнику информации.
Еще много теории и практики было бы хорошо мне затронуть в своей жизни, но на основе нескольких лет теоретических исследований и аналитики экосистемы разработки, определение выше я пропагандирую как единственно верное!
Краткое доказательство такое: обе библиотеки MobX и Rx реактивные и считаются стандартом в индустрии. При этом, они сильно отличаются, почти во всем. Но что их объединяет и как их принципы можно обобщить? См. определение выше.
Полемику на этот счет можно разводить часами, но давайте примем должное и немного порассуждаем не о причинах, а следствиях, которые мы используем в своей работе каждый день.
Принцип парадигмы достаточно простой и реализуется одним паттерном, интерфейсом подписки. Особенность заключается в том что реализация в коде может быть очень разная: прямой вызов метода или договоренность о подписке во время чтения данных, которое так же может зависеть от прокси / контекста / стека. Примешайте к этому различные фильтры (мемоизация / дебаунсы и тп), асинхронщину и квантование, порядок обхода подписчиков с глитчами и зомби, и получите такую сложность, которая в голову и не влезает. В мою точно.
Помню, как первый раз столкнулся с этим тестом и два часа пытался понять, что да как (там еще вокруг похожие тесты).
В рядовой разработке на JavaScript можно встретить очень много примеров: addEventListener позволяет установить функцию обратного вызова на появление какого-то события, менеджер состояние позволяет конструировать вычисления на основе данных других вычислений, а React.useEffect принимает вторым аргументов список зависимостей, при изменении которых эффект будет перевызван.
Но зачем все это? Реактивный интерфейс является мощным механизмом уменьшения зацепленности кода. Это влияет на архитектуру всего модуля / приложения и позволяет скейлить код чище и проще.
Так же, с реактивщиной получается автоматически соблюдать SSoT. А в случае со стейт менеджерами, мы избавляемся почти от всех проблем инвалидации кеша.
Обратной стороной гибкости реактивного программирования является сложность отслеживания связей и распространения информации, т.к. убирая зацепленность, мы лишаем код наглядности. Т.е. мы явно видим в коде какие модули использует каждый модуль, но мы не видим в коде модуля какие другие модули от него зависят. К счастью, современные средства разработки, вроде статических анализаторов (являющихся частью ЯП или IDE, или отдельные), помогают находить ссылки в коде на другие части программы и облегчаю ее дебаг. Прогрессивным, но не развитым, средством дебага является отображение связей в приложении в реальном времени, частично реализованное в devtools некоторых библиотек.
По опыту могу сказать, что плохим примером использования реактивщины является описание с ее помощью транзакций. Те если нам нужно реализовать череду связанных операций, лучше это сделать последовательно и в одном месте, а не раскидывать подписки по разным частям кодовой базы.
Еще одним недостатком реактивного программирования является нагрузка на рантайм производительность кода, т.к., фактически, формирование связей между частями кода - подписки мы описываем через какие-то методы, которые отрабатывают только в рантайме. Как и во всем, следует придерживаться баланса реактивного и процедурного программирования, не оборачивая абсолютно каждую мелкую операцию в реактивный контекст, чтобы предотвратить избыточные накладные расходы.
Еще материалы:
- Эта статья на вики лучше большинства блог постов.
- Лекция про транзакции в БД.
- Доклад по архитектуре про event driven design.
- Caching versus Memoization.
- Reactive Programming в Cycle.js.
- What is Reactive Programming? By Luca Mezzalira.
- Объектное Реактивное Программирование.
- A Hands-on Introduction to Fine-Grained Reactivity от автора Solid.js
#reactive #state_management
Еще много теории и практики было бы хорошо мне затронуть в своей жизни, но на основе нескольких лет теоретических исследований и аналитики экосистемы разработки, определение выше я пропагандирую как единственно верное!
Краткое доказательство такое: обе библиотеки MobX и Rx реактивные и считаются стандартом в индустрии. При этом, они сильно отличаются, почти во всем. Но что их объединяет и как их принципы можно обобщить? См. определение выше.
Полемику на этот счет можно разводить часами, но давайте примем должное и немного порассуждаем не о причинах, а следствиях, которые мы используем в своей работе каждый день.
Принцип парадигмы достаточно простой и реализуется одним паттерном, интерфейсом подписки. Особенность заключается в том что реализация в коде может быть очень разная: прямой вызов метода или договоренность о подписке во время чтения данных, которое так же может зависеть от прокси / контекста / стека. Примешайте к этому различные фильтры (мемоизация / дебаунсы и тп), асинхронщину и квантование, порядок обхода подписчиков с глитчами и зомби, и получите такую сложность, которая в голову и не влезает. В мою точно.
Помню, как первый раз столкнулся с этим тестом и два часа пытался понять, что да как (там еще вокруг похожие тесты).
В рядовой разработке на JavaScript можно встретить очень много примеров: addEventListener позволяет установить функцию обратного вызова на появление какого-то события, менеджер состояние позволяет конструировать вычисления на основе данных других вычислений, а React.useEffect принимает вторым аргументов список зависимостей, при изменении которых эффект будет перевызван.
Но зачем все это? Реактивный интерфейс является мощным механизмом уменьшения зацепленности кода. Это влияет на архитектуру всего модуля / приложения и позволяет скейлить код чище и проще.
Так же, с реактивщиной получается автоматически соблюдать SSoT. А в случае со стейт менеджерами, мы избавляемся почти от всех проблем инвалидации кеша.
Обратной стороной гибкости реактивного программирования является сложность отслеживания связей и распространения информации, т.к. убирая зацепленность, мы лишаем код наглядности. Т.е. мы явно видим в коде какие модули использует каждый модуль, но мы не видим в коде модуля какие другие модули от него зависят. К счастью, современные средства разработки, вроде статических анализаторов (являющихся частью ЯП или IDE, или отдельные), помогают находить ссылки в коде на другие части программы и облегчаю ее дебаг. Прогрессивным, но не развитым, средством дебага является отображение связей в приложении в реальном времени, частично реализованное в devtools некоторых библиотек.
По опыту могу сказать, что плохим примером использования реактивщины является описание с ее помощью транзакций. Те если нам нужно реализовать череду связанных операций, лучше это сделать последовательно и в одном месте, а не раскидывать подписки по разным частям кодовой базы.
Еще одним недостатком реактивного программирования является нагрузка на рантайм производительность кода, т.к., фактически, формирование связей между частями кода - подписки мы описываем через какие-то методы, которые отрабатывают только в рантайме. Как и во всем, следует придерживаться баланса реактивного и процедурного программирования, не оборачивая абсолютно каждую мелкую операцию в реактивный контекст, чтобы предотвратить избыточные накладные расходы.
Еще материалы:
- Эта статья на вики лучше большинства блог постов.
- Лекция про транзакции в БД.
- Доклад по архитектуре про event driven design.
- Caching versus Memoization.
- Reactive Programming в Cycle.js.
- What is Reactive Programming? By Luca Mezzalira.
- Объектное Реактивное Программирование.
- A Hands-on Introduction to Fine-Grained Reactivity от автора Solid.js
#reactive #state_management
👍17
Контроль доступа к рантайм данным.
При работе с данными реактивно нам нужно как-то описывать связи, на которые и осуществляется подписка. Для этого могут использоваться разные паттерны.
Selector.
Селектор - самый примитивный паттерн доступа к данным, он описывает функцию чтения данных (get / getter), которая принимает на вход какой-то объект и возвращает какую-то его часть (свойство).
Его преимущество в простоте и сильных возможностях композиции.
Lense.
Линза - это селектор, как геттер, и функция сеттер - установки значения по тому же, что и у селектора, свойству. Иногда, эффективнее отслеживать не изменение результата селектора (который может содержать вычислительную нагрузку), а сам факт изменения каких-то данных (отслеживание сеттера).
Cursor.
Курсор - это более строгий паттерн, который предполагает точное указание необходимого для обработки свойтва. Это позволяет легко отслеживать входящие, исходящие и производные значению. Иногда, использование подобного подхода может показаться более вербозным, но он не накладывает ограничения как мы хотим работать с данными, а помогает лишь описать с какими данными мы хотим работать. Это может быть полезно для систем с условным использованием иммутабельных структур. Например, какие-то часто меняющиейся данные менеджер данных может мутировать, где-то использовать иммутабельные данные, где-то добавлять какие-то проверки на структуру входящих изменений, при этом приклодной API доступа к данным будет неизменным. Для удобства работы с курсорами над глубоковложенными данными можно создавать пути (path).
Proxy.
Перехватчик - это замаскированный, благодаря возможностям ЯП, курсор, который позволяет использовать все (многие) преимущества курсоров, при этом сильно упростив API.
Интересно, что ImmutableJS предполагает работу с данными через курсоры и было бы достаточно просто сделать их реактивными. Как это пытается сделать \~/ kefir.atom.
#state_management
При работе с данными реактивно нам нужно как-то описывать связи, на которые и осуществляется подписка. Для этого могут использоваться разные паттерны.
Selector.
Селектор - самый примитивный паттерн доступа к данным, он описывает функцию чтения данных (get / getter), которая принимает на вход какой-то объект и возвращает какую-то его часть (свойство).
const selectSome = (data) => data.some.property
Его преимущество в простоте и сильных возможностях композиции.
Lense.
Линза - это селектор, как геттер, и функция сеттер - установки значения по тому же, что и у селектора, свойству. Иногда, эффективнее отслеживать не изменение результата селектора (который может содержать вычислительную нагрузку), а сам факт изменения каких-то данных (отслеживание сеттера).
const lensSome = {
get: (data) => data.some.property,
set: (data, value) => data.some.property = value
}
Cursor.
Курсор - это более строгий паттерн, который предполагает точное указание необходимого для обработки свойтва. Это позволяет легко отслеживать входящие, исходящие и производные значению. Иногда, использование подобного подхода может показаться более вербозным, но он не накладывает ограничения как мы хотим работать с данными, а помогает лишь описать с какими данными мы хотим работать. Это может быть полезно для систем с условным использованием иммутабельных структур. Например, какие-то часто меняющиейся данные менеджер данных может мутировать, где-то использовать иммутабельные данные, где-то добавлять какие-то проверки на структуру входящих изменений, при этом приклодной API доступа к данным будет неизменным. Для удобства работы с курсорами над глубоковложенными данными можно создавать пути (path).
const data = { some: { test: 42 } }
const testPath = ['some', 'test']
const testCursor = new Cursor(data, testPath)
Proxy.
Перехватчик - это замаскированный, благодаря возможностям ЯП, курсор, который позволяет использовать все (многие) преимущества курсоров, при этом сильно упростив API.
const test$ = data$.some.test
const test = test$.get()
Интересно, что ImmutableJS предполагает работу с данными через курсоры и было бы достаточно просто сделать их реактивными. Как это пытается сделать \~/ kefir.atom.
#state_management
👍12
artalog
Voice message
^ Повспоминал свой опыт администрирования десять лет назад. Совсем в общем.
Думаю что делать с этой информацией, хочется поделиться же :) Попробую в следующий раз рассказать более детально про что-то конкретное: серверные комнаты и их устройство, организация мониторинга высоконагруженной критической (дорогой по даунтайму) системы, обслуживание распределенных сетей на системном и административном уровнях и тп.
Думаю что делать с этой информацией, хочется поделиться же :) Попробую в следующий раз рассказать более детально про что-то конкретное: серверные комнаты и их устройство, организация мониторинга высоконагруженной критической (дорогой по даунтайму) системы, обслуживание распределенных сетей на системном и административном уровнях и тп.
👍9
Истинность пустоты.
А вы тоже не можете запомнить что
Интересно, что результаты разные и основаны они на математической логике (источников на русском мне найти не удалось).
Там приводится забавный пример. Утверждение, “каждый ребенок бездетного человека овца” верно, потому что мы не можем его проверить и опревергнуть. А вот, “какой-то ребенок бездетного человека овца” не верно, потому что “какой-то” предполагает успешную проверку элемента, которго нет.
Я для себя придумал запоминать так: количество символов в “false” для “some” и “true” для “every” разное (4 != 5).
У оригинального твита можно найти интересные ответы и цитирования.
А вы тоже не можете запомнить что
some и every возвращают для пустого массива?Интересно, что результаты разные и основаны они на математической логике (источников на русском мне найти не удалось).
Там приводится забавный пример. Утверждение, “каждый ребенок бездетного человека овца” верно, потому что мы не можем его проверить и опревергнуть. А вот, “какой-то ребенок бездетного человека овца” не верно, потому что “какой-то” предполагает успешную проверку элемента, которго нет.
Я для себя придумал запоминать так: количество символов в “false” для “some” и “true” для “every” разное (4 != 5).
У оригинального твита можно найти интересные ответы и цитирования.
🤔16👍5