недели
— Go открыт для разработки 1.28
— В Go захотели поддержку GOARM64=v9.6
— Топовые вакансии
— Конференция, которая заканчивается концертом
📍 Навигация: Вакансии • Задачи • Собесы
#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🤔1
Разберут, как превратить AI из инструмента для отдельных задач в часть инженерного процесса
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Proglib.academy | IT-курсы
Для человека это естественная часть работы. У Claude Code этого контекста по умолчанию нет — только задача и инструкции, которые ему дали.
Поэтому в большой команде недостаточно просто выбрать хорошую модель.❗️ Нужно ещё объяснить ей, как у вас устроена разработка: какие подходы приняты, что обязательно проверять и по каким правилам принимать решения.
GenAI Data Platform, и с этой проблемой сталкивался не раз
Покажет живое демо, разберём, как встроить AI в процесс разработки так, чтобы он реально помогал, а не добавлял ещё один повод для споров на ревью.
Please open Telegram to view this post
VIEW IN TELEGRAM
В пакете несколько файлов, и всем нужна одна неэкспортируемая функция. Куда её положить.
Файлы внутри пакета не важны
Область видимости в Go это пакет, а не файл. Все файлы с одним
package foo в одной директории видят функции друг друга, включая приватные. Значит объявляйте общую функцию в любом файле, остальные её увидят без импортов и дублей. Хелперы обычно кладут в файл по смыслу, например parse.go. Свалку utils.go заводить не стоит, держите функции рядом с их сущностью.Если функция нужна нескольким пакетам
Когда приватную логику переиспользуют два и более пакета модуля, используйте
internal:internal/hashing/hashing.go // общий код
api/api.go // импортирует internal/hashing
Пакет в директории
internal импортируют только пакеты из того же поддерева. Функция экспортируется внутри internal/hashing, но снаружи модуля пакет закрыт.📍 Навигация: Вакансии • Задачи • Собесы
#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2🤔1
This media is not supported in your browser
VIEW IN TELEGRAM
AvitoTech Go&Grill в СПб уже ЗАВТРА 🔥
22 июля AvitoTech собирает Go-разработчиков на свой фирменный и максимально кайфовый формат Go&Grill. Ивент будет в баре «Юнион». В программе никакой корпоративной духоты:
— Fast food System Design — в командах соберёте архитектуру для мемного проекта;
— Go-бинго;
— зона для отдыха, бар и, конечно, вкусная еда с гриля!
Ждут Go-разработчиков и тех, кто хочет перейти в Go из другого бэкенд-стрима.
Скорее регистрируйтесь, ссылка еще активна!🤓
22 июля AvitoTech собирает Go-разработчиков на свой фирменный и максимально кайфовый формат Go&Grill. Ивент будет в баре «Юнион». В программе никакой корпоративной духоты:
— Fast food System Design — в командах соберёте архитектуру для мемного проекта;
— Go-бинго;
— зона для отдыха, бар и, конечно, вкусная еда с гриля!
Ждут Go-разработчиков и тех, кто хочет перейти в Go из другого бэкенд-стрима.
Скорее регистрируйтесь, ссылка еще активна!
Please open Telegram to view this post
VIEW IN TELEGRAM
Разработчик Мика Уэйд захостил блог на самом слабом бесплатном Oracle VPS. Это 1/8 ядра CPU и 1 ГБ памяти. Чтобы выжать из такого железа максимум, он написал собственный движок на Go. Ниже про то, почему выбрал Go и что показали замеры.
Автор пишет на Python, поэтому первым делом думал про FastAPI или чистый Python. Но на таком тесном сервере критична каждая крупица производительности, а Python по накладным расходам здесь проигрывает. Hugo отмёл из за опасений по памяти.
В итоге выбор пал на Go, хотя раньше автор на нём не писал. Решающим стало то, как Go и Python по разному управляют памятью.
У Go компактный рантайм и сборщик мусора, который не раздувает потребление на простых нагрузках. Движок собран с нуля. Посты пишутся в Markdown и конвертируются в HTML, примерно как в Hugo.
Голый минимальный Ubuntu с SSH занимал 179 Mi. После запуска приложения через bash скрипт потребление стало даже меньше, 155 Mi. Сам движок настолько лёгкий, что без нагрузки его вклад почти незаметен.
Автор прогнал трафик от 1 до 1000 RPS, по 60 секунд на ступень, около 4% запросов поисковые.
По задержке до 150 RPS ответ стабильно держится около 53 мс. На 300 RPS растёт, но остаётся здоровым. Выше сервер упирается в потолок и начинаются таймауты.
По CPU до 150 RPS движок ест меньше 20% одного ядра из двух доступных. Насыщение наступает между 300 и 500 RPS.
По памяти самое интересное. Потребление держится ровно на 18–19 МБ при низкой и средней нагрузке. Только на 1000 RPS поднимается примерно до 34 МБ с пиками около 50–60 МБ. Для веб приложения под нагрузкой это очень скромно, и здесь как раз виден компактный рантайм Go.
Связка минимального Ubuntu и движка на Go дала стабильные 53 мс и около 18 МБ памяти вплоть до 150 RPS. Хороший аргумент в пользу Go там, где ресурсов почти нет.
📍 Навигация: Вакансии • Задачи • Собесы
#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18😁3❤1
Ниже — бесплатный вебинар о том, как этого избежать ⚠️
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Forwarded from Proglib.academy | IT-курсы
Где-то есть тесты, где-то их забыли. Где-то агент следует архитектуре проекта, где-то предлагает решение, которое с ней не сочетается.
Завтра покажем, как передать AI инженерный контекст команды и не превратить его внедрение в ещё один источник хаоса.
Бесплатно. 60 минут доклада + 30 минут вопросов.
Please open Telegram to view this post
VIEW IN TELEGRAM
😁5⚡1❤1🥱1
Раньше
go fix вспоминали редко. Команда осталась со времён Go 1.0, когда язык менялся часто и код приходилось подтягивать под новые правила. После обещания об обратной совместимости нужда в ней почти отпала, и многие о ней просто забыли. В Go 1.26 её переписали заново, и теперь это инструмент модернизации кода, а не реликт.Как запускать
Команда принимает шаблоны пакетов, как
go build и go vet. Правка всех пакетов ниже текущей директории:go fix ./...
При успехе файлы меняются молча. Правки в сгенерированных файлах команда пропускает, потому что чинить нужно генератор, а не результат. Запускайте из чистого git-состояния, тогда в диффе будут только изменения от
go fix, и ревьюеру будет проще.Посмотреть правки заранее, ничего не меняя, помогает флаг
-diff:go fix -diff ./...
Список доступных анализаторов выводит отдельная команда:
go tool fix help
Можно запросить документацию по конкретному анализатору:
go tool fix help forvar
По умолчанию запускаются все анализаторы. На большом проекте удобнее применять правки по одному анализатору за раз, чтобы ревью не превращалось в кашу. Включить только нужный можно флагом с его именем, например
-any. Наоборот, выключить один и оставить остальные помогает форма -any=false.Правки под новые возможности применяются только в тех файлах, где версия Go достаточно свежая. Ориентир берётся из директивы
go в go.mod или из build-тега вроде //go:build go1.26. Так инструмент не тащит фичи туда, где они ещё не поддерживаются.Пара нюансов
Одна правка иногда открывает дорогу другой. Например,
minmax сначала подставит max, а на втором проходе увидит и min. Поэтому имеет смысл прогнать команду дважды, обычно этого хватает.Изредка встречаются семантические конфликты, когда две независимые правки вместе оставляют неиспользуемую переменную, а это ошибка компиляции в Go. Такие случаи обычно всплывают сразу при сборке, но требуют ручной доработки. Неиспользуемые импорты
go fix при этом убирает сам отдельным проходом.Мы получили команду, которую есть смысл запускать регулярно, а не раз в пятилетку. Хороший момент — сразу после апгрейда тулчейна. Обновите проект до Go 1.26, запустите
go fix ./... из чистого git-состояния и посмотрите на дифф. Заодно можно подтянуть свежие идиомы языка, которые иначе легко пропустить.📍 Навигация: Вакансии • Задачи • Собесы
#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤4
Когда в приложении на Go с GORM появляется поиск по тексту, первым в код обычно попадает
LIKE '%слово%'. На небольшой таблице это терпимо. Дальше начинаются проблемы. Запрос сканирует всю таблицу, не понимает словоформы, чувствителен к регистру, а обычный индекс ему не помогает. В PostgreSQL для таких задач есть встроенный полнотекстовый поиск на
tsvector и tsquery. GORM с ним работает без отдельных библиотек, потому что нужные операторы можно передать внутрь .Where().Как это устроено
Тип
tsvector — это нормализованный набор лексем из текста. Функция to_tsvector приводит слова к основе и выкидывает стоп-слова, поэтому запрос по слову running находит документ со словом run. Тип tsquery описывает сам поисковый запрос. Функция
plainto_tsquery берёт строку от пользователя и превращает её в запрос, безопасно игнорируя спецсимволы вроде & и |. Оператор @@ проверяет, совпадает ли вектор с запросом, и возвращает булево значение.Базовый вариант
Проще всего собрать условие прямо в
.Where(). Модель и функция поиска выглядят так:package main
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type Product struct {
ID uint `gorm:"primaryKey"`
Title string
Description string
}
func SearchProducts(db *gorm.DB, term string) ([]Product, error) {
var products []Product
err := db.Where(
"to_tsvector('english', title || ' ' || description) @@ plainto_tsquery('english', ?)",
term,
).Find(&products).Error
return products, err
}
Здесь
title и description склеиваются в один вектор, а ввод пользователя уходит параметром через ?, так что про SQL-инъекции можно не беспокоиться. Минус подхода в том, что вектор считается заново для каждой строки в момент запроса. Индекс тут не используется, и на большой таблице это становится медленно.Быстрый вариант с отдельным столбцом и GIN-индексом
Чтобы не пересчитывать вектор на лету, его хранят в отдельном столбце и ускоряют индексом типа GIN. Столбец удобно сделать генерируемым, тогда PostgreSQL сам поддерживает его в актуальном состоянии при любой вставке или обновлении.
В модели этот столбец помечается как доступный только для чтения. Тег
-> говорит GORM не пытаться писать в него, ведь значение вычисляет база:type Book struct {
ID uint `gorm:"primaryKey"`
Title string
Description string
SearchVector string `gorm:"->;type:tsvector"`
}Сам генерируемый столбец и индекс создаются сырым SQL после
AutoMigrate, потому что синтаксис генерируемых столбцов GORM через теги не выразит:func InitDatabase(db *gorm.DB) {
db.AutoMigrate(&Book{})
db.Exec(`
ALTER TABLE books
ADD COLUMN IF NOT EXISTS search_vector tsvector
GENERATED ALWAYS AS (
to_tsvector('english', coalesce(title, '')) ||
to_tsvector('english', coalesce(description, ''))
) STORED;
`)
db.Exec(`
CREATE INDEX IF NOT EXISTS idx_books_search_vector
ON books USING gin(search_vector);
`)
}Запрос теперь обращается к готовому столбцу, поэтому нагрузка не растёт вместе с размером таблицы:
func FastSearch(db *gorm.DB, term string) ([]Book, error) {
var results []Book
err := db.Where("search_vector @@ websearch_to_tsquery('english', ?)", term).
Find(&results).Error
return results, err
}Здесь вместо
plainto_tsquery стоит websearch_to_tsquery. Он понимает привычный по поисковикам синтаксис. Кавычки задают точную фразу, а минус перед словом исключает его из выдачи. Для строки поиска от пользователя это обычно удобнее.Что выбрать
Для прототипа или небольшой таблицы хватит базового варианта через
to_tsvector прямо в .Where(). Как только объём данных растёт и поиск начинает тормозить, переходите на генерируемый столбец с GIN-индексом. Логика запроса при этом почти не меняется, а скорость перестаёт зависеть от размера таблицы.📍 Навигация: Вакансии • Задачи • Собесы
#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤2