Есть такая утилита в тулчейне Go — go fix. В задачу которой входила модернизация кода под новые конструкции — как в языке, так и в стандартной библиотеке. Эдакий аналог
go fmt который вместо единого стиля, выравнивал использования языковых конструкций по кодобазе. И вроде отличная идея, но с одной проблемой: почти десять лет никто её не поддерживал и не модернизировал. Те сама утилита осталась в далеких временах Go 1.8. Причина подобного довольно тривиальна: нет необходимости в обобщенной модернизации кода, а значит нет и свободных ресурсов под это. Тем более сам go fix был написан с использованием большого числа костылей, которые усложняли любую попытку модернизации.Однако всё изменилось с приходом LLM: модели OpenAI, Anthropic, Alibaba и прочих обучаются на огромных массивах данных в свободном доступе и код генерируют исходя из увиденного. И тут стало понятно: если модели всегда будут учится на старом коде, то и предлагать они будут всегда старые паттерны. Поэтому, недавно вернувшийся в Google, Алан Донован (да-да, тот самый от кого у вас та самая голубая книжка) всерьез озаботился вопросом модернизации кода.
Первый шаг — пускаем старый кода под нож. Полностью.
Второй шаг — это полная переделка команды на основе различных анализаторов из gopls. Которые, в свою очередь, используют фреймворк analysis.
Результат: у нас есть «модернизатор» кода который заменяет «устаревшие» паттерны их современными аналогами.
Приведу несколько примеров. Начиная с 1.26 подъехал новый синтаксис
new который умеет в значения. А модернизатор умеет распознавать где он нужен:
data, err := json.Marshal(&RequestJSON{
URL: url,
Attempts: newInt(10),
})
func newInt(x int) *int { return &x }
Становится
data, err := json.Marshal(&RequestJSON{
URL: url,
Attempts: new(10),
})
Тоже самое касаемо использования конкатенации строк внутри циклов:
s := ""
for _, b := range bytes {
s += fmt.Sprintf("%02x", b)
}
use(s)
Становится
var s strings.Builder
for _, b := range bytes {
s.WriteString(fmt.Sprintf("%02x", b))
}
use(s.String())
Те из коробки мы получаем и более краткий и более производительный код. Еще одна фича, которая доступна ещё и «обычным смертным»: новая аннотация
//go:fix inline которая позволяет проводить inlining функций. Те если go fix встроен в ваш пайплайн, все перестановки произойдут автоматически, что удобно когда у вас был большой рефакторинг и внешних пользователей надо уведомить о новом расположении (или сигнатуре) функций.Сама команда Go Core опубликовала отличные статьи которые показывают паттерны использования нового функционала и внутрянку того, как это работает. Рекомендую к прочтению.