child_process
В ноде есть 4 способа запуска дочернего процесса:
#w_corner_nodejs
В ноде есть 4 способа запуска дочернего процесса:
child_process.spawn - начинает асинхронно отдтавать данные сразу, как запустится процесс. Его выгодно использовать при работе с большими объемами данных, например, с огромными файлами или выводом результатов утилит вроде curl. Данные получаем при помощи event-listener'а(.on('data', () => {...}))..exec - ждёт от процесса сигнала завершения и получаем набор данных от него целиком, хорошо подходит, чтобы получить какой-то не большой текст, например код статуса, данные возвращает в callback. При попытке работать с большим потоком вывода по-умолчанию нода вернёт ошибку..execFile - как exec, но напрямую запускает исполняемый файл, без оболочки..fork - как spawn, но позволяет обмениваться сообщениями с дочерними процессами через функции send/on.#w_corner_nodejs
keyof в поисках типаЖили были функции без типов. Среди них были такие,
как
prop, возвращающие поля из объекта.
const prop = (obj, key) => obj[key]
Когда наступило время раздора и хаоса и пришли типы, неопытные программисты часто ошибались в том, как организовать верный вывод типов таких функций, но для любого поля результат был
any. (и жили они без noImplicitAny)
const prop = (obj: {}, key: any) => obj[key]
const example = { meow: 'meow' }
prop(example, 'meow') // type: any
"Как так!", — восклицали они, — "Ведь мы видели, что по ключам всегда получаем тип!"
И были правы. В TypeScript существует поиск типов (
Lookup Types) , который и позволяет получить связанный с ключем тип.Тогда к ним пришел важный тип и дал новое магическое слово -
keyof.Оно давало особую способность проникать в публичные имена ключей типов и создавать литеральный объединенный тип (
Union).*
const example = { meow: 'meow', murr: 'murr' }
type CatSays = keyof typeof example // "meow" | "murr"
Благодоря знанию о
keyof и Lookup Types они быстро сообразили, как затипизировать их функцию prop:
const prop<T, K extends keyof T>(obj: T, key: K) => obj[key]
Теперь они смогут спокойно жить и припевать в типобезопасном мире, типизируя любые функции, которые как-то получают только нужные поля объекта!
—
* с помощью
keyof можно получить все публичные не статические ключи пренадлежащие именно типу, потому в примере мы вынужденны получать запросом типа typeof.#w_corner_ts
TSLint to ESLint
TSLint обещает скоро уже стать deprecated. И уже пора бы переносить все проекты с ним на новые рельсы. Очевидно, что единсвенный выбор сейчас - ESLint. Ну и куда же в современном проекте без Prettier'а. Пройдемся немного по шагам, которые сделал я для подобного переноса.
1. Во первых, не хотелось переформатировать проект, потому я сразу пошел искать тулзу, которая мне переконвертирует все мои правила из TSLint, и супер, что такая уже есть - tslint-to-eslint-config.
Запускаем
3. Перименуем
4. Обновим поле
6. PROFIT! Можно удалять tslint и избавляться от правил из
Некоторые мои проекты хранятся в монорепо, тч для нормальной работы
Также
P.S. Все же с
#w_corner_ts
TSLint обещает скоро уже стать deprecated. И уже пора бы переносить все проекты с ним на новые рельсы. Очевидно, что единсвенный выбор сейчас - ESLint. Ну и куда же в современном проекте без Prettier'а. Пройдемся немного по шагам, которые сделал я для подобного переноса.
1. Во первых, не хотелось переформатировать проект, потому я сразу пошел искать тулзу, которая мне переконвертирует все мои правила из TSLint, и супер, что такая уже есть - tslint-to-eslint-config.
Запускаем
npx tslint-to-eslint-config
2. Тулза оказалась достаточно не плохой. Но все нужные пакеты для использования ESLint она сама не поставила :(. Поставим сами, за одно добавим Prettier. (хотя и создатель сказал не использовать, но я продлжаю выбирать yarn в качестве своего менеджера зависимостей, как минимум тк я подсел на workspaces)yarn add eslint eslint-config-prettier eslint-plugin-prettier prettier @typenoscript-eslint/parser @typenoscript-eslint/eslint-plugin @typenoscript-eslint/eslint-plugin-tslint -D
3. Перименуем
eslintrc.js в .eslintrc.js, либо придётся добавить флаг в скрипте -c eslintrc.js.4. Обновим поле
noscripts в package.json."lint": "eslint --ignore-path .gitignore --ext .js,.jsx,.ts,.tsx"
5. Добавим Prettier. Сперва в массив plugins - plugins: [..., 'prettier'], затем в rules - rules: { 'prettier/prettier': 'error', ... }
6. Почему-то tslint-to-eslint-config генерирует несколько не сущесвующих правил в плагине @typenoscript-eslint/eslint-plugin, тч после первого запуска lint'a вам придется их подтереть или поискать альтернативы.6. PROFIT! Можно удалять tslint и избавляться от правил из
@typenoscript-eslint/tslint плагина.Некоторые мои проекты хранятся в монорепо, тч для нормальной работы
ESLint потребовалась небольшая докрутка: parserOptions.project в .eslintrc.js поддерживает также массив, тч потребовалось внести каждое приложение, содержащее tsconfig.json отдельно.Также
vscode сразу не хотел обрабатывать нужные конфиги, не беда, в issue к плагину vscode-eslint предложили рабочее решение.P.S. Все же с
tslint-to-eslint-config некоторые правила останутся не перенесеными, тч смотрим также созланный тулзой файл tslint-to-eslint-config.log.#w_corner_ts
GitHub
GitHub - palantir/tslint: :vertical_traffic_light: An extensible linter for the TypeScript language
:vertical_traffic_light: An extensible linter for the TypeScript language - palantir/tslint
Второй подход к снаряду поиска типов
Сколько же решений по типизации экшенов выдает Stackoverflow, вплоть до пакетов с тремя звездочками на Github и каждый способ не лишен изъянов.
Возьмем например довольно очевидный способ создания экшена "в лоб":
И по общей договоренности с командой мы решили, что тип поля
И так, приступим исправлять типизацию.
Что же для нас такое этот
Это функция, принимающая
Чтобы это сделать мы воспользуемся таким вот хитрым хелпером, который позволит доказать, что тип действительно строка (если у вас есть идеи как это сделать проще - велком в личку).
Итоговый
P.S. В примерах не исключены ошибки ☺️
Всех с наступающим!🎄
#w_corner_ts
Сколько же решений по типизации экшенов выдает Stackoverflow, вплоть до пакетов с тремя звездочками на Github и каждый способ не лишен изъянов.
Возьмем например довольно очевидный способ создания экшена "в лоб":
interface Action<T, P> {
readonly type: T;
readonly payload?: P;
}
const createAction = <T extends string, P>(type: T) => (payload: P): Action<T, P> => {
return { type, payload };
}
В таком случае от нас TS будет требовать пробрасывать вторым аргументом в дженерик payload, что нам не всегда нужно (тк нельзя в дженерик с двумя аргументами передавать только один, ну и если попробуем от этого избавиться, то все равно в конце концов мы теряем тип от type).И по общей договоренности с командой мы решили, что тип поля
type обязательно должен быть строкой.И так, приступим исправлять типизацию.
Что же для нас такое этот
createAction в итоге. Это функция, принимающая
type и payload и возвращающая объект с этими двумя полями, а главное сохраняющая типы.const createAction = (type) => (payload) => ({
type,
payload,
})
И первый тип, с которым надо нам надо разобраться - это тип Action, содержащий payload, type и более базовый тип - ReduxAction (для него достаточно поля type)interface ReduxAction<T extends string> {
type: T
}
export interface Action<Type extends string, Payload = void> extends ReduxAction<Type> {
payload?: Payload
}
Тут все довольно просто. Обернем в это createAction.const createAction = <T extends string, P>(type: T) => (payload?: P): Action<T, P> => ({
type,
payload,
})
Чтож, мы пришли примерно к тому же, что и было в примере с SO. Только payload вне зависимости от экшена не обязательный, а типы этого поля так и не выводятся. Добавим магии lookup types и посмотрим, что у нас получится.export const createAction = <A extends Action<A['type'], A['payload']>>(type: A['type']) => (payload: A['payload']) => ({
type,
payload,
})
Теперь у нас выводится типы тайпсрипта по типу экшена. Так мы не можем доказать тайпчекеру, что тип у A['type'] - строка, и это не сработает (пример). Впрочем, мы и не пытались.Чтобы это сделать мы воспользуемся таким вот хитрым хелпером, который позволит доказать, что тип действительно строка (если у вас есть идеи как это сделать проще - велком в личку).
type StingTypeField = {
type: string
}
type LookupStringTypeField<T, K> = K extends keyof T ? (T extends StingTypeField ? T[K] : never) : never
В LookupStringTypeField мы говорим, что поле в объекте точно есть поле K и оно точно строка, а иначе и не может быть (never).Итоговый
createAction:const createAction = <A extends Action<LookupStringTypeField<A, 'type'>, A['payload']>>(type: A['type']) => (payload: A['payload']) => ({
type,
payload,
})
И конечно ссылка с примером.P.S. В примерах не исключены ошибки ☺️
Всех с наступающим!🎄
#w_corner_ts
www.typenoscriptlang.org
TS Playground - An online editor for exploring TypeScript and JavaScript
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
Небольшой пост по безопасности на фронтенде, куда вообще смотреть? Заметил, что мало кто в этой теме разбирается даже на базовом уровне, а тема важная.
Основные вопросы:
Виды атак, какой вектор, какая цель?
XSS, CSRF, clickjacking.
Как защититься?
CORS + SOP, CSP, Cookie: secure, httpOnly, SameSite
https://application.security/free-application-security-training - в интерактивном режиме показывается как можно произвести атаку и как от нее защититься
https://developer.mozilla.org/ru/docs/Web/HTTP/CORS
https://developer.mozilla.org/ru/docs/Web/HTTP/CSP
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
https://developer.mozilla.org/ru/docs/Web/HTTP/Cookies#secure_(%D0%B1%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D1%8B%D0%B5)_%D0%B8_httponly_cookies
https://habr.com/ru/post/340146/ - про то, как работает JWT
#w_corner_secure
Основные вопросы:
Виды атак, какой вектор, какая цель?
XSS, CSRF, clickjacking.
Как защититься?
CORS + SOP, CSP, Cookie: secure, httpOnly, SameSite
https://application.security/free-application-security-training - в интерактивном режиме показывается как можно произвести атаку и как от нее защититься
https://developer.mozilla.org/ru/docs/Web/HTTP/CORS
https://developer.mozilla.org/ru/docs/Web/HTTP/CSP
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
https://developer.mozilla.org/ru/docs/Web/HTTP/Cookies#secure_(%D0%B1%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D1%8B%D0%B5)_%D0%B8_httponly_cookies
https://habr.com/ru/post/340146/ - про то, как работает JWT
#w_corner_secure
Kontra
Application Security Training For Developers | Kontra
Kontra is an Application Security Training platform built for modern development teams.
MSW
Часто вам приходилось разрабатывать интерфейс без готовой ручки на бэкенде? Все эти временные данные на уровне стора или Promise.resolve с данными на уровне сервисов/sdk и прочие подходы, обеспечивающие нам одни и теже данные. А писать e2e тесты, когда чтобы замокать результат запросов всегда приходилось придумывать свои велосипеды (да-да, е2е с фейковыми данными запросами ужас и моветон - мы всегда поднимаем весь стек и ждём, что нигде ничего не отвалится и нашей машинке хватит сил).
Хватит. Почти всегда для того, чтобы подсунуть фэйковые данные на уровне сети я выбирал nock, но время идёт, индустрия движется, а подход к моку сервера в тестах остаётся прежним. Только не с Mock Service Worker и вот вам несколько причин перейти на него:
1. Простая установка
2. Возможность запускать одни и те же обработчики и для серверных (например,в случае с SSR) и для клиентских тестов из коробки
3. Возможность делать более умные обработчики на этапе жизни «без нужной бэкендовой ручки», а затем переиспользовать их в тестах
4. Поддержка rest и grqphql
5. Максимально прозрачное поведение и простота отладки
6. Ваши обработчики похожи на реальные express мидлвары
Ставим пакет, запускаем
#w_corner_testing
Часто вам приходилось разрабатывать интерфейс без готовой ручки на бэкенде? Все эти временные данные на уровне стора или Promise.resolve с данными на уровне сервисов/sdk и прочие подходы, обеспечивающие нам одни и теже данные. А писать e2e тесты, когда чтобы замокать результат запросов всегда приходилось придумывать свои велосипеды (да-да, е2е с фейковыми данными запросами ужас и моветон - мы всегда поднимаем весь стек и ждём, что нигде ничего не отвалится и нашей машинке хватит сил).
Хватит. Почти всегда для того, чтобы подсунуть фэйковые данные на уровне сети я выбирал nock, но время идёт, индустрия движется, а подход к моку сервера в тестах остаётся прежним. Только не с Mock Service Worker и вот вам несколько причин перейти на него:
1. Простая установка
2. Возможность запускать одни и те же обработчики и для серверных (например,в случае с SSR) и для клиентских тестов из коробки
3. Возможность делать более умные обработчики на этапе жизни «без нужной бэкендовой ручки», а затем переиспользовать их в тестах
4. Поддержка rest и grqphql
5. Максимально прозрачное поведение и простота отладки
6. Ваши обработчики похожи на реальные express мидлвары
Ставим пакет, запускаем
npx msw init public/ --save и вперед. Не забываем читать доку, и экспериментировать, думаю, обязательно найдете больше юзкейсов для себя.#w_corner_testing
mswjs.io
Quick start
Get MSW up and running in under five minutes.
Да будет Typenoscript
С этого поста хочу начать последовательный цикл дипдайва в тайпскрипт, в самом широком смысле: от причин использования, простейших типов и их юзкейсов, до устройства системы типов, транспилятора, точек его расширения и всего вокруг этого чудесного инструмента.
Начнем с самого начала: с базовых типов, из которых выводится все остальное.
То, что TypeScript является типизированной надстройкой над JavaScript, от которой после компиляции не остаётся и следа, означает, что первый перенял от второго всю его идеологию. Одним из таких моментов является разделение типов данных на типы значения (примитивные) и ссылочные типы.
Корнем всей иерархии типов можно считать unknown, который является типобезопасным аналогом any. Все типы совместимы с типом unknown, в, то время как сам тип unknown совместим только с самим собой и типом any.
Произвольный тип any — с него для многих и начнется знакомство с системой типов TypeScript.
Далее идут простые примитивные типы, имеющие свои аналоги в JavaScript: number, string, boolean, bigint, symbol. Важно понимать, что типы, идентификаторы которых начинаются с прописной буквы представляют объектные типы (ссылочные типы) описывающие одноимённые типы из JavaScript (Number, String, Boolean и т.д.). В Typenoscript их можно расширить (через extends) и реализовать (через implements).
В отдельную категорию можно вынести примитивные типы null, undefined, void, never, считая их в некотором роде «типами отсутствия».
Enum - перечисление также считается примитивным типом.
Для каждого из этих типов есть литеральный подтип, которые, как можно понять из названия, представляют литералы обычных примитивных типов.
#w_corner_ts
С этого поста хочу начать последовательный цикл дипдайва в тайпскрипт, в самом широком смысле: от причин использования, простейших типов и их юзкейсов, до устройства системы типов, транспилятора, точек его расширения и всего вокруг этого чудесного инструмента.
Начнем с самого начала: с базовых типов, из которых выводится все остальное.
То, что TypeScript является типизированной надстройкой над JavaScript, от которой после компиляции не остаётся и следа, означает, что первый перенял от второго всю его идеологию. Одним из таких моментов является разделение типов данных на типы значения (примитивные) и ссылочные типы.
Корнем всей иерархии типов можно считать unknown, который является типобезопасным аналогом any. Все типы совместимы с типом unknown, в, то время как сам тип unknown совместим только с самим собой и типом any.
Произвольный тип any — с него для многих и начнется знакомство с системой типов TypeScript.
Далее идут простые примитивные типы, имеющие свои аналоги в JavaScript: number, string, boolean, bigint, symbol. Важно понимать, что типы, идентификаторы которых начинаются с прописной буквы представляют объектные типы (ссылочные типы) описывающие одноимённые типы из JavaScript (Number, String, Boolean и т.д.). В Typenoscript их можно расширить (через extends) и реализовать (через implements).
В отдельную категорию можно вынести примитивные типы null, undefined, void, never, считая их в некотором роде «типами отсутствия».
Enum - перечисление также считается примитивным типом.
Для каждого из этих типов есть литеральный подтип, которые, как можно понять из названия, представляют литералы обычных примитивных типов.
#w_corner_ts
React Testing Library и Enzyme
Все больше и больше проектов уходят с Enzyme и переходят на RTL. Про это сейчас пишут статьи, делают доклады и даже оффициальная дока Recat рекомендует React Testing Library. Чем же так не угодил Enzyme и почему от него стоит отказаться.
1. Он завязан на кишки React, а значит очередное обновление ломает обратную совместимость и требует обновление Enzyme (а также вероятно написанных тестов)
2. Enzyme родился в Airbnb, но сейчас фактически поддерживается одним человеком.
3. Enzyme периодически вынуждает тестировать реализацию как «белый ящик», что также делает тесты более хрупкими.
Как начать писать тесты с RTL? Лично я рекомендую для старта почитать документацию, посмотреть мой доклад и этот плейлист. Для более заинтересованных в тестах также не могу оставить без внимания интенсив Hexlet по тестированию фронтенда.
#w_corner_testing
Все больше и больше проектов уходят с Enzyme и переходят на RTL. Про это сейчас пишут статьи, делают доклады и даже оффициальная дока Recat рекомендует React Testing Library. Чем же так не угодил Enzyme и почему от него стоит отказаться.
1. Он завязан на кишки React, а значит очередное обновление ломает обратную совместимость и требует обновление Enzyme (а также вероятно написанных тестов)
2. Enzyme родился в Airbnb, но сейчас фактически поддерживается одним человеком.
3. Enzyme периодически вынуждает тестировать реализацию как «белый ящик», что также делает тесты более хрупкими.
Как начать писать тесты с RTL? Лично я рекомендую для старта почитать документацию, посмотреть мой доклад и этот плейлист. Для более заинтересованных в тестах также не могу оставить без внимания интенсив Hexlet по тестированию фронтенда.
#w_corner_testing
piotrstaniow.pl
Time to say goodbye - Enzyme.js
The world has already moved - to React Testing Library
Заметки
идеальная система не та, в которую уже нечего добавить, а та, из которой уже нечего убрать
За последние лет 8 я попробовал минимум 30 приложений для ведения заметок, дел, чеклистов, WTR, финансов и прочих потоков информации, которые хочу структурировать.
А хотелось структурировать все. GTD для всех дел. Цеттелькастен для всех заметок. Выжать максимум из приложений для финансов. Еженедельная очистка want to read инбокса.
Косу нужно было идеально заточить, чтобы косить.
В результате вместо того, чтобы выполнять задуманную работу, куча времени уходило на поиск и освоение очередного разухабистого инструмента для GTD, обвес и настройка плагинами Obsidian’а, докрутка базы знаний в Notion. В конце концов полное отчаяние от того, что в итоге снова получилось слишком сложно.
Тогда я решил зайти с противоположного конца. Завел просто файлик в облаке.
В него писал короткий список с перечислением проектов, над которыми я фокусируюсь в текущую неделю. Сразу под этим списком вписывал все дни недели, а каждый вечер писал список из нескольких пунктов под следующим днем. Тоже самое сделал с финансами.
Через несколько недель такого упрощения я понял, какие именно элементы в моей системе продуктивности были лишние, избавился от них и смог вернуться в Things3.
Так же поступил с моим Obsidian. Создал новый сейф, избавился от всех лишних плагинов и сложных структур в заметках, оставил только самое необходимое.
В итоге пришло осознание, что для Zettelkasten'а достаточно папки с текстовыми файлами, куда я записываю сформировавшиеся мысли и иногда перечитываю их.
Для написания больших текстов вернулся к org-моду emacs.
Итогом пусть будет мысль, что практика - хорошо, а паралич выбора и FOMO - плохо. Надеюсь этот виток ведения дел окажется более удачным.
идеальная система не та, в которую уже нечего добавить, а та, из которой уже нечего убрать
За последние лет 8 я попробовал минимум 30 приложений для ведения заметок, дел, чеклистов, WTR, финансов и прочих потоков информации, которые хочу структурировать.
А хотелось структурировать все. GTD для всех дел. Цеттелькастен для всех заметок. Выжать максимум из приложений для финансов. Еженедельная очистка want to read инбокса.
Косу нужно было идеально заточить, чтобы косить.
В результате вместо того, чтобы выполнять задуманную работу, куча времени уходило на поиск и освоение очередного разухабистого инструмента для GTD, обвес и настройка плагинами Obsidian’а, докрутка базы знаний в Notion. В конце концов полное отчаяние от того, что в итоге снова получилось слишком сложно.
Тогда я решил зайти с противоположного конца. Завел просто файлик в облаке.
В него писал короткий список с перечислением проектов, над которыми я фокусируюсь в текущую неделю. Сразу под этим списком вписывал все дни недели, а каждый вечер писал список из нескольких пунктов под следующим днем. Тоже самое сделал с финансами.
Через несколько недель такого упрощения я понял, какие именно элементы в моей системе продуктивности были лишние, избавился от них и смог вернуться в Things3.
Так же поступил с моим Obsidian. Создал новый сейф, избавился от всех лишних плагинов и сложных структур в заметках, оставил только самое необходимое.
В итоге пришло осознание, что для Zettelkasten'а достаточно папки с текстовыми файлами, куда я записываю сформировавшиеся мысли и иногда перечитываю их.
Для написания больших текстов вернулся к org-моду emacs.
Итогом пусть будет мысль, что практика - хорошо, а паралич выбора и FOMO - плохо. Надеюсь этот виток ведения дел окажется более удачным.
🔥3❤🔥1
Type Programming
В мире Тайпскрипта большое внимание уделяется системе типов.
Типами мы пытаемся описать предметную область: заказы, магазин, пользователь, корзина.
Это достигается простейшим описанием объектного типа или интерфейса. Куда реже мы переопределяем стандартные типы, вроде чисел и превращаем их в брендированные типы - другой мощный механизм, ставший возможным благодаря широким возможностям системы типов.
Как правило на этих возможностях использование системы типов и заканчивается. В прикладном коде мы стараемся не описывать сложное взаимодействие бизнес сущностей через систему типов. Цена этого довольно велика, а выхлоп туманный.
Другая сторона медали - системный код: библиотеки, вспомогательные утилиты, абстрагирующие от сложной системы функции, методы и классы. Хороший слой абстракции должен максимально отдалять пользователей наших системных модулей от деталей реализации. У них не должно возникать желания заглянуть за кулисы и расширить под свои требования переписывая наш прекрасный код. Для этого наш код должен быть достаточно надежным, чтобы попадать под ограничения наших возможностей, и гибким - накладывать только необходимые ограничения для пространства маневра в бизнес-коде.
Чтобы решить подобные вопросы в “классических ООП” языках были выделено множество паттернов, которые заставляют стелить соломку абсолютно везде - стратегия на интерфейсе абстрактного класса, не должно быть классов не имплементирующих какой-то интерфейс. И прочие прелестные Джава-чсв “из умных книжек” догмы ака паттерны. А все изначально от ограничений. Пока не завезли дженерики даже достаточно типобезопасной функции мап было не сделать. Првильно, стратегии. Привет, любители Го.
В языках с динамической типизацией отродясь таких проблем не было. Они не задают совершенно никаких ограничений. Действительно хорошие попытки задать подобные ограничения в динамических языках - контрактное программирование, но лично я встречал его только на слайдах. Реальных ограничений в них нет. Что сейчас и привело к различным гибридным подходам к статической системе типов.
На другой чаше весов замечательные языки для “небожителей” аля Хаскель, Идрисы и прочие Окамелы. Из более хайпящих сейчас - Раст. Ух сколько радостей и головоломок приносят типы для тех, кто пишет на них библиотеки. И сколько бы я их не пробовал везде одна проблема - система типов сильно проникает в бизнесовый код. Реальный мир вошел в радужное царство единорогов-математиков. Как итог вместо фабрик, синглтонов и прочего из банды четырех мы получаем монады, монады-трасформеры и прочие монады-состояния. (тут важно разделить ФП и программирование на типах - не путаем)
И тут у Тайпскрипта неплохая позиция. Да, для типичных пользователей это все еще часто недосягаемый уровень. Как запрограммировать обход структуры на системе типов или даже написать обобщенный класс - загадка для многих, решаемая только чат гопотой или везением со SO. Но сама возможность прекрасна и при достаточном желании можно даже писать так, чтобы типы эти не лезли в бизнес слой и ребята продолжали описывать простейшие интерфейсики и объектные типы.
А для тех, кто решит преисполниться в программировании на типах могу порекомендовать курс https://type-level-typenoscript.com - без такого введение в программирование на типах входить было куда сложнее. Только как войдете помните пожалуйста о цене программирования на типах и не заставляйте входить в этот мир других.
В мире Тайпскрипта большое внимание уделяется системе типов.
Типами мы пытаемся описать предметную область: заказы, магазин, пользователь, корзина.
Это достигается простейшим описанием объектного типа или интерфейса. Куда реже мы переопределяем стандартные типы, вроде чисел и превращаем их в брендированные типы - другой мощный механизм, ставший возможным благодаря широким возможностям системы типов.
Как правило на этих возможностях использование системы типов и заканчивается. В прикладном коде мы стараемся не описывать сложное взаимодействие бизнес сущностей через систему типов. Цена этого довольно велика, а выхлоп туманный.
Другая сторона медали - системный код: библиотеки, вспомогательные утилиты, абстрагирующие от сложной системы функции, методы и классы. Хороший слой абстракции должен максимально отдалять пользователей наших системных модулей от деталей реализации. У них не должно возникать желания заглянуть за кулисы и расширить под свои требования переписывая наш прекрасный код. Для этого наш код должен быть достаточно надежным, чтобы попадать под ограничения наших возможностей, и гибким - накладывать только необходимые ограничения для пространства маневра в бизнес-коде.
Чтобы решить подобные вопросы в “классических ООП” языках были выделено множество паттернов, которые заставляют стелить соломку абсолютно везде - стратегия на интерфейсе абстрактного класса, не должно быть классов не имплементирующих какой-то интерфейс. И прочие прелестные Джава-чсв “из умных книжек” догмы ака паттерны. А все изначально от ограничений. Пока не завезли дженерики даже достаточно типобезопасной функции мап было не сделать. Првильно, стратегии. Привет, любители Го.
В языках с динамической типизацией отродясь таких проблем не было. Они не задают совершенно никаких ограничений. Действительно хорошие попытки задать подобные ограничения в динамических языках - контрактное программирование, но лично я встречал его только на слайдах. Реальных ограничений в них нет. Что сейчас и привело к различным гибридным подходам к статической системе типов.
На другой чаше весов замечательные языки для “небожителей” аля Хаскель, Идрисы и прочие Окамелы. Из более хайпящих сейчас - Раст. Ух сколько радостей и головоломок приносят типы для тех, кто пишет на них библиотеки. И сколько бы я их не пробовал везде одна проблема - система типов сильно проникает в бизнесовый код. Реальный мир вошел в радужное царство единорогов-математиков. Как итог вместо фабрик, синглтонов и прочего из банды четырех мы получаем монады, монады-трасформеры и прочие монады-состояния. (тут важно разделить ФП и программирование на типах - не путаем)
И тут у Тайпскрипта неплохая позиция. Да, для типичных пользователей это все еще часто недосягаемый уровень. Как запрограммировать обход структуры на системе типов или даже написать обобщенный класс - загадка для многих, решаемая только чат гопотой или везением со SO. Но сама возможность прекрасна и при достаточном желании можно даже писать так, чтобы типы эти не лезли в бизнес слой и ребята продолжали описывать простейшие интерфейсики и объектные типы.
А для тех, кто решит преисполниться в программировании на типах могу порекомендовать курс https://type-level-typenoscript.com - без такого введение в программирование на типах входить было куда сложнее. Только как войдете помните пожалуйста о цене программирования на типах и не заставляйте входить в этот мир других.
Type-Level TypeScript
An online course to become a TypeScript expert. Discover the most advanced features of the type system while solving fun challenges!
🔥3🦄2😱1
Top-down и bottom-up команды
Два разных подхода: продумать и сделать или сесть и начать с экспериментов. И быть готовым выкинуть несколько прототипов.
Оба подхода имеют право на жизнь. В одном мы силами системных архитекторов и аналитиков проектируем систему и потом делаем, а в другом мы должны что-то постоянно пробовать делать.
Провальный подход карго-культа на проектирование классно описан в книге про Agile (про разработку системы для полиции), а провалы вторых можно наблюдать в каждом третьем стартапе и сломанных ad-hoc процессах в ваших компаниях.
Есть такое предположение, что в одной тесно интегрированной команде ужиться тем и другим будет невозможно, но хорошо работает синергия таких команд в проекте.
Хорошо - когда ты понимаешь какая команда у вас и как вам комфортно двигаться вместе. Плохо - "ломать людей" и навязывать свой путь решения проблем.
Два разных подхода: продумать и сделать или сесть и начать с экспериментов. И быть готовым выкинуть несколько прототипов.
Оба подхода имеют право на жизнь. В одном мы силами системных архитекторов и аналитиков проектируем систему и потом делаем, а в другом мы должны что-то постоянно пробовать делать.
Провальный подход карго-культа на проектирование классно описан в книге про Agile (про разработку системы для полиции), а провалы вторых можно наблюдать в каждом третьем стартапе и сломанных ad-hoc процессах в ваших компаниях.
Есть такое предположение, что в одной тесно интегрированной команде ужиться тем и другим будет невозможно, но хорошо работает синергия таких команд в проекте.
Хорошо - когда ты понимаешь какая команда у вас и как вам комфортно двигаться вместе. Плохо - "ломать людей" и навязывать свой путь решения проблем.
🔥3
FSMoothy
Сходил на Kolesa.conf. И тут подъехали видео докладов.
Самой мякоткой для меня, конечно, был доклад про конечные автоматы.
Когда узнал, что Кирилл собрался делать доклад на тему КА - я поднапрягся и доделал свою либу для TypeORM (typeorm-fsm). До того, как в проектах мы переехали на нее использовали какой-то огрызок с самописной обвязкой. Тут же я приложил чуть больше своего api-дизайнерского скилла и вроде даже получилось скрестить суть-фундамент с практической пользой.
Как мне кажется, основой такой библиотеки в приложении к самомой логике автоматов должны служить два подхода: Observer (реакция на события), DI (использование внешних систем на переходах).
Пробывал ли я еще что-то? Да, посмотрел много вариантов в npm. Везде свои трейдофы. На фронтовом проекте я ранее применял XState. Давайте рассмотрим что меня в нем не устроило:
- Портянка для описания в виде js объекта. Переходы описываются вербозно (зато есть визуализатор), поддерживает стандарт State Chart'ов.
- Observer на action'ах. Описывается очень вербозно. В разных частях портянки объекта-описания.
- Активный конечный автомат (actor). Круто! Но, в таком виде на бэке скорее очень мало куда подойдет.
- Персист данных встроенный в саму либу. На самом же деле логика персиста ложится на клиентскую часть. В экосистеме готового ничего нет.
- Своя система работы с эффектами. Выглядит прикольно, но на деле в таком виде нужно только для активного конечного автомата.
Есть более простые реализации конечных автоматов. Но в них всегда не хватает каких-то фич, которые фундаментальные, а без них некоторые кейсы решать очень сложно:
- Гварды. Условия на переходах. Без них никуда. Иначе логика также размажется по коду.
- Не все события можно отследить. В моем понимании у события есть следующий следующий жизненный цикл: покидаем предыдущее состояние (onLeave), входим в новое (onEnter), меняем состояние (transition), сработали глобальные подписчики, окончание перехода (onExit). Отсутсвие части этих подписчиков также заставляет размазать часть логики из перехода в клиентский код.
- Вложенные и паралельные состояния. Когда горит красный сигнал светофора - может загореться зеленный сигнал для пешехода. Согласование состояния - одна из фундаментальных фишек автомата. Мы можем сделать отдельное состояние для этого случая или сделать вложенный автомат для состояния "красный сигнал" у светофора. Наличие этой фичи решает проблему роста автомата (state explosion problem).
- Вложенные данные. Автоматы также могут содержать дополнительные атрибуты. Например, счетчик времени. И использовать их на переходах.
- Асинхронные подгрузки. Может потребоваться подгружать начальное состояние и вложенные данные из внешних источников.
...
- и на самом деле много чего еще
Моим решением стало написание собственной либы - fsmoothy. В ней все описанные вещи заложены в дизайн и уже реализованны. Дальнейшее расширение планируется за счет написания отдельных пакетов поверх нее и расширения экосистемы.
Выделяйте автоматы у себя в коде явно, думайте о них при проектировании. Берегите свою кодовую базу!💎
Сходил на Kolesa.conf. И тут подъехали видео докладов.
Самой мякоткой для меня, конечно, был доклад про конечные автоматы.
Когда узнал, что Кирилл собрался делать доклад на тему КА - я поднапрягся и доделал свою либу для TypeORM (typeorm-fsm). До того, как в проектах мы переехали на нее использовали какой-то огрызок с самописной обвязкой. Тут же я приложил чуть больше своего api-дизайнерского скилла и вроде даже получилось скрестить суть-фундамент с практической пользой.
Как мне кажется, основой такой библиотеки в приложении к самомой логике автоматов должны служить два подхода: Observer (реакция на события), DI (использование внешних систем на переходах).
Пробывал ли я еще что-то? Да, посмотрел много вариантов в npm. Везде свои трейдофы. На фронтовом проекте я ранее применял XState. Давайте рассмотрим что меня в нем не устроило:
- Портянка для описания в виде js объекта. Переходы описываются вербозно (зато есть визуализатор), поддерживает стандарт State Chart'ов.
- Observer на action'ах. Описывается очень вербозно. В разных частях портянки объекта-описания.
- Активный конечный автомат (actor). Круто! Но, в таком виде на бэке скорее очень мало куда подойдет.
- Персист данных встроенный в саму либу. На самом же деле логика персиста ложится на клиентскую часть. В экосистеме готового ничего нет.
- Своя система работы с эффектами. Выглядит прикольно, но на деле в таком виде нужно только для активного конечного автомата.
Есть более простые реализации конечных автоматов. Но в них всегда не хватает каких-то фич, которые фундаментальные, а без них некоторые кейсы решать очень сложно:
- Гварды. Условия на переходах. Без них никуда. Иначе логика также размажется по коду.
- Не все события можно отследить. В моем понимании у события есть следующий следующий жизненный цикл: покидаем предыдущее состояние (onLeave), входим в новое (onEnter), меняем состояние (transition), сработали глобальные подписчики, окончание перехода (onExit). Отсутсвие части этих подписчиков также заставляет размазать часть логики из перехода в клиентский код.
- Вложенные и паралельные состояния. Когда горит красный сигнал светофора - может загореться зеленный сигнал для пешехода. Согласование состояния - одна из фундаментальных фишек автомата. Мы можем сделать отдельное состояние для этого случая или сделать вложенный автомат для состояния "красный сигнал" у светофора. Наличие этой фичи решает проблему роста автомата (state explosion problem).
- Вложенные данные. Автоматы также могут содержать дополнительные атрибуты. Например, счетчик времени. И использовать их на переходах.
- Асинхронные подгрузки. Может потребоваться подгружать начальное состояние и вложенные данные из внешних источников.
...
- и на самом деле много чего еще
Моим решением стало написание собственной либы - fsmoothy. В ней все описанные вещи заложены в дизайн и уже реализованны. Дальнейшее расширение планируется за счет написания отдельных пакетов поверх нее и расширения экосистемы.
Выделяйте автоматы у себя в коде явно, думайте о них при проектировании. Берегите свою кодовую базу!
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
Кирилл Мокевнин, Конечные автоматы как способ значительно упростить логику и понимание кода
Kolesa Conf'23, доклад
В этом докладе мы увидим, что практически любая бизнес-логика в коде укладывается в модель конечного автомата, то есть состоит из набора состояний и переходов между ними. Такой взгляд на происходящее позволит изменить подход к проектированию…
В этом докладе мы увидим, что практически любая бизнес-логика в коде укладывается в модель конечного автомата, то есть состоит из набора состояний и переходов между ними. Такой взгляд на происходящее позволит изменить подход к проектированию…
🔥7👍1🦄1
Стримы
В последнее время я регулярно стримлю на канал MemeBattle. У нас кончились кредиты на AWS и мы в рамках стримов сейчас переезжаем на Яндекс Клауд.
Но это не все темы для стримов. Недавно закончился Advent of Typenoscript и мы совместно с @xufostation и другими ребятами, которые прошли весь этот челендж, застримили решение почти всех задачек с довольно подробным разбором. В итоге получился такой мастер класс по Type Level программированию. Думаю, те, кто захочет повторить и послушать как решать такие задачки вынесут много полезного.
В планах на следующие стримы продолжить переписывать одни из наших сервисов для хранения истории Ligretto игр на Platformatic (что это и зачем можно также узнать из стримов), переписать несколько babel плагинов на swc на Rust'е и много чего еще полезного.
В общем, агитирую подписаться на наш канал, ставить лайки, жать на колокольчик чтобы первыми узнавать о предстоящих стримах и конечно же приходить нас смотреть!
https://www.youtube.com/@memebattle_dev/streams
В последнее время я регулярно стримлю на канал MemeBattle. У нас кончились кредиты на AWS и мы в рамках стримов сейчас переезжаем на Яндекс Клауд.
Но это не все темы для стримов. Недавно закончился Advent of Typenoscript и мы совместно с @xufostation и другими ребятами, которые прошли весь этот челендж, застримили решение почти всех задачек с довольно подробным разбором. В итоге получился такой мастер класс по Type Level программированию. Думаю, те, кто захочет повторить и послушать как решать такие задачки вынесут много полезного.
В планах на следующие стримы продолжить переписывать одни из наших сервисов для хранения истории Ligretto игр на Platformatic (что это и зачем можно также узнать из стримов), переписать несколько babel плагинов на swc на Rust'е и много чего еще полезного.
В общем, агитирую подписаться на наш канал, ставить лайки, жать на колокольчик чтобы первыми узнавать о предстоящих стримах и конечно же приходить нас смотреть!
https://www.youtube.com/@memebattle_dev/streams
🔥8
Двадцать дней как состоялся релиз первой версии языка Gleam, который должен ознаменовать стабильность и готовность языка к продакшен моментам. И двадцать дней как я пробую этот язык с разных сторон. и мне зашло
Давайте посмотрим, что включено в первый релиз и отмечено core-командой как стабильное:
⭐️ Дизайн языка. Все четко, язык похож на Rust+Elixir, но максимально минималистичнее - я бы сказал, что даже минималистичнее Go
⭐️ Компилятор. Тут тоже есть чем удивить: реализация TCO для JS, довольно понятный как Erlang, так и JS код на выходе. Написан на Rust’е, так что все работает быстро
⭐️ Build Tool. За то время, что пользуюсь ощущение, примерно как от Cargo, четенько
⭐️ Форматирование. Немного вкусовщины, но в целом все по кайфу
⭐️ Языковой сервер. Пока самая слабенькая часть. Нет, например, подсказок по маркированным(labeled) аргументам, автодополнение довольно глуповатое, не всегда ошибки там где надо показываются и еще пяток мелочей. Но в репозитории языка висит довольно много PR’ов улучшающих LSP.
⭐️ Компилятор в WASM и JS-биндинги. JS-биндинги имеют свой вполне очевидный рантайм оверхед. Прелюдия не большая, что в простых примерах ворочающих списки дает меньший выхлоп в бандл чем тот же ReScript.
Экосистема языка показалась мне не большой, но все минимальное для вебчика уже есть. wisp в качестве минималистичного web-фреймворка. lustre - elm-like фронтенд фреймворк. Есть свой индекс для пакетов - можно посмотреть что вообще есть.
Сам Gleam в первую очередь направлен хоститься на виртуальной машине Erlang - BEAM, что довольно четко очерчивает границы применимости и нишевость языка. Однако хороший интероп в JS с простым FFI и без расскраски функций - сильно расширяют его возможности.
Если вас заинтересовало - для быстрого ознакомления есть тур на оффициальном сайте, а чтобы попрактиковаться есть бесплатный трек с обучением на Exercism.
Давайте посмотрим, что включено в первый релиз и отмечено core-командой как стабильное:
Экосистема языка показалась мне не большой, но все минимальное для вебчика уже есть. wisp в качестве минималистичного web-фреймворка. lustre - elm-like фронтенд фреймворк. Есть свой индекс для пакетов - можно посмотреть что вообще есть.
Сам Gleam в первую очередь направлен хоститься на виртуальной машине Erlang - BEAM, что довольно четко очерчивает границы применимости и нишевость языка. Однако хороший интероп в JS с простым FFI и без расскраски функций - сильно расширяют его возможности.
Если вас заинтересовало - для быстрого ознакомления есть тур на оффициальном сайте, а чтобы попрактиковаться есть бесплатный трек с обучением на Exercism.
Please open Telegram to view this post
VIEW IN TELEGRAM
gleam.run
Gleam version 1
It's finally here! 🎉
🦄7👍5 2
Провел сегодня две замечательные сессии на TechTrain в роли эксперта, что поставило окончательную точку после трех месяцев подготовки в роли члена программного комитета. Время пролетело незаметно и как по мне, так вышло очень хорошо.
Мне в целом, нравится помогать готовиться ребятам и наблюдать за тем, что у них получается в итоге. Утренний доклад с Давидом из @it_kachalka про ООП однозначно рекомендую всем к просмотру! Прям хорошая рефлексия и выводы, которые привели его к Функционально Ориентированному Программированию🦀. Дискуссия в конце вообще безумно зарядила меня на ближайшее время.
Если у вас есть что рассказать и вы еще думаете выступать или нет - выступайте. Если думаете о том, стоит ли ходить смотреть доклады - ходите. Ведь митапы, пусть и онлайн - это даже не столько доклады, где вы что-то новое узнаете. Но и тусовка, где можно обсудить свои боли и идеи. Я лично всегда очень тепло вспоминаю, как у нас проходили митапы в Новосибирске, те кулуарные темы и крутые движухи, которые мы устраивали после мероприятий с друзьями.🌈
Мне в целом, нравится помогать готовиться ребятам и наблюдать за тем, что у них получается в итоге. Утренний доклад с Давидом из @it_kachalka про ООП однозначно рекомендую всем к просмотру! Прям хорошая рефлексия и выводы, которые привели его к Функционально Ориентированному Программированию🦀. Дискуссия в конце вообще безумно зарядила меня на ближайшее время.
Если у вас есть что рассказать и вы еще думаете выступать или нет - выступайте. Если думаете о том, стоит ли ходить смотреть доклады - ходите. Ведь митапы, пусть и онлайн - это даже не столько доклады, где вы что-то новое узнаете. Но и тусовка, где можно обсудить свои боли и идеи. Я лично всегда очень тепло вспоминаю, как у нас проходили митапы в Новосибирске, те кулуарные темы и крутые движухи, которые мы устраивали после мероприятий с друзьями.
Please open Telegram to view this post
VIEW IN TELEGRAM
TechTrain 2024 Spring. Фестиваль по профессиональному росту в IT
ООП: от любви до ненависти — один шаг. Но куда? | Доклад на TechTrain 2024 Spring
О моем пути осознания, что ООП применимо только в узких областях и приносит больше проблем, чем пользы в мультипарадигмальном программировании. Как, объединив лучшие практики функционального и процедурного программирования, я пришел к ФОП (функционально …
❤🔥3🔥2🦄2 2
Continuations
Один из моих любимых топиков в программировании - различные способы зафиксировать выполнение процесса программы на определенном месте и затем вернуться к нему. Это также называют Continuation. Впервые возможности которые за этим скрыты меня впечатлили когда я погружался в генераторы и в реализацию Redux Sagas. И теперь в каждом новом языке ищу нечто подобное и нахожу новые возможности, как это можно применять.
В языках, с которыми я сталкивался чаще всего есть одна из форм сontinuation -
Кроме раскраски функций типичный сontinuation в разных языках еще и не сериализуем, а значит не получится продолжить выполнение на другой машине, что вместе с потребляемыми CPU ресурсами ставит предел применимости этой техники.
И тут для меня на сцену вышла виртуальная машина Erlang - Beam. Процессы в Beam легковесны, планировщик встроенный в VM переключает работу с зависших процессов на живые и позволяет их распределять по всем инстансам VM, которые могут находиться на разных тачках. И вооружившись Gleam’ом я попробовал решить одну классическую проблему с Telegram ботами.
Как правило, чтобы имитировать последовательное общение между чат ботом и пользователем нам нужно куда-то сохранять состояние чата с текущим пользователем. И уже на следующий ответ снова запускать всю цепочку обработчиков и проверять состояние чата. Тут в реализации начинают появляться конечные автоматы или всякие специализированные подходы, вроде сцен.
Но по своей природе это задача как раз для континуаций. И тут на сцену выходит Conversations в grammy. Где вы просто пишете
Что собственно я и сделал - реализовал аналог Conversation API, но уже на Gleam. Вы уже можете попробовать сделать на этом простых чат-ботов (я +- стабилизировал внешний интерфейс, так что вряд ли что-то большое сломаю). Тут нет покраски функций, нет проблем с сериализацией и распределением между инстансами и как мне кажется довольно просто начать это писать (и читать):
Больше примеров можно посмотреть тут и тут!
В итоге писать чат ботов выходит куда более естественно, чем с различными конечными автоматам. Пробуйте, может вам тоже понравится!
Один из моих любимых топиков в программировании - различные способы зафиксировать выполнение процесса программы на определенном месте и затем вернуться к нему. Это также называют Continuation. Впервые возможности которые за этим скрыты меня впечатлили когда я погружался в генераторы и в реализацию Redux Sagas. И теперь в каждом новом языке ищу нечто подобное и нахожу новые возможности, как это можно применять.
В языках, с которыми я сталкивался чаще всего есть одна из форм сontinuation -
async/await. Чаще всего мы маркируем функции как async и чтобы зафиксировать состояние программы и отдать управление куда-то еще используем await. Такая маркировка еще называется раскраской функций. Однако, этот подход требует сложной поддержки всего этого дела со стороны рантайма, например, в Rust для этого вообще много интересной низкоуровневой возьни - посмотрите на то как там работает Tokio и какие в нем используются примитивы. Генераторы примерно туда же, хотя они как правило дают чуть больше контроля над процессом выполнения, но с ними все те же проблемы.Кроме раскраски функций типичный сontinuation в разных языках еще и не сериализуем, а значит не получится продолжить выполнение на другой машине, что вместе с потребляемыми CPU ресурсами ставит предел применимости этой техники.
И тут для меня на сцену вышла виртуальная машина Erlang - Beam. Процессы в Beam легковесны, планировщик встроенный в VM переключает работу с зависших процессов на живые и позволяет их распределять по всем инстансам VM, которые могут находиться на разных тачках. И вооружившись Gleam’ом я попробовал решить одну классическую проблему с Telegram ботами.
Как правило, чтобы имитировать последовательное общение между чат ботом и пользователем нам нужно куда-то сохранять состояние чата с текущим пользователем. И уже на следующий ответ снова запускать всю цепочку обработчиков и проверять состояние чата. Тут в реализации начинают появляться конечные автоматы или всякие специализированные подходы, вроде сцен.
Но по своей природе это задача как раз для континуаций. И тут на сцену выходит Conversations в grammy. Где вы просто пишете
const newContext = await conversation.wait(); и оно работает. Но тут все те же проблемы сontinuation’ов и еще немного специфичных ограничений из-за деталей реализации. И Beam это может помочь решить. Что собственно я и сделал - реализовал аналог Conversation API, но уже на Gleam. Вы уже можете попробовать сделать на этом простых чат-ботов (я +- стабилизировал внешний интерфейс, так что вряд ли что-то большое сломаю). Тут нет покраски функций, нет проблем с сериализацией и распределением между инстансами и как мне кажется довольно просто начать это писать (и читать):
fn set_name_command_handler(
ctx: BotContext,
_,
) -> Result(NameBotSession, String) {
use <- telega.log_context(ctx, "set_name command")
use _ <- result.try(telega_api.reply(ctx, "What's your name?"))
use ctx, name <- telega.wait_text(ctx)
use _ <- result.try(telega_api.reply(ctx, "Your name is: " <> name <> " set!"))
Ok(NameBotSession(name: name))
}
Больше примеров можно посмотреть тут и тут!
В итоге писать чат ботов выходит куда более естественно, чем с различными конечными автоматам. Пробуйте, может вам тоже понравится!
😱6
Forwarded from igrishaev
Когда неподготовленный человек видит Лисп, он как-то реагирует: хихикает, лепит эмодзи, вовлекает других, словом — переживает. В такую минуту он напоминает школьника, который принес эротический журнал: смотрит на груди и попы, конфузится, краснеет, показывает другим под партой. Вроде бы интересно, но что с этим делать — не понятно.
Хорошо, если бы программистам объяснили: Лисп — лучший способ записать код. Любой язык можно улучшить хотя бы тем, что сделать синтаксис лиспо-подобным. Пусть даже парадигма останется прежней.
У скобочной записи есть преимущество: каждое выражение имеет начало и конец. Убедитесь, что прочли последнее предложение вдумчиво. В Лиспе каждая форма имеет начало и конец. В других языках — нет.
Предположим, я вижу выражение
Значит ли это, что выражение закончено? Конечно нет. За
Кроме того, что выражение определяется "на глазок", сюда вкрадывается приоритет операторов:
В то время на Лиспе первое выражение будет таким:
Скобки задают границы. Если скобка закрылась, то выражение закончилось, точка. Все, что следует дальше, относится ко внешнему выражению. Второе выражение сводит на нет котовасию с приоритетом операторов:
Все задано явно, вопросов быть не может. Вы, конечно, скажете, что приоритет умножения известен каждому школьнику? Тогда счастливой отладки дебажить что-то такое:
Из сказанного следует, что в Лиспе удобно работать с выражениями. Например, я могу выделить текущую форму. Обратите внимание — форму! Не метод, не сложение чисел, не класс, а именно форму! Потому что в Лиспе все это — форма. Мне не нужны хоткеи "Select method", "Select class", "Select whatever". Мне достаточно одной клавиши, чтобы покрыть все случаи.
Формы в Лиспе можно разбивать и объединять. Стоит нажать кнопку, и выражение
Форма может поглощать другие формы. Например, у меня есть код:
Теперь нужно, чтобы форма была внутри условия. Прямо над ней я пишу:
Далее, находясь внутри
Разумеется, есть другая кнопка, чтобы "выплюнуть" форму, и я получу то, что было до поглощения.
Каждый думает, что к нему это не относится, ведь он же пишет не на Лиспе. Но вот реальный пример на Джаве с цепочкой футур:
Каждый видит в меру своей испорченности, но я вижу здесь Лисп. Ему немного не повезло: нужно только переставить скобки, и получится нормально. Но вот курьез: Джава-человек в упор этого не видит. Для него это по-прежнему код на Джаве, а переставишь скобки — и все, ржака.
Теперь нужно изменить код так, чтобы
Хорошо, если бы программистам объяснили: Лисп — лучший способ записать код. Любой язык можно улучшить хотя бы тем, что сделать синтаксис лиспо-подобным. Пусть даже парадигма останется прежней.
У скобочной записи есть преимущество: каждое выражение имеет начало и конец. Убедитесь, что прочли последнее предложение вдумчиво. В Лиспе каждая форма имеет начало и конец. В других языках — нет.
Предположим, я вижу выражение
x = foo + barЗначит ли это, что выражение закончено? Конечно нет. За
bar вполне может быть продолжение:x = foo + bar * kek + lolКроме того, что выражение определяется "на глазок", сюда вкрадывается приоритет операторов:
bar * kek нельзя разорвать.В то время на Лиспе первое выражение будет таким:
(define x (+ foo bar))Скобки задают границы. Если скобка закрылась, то выражение закончилось, точка. Все, что следует дальше, относится ко внешнему выражению. Второе выражение сводит на нет котовасию с приоритетом операторов:
(define x (+ foo (* bar kek) lol))Все задано явно, вопросов быть не может. Вы, конечно, скажете, что приоритет умножения известен каждому школьнику? Тогда счастливой отладки дебажить что-то такое:
Some shit = foo && bar || test ^ foo;Из сказанного следует, что в Лиспе удобно работать с выражениями. Например, я могу выделить текущую форму. Обратите внимание — форму! Не метод, не сложение чисел, не класс, а именно форму! Потому что в Лиспе все это — форма. Мне не нужны хоткеи "Select method", "Select class", "Select whatever". Мне достаточно одной клавиши, чтобы покрыть все случаи.
Формы в Лиспе можно разбивать и объединять. Стоит нажать кнопку, и выражение
(+ foo bar) становится просто + foo bar. Далее я могу что-то сделать с его элементами. Форму можно двигать выше, ниже по текущему уровню вложенности. Можно втолкнуть ее внутрь. Можно вытолкнуть наверх из-под условия.Форма может поглощать другие формы. Например, у меня есть код:
(do-some-stuff x y z)Теперь нужно, чтобы форма была внутри условия. Прямо над ней я пишу:
(when some-condition)
(do-some-stuff x y z)Далее, находясь внутри
when, я жму кнопку, и форма втягивает в себя следующую за ней форму, и получается:(when some-condition
(do-some-stuff x y z))Разумеется, есть другая кнопка, чтобы "выплюнуть" форму, и я получу то, что было до поглощения.
Каждый думает, что к нему это не относится, ведь он же пишет не на Лиспе. Но вот реальный пример на Джаве с цепочкой футур:
return prepare(sql, executeParams)
.thenCompose((PreparedStatement stmt) -> sendBind(portal, stmt, executeParams))
.thenCompose((Integer ignored) -> sendDescribePortal(portal))
.thenCompose((Integer ignored) -> sendExecute(portal, executeParams.maxRows()))
.thenCompose((Integer ignored) -> sendClosePortal(portal))
.thenCompose((Integer ignored) -> sendCloseStatement(stmt))
.thenCompose((Integer ignored) -> sendSync())
.thenCompose((Integer ignored) -> sendFlush())
.thenCompose((Integer ignored) -> interact(executeParams))
.thenCompose((Result res) -> CompletableFuture.completedFuture(res.getResult()));Каждый видит в меру своей испорченности, но я вижу здесь Лисп. Ему немного не повезло: нужно только переставить скобки, и получится нормально. Но вот курьез: Джава-человек в упор этого не видит. Для него это по-прежнему код на Джаве, а переставишь скобки — и все, ржака.
Теперь нужно изменить код так, чтобы
stmt оставался в поле видимости на большее число шагов. Получится вот так:👍4❤🔥1🤨1 1
Малюткам DeFi-dev'ам. Часть 1.
Я успел немного копнуть в разработку DeFi. До этого я попрогал в целом для блокчейнов - смарт контакты, децентрализованное хранение (IPFS) и прочее всякое около. И был достаточно погружен в само явление DeFi как пользователь, холдер, ну и как многие пытался здесь навариться (лудка дело такое).
И если вы, как и я когда-то, заинтересовались программированием для DeFi и не знаете куда копать и с чего начать, то я надеюсь дать вам какую-то базу.
Первое, что стоит помнить и всегда держать в голове - в крипте очень много скама. Это благодатная почва как для лудоманов, так и для мошенников разных мастей (иногда они даже не осознают всю скам-природу их проекта). Идти сюда в надежде залутать шальные деньги - по сути тоже самое, что крутить слоты в надежде на драконий куш. Также слушать блогеров и прочих крипто-чуваков не стоит. Многие из них выезжают только за счет ставок против аудитории и инсайдов. Да и "большой" трейдинг в крипте держится на очень зыбких субстанциях.
Зато, на почве все еще зарождающегося рынка без внятного регулирования, находящейся до сих пор в серой зоне, каждый программист, которому интересна область финансов, может попробовать себя в деле и не прикасаться к реальным банкам с кучей бюрократии и сложностей.
По своей природе DeFi очень интересная область с точки зрения разработки. В ней сперва нашли себя шифропанки, затем стартаперы средней руки, а теперь и выросшие крипто-компании с десятками тысяч сотрудников. Если сейчас посмотреть сверху на рынок того, что тут делается, то за верхушкой айсберга крупных бирж скрывается много чего поменьше, и более интересного.
Вот такой список популярных видов проектов я накидал: AMM (автоматические маркет мейкеры), разного рода MEV автоматизация, анти-скам системы, лаунчпады, кредитование, управление активами, разные страховые системы, DEX'ы, DAO, Yield Farming, кроссчейн протоколы, NFT и прочие стартапчики использующие крипту как платежный шлюз.
В следующих частях обязательно рассмотрим каждый компонент DeFi с точки зрения потребителя и разработки в EVM и Solana сетях (может еще и Ton немного затронем, хотя тут пока с реальными DeFi проектами не густо).
Примерный список ключевых тем (на мой скромный взгляд) по DeFi: чем отличаются сети и чейны, обернутые токены, как запускаются токены, стейбл коины, пулл ликвидности, централизованные и децентрализованные платформы, автоматические маркет мейкеры, феномен Uniswap V3 и почему это круто, мемпулл, валидаторы, арбитраж, снайп и прочие боты (+ разные виды атак).
Что из того, что я перечислил выше вам знакомо? Что интересно в первую очередь?
Ну, и как мне кажется этих тем должно быть достаточно для старта DeFi-dev малютки. И, конечно, буду рад если мощные ребята докинут тем и помогут их разобрать.
Я успел немного копнуть в разработку DeFi. До этого я попрогал в целом для блокчейнов - смарт контакты, децентрализованное хранение (IPFS) и прочее всякое около. И был достаточно погружен в само явление DeFi как пользователь, холдер, ну и как многие пытался здесь навариться (лудка дело такое).
И если вы, как и я когда-то, заинтересовались программированием для DeFi и не знаете куда копать и с чего начать, то я надеюсь дать вам какую-то базу.
Первое, что стоит помнить и всегда держать в голове - в крипте очень много скама. Это благодатная почва как для лудоманов, так и для мошенников разных мастей (иногда они даже не осознают всю скам-природу их проекта). Идти сюда в надежде залутать шальные деньги - по сути тоже самое, что крутить слоты в надежде на драконий куш. Также слушать блогеров и прочих крипто-чуваков не стоит. Многие из них выезжают только за счет ставок против аудитории и инсайдов. Да и "большой" трейдинг в крипте держится на очень зыбких субстанциях.
Зато, на почве все еще зарождающегося рынка без внятного регулирования, находящейся до сих пор в серой зоне, каждый программист, которому интересна область финансов, может попробовать себя в деле и не прикасаться к реальным банкам с кучей бюрократии и сложностей.
По своей природе DeFi очень интересная область с точки зрения разработки. В ней сперва нашли себя шифропанки, затем стартаперы средней руки, а теперь и выросшие крипто-компании с десятками тысяч сотрудников. Если сейчас посмотреть сверху на рынок того, что тут делается, то за верхушкой айсберга крупных бирж скрывается много чего поменьше, и более интересного.
Вот такой список популярных видов проектов я накидал: AMM (автоматические маркет мейкеры), разного рода MEV автоматизация, анти-скам системы, лаунчпады, кредитование, управление активами, разные страховые системы, DEX'ы, DAO, Yield Farming, кроссчейн протоколы, NFT и прочие стартапчики использующие крипту как платежный шлюз.
В следующих частях обязательно рассмотрим каждый компонент DeFi с точки зрения потребителя и разработки в EVM и Solana сетях (может еще и Ton немного затронем, хотя тут пока с реальными DeFi проектами не густо).
Примерный список ключевых тем (на мой скромный взгляд) по DeFi: чем отличаются сети и чейны, обернутые токены, как запускаются токены, стейбл коины, пулл ликвидности, централизованные и децентрализованные платформы, автоматические маркет мейкеры, феномен Uniswap V3 и почему это круто, мемпулл, валидаторы, арбитраж, снайп и прочие боты (+ разные виды атак).
Что из того, что я перечислил выше вам знакомо? Что интересно в первую очередь?
Ну, и как мне кажется этих тем должно быть достаточно для старта DeFi-dev малютки. И, конечно, буду рад если мощные ребята докинут тем и помогут их разобрать.
👍7🔥6🦄2 2
Малюткам DeFi-dev'ам. Часть 2.
С майна первого Биткоина по текущий 2024 год успели родиться стони блокчейнов. Тысячи умерли еще в зачатке. И только десятки дожили до наших дней, и буквально парочка действительно окрепла и расправила крылья над полем децентрализованных финансов.
Сам феномен BTC, как валюты - потрясающий, как и идеи стоящие за блочейном Bitcoin, который по сути был создан ради нее. В отличии от классических финансов, где "хост" валюты - государство у Биткоина хостом служит множество нод, образующих сеть Bitcoin.
Чтобы обеспечить существование самого капитализированного токена без устали работают более 55к узлов сети (на август 2024). Они блок-за-блоком проверяют и передают другим узлам сети данные, которые вносят в них пользователи.
Если вы сталкивались с децентрализованным хранилищем (или хотя бы задавались вопросом), то вы скорее всего слышали о задаче двух генералов и CAP теореме. Если нет, то про первое обязательно прочитайте в Вики, а вот про CAP давайте поговорим.
CAP, где C - Согласованность, А - Доступность, P - устойчивость к разделению. Подумайте или вспомните, что предлагает вам ваша любимая база данных или брокер сообщений. Вспомнили? Как правило, просто достигаются два из трех правил, хотя сейчас с оговорками есть базы удовлетворяющие всем трем. С оговорками потому что достаточно немного поразмыслить, чтобы прийти логически к противоречивости наличия третьего. А теперь вернемся к блокчейн сетям.
Когда проектировалась сеть Биткоина, то она сразу задумывалась как децентрализованная сеть, по которой будут проходить финансовые операции. Потому нет ничего хуже отказа в обслуживании и невозможности обеспечить эту самую децентрализацию (все это с поправкой на реальность). А вот над согласованностью нужно поработать. И результатом работы стал механизм консенсуса PoW (Proof Of Work). Дорогой с точки зрения требуемых мощностей компьютеров и потребляемых энергоресурсов. И как показало время надежный и стабильный.
Еще в годы в университете я разрабатывал клиент для торрента. И вся эта возня с блокченами мне дико напоминала то, как работает этот самый торрент-протокол. Хотя, здесь идеи p2p сетей дошли до совершенно другого уровня.
У нас уже есть сети, объединяющие миллионы компьютеров (интернет). И даже есть те, кто готовы платить за электричество, чтобы хранить наши данные и держать их согласованными. В замен они получают придуманную нами награду. А давайте теперь будем выполнять на них какие-нибудь еще программы. С такими идеями в наш мир ворвался Ethereum.
EVM (Ethereum Virtual Machine) - децентрализованная виртуальная машина, сердце всего Ethereum. Для нее сперва пишется контакт на Solidity, который компилируется (с помощью компилятора solc) в специализированный байт код и выполняется на множестве нод. После компиляции полученную программу нужно также развернуть в сети. Если вам интересно все это пощупать, то возьмите Remix в качестве IDE, Hardhat для тестирования и Truffle для развертывания, ну и обязательно попробуйте развернуть стандартной либой ethers.js. Там все просто берем полученную после компиляции abi'шку (файл с содержащий информацию о внешнем интерфейсе вашей программы), бинарник (файл
С Эфиром работать приятнее всего (в следующих темах постараюсь вас в этом убедить). Пока обращусь к большинству: множество токенов и dapps запущенных на нем - подтверждение моих слов. Комьюнити взрослое, в DeFi понимающее, экосистема самая богатая (но и от нее иногда полыхает мое кресло), так что если решите делать проект - однозначно выбирайте Эфир.
Резюмируя, хоть Биткоин и стал ключевой фигурой в мире, однако, для DeFi это больше историческая фигура, а не что-то, чем сейчас дышит разработка в этой области. Так что его больше мы касаться не будем.
А вот с устройством EVM, нод, токенами на Эфире и вообще всем вокруг EVM-подобных сетей нам предстоит познакомиться далее.
С майна первого Биткоина по текущий 2024 год успели родиться стони блокчейнов. Тысячи умерли еще в зачатке. И только десятки дожили до наших дней, и буквально парочка действительно окрепла и расправила крылья над полем децентрализованных финансов.
Сам феномен BTC, как валюты - потрясающий, как и идеи стоящие за блочейном Bitcoin, который по сути был создан ради нее. В отличии от классических финансов, где "хост" валюты - государство у Биткоина хостом служит множество нод, образующих сеть Bitcoin.
Чтобы обеспечить существование самого капитализированного токена без устали работают более 55к узлов сети (на август 2024). Они блок-за-блоком проверяют и передают другим узлам сети данные, которые вносят в них пользователи.
Если вы сталкивались с децентрализованным хранилищем (или хотя бы задавались вопросом), то вы скорее всего слышали о задаче двух генералов и CAP теореме. Если нет, то про первое обязательно прочитайте в Вики, а вот про CAP давайте поговорим.
CAP, где C - Согласованность, А - Доступность, P - устойчивость к разделению. Подумайте или вспомните, что предлагает вам ваша любимая база данных или брокер сообщений. Вспомнили? Как правило, просто достигаются два из трех правил, хотя сейчас с оговорками есть базы удовлетворяющие всем трем. С оговорками потому что достаточно немного поразмыслить, чтобы прийти логически к противоречивости наличия третьего. А теперь вернемся к блокчейн сетям.
Когда проектировалась сеть Биткоина, то она сразу задумывалась как децентрализованная сеть, по которой будут проходить финансовые операции. Потому нет ничего хуже отказа в обслуживании и невозможности обеспечить эту самую децентрализацию (все это с поправкой на реальность). А вот над согласованностью нужно поработать. И результатом работы стал механизм консенсуса PoW (Proof Of Work). Дорогой с точки зрения требуемых мощностей компьютеров и потребляемых энергоресурсов. И как показало время надежный и стабильный.
Еще в годы в университете я разрабатывал клиент для торрента. И вся эта возня с блокченами мне дико напоминала то, как работает этот самый торрент-протокол. Хотя, здесь идеи p2p сетей дошли до совершенно другого уровня.
У нас уже есть сети, объединяющие миллионы компьютеров (интернет). И даже есть те, кто готовы платить за электричество, чтобы хранить наши данные и держать их согласованными. В замен они получают придуманную нами награду. А давайте теперь будем выполнять на них какие-нибудь еще программы. С такими идеями в наш мир ворвался Ethereum.
EVM (Ethereum Virtual Machine) - децентрализованная виртуальная машина, сердце всего Ethereum. Для нее сперва пишется контакт на Solidity, который компилируется (с помощью компилятора solc) в специализированный байт код и выполняется на множестве нод. После компиляции полученную программу нужно также развернуть в сети. Если вам интересно все это пощупать, то возьмите Remix в качестве IDE, Hardhat для тестирования и Truffle для развертывания, ну и обязательно попробуйте развернуть стандартной либой ethers.js. Там все просто берем полученную после компиляции abi'шку (файл с содержащий информацию о внешнем интерфейсе вашей программы), бинарник (файл
.bin, содержащий вашу програму), рассчитываем нужный газ (берем пока наугад с запасом) и делаем contract.deploy({ data: '0x' + bytecode }).send({}). С Эфиром работать приятнее всего (в следующих темах постараюсь вас в этом убедить). Пока обращусь к большинству: множество токенов и dapps запущенных на нем - подтверждение моих слов. Комьюнити взрослое, в DeFi понимающее, экосистема самая богатая (но и от нее иногда полыхает мое кресло), так что если решите делать проект - однозначно выбирайте Эфир.
Резюмируя, хоть Биткоин и стал ключевой фигурой в мире, однако, для DeFi это больше историческая фигура, а не что-то, чем сейчас дышит разработка в этой области. Так что его больше мы касаться не будем.
А вот с устройством EVM, нод, токенами на Эфире и вообще всем вокруг EVM-подобных сетей нам предстоит познакомиться далее.
🔥6❤🔥3 3🦄1
Малюткам DeFi-dev'ам. Часть 3.
И так, у нас есть какой-то байткод для EVM. Этот байткод мы будем выполнять сразу на всех нодах в сети Ethereum, тем самым никакой отдельный узел не может цензурировать наш контракт и исключает мухлеж со стороны держателей конкретной ноды (а уязвимости типа 51% решаются другими механиками).
Вообще каждой ноде не обязательно выполнять контракты, так в Ethereum сети есть три типа нод: полные, облегченные, архивные. Код смарт контрактов выполняют только полные и архивные узлы, а облегченные полагаются на них при валидации транзакций.
Так, а что же значит выполнить транзакцию?
Начнем с отправителя и получателя. Это два адреса. Адрес представляет собой 20-байтовое значения и начинаются с
И так мы - пользователь, отправитель. Наш получатель - контакт
Вот мы зашли на Eatherscan, нашли наш контракт (например, гляньте на контракт Uniswap V2, но далеко не все контракты открытые и есть тулзы для реверса из байткода) и увидели два метода
При вызове
И вот наша транзакция начала распространяться по сети и попадает в mempool (пул неподтвержденных транзакций).
Узлы начинают проверять достаточно ли у отправителя средств для выполнения транзакции, корректность подписи (можете почитать про алгоритм ECDSA) и верно ли указан Gas Limit. Валидаторы (или майнеры в случае с PoW) выбирают транзакции из mempool и включают их в блоки. Каждый блок имеет заголовок, который включает хеш предыдущего блока, временную метку, nonce и другие метаданные.
Когда уже одна из нод получит наше сообщение через вызов provider'а она начнет считать газ: ~700 газа за вызов функции (операция
Стоимость каждой операции в байткоде EVM хорошо задокументирована в спецификации и в нашем простом случае мы смогли легко сами посчитать значение, но так как контакты могут взаимодействовать с другими контрактами не вариант всегда вручную расчитывать цену.
Когда наконец транзакция включена в блок, узлы сети выполняют байткод транзакции на EVM: декодируют данные, вызывается функция, обновляется состояние.
И вот наконец происходит запись изменений в блокчейн, обновляя хранилище контракта. В дальнейшем это состояние будет доступно вызовом функции
И так, у нас есть какой-то байткод для EVM. Этот байткод мы будем выполнять сразу на всех нодах в сети Ethereum, тем самым никакой отдельный узел не может цензурировать наш контракт и исключает мухлеж со стороны держателей конкретной ноды (а уязвимости типа 51% решаются другими механиками).
Вообще каждой ноде не обязательно выполнять контракты, так в Ethereum сети есть три типа нод: полные, облегченные, архивные. Код смарт контрактов выполняют только полные и архивные узлы, а облегченные полагаются на них при валидации транзакций.
Так, а что же значит выполнить транзакцию?
Начнем с отправителя и получателя. Это два адреса. Адрес представляет собой 20-байтовое значения и начинаются с
Ox. Это может быть либо аккаунт пользователя (Externally Owned Accounts aka EOA), либо контракт, адрес которого генерируется при деплое.И так мы - пользователь, отправитель. Наш получатель - контакт
MessageStore который просто сохраняет наши сообщения на блокчейне. И да, помимо выполнения кода контакты могут записывать данные в блокчейн и хранить свое состояние.Вот мы зашли на Eatherscan, нашли наш контракт (например, гляньте на контракт Uniswap V2, но далеко не все контракты открытые и есть тулзы для реверса из байткода) и увидели два метода
setMessage(string memory newMessage и getMessage() public view returns (string memory). Чтож, пора его вызвать. Берем либу ethers тяп ляп и получаем что-то такое:
import { ethers } from "ethers";
const provider = new ethers.providers.InfuraProvider();
const privateKey = '...';
const wallet = new ethers.Wallet(privateKey, provider);
const abi = [
"function setMessage(string memory newMessage) public",
"function getMessage() public view returns (string memory)"
];
const contract = new ethers.Contract(contractAddress, abi, wallet);
const gasPrice = ethers.utils.parseUnits('20', 'gwei');
// Вызываем
const tx = await contract.setMessage("Запись от DeFi малюток!", { gasLimit: 21000, gasPrice });
// Ожидаем подтверждения транзакции
await tx.wait();
При вызове
contract.setMessage мы стартанули транзакцию от отправителя (wallet) в контракт. И вот наша транзакция начала распространяться по сети и попадает в mempool (пул неподтвержденных транзакций).
Узлы начинают проверять достаточно ли у отправителя средств для выполнения транзакции, корректность подписи (можете почитать про алгоритм ECDSA) и верно ли указан Gas Limit. Валидаторы (или майнеры в случае с PoW) выбирают транзакции из mempool и включают их в блоки. Каждый блок имеет заголовок, который включает хеш предыдущего блока, временную метку, nonce и другие метаданные.
Когда уже одна из нод получит наше сообщение через вызов provider'а она начнет считать газ: ~700 газа за вызов функции (операция
CALL),~20к газа за изменение (SSTORE),и 0 за RETURN. Тогда мы легко пройдем наш лимит (мы взяли чутка с излишком) и заплатим за это ~21000 газа * 20 Gwei = 420000 Gwei (0.00042 ETH). Если не указать явно gasLimit either за нас вызовет метод estimateGas - метод выполняет симуляцию транзакции и возвращает приблизительное количество газа, которое потребуется для её выполнения. В зависимости от состояния сети метод может ошибиться и переоценить (юзер заплатит больше) или недооценить стоимость (тогда транзакция упадет с out of gas). За 20 gwei за газ может случиться такое, что никто из валидаторв не возмет нашу транзакцию в обработку (либо ооч долго не будет брать) и если не указать gasPrice - either также может посчитать значение на основе условий сети. Стоимость каждой операции в байткоде EVM хорошо задокументирована в спецификации и в нашем простом случае мы смогли легко сами посчитать значение, но так как контакты могут взаимодействовать с другими контрактами не вариант всегда вручную расчитывать цену.
Когда наконец транзакция включена в блок, узлы сети выполняют байткод транзакции на EVM: декодируют данные, вызывается функция, обновляется состояние.
И вот наконец происходит запись изменений в блокчейн, обновляя хранилище контракта. В дальнейшем это состояние будет доступно вызовом функции
getMessage.Ethereum (ETH) Blockchain Explorer
Uniswap V2: Router 2 | Address: 0x7a250d56...659f2488d | Etherscan
Contract: Verified | Balance: $663,766.19 across 16 Chains | Transactions: 85,721,692 | As at Dec-25-2025 07:43:39 PM (UTC)
🔥2🦄2🌚1