В рамках пет-проекта я дошел до стадии, когда нужно где-то захостить MVP.
Последний раз, до перехода в большие компании на постоянный найм, я хостил свои проекты лет 7 назад: и хотя тогда все активно докеризировалось и уже почти везде начинали внедрять кубер, но маленькие проекты в маленьких компаниях все еще часто крутились на связках вида linux+nginx+mysql+php. И хотя я и умел докеризировать приложения - прод обычно разворачивался по старинке - без виртуальных контейнеров. Да и запускать в то время виртуальные контейнеры в проде по некоторым утверждением было антипаттерном из-за сильной потери в производительности, особенно учитывая, что все приложения тогда я писал на PHP, который производительностью и так не блистал.
Сейчас же я пошел ресерчить вместе с chatgpt, как и на чем мне лучше все развернуть так, чтобы это было относительно дешево и быстро в настройке, и gpt предложил мне несколько вариантов:
- так как я частично использую google-стек - заиспользовать инструменты гугла и для деплоя: GCP cloud run services / jobs + google cloud storage или внешнюю БД
- второй вариант - fly.io и другие похожие сервисы
- третий вариант - свой vps + dokku
Посчитав экономику, самый дешевый вариант под мои нагрузки получился третий - свой vps + dokku. С dokku я до этого не работал, и открыл для себя этот дивный новый мир.
dokku - это PaaS, который помогает менеджерить lifecycle приложения. По-факту, это набор bash-скриптов, который очень упрощают и оптимизируют работу с докером: одной командой можно создать выделенное окружение, задать туда энвы, настроить количество инстансов, которые будут запускаться в выделенных контейнерах. Не нужно составлять DNS вручную - они одной командой пробрасываются между контейнерами, автозаполняются и становятся доступными для вызова, что очень удобно при работе, например, с postgres.
Одна из вещей, которые мне нужно было захостить - это обработчик для tg-бота.
Упрощенно, это было запущено следующей цепочкой команд:
Дальше передеплой приложения выглядит следующим образом - мы вносим правки в код, коммитим и пушим в dokku-bot (git remote source, добавленный выше), и через git hook'и запускается магия автоматической пересборки наших контейнеров.
В ближайшее время настрою связку dokku с github actions, чтобы докручивать кастомные джобы и, например, иметь возможность гонять тесты перед тем, как пересобирать контейнеры с приложениями.
Но базово, для небольших тестовых проектов - кайф❤️
dev notes | golang digest
Последний раз, до перехода в большие компании на постоянный найм, я хостил свои проекты лет 7 назад: и хотя тогда все активно докеризировалось и уже почти везде начинали внедрять кубер, но маленькие проекты в маленьких компаниях все еще часто крутились на связках вида linux+nginx+mysql+php. И хотя я и умел докеризировать приложения - прод обычно разворачивался по старинке - без виртуальных контейнеров. Да и запускать в то время виртуальные контейнеры в проде по некоторым утверждением было антипаттерном из-за сильной потери в производительности, особенно учитывая, что все приложения тогда я писал на PHP, который производительностью и так не блистал.
Сейчас же я пошел ресерчить вместе с chatgpt, как и на чем мне лучше все развернуть так, чтобы это было относительно дешево и быстро в настройке, и gpt предложил мне несколько вариантов:
- так как я частично использую google-стек - заиспользовать инструменты гугла и для деплоя: GCP cloud run services / jobs + google cloud storage или внешнюю БД
- второй вариант - fly.io и другие похожие сервисы
- третий вариант - свой vps + dokku
Посчитав экономику, самый дешевый вариант под мои нагрузки получился третий - свой vps + dokku. С dokku я до этого не работал, и открыл для себя этот дивный новый мир.
dokku - это PaaS, который помогает менеджерить lifecycle приложения. По-факту, это набор bash-скриптов, который очень упрощают и оптимизируют работу с докером: одной командой можно создать выделенное окружение, задать туда энвы, настроить количество инстансов, которые будут запускаться в выделенных контейнерах. Не нужно составлять DNS вручную - они одной командой пробрасываются между контейнерами, автозаполняются и становятся доступными для вызова, что очень удобно при работе, например, с postgres.
Одна из вещей, которые мне нужно было захостить - это обработчик для tg-бота.
Упрощенно, это было запущено следующей цепочкой команд:
dokku apps:create tgbot - создание выделенного окружения для приложения
dokku plugin:install https://github.com/dokku/dokku-postgres.git
git remote add dokku-bot dokku@<VPS_IP>:tgbot
dokku config:set \
key=value \
...
dokku postgres:create mydb - создание БД
dokku postgres:link mydb tgbot - проброс DATABASE_URL из mydb в tgbot
dokku ps:scale tgbot worker=1 - запускаем 1 инстанс
dokku ps:report tgbot - проверяем статус
Дальше передеплой приложения выглядит следующим образом - мы вносим правки в код, коммитим и пушим в dokku-bot (git remote source, добавленный выше), и через git hook'и запускается магия автоматической пересборки наших контейнеров.
В ближайшее время настрою связку dokku с github actions, чтобы докручивать кастомные джобы и, например, иметь возможность гонять тесты перед тем, как пересобирать контейнеры с приложениями.
Но базово, для небольших тестовых проектов - кайф
dev notes | golang digest
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - dokku/dokku: A docker-powered PaaS that helps you build and manage the lifecycle of applications
A docker-powered PaaS that helps you build and manage the lifecycle of applications - dokku/dokku
2👍7❤1👾1 1
Forwarded from bruhcollective. (iTaysonLab)
the following content will be interesting for Russian-speaking only:
тут начали закупать в ТГ рекламу некого мессенджера "Telega", общающегозолотые горы стабильную работу ТГ на территории РФ
но в чем подвох? а в том, что эта "Telega" (которая https://telega.me) - является проектом VK.
но как об этом узнать? а все просто - берем APK и открываем декомпилятор
идем в ru.dahl.messenger.Extra и видим:
-> PROXY_ADDRESS = "dal.mvk.com", прокси-адрес, запишем
-> MYTRACKER_SDK_KEY = "*", SDK-ключ от трекера MyTracker, который принадлежитMai VK Group
-> CALLS_BASE_URL = "https://calls.okcdn.ru/" - те самые рабочие звонки, которые на самом деле являются звонками через инфраструктуру Одноклассников (на которых работает еще MAX и VK Звонки, ага)
а теперь берем dal.mvk.com:
-> неймсервера mvk.com идут на малоизвестный домен VKONTAKTE.RU
-> в декомпиляции официального клиента VK для Android можно найти референсы на "https://jira.mvk.com"
(и вся реклама этого клиента в ТГ ведет на трекинг-домен trk.mail.ru)
но кому не пофиг? вдруг ВК просто по приколу решили сделать форк ТГ, прикрывшись прокладкой из Татарстана?
а вот тут уже обнаруживается прикольная вещь: в клиенте есть "черный список" нежелательных ТГ-каналов, ботов и пользователей! при нажатии на которых выводится ТГ-шная "заглушка" с своим текстом:
какие правила платформы? Telegram? но таких строчек нет в официальном клиенте Telegram :)
и да - черный список включается по флагу из сервера, то есть они могут включить это в любой момент
///
а кроме этого, в клиенте есть замена иконок на ВКшные. все бы ничего, но весь код замены был взят из такого малоизвестного клиента как Catogram (https://github.com/Catogram/Catogram/blob/a34ddfb42f50b86eb7cd83fb68ea24fa041084a9/TMessagesProj/src/main/java/ua/itaysonlab/catogram/vkui/ReplaceKtx.kt)
BaseIconReplace -> ru.dahl.messenger.icons.BaseIconReplacement
No/VkIconReplace -> ru.dahl.messenger.icons.AltIconReplacement/IconReplacementNone
ReplaceKtx.newSparseInt -> ru.dahl.messenger.icons.BaseIconReplacementKt
причем взяли все подчистую - те же названия переменных, методов, параметров и даже код тот же (даже тот же sparseInt сделали root-level функцией Kotlin)
а забавный факт в том, что основной разработкой Catogram занимался... я
как-то так....
тут начали закупать в ТГ рекламу некого мессенджера "Telega", общающего
но в чем подвох? а в том, что эта "Telega" (которая https://telega.me) - является проектом VK.
но как об этом узнать? а все просто - берем APK и открываем декомпилятор
идем в ru.dahl.messenger.Extra и видим:
-> PROXY_ADDRESS = "dal.mvk.com", прокси-адрес, запишем
-> MYTRACKER_SDK_KEY = "*", SDK-ключ от трекера MyTracker, который принадлежит
-> CALLS_BASE_URL = "https://calls.okcdn.ru/" - те самые рабочие звонки, которые на самом деле являются звонками через инфраструктуру Одноклассников (на которых работает еще MAX и VK Звонки, ага)
а теперь берем dal.mvk.com:
-> неймсервера mvk.com идут на малоизвестный домен VKONTAKTE.RU
-> в декомпиляции официального клиента VK для Android можно найти референсы на "https://jira.mvk.com"
(и вся реклама этого клиента в ТГ ведет на трекинг-домен trk.mail.ru)
но кому не пофиг? вдруг ВК просто по приколу решили сделать форк ТГ, прикрывшись прокладкой из Татарстана?
а вот тут уже обнаруживается прикольная вещь: в клиенте есть "черный список" нежелательных ТГ-каналов, ботов и пользователей! при нажатии на которых выводится ТГ-шная "заглушка" с своим текстом:
<string name="ContentIsUnavailable">Материалы недоступны</string>
<string name="ContentUnavailableInfo">Этот %1$s недоступен в связи \n с нарушениями правил платформы</string>
какие правила платформы? Telegram? но таких строчек нет в официальном клиенте Telegram :)
и да - черный список включается по флагу из сервера, то есть они могут включить это в любой момент
///
а кроме этого, в клиенте есть замена иконок на ВКшные. все бы ничего, но весь код замены был взят из такого малоизвестного клиента как Catogram (https://github.com/Catogram/Catogram/blob/a34ddfb42f50b86eb7cd83fb68ea24fa041084a9/TMessagesProj/src/main/java/ua/itaysonlab/catogram/vkui/ReplaceKtx.kt)
BaseIconReplace -> ru.dahl.messenger.icons.BaseIconReplacement
No/VkIconReplace -> ru.dahl.messenger.icons.AltIconReplacement/IconReplacementNone
ReplaceKtx.newSparseInt -> ru.dahl.messenger.icons.BaseIconReplacementKt
причем взяли все подчистую - те же названия переменных, методов, параметров и даже код тот же (даже тот же sparseInt сделали root-level функцией Kotlin)
а забавный факт в том, что основной разработкой Catogram занимался... я
как-то так....
2😢13👍4🎉1👾1 1
Пока искал и отбирал статьи для t.me/digest_golang (подписывайтесь, кстати) - нашел полезное - доклад с GoLab 2025 от инженера Reddit с 10 паттернами, на которые он советует обращать внимание во время написания кода.
По названию похоже на типичную проходную статью с медиума с околонулевой ценностью, но по факту нахожу эти советы хорошими, и пару раз поймал себя на мысли что я часто указываю в ревью на те же ошибки, что описывает автор, но раньше не выделял их в отдельные паттерны.
Например:
Не дублируй логи - если ловим ошибку - мы ее или логируем, или возвращаем, но не оба сразу
Для код-ревью это хороший паттерн, потому как мысль-то вроде очевидная, но не всегда на это обращаешь внимание. Если где-то в MR на внутреннем уровне кто-то добавил лог, надо проверить, есть ли он на уровне выше. Если есть - удаляем.
Не добавляй интерфейс слишком рано
Я пришел к такому же выводу спустя несколько лет разработки на Go. Вообще, это напоминание другой базовой истины еще из "Чистого кода" - не делай преждевременных оптимизаций. Но, в индустрии во многих компаниях есть правило: любой тип должен быть с интерфейсом. По факту получается так, что в коде несколько сотен интерфейсов, а более одной реализации - у нескольких. Сначала стоит вернуть конкретный тип, а потом, если будет задача на расширение, всегда можно будет добавить интерфейс и реализовать его еще раз.
Сначала mutex, затем каналы
Каналы - это сложный механизм для синхронизации и взаимодействия горутин, и часто его использование слишком избыточно. Если появилась мысль добавить куда-то горутины или каналы, автор советует сделать так:
- сначала, если возможно, пишем синхронный код, решающий задачу
- если профилирование показывает, что это узкое место - добавляем горутины
- для синхронизации горутин sync.Mutex и sync.WaitGroup
- и только если профилирование показывает, что их недостаточно - вводим каналы
Проектировать код лучше без указателей
В Go очень часто возвращаемое значение из функций описывают следующим образом:
с логичным намерением: если будет ошибка - мы возвращаем
По факту большинство структур, с которыми мы чаще всего работаем - структуры с несколькими полями. И с точки зрения оптимизации мы не выиграем, если вернем указатель на структуру, а не саму структуру, так как скопировать эти самые несколько полей на стек почти ничего не стоит. А если мы работаем со стеком - мы снижаем нагрузку на GC.
А что мы еще снижаем - это ошибки с обработкой nil. Почти на каждом большом проекте, где я работал, хотя бы раз я с этим сталкивался - кто-то обязательно со временем вернет nil там, где его точно не будет ожидать вызывающий код.
Весь список с множеством полезных деталей можно прочитать тут - https://www.reddit.com/r/golang/comments/1oc5is8/writing_better_go_lessons_from_10_code_reviews/
dev notes | golang digest
По названию похоже на типичную проходную статью с медиума с околонулевой ценностью, но по факту нахожу эти советы хорошими, и пару раз поймал себя на мысли что я часто указываю в ревью на те же ошибки, что описывает автор, но раньше не выделял их в отдельные паттерны.
Например:
Не дублируй логи - если ловим ошибку - мы ее или логируем, или возвращаем, но не оба сразу
Для код-ревью это хороший паттерн, потому как мысль-то вроде очевидная, но не всегда на это обращаешь внимание. Если где-то в MR на внутреннем уровне кто-то добавил лог, надо проверить, есть ли он на уровне выше. Если есть - удаляем.
Не добавляй интерфейс слишком рано
Я пришел к такому же выводу спустя несколько лет разработки на Go. Вообще, это напоминание другой базовой истины еще из "Чистого кода" - не делай преждевременных оптимизаций. Но, в индустрии во многих компаниях есть правило: любой тип должен быть с интерфейсом. По факту получается так, что в коде несколько сотен интерфейсов, а более одной реализации - у нескольких. Сначала стоит вернуть конкретный тип, а потом, если будет задача на расширение, всегда можно будет добавить интерфейс и реализовать его еще раз.
Сначала mutex, затем каналы
Каналы - это сложный механизм для синхронизации и взаимодействия горутин, и часто его использование слишком избыточно. Если появилась мысль добавить куда-то горутины или каналы, автор советует сделать так:
- сначала, если возможно, пишем синхронный код, решающий задачу
- если профилирование показывает, что это узкое место - добавляем горутины
- для синхронизации горутин sync.Mutex и sync.WaitGroup
- и только если профилирование показывает, что их недостаточно - вводим каналы
Проектировать код лучше без указателей
В Go очень часто возвращаемое значение из функций описывают следующим образом:
MyFunc() (*MyStruct, error)
с логичным намерением: если будет ошибка - мы возвращаем
nil, err для удобства - не нужно писать MyStruct{}, err. Еще изредка можно услышать, что это делается для оптимизации. По факту большинство структур, с которыми мы чаще всего работаем - структуры с несколькими полями. И с точки зрения оптимизации мы не выиграем, если вернем указатель на структуру, а не саму структуру, так как скопировать эти самые несколько полей на стек почти ничего не стоит. А если мы работаем со стеком - мы снижаем нагрузку на GC.
А что мы еще снижаем - это ошибки с обработкой nil. Почти на каждом большом проекте, где я работал, хотя бы раз я с этим сталкивался - кто-то обязательно со временем вернет nil там, где его точно не будет ожидать вызывающий код.
Весь список с множеством полезных деталей можно прочитать тут - https://www.reddit.com/r/golang/comments/1oc5is8/writing_better_go_lessons_from_10_code_reviews/
dev notes | golang digest
3👍5🔥2❤1👾1
Последнее время, рефлексируя над тем, как в нашу жизнь врываются LLM - мне все больше нравится идея постоянного обучения.
Во-первых, автоматизируя большинство рутинных действий и решая большинство задач через модели - мы, по природе своей, начинаем терять навык делать это сами. А отупеть очень не хотелось бы, поэтому тут как с тренажерным залом - железки нам поднимать уже много десятилетий как не нужно, но мы сами подвергаем себя нагрузкам, чтобы не рассыпаться раньше времени. С мозгом - та же история.
Если этого мало, то вот вторая причина. У поколения наших родителей была интересная опция: ты сначала учишься, получаешь специальность, а затем всю жизнь работаешь на выученной базе нарабатывая опыт. Сейчас же тебе нужно сначала учиться, затем нарабатывать опыт, а потом, если ты не хочешь терять в уровне жизни - делать еще один цикл обучения-наработки опыта, затем еще и еще. У меня так было со сменой стека: сначала это был PHP, затем потолок по зп -> период обучения -> смена стека на Go -> наработка опыта на нем. Это позволило мне вырасти по ЗП еще выше и выйти на зарубежный рынок.
Сейчас с приходом LLM я понимаю, что следующий этап обучения будет выглядеть как углубление текущих знаний и изучение новых языков.
Через 5-10 лет, вероятно, обучение будет или направлено на архитектуру приложений, или смещено в сторону менеджмента.
К вопросу углубления знаний - сейчас это кажется очень важным. Почему? Потому что на фоне у меня работает модель, которая генерит портянки кода и дефолтные crud'ы. Если кто-то делает тоже самое на работе - это можно заменить, вопрос лишь времени и интеграции модели в различные инструменты для сбора полного контекста, такие как jira и slack.
Но если задача, которую решает инженер - действительно сложная, например поиск какого-то бага (на этот счет есть отличное свежее расследование от cloudflare - там ребята искали и фиксили сложный баг в компиляторе arm64 под огромной нагрузкой) или проектирование архитектуры в действительно сложном контексте - вот это заменить будет тяжело.
Но когда-то же LLM научится решать и такие сложные задачи? Я думаю что сейчас единственная возможность заставить LLM работать с такими сложными задачами - очень строгая документация внутри проекта по очень строгим правилам. Например, 10 сервисов общаются между собой. У каждого должна быть дока с подробным и понятным (для модели) описанием того, что делает этот сервис, причем в очень строгом формате. Должны быть прописаны связи, по которым модель может ходить от сервиса к сервису и захватывать весь контекст, и все это должно работать с одними и теми же доменами. Иначе модели просто не хватит памяти и мощности, чтобы весь этот контекст впитать и держать актуальным. А теперь вспомним, сколько сервисов и связей в дейстительно больших проектах, не говоря уже о том, сколько там костылей, неожиданных взаимодействий и какая там документация. Большие компании в ближайшие годы не смогут переписать и документировать свои сервисы так, чтобы LLM решала в них действительно сложные задачи, но и перестанет нанимать инженеров, которые занимались рутинными действиями по перекладыванию ответов в базу и обратно.
dev notes | golang digest
Во-первых, автоматизируя большинство рутинных действий и решая большинство задач через модели - мы, по природе своей, начинаем терять навык делать это сами. А отупеть очень не хотелось бы, поэтому тут как с тренажерным залом - железки нам поднимать уже много десятилетий как не нужно, но мы сами подвергаем себя нагрузкам, чтобы не рассыпаться раньше времени. С мозгом - та же история.
Если этого мало, то вот вторая причина. У поколения наших родителей была интересная опция: ты сначала учишься, получаешь специальность, а затем всю жизнь работаешь на выученной базе нарабатывая опыт. Сейчас же тебе нужно сначала учиться, затем нарабатывать опыт, а потом, если ты не хочешь терять в уровне жизни - делать еще один цикл обучения-наработки опыта, затем еще и еще. У меня так было со сменой стека: сначала это был PHP, затем потолок по зп -> период обучения -> смена стека на Go -> наработка опыта на нем. Это позволило мне вырасти по ЗП еще выше и выйти на зарубежный рынок.
Сейчас с приходом LLM я понимаю, что следующий этап обучения будет выглядеть как углубление текущих знаний и изучение новых языков.
Через 5-10 лет, вероятно, обучение будет или направлено на архитектуру приложений, или смещено в сторону менеджмента.
К вопросу углубления знаний - сейчас это кажется очень важным. Почему? Потому что на фоне у меня работает модель, которая генерит портянки кода и дефолтные crud'ы. Если кто-то делает тоже самое на работе - это можно заменить, вопрос лишь времени и интеграции модели в различные инструменты для сбора полного контекста, такие как jira и slack.
Но если задача, которую решает инженер - действительно сложная, например поиск какого-то бага (на этот счет есть отличное свежее расследование от cloudflare - там ребята искали и фиксили сложный баг в компиляторе arm64 под огромной нагрузкой) или проектирование архитектуры в действительно сложном контексте - вот это заменить будет тяжело.
Но когда-то же LLM научится решать и такие сложные задачи? Я думаю что сейчас единственная возможность заставить LLM работать с такими сложными задачами - очень строгая документация внутри проекта по очень строгим правилам. Например, 10 сервисов общаются между собой. У каждого должна быть дока с подробным и понятным (для модели) описанием того, что делает этот сервис, причем в очень строгом формате. Должны быть прописаны связи, по которым модель может ходить от сервиса к сервису и захватывать весь контекст, и все это должно работать с одними и теми же доменами. Иначе модели просто не хватит памяти и мощности, чтобы весь этот контекст впитать и держать актуальным. А теперь вспомним, сколько сервисов и связей в дейстительно больших проектах, не говоря уже о том, сколько там костылей, неожиданных взаимодействий и какая там документация. Большие компании в ближайшие годы не смогут переписать и документировать свои сервисы так, чтобы LLM решала в них действительно сложные задачи, но и перестанет нанимать инженеров, которые занимались рутинными действиями по перекладыванию ответов в базу и обратно.
dev notes | golang digest
1👍7❤3👾2
This media is not supported in your browser
VIEW IN TELEGRAM
Попробовал еще раз настроить codecompanion - плагин для nvim, который реализует привычный из Cursor и vscode чат с моделью, позволяет работать с агентом и рефакторить код inline в файле.
Предыдущая попытка была где-то полгода назад, и надо сказать - за полгода стало сильно лучше:
- Стало сильно проще конфигурировать и у проекта стала более структурированная и полная дока
- Завезли адаптеры под все известные мне модели
- Добавилась работа с агентским флоу
- Добавилась возможность писать свои плагины и тулзы для запуска в чате, в результате чего комьюнити сразу накрутило множество свистелок, которые привели codecompanion в вид, очень близкий к Cursor
Я как раз начал разрабатывать с нуля небольшой проект, в учебно-статейных целях (к слову о статьях - у меня есть блог - poltora.dev, вдруг кто-то еще не читает) - попробую в его рамках пользоваться только codecompanion и сравнить, насколько ai для nvim стал походить на ai в больших редакторах и можно ли пользоваться только им, не переключаясь на Cursor. Пока первое впечатление хорошее.
Все обновления забросил в публичный конфиг - https://github.com/itxor/go-rust-nvim-config💪
dev notes | golang digest
Предыдущая попытка была где-то полгода назад, и надо сказать - за полгода стало сильно лучше:
- Стало сильно проще конфигурировать и у проекта стала более структурированная и полная дока
- Завезли адаптеры под все известные мне модели
- Добавилась работа с агентским флоу
- Добавилась возможность писать свои плагины и тулзы для запуска в чате, в результате чего комьюнити сразу накрутило множество свистелок, которые привели codecompanion в вид, очень близкий к Cursor
Я как раз начал разрабатывать с нуля небольшой проект, в учебно-статейных целях (к слову о статьях - у меня есть блог - poltora.dev, вдруг кто-то еще не читает) - попробую в его рамках пользоваться только codecompanion и сравнить, насколько ai для nvim стал походить на ai в больших редакторах и можно ли пользоваться только им, не переключаясь на Cursor. Пока первое впечатление хорошее.
Все обновления забросил в публичный конфиг - https://github.com/itxor/go-rust-nvim-config
dev notes | golang digest
Please open Telegram to view this post
VIEW IN TELEGRAM
4❤2🔥2👾2 2
Деплой
Основной нарратив популистов накрутки опыта заключается в оппозиции российскому бигтеху. Я буду считать это оппозицией ко всему российскому IT. Я провел много интервью и всем задавал в конце один и тот же вопрос: сильное ли IT в России и почему? Практически все спикеры ссылались так или иначе на продукты и разработки российского бигтеха для аргументации сильного IT. Значит, все адепты и последователи накрутки это оппозиция сильному IT в России.
Честно, я не подписан на этот канал и подписываться не собирался, но случайно увидел репост.
Автор канала - руководитель разработки в одном из подразделений сбера.
Судя по цитате - автор не умеет строить логические цепочки и вывод из них.
Судя по посту в целом - автор последний раз собеседовался и видел какая дичь с рынком - очень давно.
Как я всегда и везде говорю - не идите работать в конторы типа сбера, яндекса или вк, можно будет очень сильно пожалеть.
Например, какому-нибудь руководителю что-то в вас не понравится, и прямо в офисе вам будут светить лампой в лицо и устраивать допрос (можете поискать последние кейсы с rutube и газпромом)
p.s. Я работал в российском бигтехе и видел, какие бывают конченные собесы и какая там корреляция найма и того, насколько сотрудник эффективно работает.
p.s.s. Я не поддерживаю накрутку опыта и вкатунов, и так как сам веду собесы - отлично умею их ловить; но если кто-то действительно шарит, и добавил себе год опыта к двум имеющимся чтобы пройти абсолютно конченный фильтр на hh - велкоме, будем рады.
Разработчика определяют его навыки, а не количество лет в резюме.
Автор канала - руководитель разработки в одном из подразделений сбера.
Судя по цитате - автор не умеет строить логические цепочки и вывод из них.
Судя по посту в целом - автор последний раз собеседовался и видел какая дичь с рынком - очень давно.
Как я всегда и везде говорю - не идите работать в конторы типа сбера, яндекса или вк, можно будет очень сильно пожалеть.
Например, какому-нибудь руководителю что-то в вас не понравится, и прямо в офисе вам будут светить лампой в лицо и устраивать допрос (можете поискать последние кейсы с rutube и газпромом)
p.s. Я работал в российском бигтехе и видел, какие бывают конченные собесы и какая там корреляция найма и того, насколько сотрудник эффективно работает.
p.s.s. Я не поддерживаю накрутку опыта и вкатунов, и так как сам веду собесы - отлично умею их ловить; но если кто-то действительно шарит, и добавил себе год опыта к двум имеющимся чтобы пройти абсолютно конченный фильтр на hh - велкоме, будем рады.
Разработчика определяют его навыки, а не количество лет в резюме.
2👍9💯4🔥2❤1
Тут сейчас активно обсуждают toon - https://github.com/johannschopplich/toon - либа, которая преобразовывает JSON в более компактный вид в целях экономии токенов при работе с LLM.
Но, есть штука интересней - https://github.com/microsoft/LLMLingua.
LLMLingua сокращает текст промпта без потери смысла, и вот это действительно экономит токены очень хорошо, потому как я обычно общаюсь с моделью не JSON'ом, а текстом.
По заявлению MS компрессия текста от 1.5 до 7 раз, в зависимости от текста и от версии🕺
В readme подробно расписано, как можно ее затестить и посмотреть на результат.
dev notes | golang digest
Но, есть штука интересней - https://github.com/microsoft/LLMLingua.
LLMLingua сокращает текст промпта без потери смысла, и вот это действительно экономит токены очень хорошо, потому как я обычно общаюсь с моделью не JSON'ом, а текстом.
По заявлению MS компрессия текста от 1.5 до 7 раз, в зависимости от текста и от версии
В readme подробно расписано, как можно ее затестить и посмотреть на результат.
dev notes | golang digest
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍8🔥5
Наверное, все уже видели новость про запуск grokipedia.com - аналога википедии от Маска, где все статьи пишет и валидирует Grok.
Думаю, что сейчас лучшее время для запуска такой платформы.
В волне бесоебства вокруг AI, где AI пихают туда, где он вообще не нужен, есть один точно верный тренд - автоматизация и суммаризация поиска. Люди все реже и реже ходят по ссылкам - сильно проще попросить ChatGPT найти информацию, провалидировать ее и выдать в сжатом виде. Даже Google в максимально короткие сроки, что удивительно для такой огромной машины, ввел авто-поиск и поставил его на первое место.
Например, по данным самой википедии человеческие просмотры страниц сократились на 8% год к году
Ресерч от Bain & Company показывает, что в среднем сейчас снижение переходов людьми по ссылкам - порядка 15-25% в целом по информационным ресурсам, так как все больше люди полагаются на выдачу AI.
Grokipedia 100% обгонит Wikipedia, воспользовавшись всеми ее знаниями и ее базой. Потому как читать огромную статью и перейти по 10 ссылкам в процессе, прочитав еще 10 - это долго, а найти, нажать кнопку и получить саммари - быстро.
Думаю, кстати, Wikipedia в ближайшее время добавит себе собственный AI, который будет делать похожие вещи или, хотя бы, сжимать смысл статьи по нажатию на одну кнопку.
dev notes | golang digest
Думаю, что сейчас лучшее время для запуска такой платформы.
В волне бесоебства вокруг AI, где AI пихают туда, где он вообще не нужен, есть один точно верный тренд - автоматизация и суммаризация поиска. Люди все реже и реже ходят по ссылкам - сильно проще попросить ChatGPT найти информацию, провалидировать ее и выдать в сжатом виде. Даже Google в максимально короткие сроки, что удивительно для такой огромной машины, ввел авто-поиск и поставил его на первое место.
Например, по данным самой википедии человеческие просмотры страниц сократились на 8% год к году
Ресерч от Bain & Company показывает, что в среднем сейчас снижение переходов людьми по ссылкам - порядка 15-25% в целом по информационным ресурсам, так как все больше люди полагаются на выдачу AI.
Grokipedia 100% обгонит Wikipedia, воспользовавшись всеми ее знаниями и ее базой. Потому как читать огромную статью и перейти по 10 ссылкам в процессе, прочитав еще 10 - это долго, а найти, нажать кнопку и получить саммари - быстро.
Думаю, кстати, Wikipedia в ближайшее время добавит себе собственный AI, который будет делать похожие вещи или, хотя бы, сжимать смысл статьи по нажатию на одну кнопку.
dev notes | golang digest
Grokipedia
Grokipedia is an open source, comprehensive collection of all knowledge.
1👍5🔥3👾2
В go-блоге вышел очень подробный разбор работы нового garbage collector в Go - Green Tea, который завезли в Go 1.25 - https://go.dev/blog/greenteagc
По утверждениям разрабочиков - оптимизация позволяет выполнять сборку мусора быстрее на 10-40 процентов (правда, не всегда).
В целом - отличная статья с иллюстрациями и объяснением что такое GC в целом и как он работает, а так же за счет чего достигнута опимизация.
Правда, ребята из dolthub недавно попробовали его запустить у себя на проде, и получилось вот это🫤 :
Я у себя на проектах и на работе пока экспериментировать с этим не буду - дождусь бенчмарков и тестов нового GC от других команд.
dev notes | golang digest
По утверждениям разрабочиков - оптимизация позволяет выполнять сборку мусора быстрее на 10-40 процентов (правда, не всегда).
В целом - отличная статья с иллюстрациями и объяснением что такое GC в целом и как он работает, а так же за счет чего достигнута опимизация.
Правда, ребята из dolthub недавно попробовали его запустить у себя на проде, и получилось вот это
For Dolt, the Green Tea collector doesn’t make any difference in real-world performance numbers. Under the hood, it seems that there’s a small regression in mark time, but this isn’t measurable in our latency benchmarks. Based on this result, we won’t be enabling Green Tea for our production builds, but we also aren’t too worried about it becoming the default in a future version of Go.
Я у себя на проектах и на работе пока экспериментировать с этим не буду - дождусь бенчмарков и тестов нового GC от других команд.
dev notes | golang digest
Please open Telegram to view this post
VIEW IN TELEGRAM
go.dev
The Green Tea Garbage Collector - The Go Programming Language
Go 1.25 includes a new experimental garbage collector, Green Tea.
1👍4🔥3😢1
Кен Томпсон - один из создателей Unix, языка программирования C и еще множества вещей, определивших наше настоящее, дал 4-х с половиной часовое интервью, где вспоминал, как это было во времена его работы в The Bell Labs.
Например, его работа над Unix началась после того, как он захотел ускорить чтение и запись на диск в рамках работы над совершенно другим проектом.
Очень нравятся такие истории от буквально кумиров прошлого, которыми я восхищался, когда учился в университете.
Легенда!💪
https://thenewstack.io/ken-thompson-recalls-unixs-rowdy-lock-picking-origins/
dev notes | golang digest
Например, его работа над Unix началась после того, как он захотел ускорить чтение и запись на диск в рамках работы над совершенно другим проектом.
Очень нравятся такие истории от буквально кумиров прошлого, которыми я восхищался, когда учился в университете.
Легенда!
https://thenewstack.io/ken-thompson-recalls-unixs-rowdy-lock-picking-origins/
dev notes | golang digest
Please open Telegram to view this post
VIEW IN TELEGRAM
The New Stack
Ken Thompson Recalls Unix’s Rowdy, Lock-Picking Origins
Ken Thompson's vivid recollection of the rowdy roomful of geeks at Bell Labs who built the digital world in a spirit of open play.
1🔥7❤2
В рамках подготовки одного материала копаюсь в Rust и пытаюсь понять, как он работает и чем отличается от Go в плане работы с памятью.
Ниже решил поделиться одним примером, который без проблем компилируется в Go, и не компилируется в Rust.
Есть код:
Этот код собирается и запускается без ошибок. Что тут происходит: мы объявляем локальный блок со своей областью видимости, где объявляем переменную
Ниже, когда блок с объявлением и копированием завершился - мы разименовываем
Давай теперь напишем тот же код на Rust:
Компилятор поведет себя примерно так:
Ну во-первых, компилятор Rust - мое почтение😎 . Очень подробный анализ ошибок (но это неспроста, ниже объяснение - почему).
А во-вторых, почему мы получили ошибку?
Все дело в базовой концепции работы Go и Rust с памятью. В Go компилятор имеет фазу escape-анализа, которая проверяет код и помечает, на стек или на кучу должна упасть та или иная переменная. Когда компилятор видит, что переменная r принимает значение из локальной области видимости (x) - он перемещает ее на кучу - в общую память процесса, с которой могут работать все потоки.
Затем, в процессе работы программы, параллельно с Go вступает в игру Garbage Collector, который дает нам гарантию, что все такие переменные, даже если мы про них забудем и не удалим их (а мы обычно этого не делаем) - будут освобождены. Скорость разработки в обмен на скорость работы программы.
У Rust нет Garbage Collector, но есть несколько концепций, которые гарантируют, что утечек памяти не будет, и одна из них - это фаза компиляции под названием анализ времени жизни. Именно он видит, что r принимает значение от объекта, время жизни которого закончится раньше, чем будет выведена r - и ругается. В случае с Rust компилятор заставляет разработчика больше думать о коде, но не запускает Garbage Collector. Сложность разработки в обмен на скорость исполнения.
dev notes | golang digest
Ниже решил поделиться одним примером, который без проблем компилируется в Go, и не компилируется в Rust.
Есть код:
func main() {
var r *int
{
x := 5
r = &x
}
fmt.Println(*r)
}
Этот код собирается и запускается без ошибок. Что тут происходит: мы объявляем локальный блок со своей областью видимости, где объявляем переменную
x = 5, и затем копируем ссылку на нее в r.Ниже, когда блок с объявлением и копированием завершился - мы разименовываем
r и выводим значение:
➜ go run main.go
5
Давай теперь напишем тот же код на Rust:
fn main() {
let r;
{
let x = 5;
r = &x;
}
println!("{}", r);
}
Компилятор поведет себя примерно так:
➜ git:(master) ✗ cargo build
Compiling memory v0.1.0 (/Users/poltora.dev/rust/memory)
error[E0597]: `x` does not live long enough
--> src/main.rs:5:13
|
4 | let x = 5;
| - binding `x` declared here
5 | r = &x;
| ^^ borrowed value does not live long enough
6 | }
| - `x` dropped here while still borrowed
7 | println!("r: {}", r);
| - borrow later used here
For more information about this error, try `rustc --explain E0597`.
error: could not compile `memory` (bin "memory") due to 1 previous error
Ну во-первых, компилятор Rust - мое почтение
А во-вторых, почему мы получили ошибку?
Все дело в базовой концепции работы Go и Rust с памятью. В Go компилятор имеет фазу escape-анализа, которая проверяет код и помечает, на стек или на кучу должна упасть та или иная переменная. Когда компилятор видит, что переменная r принимает значение из локальной области видимости (x) - он перемещает ее на кучу - в общую память процесса, с которой могут работать все потоки.
Затем, в процессе работы программы, параллельно с Go вступает в игру Garbage Collector, который дает нам гарантию, что все такие переменные, даже если мы про них забудем и не удалим их (а мы обычно этого не делаем) - будут освобождены. Скорость разработки в обмен на скорость работы программы.
У Rust нет Garbage Collector, но есть несколько концепций, которые гарантируют, что утечек памяти не будет, и одна из них - это фаза компиляции под названием анализ времени жизни. Именно он видит, что r принимает значение от объекта, время жизни которого закончится раньше, чем будет выведена r - и ругается. В случае с Rust компилятор заставляет разработчика больше думать о коде, но не запускает Garbage Collector. Сложность разработки в обмен на скорость исполнения.
dev notes | golang digest
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
dev notes
Пишу про Go, Vim, и про то, как я медленно ползу в сторону FAANG.
Веду @digest_golang
С предложениями: @junsenpub
Веду @digest_golang
С предложениями: @junsenpub
2🔥8👾2👍1
К предыдущей теме про Go, аллокации и сбощик мусора.
Go дает нам легкость написания кода - нам не нужно думать о том, где будет лежать переменная - на стеке или на куче. Как я писал выше, тут есть очевидный минус - процессорное время. Чем сложнее структура данных, тем больше вероятность ее размещения на куче, и тем больше работы будет у garbage collector по сборке мусора.
Тут как раз вышла небольшая заметка от honeycomb по этой теме - https://www.honeycomb.io/blog/how-we-saved-70-cpu-60-memory-refinery
Ребята снизили процессорное время и затраты памяти почти в два раза, просто перестав анмаршалить весь blob в структуру, а разбирая только часть ее полей, и при этом заиспользовали низкоуровневое API tinylib/msgp, чтобы читать типы без аллокаций в памяти.
По-итогу подобная оптимизация позволяет сократить кластер нод почти в два раза без потери производительности.
Для очень хорошей оптимизации иногда не нужно внедрять сложные алгоритмы или параллелить нагрузку - достаточно открыть pprof и посмотреть, сколько аллокаций делает приложение и сколько потом работает GC, чтобы эти аллокации освободить :)
dev notes | golang digest
Go дает нам легкость написания кода - нам не нужно думать о том, где будет лежать переменная - на стеке или на куче. Как я писал выше, тут есть очевидный минус - процессорное время. Чем сложнее структура данных, тем больше вероятность ее размещения на куче, и тем больше работы будет у garbage collector по сборке мусора.
Тут как раз вышла небольшая заметка от honeycomb по этой теме - https://www.honeycomb.io/blog/how-we-saved-70-cpu-60-memory-refinery
Ребята снизили процессорное время и затраты памяти почти в два раза, просто перестав анмаршалить весь blob в структуру, а разбирая только часть ее полей, и при этом заиспользовали низкоуровневое API tinylib/msgp, чтобы читать типы без аллокаций в памяти.
По-итогу подобная оптимизация позволяет сократить кластер нод почти в два раза без потери производительности.
Для очень хорошей оптимизации иногда не нужно внедрять сложные алгоритмы или параллелить нагрузку - достаточно открыть pprof и посмотреть, сколько аллокаций делает приложение и сколько потом работает GC, чтобы эти аллокации освободить :)
dev notes | golang digest
2 7🔥4👍3
Пока копался во внутренностях Go и сравнивал его с Rust, нашел полезное.
Как известно, в Go фаза escape analysis решает, кто и куда будет аллоцирован - в кучу или на стек. Базовое правило простое: живешь в пределах функции - на стек, живешь дольше - на кучу.
И Go, как язык самостоятельный, иногда может решить аллоцировать на кучу то, что мы ожидали на стеке. Плюс в том, что Go сам умеет объяснять, почему он это сделал.
Достаточно запустить build с флагом -m:
И компилятор выдаст подобный листинг:
Что это значит:
-
Иногда достаточно переписать сигнатуру или убрать лишний & - и аллокации исчезают, и это хороший способ выжать из Go больше перфоманса.
dev notes | golang digest
Как известно, в Go фаза escape analysis решает, кто и куда будет аллоцирован - в кучу или на стек. Базовое правило простое: живешь в пределах функции - на стек, живешь дольше - на кучу.
И Go, как язык самостоятельный, иногда может решить аллоцировать на кучу то, что мы ожидали на стеке. Плюс в том, что Go сам умеет объяснять, почему он это сделал.
Достаточно запустить build с флагом -m:
go build -gcflags='-m' ./...
И компилятор выдаст подобный листинг:
./main.go:23:13: &user escapes to heap
./main.go:45:22: moved to heap: buf
Что это значит:
-
escapes to heap - компилятор понял, что значение будет жить дольше функции и положил его в кучу - часто это происходит из-за того, что ты вернул указатель на локальную переменную или замкнул переменную в анонимную функцию:
func outer() func(int) int {
local := 10
return func(x int) int {
return x * local // local уходит в кучу
}
}
Иногда достаточно переписать сигнатуру или убрать лишний & - и аллокации исчезают, и это хороший способ выжать из Go больше перфоманса.
dev notes | golang digest
2👍7🔥3👾2❤1
По итогам 3-х последних сообщений выше и моих разбирательств с тем, как Rust работает с памятью и чем это отличается от работы с памятью в Go - набросал небольшую статью.
Внутри разбор семплов процессора, анализ дампов программы на Go, сравнение ее с дампами программы на Rust и вывод, что работает быстрее, что надежнее, а что удобнее.
Велкоме - https://poltora.dev/rust-vs-go-memory-ru/
dev notes | golang digest
Внутри разбор семплов процессора, анализ дампов программы на Go, сравнение ее с дампами программы на Rust и вывод, что работает быстрее, что надежнее, а что удобнее.
Велкоме - https://poltora.dev/rust-vs-go-memory-ru/
dev notes | golang digest
2❤7 4👍3🔥2
В большинстве проектов, с которыми я работал, обычно используют "дефолтный" тип для uuid-идентификаторов - UUIDv4.
UUIDv4 - это 122 бита чистого рандома, отличный тип для уникального идентификатора. Но, обычно мы работаем с этим типом в базах, часто поле с этим типом помечается как primary key, и минус его в том, что он, при вставке в базу в индексируемом поле, дает хаотичный порядок.
Простыми словами: при вставке в базу UUIDv4 попадает в случайное место индекса, из-за чего таблица постоянно разрывается на куски, индекс разрастается и вставки начинают работать медленее.
Посмотрим на примере с b-tree индексами.
Как работает b-tree:
- индекс - это дерево, в котором данные упорядочены по ключу
- листовые страницы хранят отсортированные значения PK
- новые ключи вставляются так, чтобы порядок сохранялся
Что происходит, когда мы вставляем в индекс UUIDv4:
- новая вставка попадает в происзвольное место середины b-tree
- это чаще провоцирует page split - деление страниц дерева пополам и перенос записей в новую страницу
- это дорогие операции, они увеличивают глубину дерева
Получается, что b-tree, который должен быть плотным и последовательным, превращается в хаотичный набор частично заполненных страниц из-за случайного порядка ключей.
Как это решить? Использовать UUIDv7.
Во-первых, этот тип хранит в себе не только рандомный ключ, но и время:
- первые 48 бит - timestamp
- остальные - рандомный ключ + секвенс, чтобы избежать коллизий
Во-вторых, все значения монотонно возрастают из-за включенного в ключ timestamp.
Что умеет v7, чего не умеет v4:
- когда мы сортируем по uuid - фактически, мы сортируем по времени
- когда мы вставляем в индекс - новые записи всегда будут добавляться в конец b-tree дерева, а не в рандомное место
Получается, что используя UUIDv7 мы автоматически оптимизируем вставку в индекс уменьшая оверхед уменьшением количества page split.
Вывод: используйте UUIDv7, он лучше, стабильней, и можно писать😎
dev notes | golang digest
UUIDv4 - это 122 бита чистого рандома, отличный тип для уникального идентификатора. Но, обычно мы работаем с этим типом в базах, часто поле с этим типом помечается как primary key, и минус его в том, что он, при вставке в базу в индексируемом поле, дает хаотичный порядок.
Простыми словами: при вставке в базу UUIDv4 попадает в случайное место индекса, из-за чего таблица постоянно разрывается на куски, индекс разрастается и вставки начинают работать медленее.
Посмотрим на примере с b-tree индексами.
Как работает b-tree:
- индекс - это дерево, в котором данные упорядочены по ключу
- листовые страницы хранят отсортированные значения PK
- новые ключи вставляются так, чтобы порядок сохранялся
Что происходит, когда мы вставляем в индекс UUIDv4:
- новая вставка попадает в происзвольное место середины b-tree
- это чаще провоцирует page split - деление страниц дерева пополам и перенос записей в новую страницу
- это дорогие операции, они увеличивают глубину дерева
Получается, что b-tree, который должен быть плотным и последовательным, превращается в хаотичный набор частично заполненных страниц из-за случайного порядка ключей.
Как это решить? Использовать UUIDv7.
Во-первых, этот тип хранит в себе не только рандомный ключ, но и время:
- первые 48 бит - timestamp
- остальные - рандомный ключ + секвенс, чтобы избежать коллизий
Во-вторых, все значения монотонно возрастают из-за включенного в ключ timestamp.
Что умеет v7, чего не умеет v4:
- когда мы сортируем по uuid - фактически, мы сортируем по времени
- когда мы вставляем в индекс - новые записи всегда будут добавляться в конец b-tree дерева, а не в рандомное место
Получается, что используя UUIDv7 мы автоматически оптимизируем вставку в индекс уменьшая оверхед уменьшением количества page split.
Вывод: используйте UUIDv7, он лучше, стабильней, и можно писать
order by id desc и получать очень быструю сортировку по времени dev notes | golang digest
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥8 6❤4👍4
Когда-то я активно юзал wakatime - система плагинов для всех известных и неизвестных IDE и редакторов, которая трекает сколько времени ты потратил на разработку. Первое время было фаново, а затем стало больше походить на какой-то инструмент эффективных менеджеров.
Сейчас вот на reddit релизнули нечто похожее, но интересней - плагин triforce для neovim - https://github.com/gisketch/triforce.nvim
Если коротко, он добавляет элементы RPG в процесс написания кода - XP, уровни и достижения. Выглядит очень круто!
Реальной пользы, конечно, маловато, но мне, как человеку который пишет много кода каждый день, любая геймификация в этот процесс заходит очень хорошо❤️
dev notes | golang digest
Сейчас вот на reddit релизнули нечто похожее, но интересней - плагин triforce для neovim - https://github.com/gisketch/triforce.nvim
Если коротко, он добавляет элементы RPG в процесс написания кода - XP, уровни и достижения. Выглядит очень круто!
Реальной пользы, конечно, маловато, но мне, как человеку который пишет много кода каждый день, любая геймификация в этот процесс заходит очень хорошо
dev notes | golang digest
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥8❤4👍4