Зачем нужно знать об идемпотентности
Идемпотентность – это свойство какой-либо операции, например, вызова функции или выполнения HTTP-запроса. Операция считается идемпотентной, если повторные выполнения приводят к тому же результату что и первое выполнение.
Возьмем команду mkdir в линуксе. Она создает директорию:
А дальше делаем выводы. Если мы напишем какой-то скрипт, выполняющий подготовку файловой системы, например создающий базовую структуру для нового проекта (типа ./prepare.sh /lala), то отсутствие идемпотентности начнет серьезно мешать. Что может пойти не так?
Во время и после отработки: 1. Отключат свет 2. Не хватит прав 3. Мы что-то случайно удалим и захотим все восстановить 4. Кончится место. И так далее, список может быть большим. Во всех этих ситуациях понадобится повторный запуск и тут бах, он начинает падать с file exists. Соответственно придется вообще все удалять и запускать скрипт так, как будто его раньше не запускали. Мягко говоря это неудобно. Но мы можем обеспечить идемпотентность самостоятельно. Для команды mkdir достаточно добавить флаг -p и повторный запуск перестанет падать с ошибкой
Не все команды имеют флаги идемпотентности, местами нужно прямо писать код с условиями. В конечном итоге подобные sh скрипты превращаются в ад. Именно поэтому появились инструменты управления конфигурацией типа Ansible, одна из основных задач, которых обеспечивать идемпотентность.
Докер тоже решает эту задачу. Так, при сборке образа на основе Dockerfile нам не важно что было раньше, то идемпотентность обеспечивается автоматически. Именно поэтому bash команды внутри Dockerfile это не тоже самое что и реальные bash скрипты. А сборка легко кешируется
Теперь про идемпотентность в HTTP. Там она закреплена прямо на уровне спецификации: https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.2… Например GET, по спецификации, является идемпотентным методом, а POST нет. Тут стоит оговориться что, сам по себе, HTTP этого обеспечить не может. Все зависит от разработчиков. И не знание этих особенностей или игнорирование может приводит к довольно серьезным последствиям.
Из доки: For example, if a client sends a PUT request and the underlying connection is closed before any response is received, then the client can establish a new connection and retry the idempotent request.
Идемпотентность позволяет безопасно делать ретраи и кешировать запросы
А вот то, что POST не идемпотентный нам подсказывает даже браузер. Помните когда после POST-запроса пытаешься сделать f5, то браузер предупреждает о повторной отправке данных и что это не безопасно. Если пройдет валидация, то что-то случится два раза, например выполнится оплата
Тут мы приходим к интересному моменту. Представьте что вы работаете с платежным сервисом типа Stipe. Как обезопасить себя и клиентов от повторных списаний денег при отправке запросов? Это легко случается, когда возникают сетевые ошибки при повторных запросах.
Стандартный способ – добавления ключа идемпотентности. То есть при отправке запроса на списание денег, мы указываем специальный параметр, идентификатор транзакции. Обычно это номер заказа. А платежный сервис на его основе обеспечивает идемпотентность. https://stripe.com/docs/api/idempotent_requests
Идемпотентность особенно важна при работе с очередьми, типа rabbitmq. В этой части ретраи неизбежны и возникает скорее обратная проблема, как остановить то что надо остановить. Тут могут помочь автоматы и превращение at-least-once в at-most-once.
Как все это ложиться на код? Многое из того что я описал, обеспечивается кодом, который мы пишем. Каждый раз когда вы создаете код, выполняющий побочные эффекты на уровне ввода/вывода (фс, сеть), задумайтесь об идемпотентности. Вполне вероятно она тут очень в тему.
Ссылки: Телеграм | Youtube | VK
p.s. Является ли метод DELETE в HTTP идемпотентным
Идемпотентность – это свойство какой-либо операции, например, вызова функции или выполнения HTTP-запроса. Операция считается идемпотентной, если повторные выполнения приводят к тому же результату что и первое выполнение.
Возьмем команду mkdir в линуксе. Она создает директорию:
mkdir jopa
. Что будет если выполнить эту команду два раза? Во второй раз мы получим ошибку. То есть операция не идемпотентная. Тоже самое справедливо и для многих других команд работающих с файловой системой. Что дальше?А дальше делаем выводы. Если мы напишем какой-то скрипт, выполняющий подготовку файловой системы, например создающий базовую структуру для нового проекта (типа ./prepare.sh /lala), то отсутствие идемпотентности начнет серьезно мешать. Что может пойти не так?
Во время и после отработки: 1. Отключат свет 2. Не хватит прав 3. Мы что-то случайно удалим и захотим все восстановить 4. Кончится место. И так далее, список может быть большим. Во всех этих ситуациях понадобится повторный запуск и тут бах, он начинает падать с file exists. Соответственно придется вообще все удалять и запускать скрипт так, как будто его раньше не запускали. Мягко говоря это неудобно. Но мы можем обеспечить идемпотентность самостоятельно. Для команды mkdir достаточно добавить флаг -p и повторный запуск перестанет падать с ошибкой
Не все команды имеют флаги идемпотентности, местами нужно прямо писать код с условиями. В конечном итоге подобные sh скрипты превращаются в ад. Именно поэтому появились инструменты управления конфигурацией типа Ansible, одна из основных задач, которых обеспечивать идемпотентность.
Докер тоже решает эту задачу. Так, при сборке образа на основе Dockerfile нам не важно что было раньше, то идемпотентность обеспечивается автоматически. Именно поэтому bash команды внутри Dockerfile это не тоже самое что и реальные bash скрипты. А сборка легко кешируется
Теперь про идемпотентность в HTTP. Там она закреплена прямо на уровне спецификации: https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.2… Например GET, по спецификации, является идемпотентным методом, а POST нет. Тут стоит оговориться что, сам по себе, HTTP этого обеспечить не может. Все зависит от разработчиков. И не знание этих особенностей или игнорирование может приводит к довольно серьезным последствиям.
Из доки: For example, if a client sends a PUT request and the underlying connection is closed before any response is received, then the client can establish a new connection and retry the idempotent request.
Идемпотентность позволяет безопасно делать ретраи и кешировать запросы
А вот то, что POST не идемпотентный нам подсказывает даже браузер. Помните когда после POST-запроса пытаешься сделать f5, то браузер предупреждает о повторной отправке данных и что это не безопасно. Если пройдет валидация, то что-то случится два раза, например выполнится оплата
Тут мы приходим к интересному моменту. Представьте что вы работаете с платежным сервисом типа Stipe. Как обезопасить себя и клиентов от повторных списаний денег при отправке запросов? Это легко случается, когда возникают сетевые ошибки при повторных запросах.
Стандартный способ – добавления ключа идемпотентности. То есть при отправке запроса на списание денег, мы указываем специальный параметр, идентификатор транзакции. Обычно это номер заказа. А платежный сервис на его основе обеспечивает идемпотентность. https://stripe.com/docs/api/idempotent_requests
Идемпотентность особенно важна при работе с очередьми, типа rabbitmq. В этой части ретраи неизбежны и возникает скорее обратная проблема, как остановить то что надо остановить. Тут могут помочь автоматы и превращение at-least-once в at-most-once.
Как все это ложиться на код? Многое из того что я описал, обеспечивается кодом, который мы пишем. Каждый раз когда вы создаете код, выполняющий побочные эффекты на уровне ввода/вывода (фс, сеть), задумайтесь об идемпотентности. Вполне вероятно она тут очень в тему.
Ссылки: Телеграм | Youtube | VK
p.s. Является ли метод DELETE в HTTP идемпотентным
👍67❤48🔥16👀2
Именование в программировании
В этом посте я разберу наиболее общие правила, принятые в среде разработчиков. Для примеров будет использоваться javascript, но это не принципиально. Рекомендации подходят для всех.
Нотация
Перед тем, как говорить о семантике, давайте посмотрим на синтаксис. Существует несколько популярных нотаций именования:
• Верблюжья нотация (CamelCase): myClass
• Змеиная нотация (snake_case): my_const
• Шашлычная нотация (kebab-case): my-data
• Особняком стоит Венгерская нотация
В реальности их гораздо больше, хотя многие вышли из обихода и не употребляются, либо употребляются крайне редко (по крайней мере, вряд ли многие помнят COBOL-CASE).
Возникает вопрос, какой выбрать стиль? Ответ очень прост. В каждом конкретном языке программирования существует общепризнанный — часто официальный — стандарт кодирования. Именно он должен являться для вас ориентиром. Потратьте время, найдите стандарт для вашего языка и пробегитесь по нему, обычно он лежит на гитхабе и содержит большое количество показательных примеров.
Размер имеет значение
Те, кто сдавал лабораторные по программированию, хорошо помнят, что большинство переменных в них были однобуквенными. Интересный факт состоит в том, что в первых языках программирования идентификаторы были таки односимвольными, как обозначения в математике. Первым языком, судя по всему, который начал использовать слова как идентификаторы, был Лисп. С тех пор (шестидесятые) утекло много воды и использование однобуквенных идентификаторов в современном мире рассматривается как моветон.
И все же их можно и нужно использовать в некоторых ситуациях. Обычно это счетчики и индексы.
Сущность-Действие
Сравните:
Когда мы реализуем функцию, то описываем некоторое действие, а действия в естественных языках выражаются глаголами. Очевидным следствием является то, что имя функции должно быть глаголом. Удивительно, при всей простоте и естественности этого правила, новички часто именуют функции как существительные.
С переменными обычно такой проблемы не возникает, никто не использует глаголы для их именования, но на всякий случай: значение - существительное.
Предикаты
Напомню, что предикат — это функция-проверка, она всегда возвращает либо true, либо false.
В большинстве языков предикаты предваряют префиксом is.
Но не все языки следуют этому правилу. В большинстве лиспов, а так же в ruby (который взял это из лиспов) используется знак ? в конце слова:
Если учесть, что в указанных языках вызов функции не требует скобок в конце, то такая форма смотрится особенно естественной.
Вхождение
Не все предикаты можно выразить через is. Например, как задать вопрос, если мы хотим узнать, есть ли в списке чисел нечетное? В таких ситуациях принято использовать слово has:
Количество
Если вам нужна переменная, в которой содержится количество чего-либо, используйте комбинацию: сущность во множественном числе + count.
Это правило важнее даже в другом варианте, а именно, как не надо называть переменную, обозначающую количество:
Такое именование гарантированно вводит в заблуждение. Сущность во множественном числе всегда должна обозначать только коллекцию.
Примеры
p.s. Как бы вы назвали переменную, содержащую массив цен разных товаров после применения скидки?
Ссылки: Телеграм | Youtube | VK
В этом посте я разберу наиболее общие правила, принятые в среде разработчиков. Для примеров будет использоваться javascript, но это не принципиально. Рекомендации подходят для всех.
Нотация
Перед тем, как говорить о семантике, давайте посмотрим на синтаксис. Существует несколько популярных нотаций именования:
• Верблюжья нотация (CamelCase): myClass
• Змеиная нотация (snake_case): my_const
• Шашлычная нотация (kebab-case): my-data
• Особняком стоит Венгерская нотация
В реальности их гораздо больше, хотя многие вышли из обихода и не употребляются, либо употребляются крайне редко (по крайней мере, вряд ли многие помнят COBOL-CASE).
Возникает вопрос, какой выбрать стиль? Ответ очень прост. В каждом конкретном языке программирования существует общепризнанный — часто официальный — стандарт кодирования. Именно он должен являться для вас ориентиром. Потратьте время, найдите стандарт для вашего языка и пробегитесь по нему, обычно он лежит на гитхабе и содержит большое количество показательных примеров.
Размер имеет значение
Те, кто сдавал лабораторные по программированию, хорошо помнят, что большинство переменных в них были однобуквенными. Интересный факт состоит в том, что в первых языках программирования идентификаторы были таки односимвольными, как обозначения в математике. Первым языком, судя по всему, который начал использовать слова как идентификаторы, был Лисп. С тех пор (шестидесятые) утекло много воды и использование однобуквенных идентификаторов в современном мире рассматривается как моветон.
И все же их можно и нужно использовать в некоторых ситуациях. Обычно это счетчики и индексы.
Сущность-Действие
Сравните:
bed(); // bad
sleep(); // good
Когда мы реализуем функцию, то описываем некоторое действие, а действия в естественных языках выражаются глаголами. Очевидным следствием является то, что имя функции должно быть глаголом. Удивительно, при всей простоте и естественности этого правила, новички часто именуют функции как существительные.
С переменными обычно такой проблемы не возникает, никто не использует глаголы для их именования, но на всякий случай: значение - существительное.
Предикаты
Напомню, что предикат — это функция-проверка, она всегда возвращает либо true, либо false.
В большинстве языков предикаты предваряют префиксом is.
isEmpty()
isValid()
isBusy()
Но не все языки следуют этому правилу. В большинстве лиспов, а так же в ruby (который взял это из лиспов) используется знак ? в конце слова:
empty?
valid?
busy?
Если учесть, что в указанных языках вызов функции не требует скобок в конце, то такая форма смотрится особенно естественной.
Вхождение
Не все предикаты можно выразить через is. Например, как задать вопрос, если мы хотим узнать, есть ли в списке чисел нечетное? В таких ситуациях принято использовать слово has:
node.hasChildren()
Количество
Если вам нужна переменная, в которой содержится количество чего-либо, используйте комбинацию: сущность во множественном числе + count.
symbolsCount
peopleCount
Это правило важнее даже в другом варианте, а именно, как не надо называть переменную, обозначающую количество:
errors
Такое именование гарантированно вводит в заблуждение. Сущность во множественном числе всегда должна обозначать только коллекцию.
Примеры
// Нормализация данных
normalizeDomainName('hexlet.io');
// Извлечение части данных
getName(user);
getDomainFromEmail('support@hexlet.io');
// Получение массива с ошибками
const errors = validate(user);
if (errors.length > 0) {
// ...
}
// Подсчеты
calculateDiff(first, second)
// Допуск
canSwim(user)
canViewProfile(user)
p.s. Как бы вы назвали переменную, содержащую массив цен разных товаров после применения скидки?
Ссылки: Телеграм | Youtube | VK
👍67❤16🔥5🥱2👀2🤷♂1🤯1
Развитие сюжета про Василия
Когда я начал пост, то планировал как можно быстрее объяснить общие принципы работы бизнесов и нырнуть в особенности связанные с расчетом расходной части куда входит ФОТ. В процессе затянуло и стало интересно писать историю, через которую можно показать не только статическое устройство бизнеса, но и стадии его развития, с попутным объяснением ключевых концепций на разных этапах. Одна из вещей которую я точно хочу показать, это разницу между стартапом и сложившимся бизнесом и переход от одной стадии к другой.
Поэтому не будем спешить, а будем наслаждаться процессом и историей. Была идея сделать опрос на тему развития сюжета, но кажется, интереснее, когда для вас это сюрприз. А вот темы, которые затрагиваются внутри можно разворачивать или наоборот, пробегать быстро. Например, в первом посту я несколькими абзацами рассказал вещи про которые пишут книги и до которых доходят годами.
Чтобы дальше было легче двигаться, мне интересно поболтать с вами на тему своих бизнесов. Были ли у вас такие мысли или попытки. Чего вы боитесь, чего вы не знаете, но хотели бы узнать, что вы не понимаете. Я накину список тем, которые имеет смысл обсуждать в рамках бизнесов:
⁃ Финансовое планирование
⁃ Управленческая отчетность (p&l, баланс, кешфлоу, кассовый метод или метод начислений)
⁃ Юнит-экономика (cac, ltv, arpu, churn rate)
⁃ Маркетинг (перфоманс, посевы, ctr, cpa, crm, посадочные, упаковка, seo)
- Аналитика (сквозная аналитика, аналитика продаж, продуктовая аналитика)
⁃ Продажи
⁃ Менеджмент (KPI, дерево метрик)
⁃ Рынки (рост, алый океан, product marketing fit, конкуренты)
⁃ Продукт
Ссылки: Телеграм | Youtube | VK
p.s. Следующую часть планирую написать завтра или на выходных
Когда я начал пост, то планировал как можно быстрее объяснить общие принципы работы бизнесов и нырнуть в особенности связанные с расчетом расходной части куда входит ФОТ. В процессе затянуло и стало интересно писать историю, через которую можно показать не только статическое устройство бизнеса, но и стадии его развития, с попутным объяснением ключевых концепций на разных этапах. Одна из вещей которую я точно хочу показать, это разницу между стартапом и сложившимся бизнесом и переход от одной стадии к другой.
Поэтому не будем спешить, а будем наслаждаться процессом и историей. Была идея сделать опрос на тему развития сюжета, но кажется, интереснее, когда для вас это сюрприз. А вот темы, которые затрагиваются внутри можно разворачивать или наоборот, пробегать быстро. Например, в первом посту я несколькими абзацами рассказал вещи про которые пишут книги и до которых доходят годами.
Чтобы дальше было легче двигаться, мне интересно поболтать с вами на тему своих бизнесов. Были ли у вас такие мысли или попытки. Чего вы боитесь, чего вы не знаете, но хотели бы узнать, что вы не понимаете. Я накину список тем, которые имеет смысл обсуждать в рамках бизнесов:
⁃ Финансовое планирование
⁃ Управленческая отчетность (p&l, баланс, кешфлоу, кассовый метод или метод начислений)
⁃ Юнит-экономика (cac, ltv, arpu, churn rate)
⁃ Маркетинг (перфоманс, посевы, ctr, cpa, crm, посадочные, упаковка, seo)
- Аналитика (сквозная аналитика, аналитика продаж, продуктовая аналитика)
⁃ Продажи
⁃ Менеджмент (KPI, дерево метрик)
⁃ Рынки (рост, алый океан, product marketing fit, конкуренты)
⁃ Продукт
Ссылки: Телеграм | Youtube | VK
p.s. Следующую часть планирую написать завтра или на выходных
🔥58👍19❤8👀3
Ура! вышло новое видео где мы с Андреем Мелиховым обсуждаем текущее состояние и будущее Node.js для разработки и разработчиков https://www.youtube.com/watch?v=98qu3CqRNb8
Ссылки: VK | Rutube | Подкасты
Ссылки: VK | Rutube | Подкасты
YouTube
Есть ли будущее у Node.js? / Андрей Мелихов #6
Node.js — мощный инструмент, который часто используется как для фронтенда, так и для бэкенда. В этом видео вместе с Андреем Мелиховым, Lead Developer в Yandex.Cloud@devschacht, обсудим, как Node.js помогает создавать BFF (Backend For Frontend), проблемы…
🔥47👍17🤮2
Что происходит в JS/TS
После выпуска с Андреем пришло много интересных комментов плюс кое что обсудили в твиттере. И вот что интересного оттуда можно вынести:
⁃ Graphql был ошибкой. https://x.com/mokevnin/status/1824431153295577236
⁃ Все массово валят (и довольны) на https://trpc.io/
⁃ Нормальная ORM (почти) в Node.js для ts и js это Drizzle (призма нет) https://orm.drizzle.team/
⁃ Хуки в реакте были ошибкой: https://x.com/mokevnin/status/1824148007820161095 охеренный тред с Ситником
- react-query превратился в tanstack, который умеет все для всех фреймворков https://tanstack.com/
⁃ В js есть интересная экосистема тул https://unjs.io/
- zod классная либа для валидации https://zod.dev/
⁃ Vue > 3.3 офигенен https://x.com/xanf_ua/status/1824130658790240456
- Я умею дышать маткой
После выпуска с Андреем пришло много интересных комментов плюс кое что обсудили в твиттере. И вот что интересного оттуда можно вынести:
⁃ Graphql был ошибкой. https://x.com/mokevnin/status/1824431153295577236
⁃ Все массово валят (и довольны) на https://trpc.io/
⁃ Нормальная ORM (почти) в Node.js для ts и js это Drizzle (призма нет) https://orm.drizzle.team/
⁃ Хуки в реакте были ошибкой: https://x.com/mokevnin/status/1824148007820161095 охеренный тред с Ситником
- react-query превратился в tanstack, который умеет все для всех фреймворков https://tanstack.com/
⁃ В js есть интересная экосистема тул https://unjs.io/
- zod классная либа для валидации https://zod.dev/
⁃ Vue > 3.3 офигенен https://x.com/xanf_ua/status/1824130658790240456
- Я умею дышать маткой
🤣58🔥26👍16❤10🗿4😁3🤮2
Васятка делает стартап. Часть вторая
Наутро после бурной ночи Вася проснулся с легким похмельем и тяжестью на душе. Его стартап, который еще вчера казался светлым будущим, теперь выглядел не иначе как пропасть, в которую он неуклонно скатывался. Однако, вместо того чтобы предаваться унынию, Вася решил, что пора действовать. Он поставил перед собой задачу разобраться в юнит-экономике своего проекта до конца.
Вася сел за стол с калькулятором, блокнотом и чашкой крепкого кофе. Он знал, что ключом к успеху стартапа является правильный баланс между доходами и расходами на каждого клиента. Начать следовало с пересчета всех показателей, о которых говорили его друзья.
Подсчет LTV (life Time Value)
Вася понял, где-то сильно просчитался. Несмотря на то, что он установил цену подписки в $10, далеко не все пользователи оставались на платформе на длительный срок. Отток пользователей (Churn Rate) оказался выше ожидаемого, и за первый месяц составил примерно 30.74%. Это означало, что почти треть всех пользователей отписывались каждый месяц, что било по самолюбию Васи, ведь его продукт был лучше тех, которыми он пользовался сам. В результате, средний пользователь приносил ему лишь $25, прежде чем отписывался.
Что тут не так, подумал Вася и решил спросить у ChatGPT, а есть ли какие-то средние показатели оттока пользователей у таких приложений, на которые он мог бы ориентироваться? ChatGPT сказал, что в среднем отток составляет 5-10% в месяц. При таком оттоке, ltv бы составил 100$-200$, что уже значительно интереснее. Похоже надо было связаться с пользователями и спросить чего им не хватает в продукте.
Подсчет CAC (Customer Acquisition Cost)
Теперь Васе было понятно, что расходы на рекламу и продвижение нельзя игнорировать. Потратив $1000 на маркетинг и получив лишь 10 новых подписчиков, Вася увидел, что каждый новый клиент обходится ему в $100. С такими показателями бизнес не мог быть прибыльным даже теоретически.
Расчет Окупаемости (Payback Period)
Изучая принципы создания юнит-экономики, Вася познакомился с понятием COGS (Cost of Goods Sold), которые включают в себя прямые затраты на обслуживание одного клиента. Например серверные расходы, поддержку, лицензии и т.д.
Этот показатель важно учитывать при попытке посчитать окупаемость. Вася разумно прикинул, что скоро ему придется нанять специалиста службы поддержки, так как вопросов стало много, а времени на них отвечать мало. Он посчитал что это в пересчете на каждого пользователя такой специалист будет обходиться в 2$.
Зная переменные затраты, можно рассчитать маржинальную прибыль, которая затем участвует в формуле для расчета срока окупаемости клиента. Маржинальная прибыль это разница между доходом и переменными затратами на одного пользователя (COGS). Рассчитывается как ARPU минус COGS. Например, если ARPU $10, а COGS $2, то маржинальная прибыль составит $8.
Остался последний шаг, посчитать окупаемость, то есть время необходимое для окупаемости затрат на привлечения. Рассчитывается как CAC, делённый на Contribution Margin.
У Васи получилось: $100 / $8 = 12.5 месяцев. У него потемнело в глазах, ему пришлось на время переключиться, чтобы осознать невыносимую легкость бытия. Он пошел проветриться, заодно купить хлеб.
Сравнение CAC и LTV
Пожалуй, это был самый болезненный момент для Васятки. CAC в $100 значительно превышает LTV в $25, а это означает, что каждый новый клиент приносит ему убытки. Если бы он продолжил в том же духе, деньги закончились бы очень быстро, и стартап пришлось бы закрывать.
Вася уже не переживал, его разум был чист и сфокусирован на поиске решения. Он еще раз окинул взглядом все цифры и начал писать план выхода в плюс. Вот что он решил:
А теперь поиграем в игру) Давайте поможем Васятке найти пути выхода из сложившейся ситуации. Какие действия он может предпринять, чтобы воздействовать на показатели? И на какие в первую очередь?
Третья часть будет основываться на ответах, потому что у нас есть развилка идти в продукт или продажи (куда важнее в текущей ситуации?)
Ссылки: Телеграм | Youtube | VK
Наутро после бурной ночи Вася проснулся с легким похмельем и тяжестью на душе. Его стартап, который еще вчера казался светлым будущим, теперь выглядел не иначе как пропасть, в которую он неуклонно скатывался. Однако, вместо того чтобы предаваться унынию, Вася решил, что пора действовать. Он поставил перед собой задачу разобраться в юнит-экономике своего проекта до конца.
Вася сел за стол с калькулятором, блокнотом и чашкой крепкого кофе. Он знал, что ключом к успеху стартапа является правильный баланс между доходами и расходами на каждого клиента. Начать следовало с пересчета всех показателей, о которых говорили его друзья.
Подсчет LTV (life Time Value)
Вася понял, где-то сильно просчитался. Несмотря на то, что он установил цену подписки в $10, далеко не все пользователи оставались на платформе на длительный срок. Отток пользователей (Churn Rate) оказался выше ожидаемого, и за первый месяц составил примерно 30.74%. Это означало, что почти треть всех пользователей отписывались каждый месяц, что било по самолюбию Васи, ведь его продукт был лучше тех, которыми он пользовался сам. В результате, средний пользователь приносил ему лишь $25, прежде чем отписывался.
Что тут не так, подумал Вася и решил спросить у ChatGPT, а есть ли какие-то средние показатели оттока пользователей у таких приложений, на которые он мог бы ориентироваться? ChatGPT сказал, что в среднем отток составляет 5-10% в месяц. При таком оттоке, ltv бы составил 100$-200$, что уже значительно интереснее. Похоже надо было связаться с пользователями и спросить чего им не хватает в продукте.
Подсчет CAC (Customer Acquisition Cost)
Теперь Васе было понятно, что расходы на рекламу и продвижение нельзя игнорировать. Потратив $1000 на маркетинг и получив лишь 10 новых подписчиков, Вася увидел, что каждый новый клиент обходится ему в $100. С такими показателями бизнес не мог быть прибыльным даже теоретически.
Расчет Окупаемости (Payback Period)
Изучая принципы создания юнит-экономики, Вася познакомился с понятием COGS (Cost of Goods Sold), которые включают в себя прямые затраты на обслуживание одного клиента. Например серверные расходы, поддержку, лицензии и т.д.
Этот показатель важно учитывать при попытке посчитать окупаемость. Вася разумно прикинул, что скоро ему придется нанять специалиста службы поддержки, так как вопросов стало много, а времени на них отвечать мало. Он посчитал что это в пересчете на каждого пользователя такой специалист будет обходиться в 2$.
Зная переменные затраты, можно рассчитать маржинальную прибыль, которая затем участвует в формуле для расчета срока окупаемости клиента. Маржинальная прибыль это разница между доходом и переменными затратами на одного пользователя (COGS). Рассчитывается как ARPU минус COGS. Например, если ARPU $10, а COGS $2, то маржинальная прибыль составит $8.
Остался последний шаг, посчитать окупаемость, то есть время необходимое для окупаемости затрат на привлечения. Рассчитывается как CAC, делённый на Contribution Margin.
У Васи получилось: $100 / $8 = 12.5 месяцев. У него потемнело в глазах, ему пришлось на время переключиться, чтобы осознать невыносимую легкость бытия. Он пошел проветриться, заодно купить хлеб.
Сравнение CAC и LTV
Пожалуй, это был самый болезненный момент для Васятки. CAC в $100 значительно превышает LTV в $25, а это означает, что каждый новый клиент приносит ему убытки. Если бы он продолжил в том же духе, деньги закончились бы очень быстро, и стартап пришлось бы закрывать.
Вася уже не переживал, его разум был чист и сфокусирован на поиске решения. Он еще раз окинул взглядом все цифры и начал писать план выхода в плюс. Вот что он решил:
А теперь поиграем в игру) Давайте поможем Васятке найти пути выхода из сложившейся ситуации. Какие действия он может предпринять, чтобы воздействовать на показатели? И на какие в первую очередь?
Третья часть будет основываться на ответах, потому что у нас есть развилка идти в продукт или продажи (куда важнее в текущей ситуации?)
Ссылки: Телеграм | Youtube | VK
Telegram
Организованное программирование | Кирилл Мокевнин
Как из джуниора дойти до мидла, а потом и до синьора
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
❤45🔥26👍19🤔2😁1
Ловушки обучения
Во время обучения бывают ситуации, когда ожидания не совпадают с реальностью, и вы не видите нужного результата. Причин может быть масса, но среди них выделяется группа, связанная с когнитивными искажениями. Об этой группе мы и поговорим.
Меня неправильно учат
Хотя такое встречается сплошь и рядом, часто ученик не осознает глубины происходящего процесса. Мозг привык к подходам, заложенными родителями, школой, секциями, и не находит ассоциаций. Учащегося пугает состояние неопределенности и непредсказуемости (с его точки зрения).
Я думаю, что все сталкивались с подобной ситуацией в школе. Когда нам казалось, что учитель — злодей, а спустя много лет мы отзывались о нем как о единственном, кто действительно нас чему-то научил. Тоже самое происходит и в институте.
Надо не забывать, что обучение новому происходит всегда в режиме дискомфорта — особенно в ситуациях, когда мозгу сложно, и он не знает, что ему делать. По этой же причине выполнение физических упражнений, требующих сложной координации тела, является очень эффективным способом нагружать организм. Посмотрите на распространенный в современном фитнесе функциональный тренинг.
Я все понял
> Все понятно, но как дело касается практики — прихожу в ступор (студент Хекслета)
Эффект «я все понял» проявляется невероятно часто у подавляющего большинства людей. Когда мы смотрим или читаем теорию, нам кажется, что мы все понимаем. Но как доходит до практики, выясняется, что ничего не получается. И на поверку оказывается, что «я ничего не понял».
Существует множество приемов, помогающих определить ваше реальное понимание изученного, например:
• Попробовать сделать это самостоятельно на практике
• Рассказать своими словами другому — так, чтобы он тоже понял (будучи автором курсов, я учусь сильнее, чем учатся мои студенты)
Пока вы не проверили «понимашку», считайте, что вы находитесь во власти эффекта «я все понял», которому доверять нельзя.
Кстати, по этой причине почти не работают большие теоретические курсы и книги в отрыве от производства. Вы можете пройти их до конца с ощущением понимания происходящего, но на практике это будет самообманом.
Я должен знать, как сделать правильно — до того, как начну делать
Вспомните школьные физику, алгебру, геометрию, химию. По этим предметам мы решали огромное количество задач, и никогда не наступал момент, чтобы можно было сказать «теперь я легко могу решить любую задачу» (в рамках известной теории). То есть, вы гарантированно знаете теорию, которая используется в задаче, но задача все равно не решается. И даже после десятков решенных задач, все равно находятся такие, которые не поддаются.
Любая задача в подобных областях — это больше, чем применение теории. Это включение многих видов мышления, помогающих разбить задачу на части, выделить в ней главное (абстрагироваться), найти закономерности, скомбинировать известные приемы. Я уже не говорю про то, что в процессе вы будете постоянно ошибаться и отбрасывать неверные варианты. Постепенно появляется «чутье», ошибок становится меньше, прямых попаданий больше.
Именно это и есть обучение. К сожалению или к счастью, другого пути нет. Важные выводы:
• Не существует единственно верного и тем более «правильного» пути. Всегда есть компромисс.
• Нельзя заранее знать «как правильно». Удачные решения — это фундаментальные знания + опыт предыдущих поколений + ваш собственный опыт (шишки).
• Попытка использовать существующее (возможно, подходящее решение) без глубокого понимания проблематики (самая частая ситуация) приводит к тому, что появляется ложное ощущение «я умею» (а не только «я знаю»). В своей практике постоянно наблюдаю подобную картину: программист с годами опыта попадает в ситуацию, где не работает привычный инструмент, теряется, и либо ничего не может делать, либо делает нечто совершенно непригодное к использованию.
Интересно, что чаще важнее знать «как делать не нужно» и «почему». И, хотя почти всегда можно об этом прочитать в интернете или книгах, но по-настоящему мозг осознает и понимает только свой собственный опыт.
Ссылки: Телеграм | Youtube | VK
Во время обучения бывают ситуации, когда ожидания не совпадают с реальностью, и вы не видите нужного результата. Причин может быть масса, но среди них выделяется группа, связанная с когнитивными искажениями. Об этой группе мы и поговорим.
Меня неправильно учат
Хотя такое встречается сплошь и рядом, часто ученик не осознает глубины происходящего процесса. Мозг привык к подходам, заложенными родителями, школой, секциями, и не находит ассоциаций. Учащегося пугает состояние неопределенности и непредсказуемости (с его точки зрения).
Я думаю, что все сталкивались с подобной ситуацией в школе. Когда нам казалось, что учитель — злодей, а спустя много лет мы отзывались о нем как о единственном, кто действительно нас чему-то научил. Тоже самое происходит и в институте.
Надо не забывать, что обучение новому происходит всегда в режиме дискомфорта — особенно в ситуациях, когда мозгу сложно, и он не знает, что ему делать. По этой же причине выполнение физических упражнений, требующих сложной координации тела, является очень эффективным способом нагружать организм. Посмотрите на распространенный в современном фитнесе функциональный тренинг.
Я все понял
> Все понятно, но как дело касается практики — прихожу в ступор (студент Хекслета)
Эффект «я все понял» проявляется невероятно часто у подавляющего большинства людей. Когда мы смотрим или читаем теорию, нам кажется, что мы все понимаем. Но как доходит до практики, выясняется, что ничего не получается. И на поверку оказывается, что «я ничего не понял».
Существует множество приемов, помогающих определить ваше реальное понимание изученного, например:
• Попробовать сделать это самостоятельно на практике
• Рассказать своими словами другому — так, чтобы он тоже понял (будучи автором курсов, я учусь сильнее, чем учатся мои студенты)
Пока вы не проверили «понимашку», считайте, что вы находитесь во власти эффекта «я все понял», которому доверять нельзя.
Кстати, по этой причине почти не работают большие теоретические курсы и книги в отрыве от производства. Вы можете пройти их до конца с ощущением понимания происходящего, но на практике это будет самообманом.
Я должен знать, как сделать правильно — до того, как начну делать
Вспомните школьные физику, алгебру, геометрию, химию. По этим предметам мы решали огромное количество задач, и никогда не наступал момент, чтобы можно было сказать «теперь я легко могу решить любую задачу» (в рамках известной теории). То есть, вы гарантированно знаете теорию, которая используется в задаче, но задача все равно не решается. И даже после десятков решенных задач, все равно находятся такие, которые не поддаются.
Любая задача в подобных областях — это больше, чем применение теории. Это включение многих видов мышления, помогающих разбить задачу на части, выделить в ней главное (абстрагироваться), найти закономерности, скомбинировать известные приемы. Я уже не говорю про то, что в процессе вы будете постоянно ошибаться и отбрасывать неверные варианты. Постепенно появляется «чутье», ошибок становится меньше, прямых попаданий больше.
Именно это и есть обучение. К сожалению или к счастью, другого пути нет. Важные выводы:
• Не существует единственно верного и тем более «правильного» пути. Всегда есть компромисс.
• Нельзя заранее знать «как правильно». Удачные решения — это фундаментальные знания + опыт предыдущих поколений + ваш собственный опыт (шишки).
• Попытка использовать существующее (возможно, подходящее решение) без глубокого понимания проблематики (самая частая ситуация) приводит к тому, что появляется ложное ощущение «я умею» (а не только «я знаю»). В своей практике постоянно наблюдаю подобную картину: программист с годами опыта попадает в ситуацию, где не работает привычный инструмент, теряется, и либо ничего не может делать, либо делает нечто совершенно непригодное к использованию.
Интересно, что чаще важнее знать «как делать не нужно» и «почему». И, хотя почти всегда можно об этом прочитать в интернете или книгах, но по-настоящему мозг осознает и понимает только свой собственный опыт.
Ссылки: Телеграм | Youtube | VK
Telegram
Организованное программирование | Кирилл Мокевнин
Как из джуниора дойти до мидла, а потом и до синьора
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
🔥73👍35❤16❤🔥3💯2👀1
Концепции в разных языках программирования, которые помогают лучше понять возможности кодинга как-такового. Многие из этих концепций сильно облегчают жизнь и кардинально меняют способы описания логики. Поехали =>
Uniform Function Call Syntax. Фича языков D и NiM, позволяющая вызывать функцию тремя разными способами: как метод, как функцию и как команду. Удобно для создания цепочек. Во всех случаях это всего лишь функция:
Actor Model. Основной язык Erlang/Elixir и куча либ в других языках. Способ организации кода в легковесные изолированные процессы, общающиеся друг с другом через сообщения. Нет шаред стейта, легко делать канкаренси. Настоящий ООП по Алану Кею.
Pipeline. В языках Elixir, F#, Clojure, Haskell да и пожалуй во всех фп. Позволяет заменять вложенные вызовы функций на плоскую цепочку. Древнейшая концепция, во всю используется в шеле. Мастхев для языков где функции правят балом.
Currying (и частичное применение туда же) Из популярных по умолчанию в ядре в Haskell, Ocaml-подобных, там функции сразу такие. В остальных языках ручками. Очень сильно повышает выразительность и упрощает многие конструкции. Реальное осознание только через haskell
Homoiconicity. Свойство языков, в которых код этого языка одновременно является валидной структурой данных на этом же языке. Относится ко всем лиспам. Дает нереально крутые макросы. Плюс легкую трансформацию кода кодом. Поэтому в лиспах почти все либы, а не часть языка
Pattern Matching (+ Destructuring). Фича ФП языков, которая адаптирована многими императивными. Позволяет полностью изменить принцип работы с условными конструкциями, они становятся не нужны, а сама обработка разных условий становится и проще и понятнее
Mixin (Trait). Фича Ruby, PHP, Лиспов. Имитируется в JS. Один из лучших способ обобщать какое-то поведение и добавлять его в существующие классы. Правильная альтернатива наследованию (в том числе множественному) и абстрактным классам
Открытые классы. Smalltalk, Ruby, Python, JS (прототипы), Kotlin (частично в extension methods). Возможность поменять любой существующий класс прямо в рантайме. Значительно упрощает, например, тестирование. Снижает зависимость от IoC. Проще фиксить либы. Опасная и мегамощная фича
Message Passing. Настоящий в Smaltalk, Ruby, Python, PHP. Это не просто выбор полиморной реализации, а возможность определить общую реакцию для всех явно не определенных сообщений. Открывать путь к динамическим методам, которые нигде не определены.
В JS такое делается только через Proxy, который позволяет перехватывать любой вызов. Правда только для свойств. Для методов придется сильно извращаться и все равно получится очень тяжелое решение. Поэтому там это делают только в учебных целях.
Multimethods. Clojure и остальные лиспы (через CLOS). Киллер фича, позволяющая делать мультидиспетчеризацию (не только по типу) при создании полиморфных реализаций. Значительно сокращает количество и сложность иерархий классов. Обобщает полиморфизм.
List Comprehension. Фича почти всех ФП языков + Python, Smalltalk. Удобный механизм адаптированный прямиком из математики, для описания преобразования коллекций. Заменяет мапы/фильтры/вотевер.
Monads. Тут все просто. Монада это моноид в категории эндофункторов 😄 В целом штука, позволяющая управлять потоком выполнения и делать с ним всякое интересное. Из крутого: Maybe, Either. Порекомендуйте крутую литературу для интересующихся плс!
Generator. Есть во многих языках. Позволяют создавать бесконечные коллекции благодаря тому, что они формируются не сразу, а генерируются в процессе обхода. Часто связаны с ключевиком yield. Значительно упрощают написание итераторов
Еще можно добавить про горячую замену кода. Смолтолк и Эрланг тут чемпионы. Код на эрланге может десятилетиями работать без остановки и постоянно обновляться
Ссылки: Телеграм | Youtube | VK
Uniform Function Call Syntax. Фича языков D и NiM, позволяющая вызывать функцию тремя разными способами: как метод, как функцию и как команду. Удобно для создания цепочек. Во всех случаях это всего лишь функция:
p.move(5, 7)
move(p, 5, 7)
p.move 5, 7
Actor Model. Основной язык Erlang/Elixir и куча либ в других языках. Способ организации кода в легковесные изолированные процессы, общающиеся друг с другом через сообщения. Нет шаред стейта, легко делать канкаренси. Настоящий ООП по Алану Кею.
Pipeline. В языках Elixir, F#, Clojure, Haskell да и пожалуй во всех фп. Позволяет заменять вложенные вызовы функций на плоскую цепочку. Древнейшая концепция, во всю используется в шеле. Мастхев для языков где функции правят балом.
promise
|> await
|> x => doubleSay(x, ', ')
|> capitalize
|> x => x + '!'
|> x => new User.Message(x)
|> x => stream.write(x)
|> await
|> console.log;
Currying (и частичное применение туда же) Из популярных по умолчанию в ядре в Haskell, Ocaml-подобных, там функции сразу такие. В остальных языках ручками. Очень сильно повышает выразительность и упрощает многие конструкции. Реальное осознание только через haskell
Homoiconicity. Свойство языков, в которых код этого языка одновременно является валидной структурой данных на этом же языке. Относится ко всем лиспам. Дает нереально крутые макросы. Плюс легкую трансформацию кода кодом. Поэтому в лиспах почти все либы, а не часть языка
Pattern Matching (+ Destructuring). Фича ФП языков, которая адаптирована многими императивными. Позволяет полностью изменить принцип работы с условными конструкциями, они становятся не нужны, а сама обработка разных условий становится и проще и понятнее
Mixin (Trait). Фича Ruby, PHP, Лиспов. Имитируется в JS. Один из лучших способ обобщать какое-то поведение и добавлять его в существующие классы. Правильная альтернатива наследованию (в том числе множественному) и абстрактным классам
Открытые классы. Smalltalk, Ruby, Python, JS (прототипы), Kotlin (частично в extension methods). Возможность поменять любой существующий класс прямо в рантайме. Значительно упрощает, например, тестирование. Снижает зависимость от IoC. Проще фиксить либы. Опасная и мегамощная фича
Message Passing. Настоящий в Smaltalk, Ruby, Python, PHP. Это не просто выбор полиморной реализации, а возможность определить общую реакцию для всех явно не определенных сообщений. Открывать путь к динамическим методам, которые нигде не определены.
В JS такое делается только через Proxy, который позволяет перехватывать любой вызов. Правда только для свойств. Для методов придется сильно извращаться и все равно получится очень тяжелое решение. Поэтому там это делают только в учебных целях.
Multimethods. Clojure и остальные лиспы (через CLOS). Киллер фича, позволяющая делать мультидиспетчеризацию (не только по типу) при создании полиморфных реализаций. Значительно сокращает количество и сложность иерархий классов. Обобщает полиморфизм.
List Comprehension. Фича почти всех ФП языков + Python, Smalltalk. Удобный механизм адаптированный прямиком из математики, для описания преобразования коллекций. Заменяет мапы/фильтры/вотевер.
Monads. Тут все просто. Монада это моноид в категории эндофункторов 😄 В целом штука, позволяющая управлять потоком выполнения и делать с ним всякое интересное. Из крутого: Maybe, Either. Порекомендуйте крутую литературу для интересующихся плс!
Generator. Есть во многих языках. Позволяют создавать бесконечные коллекции благодаря тому, что они формируются не сразу, а генерируются в процессе обхода. Часто связаны с ключевиком yield. Значительно упрощают написание итераторов
Еще можно добавить про горячую замену кода. Смолтолк и Эрланг тут чемпионы. Код на эрланге может десятилетиями работать без остановки и постоянно обновляться
Ссылки: Телеграм | Youtube | VK
Telegram
Организованное программирование | Кирилл Мокевнин
Как из джуниора дойти до мидла, а потом и до синьора
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
👍73🔥32❤26🤡4👎1👀1
Пост-знакомство
На днях канал перевалил за 7000 тысяч подписчиков, ура! В связи с этим предлагаю попробовать сделать пост знакомство, где каждый сможет рассказать про себя и попиарить свой телеграм/ютуб/вотевер. Нужны сотрудники - пишите, ищите работу - пишите. Начну с себя:
В разработке я с 2007 года. Начинал с php, потом ruby, clojure, js/ts (фронт/бек), java, erlang/elixir, python, увлечение функциональщиной (ocaml, haskell), тимлидство, управление людьми, стартапы, vim. Могу сказать что хорошо разбираюсь в бекенд фреймворках (в том числе писал свои и они в продакшене), orm, devops, тестировании, инженерной культуре за что меня приглашают в качестве консультанта или тренера в разные компании. В 2013 я присоединился к Рахиму делать Хекслет и вот уже 11 лет занимаюсь бизнесом, попутно прокачавшись в методологиях, преподавании и многих других страшных штуках. Теперь вещаю все это вам тут и на ютубе)
p.s. И исчо, у нас пока тут с вами нет чата, но я вижу желание общаться больше чем просто в постах. Поэтому предлагаю присоединиться, в наше Хекслет комьюнити, где уже 8000 человек. @hexletcommunity здесь можно поболтать и с опытными разработчиками и помочь новичкам, которые тоже тусуют в этом чате.
Ссылки: Телеграм | Youtube | VK
На днях канал перевалил за 7000 тысяч подписчиков, ура! В связи с этим предлагаю попробовать сделать пост знакомство, где каждый сможет рассказать про себя и попиарить свой телеграм/ютуб/вотевер. Нужны сотрудники - пишите, ищите работу - пишите. Начну с себя:
В разработке я с 2007 года. Начинал с php, потом ruby, clojure, js/ts (фронт/бек), java, erlang/elixir, python, увлечение функциональщиной (ocaml, haskell), тимлидство, управление людьми, стартапы, vim. Могу сказать что хорошо разбираюсь в бекенд фреймворках (в том числе писал свои и они в продакшене), orm, devops, тестировании, инженерной культуре за что меня приглашают в качестве консультанта или тренера в разные компании. В 2013 я присоединился к Рахиму делать Хекслет и вот уже 11 лет занимаюсь бизнесом, попутно прокачавшись в методологиях, преподавании и многих других страшных штуках. Теперь вещаю все это вам тут и на ютубе)
p.s. И исчо, у нас пока тут с вами нет чата, но я вижу желание общаться больше чем просто в постах. Поэтому предлагаю присоединиться, в наше Хекслет комьюнити, где уже 8000 человек. @hexletcommunity здесь можно поболтать и с опытными разработчиками и помочь новичкам, которые тоже тусуют в этом чате.
Ссылки: Телеграм | Youtube | VK
Telegram
Организованное программирование | Кирилл Мокевнин
Как из джуниора дойти до мидла, а потом и до синьора
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
❤60👍28🔥8🤔2🤮1
Долгожданный выпуск с
@VBragilevsky
где мы прошлись по системе образования http://youtube.com/watch?v=38N2c6SWnZE Показали все что скрыто изнутри и сравнили с европейским и американским
@VBragilevsky
где мы прошлись по системе образования http://youtube.com/watch?v=38N2c6SWnZE Показали все что скрыто изнутри и сравнили с европейским и американским
YouTube
Где учат лучше: в США, Европе или России? / Виталий Брагилевский #7
Всем ли программистам нужно высшее образование и чем оно отличается в разных странах? В этом видео вместе с Виталием Брагилевским (https://bravit.pro) разберём, когда высшее образование необходимо, а когда можно обойтись без него, обсудим важность математики…
👍35🔥14❤9👀1🙈1
Как понимать критичность разных кусков кода при разработке и ревью. Что от чего зависит, где можно и нужно забить, а где нет. (твиттер-тред)
Глобально и немного грубо весь прикладной код можно разделить на три уровня: Домен – то где бизнес логика + хранилища (бд), Управляющий код – то что оперирует доменом + инфраструктурный код и Представление – любые выходные данные типа binary, json, html и так далее.
Ошибки на этих уровнях имеют совсем разные последствия. Некоторые целиком влияют на архитектуру и дальнейшую поддержку всего проекта, другие же локальны и создают грязный код по месту. Важно четко разделять их, для того чтобы не создавать напряжение там где его нет
Самое простое – представление. Код формирующий вывод может быть грязным и будет грязным. Главное что нужно понимать – это неизбежно. С этим нужно смириться и не нужно пытаться доводить его до совершенства. От этого кода не зависят другие части системы, это конечная точка
Как пример код формирующий jsx в React. Если его много и он тяжелый, то его лучше разделять, но нет смысла пытаться делать его максимально компактным и красивым. Сегодня код один, завтра другой, потом вообще все поменяли и выкинули
Тоже самое касается переводов. Я знаю людей которые стремятся следить за ключами, убирают дубли, удаляют не используемые. Само по себе это неплохо, но есть черта после которой такая работа превращается в мышиную возню. Чистить можно бесконечно, но влияния на качество нет
Теперь обратная сторона – Домен. Сущности и связи между ними – буквально ключевая вещь. Абсолютно весь остальной код зависит от этого, то как вы разбиваете приложение тоже зависит от этого. Важно определить с чем мы имеем дело и какие кейсы нас ждут впереди
Например на Хекслете у урока может быть только одна практика (o2o). Почему не несколько? Если сделать несколько, то сложность системы возрастет многократно. Проще исходить из того, что если одной практики мало, то значит урок надо разбивать. Ключевое влияние на всю систему
Организация домена в свою очередь влияет на то как мы храним данные и здесь тоже все очень важно. Грязи в базе должно быть минимум. Изменения структуры, восстановление неконсистентных данных – все это очень дорого. Причем важна не только нормализация, но и денормализация
Если говорить про фронт, то аналогом будет структура состояния. Ее гораздо проще менять чем структуру базы данных, однако состояние это ключевая вещь. Нужно хорошо об этом думать и знать как, в принципе, грамотно организовывать стейт (привет автоматы). У меня аж целый курс есть
Дальше идем в инфраструктурный и управляющий код. Этого кода обычно много и он бывает очень разный. С ходу можно выделить API, то есть все что торчит наружу. Как только появляются реальные клиенты, то все, мы повязаны. Обновление API – одна из самых болезненных операций
Поэтому об API нужно думать много и до того, как код написан. При этом API так же зависит от Домена. API не обязательно HTTP, вполне возможно что вы проектируете библиотеку или какую-то подсистему
Помимо этого есть отдельная категория хорошо изолированных абстракций, типа математических или других чистых функций, интерфейс которых довольно стабилен. В таком случае качество внутренностей не важно вообще. Это фиксированный тех долг, который не влияет на систему
Простой пример – сортировка. Она может быть написана сколь угодно плохо, лишь бы работала. Переписать всегда успеем, если нас это устраивает по производительности. Кстати не могу не порекомендовать фантастический гайд https://optimization.guide/
Остальной код уже сложнее категоризировать. Здесь уже по ситуации. Если речь идет про извлечение данных, то код может быть достаточно грязным, если изменение – то требования к нему выше. Плюс важно разделение по слоям. Например применение ServiceLayer.
Все это помогает мне и при написании своего кода и при ревью. На вещи, которые мало влияют можно обращать меньше внимания, но когда речь идет про, например, Домен. Мы обязательно проговариваем это голосом. Это позволяет использовать асинхронный код ревью, то есть уже после мержа
Ссылки: Телеграм | Youtube | VK
Глобально и немного грубо весь прикладной код можно разделить на три уровня: Домен – то где бизнес логика + хранилища (бд), Управляющий код – то что оперирует доменом + инфраструктурный код и Представление – любые выходные данные типа binary, json, html и так далее.
Ошибки на этих уровнях имеют совсем разные последствия. Некоторые целиком влияют на архитектуру и дальнейшую поддержку всего проекта, другие же локальны и создают грязный код по месту. Важно четко разделять их, для того чтобы не создавать напряжение там где его нет
Самое простое – представление. Код формирующий вывод может быть грязным и будет грязным. Главное что нужно понимать – это неизбежно. С этим нужно смириться и не нужно пытаться доводить его до совершенства. От этого кода не зависят другие части системы, это конечная точка
Как пример код формирующий jsx в React. Если его много и он тяжелый, то его лучше разделять, но нет смысла пытаться делать его максимально компактным и красивым. Сегодня код один, завтра другой, потом вообще все поменяли и выкинули
Тоже самое касается переводов. Я знаю людей которые стремятся следить за ключами, убирают дубли, удаляют не используемые. Само по себе это неплохо, но есть черта после которой такая работа превращается в мышиную возню. Чистить можно бесконечно, но влияния на качество нет
Теперь обратная сторона – Домен. Сущности и связи между ними – буквально ключевая вещь. Абсолютно весь остальной код зависит от этого, то как вы разбиваете приложение тоже зависит от этого. Важно определить с чем мы имеем дело и какие кейсы нас ждут впереди
Например на Хекслете у урока может быть только одна практика (o2o). Почему не несколько? Если сделать несколько, то сложность системы возрастет многократно. Проще исходить из того, что если одной практики мало, то значит урок надо разбивать. Ключевое влияние на всю систему
Организация домена в свою очередь влияет на то как мы храним данные и здесь тоже все очень важно. Грязи в базе должно быть минимум. Изменения структуры, восстановление неконсистентных данных – все это очень дорого. Причем важна не только нормализация, но и денормализация
Если говорить про фронт, то аналогом будет структура состояния. Ее гораздо проще менять чем структуру базы данных, однако состояние это ключевая вещь. Нужно хорошо об этом думать и знать как, в принципе, грамотно организовывать стейт (привет автоматы). У меня аж целый курс есть
Дальше идем в инфраструктурный и управляющий код. Этого кода обычно много и он бывает очень разный. С ходу можно выделить API, то есть все что торчит наружу. Как только появляются реальные клиенты, то все, мы повязаны. Обновление API – одна из самых болезненных операций
Поэтому об API нужно думать много и до того, как код написан. При этом API так же зависит от Домена. API не обязательно HTTP, вполне возможно что вы проектируете библиотеку или какую-то подсистему
Помимо этого есть отдельная категория хорошо изолированных абстракций, типа математических или других чистых функций, интерфейс которых довольно стабилен. В таком случае качество внутренностей не важно вообще. Это фиксированный тех долг, который не влияет на систему
Простой пример – сортировка. Она может быть написана сколь угодно плохо, лишь бы работала. Переписать всегда успеем, если нас это устраивает по производительности. Кстати не могу не порекомендовать фантастический гайд https://optimization.guide/
Остальной код уже сложнее категоризировать. Здесь уже по ситуации. Если речь идет про извлечение данных, то код может быть достаточно грязным, если изменение – то требования к нему выше. Плюс важно разделение по слоям. Например применение ServiceLayer.
Все это помогает мне и при написании своего кода и при ревью. На вещи, которые мало влияют можно обращать меньше внимания, но когда речь идет про, например, Домен. Мы обязательно проговариваем это голосом. Это позволяет использовать асинхронный код ревью, то есть уже после мержа
Ссылки: Телеграм | Youtube | VK
optimization.guide
Продуманная оптимизация
Наконец появилась толковая бесплатная книга о серверной оптимизации на русском. Написано толково и с юмором. Рекомендую!
🔥44👍35❤12✍1🤮1👀1
Фиганул статью на хабр про монокультуру в программировании: https://habr.com/ru/articles/838682/ Где рассказываю про то, как монокультура (использование одной технологии повсеместно) мешает и вредит проектам
Ссылки: Телеграм | Youtube | VK
Ссылки: Телеграм | Youtube | VK
Хабр
Монокультура в программировании
Монокультура в программировании — это использование одного стека для решения всех возникающих задач. Она существует не только на уровне конкретного человека и его предпочтений, но также часто...
👍50🔥12👏4❤3👀1
Куда переезжать из ноушена? Спойлер: мы нашли замену
Морально мы были готовы к письму счастья, так как с 12 сентября вступал запрет на предоставление сервисов из США, но честно говоря надеялись, что они не будут вычислять по айпи и набивать. В итоге именно это они и собираются сделать независимо от того, где находится компания на которую все зарегано. Что ж, я сегодня плотно засел за сервисы, чтобы найти что-то подходящее. Я нашел таки сервис, который нас устроил, но сначала немного вводных.
https://vc.ru/u/14739-kirill-mokevnin/1429593-kuda-pereezzhat-iz-noushena-spoiler-my-nashli-zamenu
Морально мы были готовы к письму счастья, так как с 12 сентября вступал запрет на предоставление сервисов из США, но честно говоря надеялись, что они не будут вычислять по айпи и набивать. В итоге именно это они и собираются сделать независимо от того, где находится компания на которую все зарегано. Что ж, я сегодня плотно засел за сервисы, чтобы найти что-то подходящее. Я нашел таки сервис, который нас устроил, но сначала немного вводных.
https://vc.ru/u/14739-kirill-mokevnin/1429593-kuda-pereezzhat-iz-noushena-spoiler-my-nashli-zamenu
13👍47🔥6❤1👀1
Когда нужно внедрять микросервисы? Новый выпуск с кофаундером и техническим директором проекта Scentbird, который захватил американский рынок уже на канале: youtube.com/watch?v=cqKJD3ovxEc
В этом выпуске Андрей рассказывает про техническую составляющую проекта, который обслуживает сотни тысяч клиентов, предоставляя духи по подписке (и не только) по всем штатам. Какие технологии, принципы, организация, найм, совершенные ошибки. Показать все что скрыто.
В этом выпуске Андрей рассказывает про техническую составляющую проекта, который обслуживает сотни тысяч клиентов, предоставляя духи по подписке (и не только) по всем штатам. Какие технологии, принципы, организация, найм, совершенные ошибки. Показать все что скрыто.
4🔥19👍16⚡2👀1
Игры разума. Проект, который может вас затянуть!
Попробую ввести традицию пятничных постов, где я рассказываю что-то интересное, вокруг it или про it, но не код. Где-то в 2008 году, я наткнулся на сайт braingames.ru, на котором собраны всевозможные логические задачи. В то время меня от них знатно перло и я годами заходил на этот сайт и решал их. У проекта большое комьюнити и множество волонтеров помогающих с добавлением заданий, проверок решений и другими вещами, вплоть до разработки или юридического сопровождения.
Предлагаю решить одну задачку оттуда:
Мегамозг может выйти на свободу, если он справится с заданием: перед ним две двери, одна из них ведет на волю, другая — дорога к смерти. Здесь же сидят два стражника, причем один из них либо лжец, либо правдивец, а второй — хитрец, то есть человек, который говорит правду и ложь строго поочередно (либо на нечетные вопросы отвечает ложью, а на четные — правдой, либо наоборот). Оба стражника знают, какая из дорог ведет на волю, но Мегамозгу неизвестно, кто из стражников хитрец. Мегамозг имеет право задать два вопроса одному из стражников (вопросы должны быть простыми). Как ему определить дорогу, ведущую на свободу?
Источник: https://braingames.ru/?path=comments&puzzle=94
Ссылки: Телеграм | Youtube | VK
Попробую ввести традицию пятничных постов, где я рассказываю что-то интересное, вокруг it или про it, но не код. Где-то в 2008 году, я наткнулся на сайт braingames.ru, на котором собраны всевозможные логические задачи. В то время меня от них знатно перло и я годами заходил на этот сайт и решал их. У проекта большое комьюнити и множество волонтеров помогающих с добавлением заданий, проверок решений и другими вещами, вплоть до разработки или юридического сопровождения.
Предлагаю решить одну задачку оттуда:
Мегамозг может выйти на свободу, если он справится с заданием: перед ним две двери, одна из них ведет на волю, другая — дорога к смерти. Здесь же сидят два стражника, причем один из них либо лжец, либо правдивец, а второй — хитрец, то есть человек, который говорит правду и ложь строго поочередно (либо на нечетные вопросы отвечает ложью, а на четные — правдой, либо наоборот). Оба стражника знают, какая из дорог ведет на волю, но Мегамозгу неизвестно, кто из стражников хитрец. Мегамозг имеет право задать два вопроса одному из стражников (вопросы должны быть простыми). Как ему определить дорогу, ведущую на свободу?
Источник: https://braingames.ru/?path=comments&puzzle=94
Ссылки: Телеграм | Youtube | VK
braingames.ru
Логические задачи [Игры разума — Сообщество любителей головоломок]
Около 500 уникальных задач разного уровня сложности тщательно отобранных и обработанных
коллективом модераторов сайта. Основной идеей сайта является недоступность ответов до момента самостоятельного решения задачи, а также проверка ответов людьми, прошедшими…
коллективом модераторов сайта. Основной идеей сайта является недоступность ответов до момента самостоятельного решения задачи, а также проверка ответов людьми, прошедшими…
1👍33🤯9🔥7❤3
Любителям Go и им сочувствующим, крайне рекомендую канал Николая Тузова. Он ведет самый популярный русскоязычный youtube-канал посвященный Go где рассматривает все от собеседований до принципов написания кода. Вот что сам Коля говорит про него: “основная идея канала - сложные вещи простым языком. Стараюсь всегда копать максимально глубоко, но при этом максимально понятно. К примеру, если уж разбираем мапы, то спустимся вплоть до разбора их исходного кода и того, как конкретно там устроены бакеты)”
И естественно у него есть телеграм канал который мне еще предстоит обогнать!
Несколько интересных материалов:
Как на самом деле устроен тип Map в Golang?
JWT простым языком - краткий ликбез
Приятно, что студенты Хекслета доходят так далеко 🙂
И естественно у него есть телеграм канал который мне еще предстоит обогнать!
Несколько интересных материалов:
Как на самом деле устроен тип Map в Golang?
JWT простым языком - краткий ликбез
Приятно, что студенты Хекслета доходят так далеко 🙂
YouTube
Николай Тузов — Golang
Сложные вещи простым языком.
Меня зовут Николай. Я много лет занимаюсь разработкой, и много лет дружу с Go. Сейчас работаю в компании Different Technologies (мексиканский финтех), ранее работал в Lamoda и Gaijin Entertainment. Помимо Go и вообще бэкэнда…
Меня зовут Николай. Я много лет занимаюсь разработкой, и много лет дружу с Go. Сейчас работаю в компании Different Technologies (мексиканский финтех), ранее работал в Lamoda и Gaijin Entertainment. Помимо Go и вообще бэкэнда…
👍59❤19🔥13💯3❤🔥2👏1🤔1🤝1
Как значительно упростить интеграции между вашим проектом и сторонними системами (твиттер-тред)
Все что касается событий, рекламных кабинетов, crm, аналитик, слака и кучи других систем. Вы используете сервисы типа Zapier?
Сначала про задачу. В любом SaaS сервисе, помимо самого продукта и его фич, есть много всего вокруг. CRM для продаж, система сквозной аналитики, рекламные кабинеты, событийная анилитка, автоматизация маркетинга (email, боты), виджеты на сайте и так далее. Тонны систем
И все они работают в связке. Когда на сайте оставляют заявку, она должна попасть в CRM продавцам, должна попасть в рекламный кабинет и систему сквозной аналитики для анализа эффективности, а еще нужна нотификация в слак и тикет на работу с клиентов после того как сделка закрылась
Мы получаем взаимодействие не просто точка-точка, а целый пайплайн, в котором задействованы по 3-5, сервисов. Иногда взаимодействие идет без самого сервиса. Иногда наш сервис должен как генерировать события, так и уметь обрабатывать ответы от других систем
И, реклама, это всего лишь один из примеров. Нам так же нужно строить онбординг, а для этого есть свои сервисы, нужно запускать ботов, нужно выполнять продуктовую аналитику, нужно рассылать письма по событиям (и даже целые цепочки писем). Для всего этого есть свои решения
На вскидку то что мы используем чтобы было понятнее. Некоторые из них супер, другие не очень, но без них мы бы порвались: http://activecampaign.com, http://amplitude.com, http://rick.ai, http://trengo.com, http://sparkpost.com и т.п.
Во всех сервисах есть интеграции, но они не покрывают все. Всегда есть сервисы между которыми нет прямой связи. Плюс есть сайт, с которым нет связи вообще ни у кого если мы ее не сделаем сами. Как в таком случае строится логика работы?
Самый деревянный вариант – на каждое событие, например, регистрацию, делать в коде обработчик, который отправляет событие в нужную систему. Потом оказывается что регистрация нужна в 5 разных местах, поэтому обработчик резко вырастает в размерах. А событий надо много и везде
Вот тут все превращается в ад. В коде приходится прописывать абсолютно каждый сервис. Например появилась новая аналитика, которой нужно 5 событий. Нам придется пойти и в 5 местах на сайте добавить вызов api этого сервиса. И это в лучшем случае, если отправка событий изолирована
Достаточно давно появился сервис, который захватил эту нишу: Zapier. Он позволяет соединять между собой все что имеет апи. Это визуальный конструктор, в котором мы указываем откуда и какие взять данные и куда их отправить, причем выполнив нужные преобразования. Он сразу включает в себя интеграцию со всеми популярными сервисами, поэтому здесь не нужно программирование. Мы просто говорим чего хотим от одной системы и куда это надо послать.
Zapier вводит два понятия: действие и триггер. Триггер это событие, которое происходит внутри какого-то сервиса. Чтобы Zapier мог его получить, нужно внутри сервиса настроить отправку события на вебхук запира. Большая часть сервисов так делает из коробки
А действие это вызов апи какого-то сервиса, в которое мы хотим из запира отправить данные. Например заполнить таблицу в гугл доках, создать мессадж в слаке или отправить письмо.
То есть так мы интегрируем сервисы между собой. А как же события нашего проекта? Очень просто, внутри запира создаются эндпоинты для разных событий и дальше, наш сайт отправляет события вместе с данными именно на эти эндпоинты. Сайт знает только про запир
Теперь, если нам нужно отправлять событие регистрации в какую-то новую систему, мы просто идем в запир и делаем связку "регистрация" => "создание клиента в pipedrive" (как пример). Сайт не трогаем, нет деплоя, даже программистов нет. Это могут делать аналитики/маркетологи
Запир оч дорогой инструмент + он не работает в рф, поэтому часть задач мы решаем с помощью сервисов типа интегромата, но большая часть наших интеграций проходит через n8n.io, который имеет self-hosted версию (и вообще это open source). Если вы еще его не юзаете, то крайне рекомедную
Ссылки: Телеграм | Youtube | VK
Все что касается событий, рекламных кабинетов, crm, аналитик, слака и кучи других систем. Вы используете сервисы типа Zapier?
Сначала про задачу. В любом SaaS сервисе, помимо самого продукта и его фич, есть много всего вокруг. CRM для продаж, система сквозной аналитики, рекламные кабинеты, событийная анилитка, автоматизация маркетинга (email, боты), виджеты на сайте и так далее. Тонны систем
И все они работают в связке. Когда на сайте оставляют заявку, она должна попасть в CRM продавцам, должна попасть в рекламный кабинет и систему сквозной аналитики для анализа эффективности, а еще нужна нотификация в слак и тикет на работу с клиентов после того как сделка закрылась
Мы получаем взаимодействие не просто точка-точка, а целый пайплайн, в котором задействованы по 3-5, сервисов. Иногда взаимодействие идет без самого сервиса. Иногда наш сервис должен как генерировать события, так и уметь обрабатывать ответы от других систем
И, реклама, это всего лишь один из примеров. Нам так же нужно строить онбординг, а для этого есть свои сервисы, нужно запускать ботов, нужно выполнять продуктовую аналитику, нужно рассылать письма по событиям (и даже целые цепочки писем). Для всего этого есть свои решения
На вскидку то что мы используем чтобы было понятнее. Некоторые из них супер, другие не очень, но без них мы бы порвались: http://activecampaign.com, http://amplitude.com, http://rick.ai, http://trengo.com, http://sparkpost.com и т.п.
Во всех сервисах есть интеграции, но они не покрывают все. Всегда есть сервисы между которыми нет прямой связи. Плюс есть сайт, с которым нет связи вообще ни у кого если мы ее не сделаем сами. Как в таком случае строится логика работы?
Самый деревянный вариант – на каждое событие, например, регистрацию, делать в коде обработчик, который отправляет событие в нужную систему. Потом оказывается что регистрация нужна в 5 разных местах, поэтому обработчик резко вырастает в размерах. А событий надо много и везде
Вот тут все превращается в ад. В коде приходится прописывать абсолютно каждый сервис. Например появилась новая аналитика, которой нужно 5 событий. Нам придется пойти и в 5 местах на сайте добавить вызов api этого сервиса. И это в лучшем случае, если отправка событий изолирована
Достаточно давно появился сервис, который захватил эту нишу: Zapier. Он позволяет соединять между собой все что имеет апи. Это визуальный конструктор, в котором мы указываем откуда и какие взять данные и куда их отправить, причем выполнив нужные преобразования. Он сразу включает в себя интеграцию со всеми популярными сервисами, поэтому здесь не нужно программирование. Мы просто говорим чего хотим от одной системы и куда это надо послать.
Zapier вводит два понятия: действие и триггер. Триггер это событие, которое происходит внутри какого-то сервиса. Чтобы Zapier мог его получить, нужно внутри сервиса настроить отправку события на вебхук запира. Большая часть сервисов так делает из коробки
А действие это вызов апи какого-то сервиса, в которое мы хотим из запира отправить данные. Например заполнить таблицу в гугл доках, создать мессадж в слаке или отправить письмо.
То есть так мы интегрируем сервисы между собой. А как же события нашего проекта? Очень просто, внутри запира создаются эндпоинты для разных событий и дальше, наш сайт отправляет события вместе с данными именно на эти эндпоинты. Сайт знает только про запир
Теперь, если нам нужно отправлять событие регистрации в какую-то новую систему, мы просто идем в запир и делаем связку "регистрация" => "создание клиента в pipedrive" (как пример). Сайт не трогаем, нет деплоя, даже программистов нет. Это могут делать аналитики/маркетологи
Запир оч дорогой инструмент + он не работает в рф, поэтому часть задач мы решаем с помощью сервисов типа интегромата, но большая часть наших интеграций проходит через n8n.io, который имеет self-hosted версию (и вообще это open source). Если вы еще его не юзаете, то крайне рекомедную
Ссылки: Телеграм | Youtube | VK
2👍43🔥16🤔2
На ютубе вышло душевное видео с моим старым другом Антоном Плешивцевым, который прошел длинный путь от одного из первых разработчиков Aviasales в тайланде (у них там офис) до технического директора создавшему 8 лет назад с нуля проект Bravado на американском рынке, крупнейшему маркетплейсу продавцов.
Поговорили мы обо всем чем только можно. О том как изменился фронтенд за 14 лет, истории из тайской жизни, организация удаленной работы, создание собственной игры и попадание в Stream, рекрутинг в сша, преимущества go и куче других тем. Наслаждайтесь 🙂 https://www.youtube.com/watch?v=qhbXHlgE6Yo
Поговорили мы обо всем чем только можно. О том как изменился фронтенд за 14 лет, истории из тайской жизни, организация удаленной работы, создание собственной игры и попадание в Stream, рекрутинг в сша, преимущества go и куче других тем. Наслаждайтесь 🙂 https://www.youtube.com/watch?v=qhbXHlgE6Yo
YouTube
(Без)облачная жизнь и работа на Aviasales в Таиланде / Антон Плешивцев / #9
Помните период, когда во всех рекламах с ИТ были пальмы, пляж и преимущества удалённой работы? В этом выпуске обсуждаем, так ли классно работать в Таиланде, изменения в мире фронтенда, вспоминая о старых технологиях и появлении Angular.
В этом мне поможет…
В этом мне поможет…
2🔥35👍23❤6👻1
Что вы предпочитаете: обычные утверждения (asserts) или матчеры? Сначала немного терминов. Утверждения это когда мы пишем
Утверждения часто встроены прямо в сам язык и обычно их немного, буквально 3-5. Больше могут добавлять тестовые фреймворки, но без фанатизма. Их легко запомнить и легко пользоваться, но, как правило, они не информативны: "ожидали тру, пришло фолс", "ожидали 5 пришло 3"
С матчерами ситуация отличается. Обычно их много или очень много. Только базовых внутри тестовых фреймворках много десятков, плюс модификаторы, плюс экстеншены. Короче сотня другая легко. Использовать их уже целое искусство, за этим нужно следить и постоянно корректировать коллег
А в чем плюсы? Если вам нужна документация из тестов, то матчеры сделают ее понятнее. Обычно (но не всегда) вывод матчеров содержит больше полезной информации для отладки, что упрощает само тестирование. Ну и во многих языках тестовые фреймворки с матчерами являются стандартом
Есть еще всякие особые истории типа property-based тестирования или снепшот или скриншот тестирования, но это здесь мы про них не говорим. Больше вам на заметку, если не знаете про них, то обязательно почитайте.
В принципе на этом можно было бы и закончить, если бы не одна статья, которая в 2009 году значительно повлияла на проверки в тестах. Эта статья про Power Assert в Groovy https://dontmindthelanguage.wordpress.com/2009/12/11/groovy-1-7-power-assert/… Спойлер: лучшее от обоих миров: утверждений и матчеров с добавлением магии
Концепция такая, у нас есть ровно одно утверждение, внутри которого мы делаем любую проверку. Это утверждение, анализирует результат *каждого* подвыражения и выводит его для отладки. Так мы получаем максимум информации о том что пошло не так. Ниже реальный вывод
Концепция оказалась настолько удачной и удобной, что либу Power Assert портировали практически в каждый язык. Лучше всего пожалуй описано в JS, там в начале ридми есть хороший блок, с объяснением почему именно этот подход: https://github.com/power-assert-js/power-assert#description
Кто-нибудь уже использовал Power Assert? Или вы не знали про него?
Ссылки: Телеграм | Youtube | VK
p.s. Скиньте в комментариях порт power assert или аналогичную либу из вашего языка/экосистемы
assert lala.isJopa()
или assert_equal lala, "jopa"
. Матчеры это expect(lala.isJopa()).isTrue()
expect(lala).toBe("jopa")
. В чем реальная разница между этими подходами и есть ли другие варианты?Утверждения часто встроены прямо в сам язык и обычно их немного, буквально 3-5. Больше могут добавлять тестовые фреймворки, но без фанатизма. Их легко запомнить и легко пользоваться, но, как правило, они не информативны: "ожидали тру, пришло фолс", "ожидали 5 пришло 3"
С матчерами ситуация отличается. Обычно их много или очень много. Только базовых внутри тестовых фреймворках много десятков, плюс модификаторы, плюс экстеншены. Короче сотня другая легко. Использовать их уже целое искусство, за этим нужно следить и постоянно корректировать коллег
А в чем плюсы? Если вам нужна документация из тестов, то матчеры сделают ее понятнее. Обычно (но не всегда) вывод матчеров содержит больше полезной информации для отладки, что упрощает само тестирование. Ну и во многих языках тестовые фреймворки с матчерами являются стандартом
Есть еще всякие особые истории типа property-based тестирования или снепшот или скриншот тестирования, но это здесь мы про них не говорим. Больше вам на заметку, если не знаете про них, то обязательно почитайте.
В принципе на этом можно было бы и закончить, если бы не одна статья, которая в 2009 году значительно повлияла на проверки в тестах. Эта статья про Power Assert в Groovy https://dontmindthelanguage.wordpress.com/2009/12/11/groovy-1-7-power-assert/… Спойлер: лучшее от обоих миров: утверждений и матчеров с добавлением магии
Концепция такая, у нас есть ровно одно утверждение, внутри которого мы делаем любую проверку. Это утверждение, анализирует результат *каждого* подвыражения и выводит его для отладки. Так мы получаем максимум информации о том что пошло не так. Ниже реальный вывод
assert(types[index].name === bob.name)
| || | | | |
| || | | | "bob"
| || | | Person{name:"bob",age:5}
| || | false
| |11 "alice"
| Person{name:"alice",age:3}
["string",98.6,true,false,null,undefined,#Array#,#Object#,NaN,Infinity,/^not/,#Person#]
--- [string] bob.name
+++ [string] types[index].name
@@ -1,3 +1,5 @@
-bob
+alice
Концепция оказалась настолько удачной и удобной, что либу Power Assert портировали практически в каждый язык. Лучше всего пожалуй описано в JS, там в начале ридми есть хороший блок, с объяснением почему именно этот подход: https://github.com/power-assert-js/power-assert#description
Кто-нибудь уже использовал Power Assert? Или вы не знали про него?
Ссылки: Телеграм | Youtube | VK
p.s. Скиньте в комментариях порт power assert или аналогичную либу из вашего языка/экосистемы
Don't mind the language
Groovy 1.7 Power Assert
I already mentioned this in my previous post, but I wanted to go a little bit deeper on this: the new Groovy Power Assert (and no, let’s not call is GPA). Groovy Power Assert makes assertions…
👍38❤12🔥5🥴2🐳1