dev notes @junsenior Channel on Telegram

dev notes

@junsenior


dev notes (English)

Are you a developer looking for a place to share your notes and insights on programming? Look no further than 'dev notes' Telegram channel, created by the user @junsenior. This channel is a hub for developers of all levels to come together and exchange ideas, tips, and resources to enhance their coding skills. 'dev notes' is not just a channel, it's a community where like-minded individuals can connect and learn from each other. Whether you're a beginner looking to improve your coding basics or an experienced developer wanting to stay updated on the latest trends, 'dev notes' has something for everyone. Join us today and be a part of this vibrant community of developers sharing their passion for coding!

dev notes

12 Jan, 18:24


Попробовал на днях Cursor. Если вдруг кто-то еще не сталкивался, то это среда разработки, построенная на основе Visual Studio Code, куда встроена большая языковая модель, которая умеет держать в контексте открытый проект и дописывать его по запросам.

Ощущения - очень крутые ❤️ Открыл рабочий проект, описал на английском, что я хочу и в каких файлах стоит посмотреть пример, и через 10 минут и еще 3 промпта у Cursor написал столько кода, сколько я писал бы часа 2.
Затем он поправил тесты с учетом функционала, который сам же дописал, и суммарно у меня все все, включая освоение интерфейса, ушло минут 30.
В целом - буду использовать, вероятно даже попробую пробную версию и отпишусь потом, стоит ли она того. Как по мне это сильно круче Copilot от github, которым я пользуюсь уже пару лет.

Что еще на мой взгляд круто - так это возможность обучаться с его помощью. Например, я сейчас фоном учу Rust, и Cursor, помимо того, что умеет писать код, создавая все нужные файлы, умеет еще и описывать что происходит в том или ином файле.
Например, ты можешь попросить его создать новый проект на Rust, взять API какого-нибудь сервиса и интегрироваться с ним. А затем попросить его построчно объяснить, что происходит и какая конструкция за что отвечает.

Cursor обработает до 2000-х тысяч правок в коде бесплатно, затем нужно будет заплатить.

Единственный минус - это ощущение, что вся эта история с нейросетями через 3-5 лет очень сильно поменяет рынок труда 🙂

dev notes

29 Dec, 10:10


Все начали писать про итоги и планы, и я тоже решил написать.

Изначально этот канал назывался "1000 дней программирования", и я вел его с целью показать мой путь от джуна до синьора, отсюда и id канала - @junsenior. 1000 дней прошли пару лет назад и лычка синьора у меня уже тоже давно есть. В целом, за 5 лет с момента первого поста я успел поменять PHP на Go, поработать в российском бигтехе, а потом перейти на валютную удаленку в большую и быстро развивающуюся компанию, в которой работаю уже полтора года.
В 2024-ом году я не сменил язык и работу (что для меня удивительно), но решил много интересных и сложных задач. Например, за год я развернул несколько сервисов с нуля, много работал с параллельным программированием, много строил архитектуру, рефачил большие объемы кода и собеседовал людей.

Но главный результат этого года для меня - у меня появилось понимание того, к чему я хочу стремиться дальше. А дальше я хочу попасть в бигтех, но уже американский. В идеале - MAANG, под которым я понимаю пару десятков самых больших американских тех-компаний. Дедлайн, который я сам себе выставил, - 3 года (если в ближайшие пару лет нас не заменят нейросети, конечно). Получается, новый челлендж в 1000 дней 🙂

Горизонт работы, для того, чтобы хотя бы собеседование в такую компанию стало возможным, прочерчивается через 3 основных вещи, на которые я буду делать упор.
1 - английский. Очевидно, собеседование будет на английском, и хотя я активно его учу последние пару лет, в ближайшее время я хочу повысить как эффективность этого обучения, так и интенсивность, о чем тоже планирую тут писать.
2 - алгоритмы. У меня уже было несколько подходов к алгосам, но каждый раз не хватало мотивации и усидчивости, и обычно я забрасывал это дело через месяц-два. Сейчас у меня есть и мотивация, и понимание как правильно решать алгосы так, чтобы запоминать решение, и купленный курс по алгосам от @tenfoundation :), который я планирую пройти в ближайшие полгода.
3 - system design. Тут в планах начать с курса от balun.courses, который я тоже купил и теперь жду старта 11-ого февраля. В общем и целом system design мне всегда очень нравился, так что тут не ожидаю никаких проблем, ожидаю только массив полезной и крутой инфы.

О каждом из этих пунктов я буду тут писать и делиться тем, что мне кажется интересным. Так же в планах возообновить стримы (да, олдфаги помнят, как года 3-4 назад я уже пытался это делать), и вернуться к менторству, в том числе и на бесплатной основе, о чем я тоже планирую тут написать.

В общем, планы намечены, что делать - тоже понятно. Впереди много работы, и, надеюсь, много контента, которым я тут буду делиться.

Желаю нам всем, чтобы 2025-ый год стал лучше, чем год уходящий. Мира вам, и с наступающим!

dev notes

01 Dec, 22:21


Посмотрел еще один доклад, который долго лежал у меня в закладках, на этот раз про отладку параллельного кода в Go - https://www.youtube.com/watch?v=D_S9qQ7jzkQ

Я последнее время активно юзаю Obsidian для конспектирования любой полезной инфы, и доклад выше не стал исключением. Чтобы эти заметки пылились не только у меня в базе знаний, ниже - конспект интересных моментов и тезисов.

Очевидно, что отладка параллельного кода сильно сложнее, чем отладка последовательного кода, выполняющегося в одном потоке. Самая большая при такой отладке - он часто имеет не повторяющееся поведение при одинаковых входных данных и параметрах железа, где он запускается.

Пакет https://github.com/xiegeo/coloredgoroutine подсвечивает вывод каждой горутины отдельным цветом, что может быть полезно при отладке.

Использование флага GODEBUG=schedtrace позволит вывести отладочную информацию про то, как планировщик управляет горутинами:

➜ GODEBUG=schedtrace=5000 ./main
SCHED 0ms: gomaxprocs=10 idleprocs=8 threads=3 spinningthreads=1 needspinning=0 idlethreads=0 runqueue=1 [0 0 0 0 0 0 0 0 0 0]


Еще один полезный лайфхак для отладки горутин - это добавление в них меток. Например, запускаем код, где поднимаются несколько воркеров:

func main() {
go func() {
// some work...
}()

go func() {
// some work...
}()

go func() {
// some work...
}()


В любом отладчике горутина будет помечена номером, обозначающим порядковый номер, под которым эта горутина запустилась. Но чтобы понять, какой именно воркер соответствует какому именно номеру, можно добавить теги:


func main() {
go func() {
labels := pprof.Labels("fetcher", "main_goroutine")
pprof.Do(ctx, labels, func(ctx context.Context) {
// some work
})
}()

go func() {
labels := pprof.Labels("worker_1", "main_goroutine")
pprof.Do(ctx, labels, func(ctx context.Context) {
// some work
})
}()

go func() {
labels := pprof.Labels("worker_2", "main_goroutine")
pprof.Do(ctx, labels, func(ctx context.Context) {
// some work
})
}()

// ...
}


И затем, в отладчике можно вывести горутину по конкретному тегу:

(dlv) goroutines -l -with label fetcher
Goroutine 21 - User: ./main.go:20 main.main.func1.1 (0x1003befcc) [chan send]
Labels: "fetcher":"main_goroutine"
[1 goroutines]


Хорошая статья, где описывается как это сделать более подробно и где автор показывает ряд других решений для добавления меток в горутины: https://blog.jetbrains.com/go/2020/03/03/how-to-find-goroutines-during-debugging/#using-a-custom-library-to-enable-debugging-labeling

Вторая часть доклада - про deadlock'и и про то, как с ними бороться.
Из полезного, либа, которая помогает найти дедлоки - https://github.com/sasha-s/go-deadlock
К примеру, автор этой библиотеки с помощью нее же нашел потенциальные дедлоки в коде cockroach db: https://github.com/cockroachdb/cockroach/issues/7972

dev notes

24 Nov, 22:55


Посмотрел доклад "Debugging Go Application" от Matt Boyle из Cloudflare

Сначала коротко. Итак, у нас что-то сломалось, что делаем:
* Сначала проанализируй код глазами и удостоверься, что ты не видишь явных ошибок;
* Затем пишем тест на участок кода, который потенциально выдает ошибки и проходимся по нему отладчиком;
* Затем покрываем код логами, если он еще не покрыт;
* Затем добавляем метрики: успешные/не успешные запросы, время запроса, etc
* И последний шаг - покрываем код трейсами, если они еще не были добавлены.

Теперь более подробный конспект деталей, которые мне показались интересными.
Про логирование. В прошлом году в Go завезли расширенный логгер - slog, и если ты все еще по какой-то причине используешь стороннее решение, например logrus, то можно смело переезжать.

В коде, который Мэт демонстрирует, используется паттерн передачи логгера через контекст:

ctx := context.Background()
// Create a logger that writes to the log file
logger := slog.New(slog.NewJSONHandler(logFile, nil))
ctx = slogctx.With(ctx, logger)


Тут же объясняется, почему он его использует: Мэт заметил, что в нескольких opensource-решениях гугла используют такой подход, и раз компания, разработавшая этот язык так делает, разработчики Cloudflare посчитали эту практику хорошей, и со временем стали использовать ее в своих проектах.

Следующий момент - это утилита filebeat. Я ранее про нее не знал, и взял себе на заметку, что это самый простой способ синхронизировать логи из файла с elasticsearch.

Дальше, переходя к секции с трейсингом, Мэт рассказывает про пакет для сбора метрик от VictoriaMetrics - https://github.com/VictoriaMetrics/VictoriaMetrics. В целом выглядит типично для пакетов подобного рода, но в использовании пакет выглядит проще, чем похожий пакет для Datadog, который я использую в своих рабочих проектах.

Если ты ранее никогда не использовал метрики, то Мэт рекомендует для начала мониторить RED-набор метрик:
- Rate
- Error
- Duration

И последняя часть доклада - трейсинг. Трейсинг показывает, где запрос от клиента выполняется дольше всего и какие места мы можем оптимизировать. В демо-проекте трейсы собираются через пакеты от opentelemetry, а визуализируются локально через jaeger.

В целом доклад простой и полезный, особенно полезно, что из коробки в примере Мэта все работает, и можно обратиться к его коду, например, когда понадобится настроить метрики для какого-нибудь пет-проекта.

https://www.youtube.com/watch?v=7YfFBTkGIOI

dev notes

17 Nov, 17:23


Паттерн Circuit Breaker

Сейчас я работаю над приложением с API с нагрузкой в несколько тысяч RPS. Каждый вызов API, помимо прочего, провоцирует запросы во внешние сервисы. Недавно у меня появилась типичная проблема: если внешний сервис перестает отвечать из-за каких-либо ошибок на его стороне, я хочу, чтобы все новые запросы временно прекращали попытки обращаться к нему. Спустя некоторое время, когда внешний сервис вновь заработает, мы снова начнем делать запросы.

Проблема распространенная, я много раз решал ее сам и видел множество сторонних решений. Объединяет их общий принцип: существует глобальный стейт, доступный всем потокам, в который сохраняется статус внешнего сервиса — работает он или лежит. Каждый обработчик, перед вызовом этого сервиса, читает этот статус и принимает решение: делать вызов или нет.
При этом был какой-то обработчик, который опрашивал внешний сервис, и, если тот начинал отвечать, менял глобальный стейт.

Недавно узнал, что у этого паттерна есть название — Circuit Breaker. Общий принцип паттерна я описал выше, за исключением того, что вместо дополнительного обработчика каноничный подход подразумевает, что через определенный промежуток времени “пропускается” несколько запросов, и, если они успешны, глобальный стейт изменяется.

Нашел хорошую статью с примитивной реализацией с нуля и объяснением, что и как работает: https://rednafi.com/go/circuit_breaker/
Хороший пример, который при желании можно доработать и использовать в своих проектах.

dev notes

10 Oct, 20:20


Некоторое время назад я написал большой гайд о том, как настроить neovim с нуля и привести его к виду, пригодному для разработки: с подсветкой синтаксиса, пониманием кода, автокомплитом, и десятком других возможностей, к которым мы привыкли в IDE.

Мотивация у меня простая. Когда я только начинал разбираться в теме, я не видел ни одного гайда, следуя которому я не столкнулся бы с ошибками или в котором все сразу бы заработало. Большинство авторов или упускают множество моментов, или не раскрывают весь контекст, из-за чего новичку тяжело понять, в чем проблема и как ее решить.

Чтобы это исправить, в своей статье я настраивал neovim на чистой тачке, начиная с установки и конфигурирования консоли и заканчивая тем, что редактор стал похож на IDE.

Затем я перевел статью на английский и опубликовал ссылку на нее на различные тематические ресурсы.
И как показывает статистика, в 2024-ом году писать код в консоли все еще кому-то интересно 🙂

Поэтому я дописал вторую часть, где показал как настроить вторую пачку плагинов, которые вместе с первой составляют мой базовый набор: с ним можно без проблем писать код, иметь интеграцию с гитом и большинство привычных возможностей из IDE.

Го читать - https://poltora.dev/neovim-for-developers-2-ru/

dev notes

24 Aug, 21:36


✉️

dev notes

14 Aug, 07:57


Релиз Go 1.23

Самое большое обновление - появились итераторы. В пакеты slices и maps добавлены новые методы для работы с итераторами, например метод Chunk из пакета slices позволяет перебирать слайс пачками из заданного числа элементов:


people := People{
{"Gopher", 13},
{"Alice", 20},
{"Bob", 5},
{"Vera", 24},
{"Zac", 15},
}

for c := range slices.Chunk(people, 2) {
fmt.Println(c)
}


Помимо этого, из интересного, еще сильней оптимизировали PGO, о которых я писал тут. Теперь, за счет более эффективного использования стека, с помощью этих оптимизаций можно бесплатно выиграть еще несколько процентов в потреблении ресурсов и скорости работы приложения.

Ощущения пока, конечно, не однозначные. С одной стороны - итераторы позволят эффективно обрабатывать любую потоковую информацию, с другой стороны очень не хочется, чтобы Go усложнялся в таком же режиме и дальше, выглядит как путь к C++.

dev notes

12 Aug, 05:37


Domain need to be a database agnostic

Продолжаю читать книгу "Go with domains" и учиться строить DDD-приложения.

Ранее я уже писал о двух правилах построения DDD: вся логика должна быть упрощена до типов, которые имеют поведение и всегда держите валидное состояние домена в одном месте.

Дальше автор пишет про третье правило - домен не должен работать с базой данных (будь то реляционная, in-memory или любая другая БД) напрямую.

У нас есть как минимум три причины чтобы следовать этому:
• Домены по определению описывают сущности, связанные с бизнес-логикой, а не с DB-слоем, и их нужно различать.
• Вероятно, мы захотим хранить данные в базе в более оптимальном виде. Например, если в домене у нас есть тип []string, то в DB-слое мы, вероятно, захотим использовать pq.StringArray
• В Go нет ORM-решений и магии в виде аннотаций из коробки, что сильно усложняет интеграцию домена с DB-слоем

И пример хорошего кода на основе всех трех правил:

func (g Server) MakeHourAvailable(ctx context.Context, request *trainer.UpdateHourRequest) (*trainer.EmptyResponse, error) {
trainingTime, err := protoTimestampToTime(request.Time)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "unable to parse time")
}

if err := g.hourRepository.UpdateHour(ctx, trainingTime, func(h *hour.Hour) (*hour.Hour, error) {
if err := h.MakeAvailable(); err != nil {
return nil, err
}

return h, nil
}); err != nil {
return nil, status.Error(codes.Internal, err.Error())
}

return &trainer.EmptyResponse{}, nil
}


В 18 строк тут уместилась логика без изменения домена - она вся инкапсулирована в сам домен. У типа, которым мы оперируем - Hour, есть поведение - MakeAvailable(), которое мы используем. И вся логика работы со слоем базы данных скрыта и так же инкапсулирована с помощью паттерна репозиторий - о котором я расскажу в следующем посте.

dev notes

31 Jul, 03:49


Вчера я писал о первом совете из книги Go with Domains: стоит определять бизнес логику так, как она звучит.

Продолжаем знакомиться с этой книгой, и сегодня хочу написать про второе правило внедрения DDD в приложение: всегда держите валидное состояние в памяти в одном месте.

Это значит, что вся логика работы с доменом должна быть определена в отдельном пакете и скрыта от других пакетов. Менять состояние домена должно только публичное API. Автор также не советует создавать геттеры и сеттеры.

Возвращаясь к нашему примеру с тренажерным залом из вчерашнего поста, инкапсулируем домен Hour:


type Hour struct {
hour time.Time
availability Availability
}

// ...

func NewAvailableHour(hour time.Time) (*Hour, error) {
if err := validateTime(hour); err != nil {
return nil, err
}

return &Hour{
hour: hour,
availability: Available,
}, nil
}


Плохой пример использования этого домена, порождающий большое количество веток условий:


h := hour.NewAvailableHour("13:00")

if h.HasTrainingScheduled() {
h.SetState(hour.Available)
} else {
return some error
}


и хороший пример:


func (h *Hour) CancelTraining() error {
if !h.HasTrainingScheduled() {
return some error
}

h.availability. Available

return nil
}

h := hour.NewAvailableHour("13:00")
if err := h.CancelTraining(); err != nil {
return err
}


Вся работа с доменом - только в пакете с доменом, никакая логика по установке каких-либо состояний не выносится наружу.

dev notes

24 Jul, 05:25


Большинство компаний, особенно относительно больших, сейчас имеют в своей инфраструктуре кубер или его аналоги, внутри которого множество подов обмениваются друг с другом запросами.
Часто под не светит свои порты во внешний мир и сервис в целом не имеет внешнего домена, доступного снаружи.

С опозданием, но теперь и я узнал о команде, которая позволяет бить в закрытые от внешнего мира поды с локальной машины (единственное условие - находиться в той же vpn сети и иметь права на выполнение команды port-forward в кубере), спешу поделиться.
Сначала находим нужный под в нужном окружении:

➜ ~ kubectl get pods -n prod | grep pod_name_prefix


Затем делаем post-forward с порта на найденном поде на наш локальный:

➜ ~ kubectl port-forward pod_full_name -n=prod 7000:7000
➜ ~ Forwarding from 127.0.0.1:7000 -> 7000
➜ ~ Forwarding from [::1]:7000 -> 7000
➜ ~ Handling connection for 7000

И затем в другой вкладке делаем нужный запрос на перенаправленный порт, но уже на нашу локальную машину:

➜ ~ curl -s http://localhost:7000/mypage

И, вуаля, запрос на под, закрытый для внешнего мира, успешно отправлен 🧙

dev notes

22 Jul, 03:32


Я активно уже несколько месяцев веду канал с дайджестом статей по Go: @digest_golang, пробил там первую тысячу и просмотрел за это время огромное количество статей и материалов.
Хочу продублировать сюда несколько интересных статей за последнее время, думаю что кто-то найдет это полезным:

* Generic Concurrency в Go - автор затрагивает тему дженериков и приводит паттерны, по которым их можно использовать в асинхронной работе вместе с горутинами. Дженерики добавили в Go больше года назад, но многие разработчики, исходя из моих наблюдений, все еще не используются ими или боятся их использовать, хотя по-моему, инструмент очень крутой. У меня было несколько кейсов, когда получилось действительно убрать очень много дублирующего кода.
* No sleep until we build the ideal pub/sub library in Go - очень крутой материал, где автор, кстати с использованием дженериков и горутин, что отлично продолжит первую статью, пишет библиотеку для pub/sub. Отличный материал для понимания работы подобных библиотек и для практики работы с многопоточным программированием.
* Hash-Based Bisect Debugging in Compilers and Runtimes - сильно технический, но очень полезный ман о том, как искать и править баги в коде с помощью поиска по бинарному дереву через инструмент Bisect.

dev notes

05 Jun, 04:51


Скорее всего у тебя в проекте, на каком бы языке он не был написан, в корне лежит большой Makefile. На команды, определенные там, часто завязывается ci/cd, через make удобно настраивать локальный запуск проекта.
Например, у меня в компании Makefile с определенными командами - обязательное требование, без которого невозможно поднять новый сервис.
Тема и правда удобная, но есть один большой минус - эти файлы очень плохо читаются и еще сложнее что-то туда добавить. В поисках альтернативы для go-проектов нашел mage - тулза, задача которой убрать сложность чтения и записи make-команд. Решается это с помощью определения тех же команд внутри go-файла, что выглядит, пишется и читается сильно удобней:

//go:build mage

package main

import (
"github.com/magefile/mage/sh"
)

// Runs go mod download and then installs the binary.
func Build() error {
if err := sh.Run("go", "mod", "download"); err != nil {
return err
}
return sh.Run("go", "install", "./...")
}


Каждый метод затем можно вызвать из консоли:

mage -h build


Тулза умеет запускать sh-команды, повторяет большинство флагов и команд, реализованных в make и в целом сделана так, чтобы переход на нее был максимально мягким. Подробная дока - тут

#tools #note

dev notes

02 Jun, 12:30


Открыл для себя google apps script - инструмент, позволяющий работать с инфрой гугла с помощью js-подобного кода и ставить задачи по времени like крон.

Например, задача: вам на почту приходят письма, и некоторые из них - супер важные. Предположим, что как только супер-важное письмо пришло - вам нужно сгенерировать отчет и отправить его заказчику.
При этом тот, кто отправляет письма не хочет и не может заинтегрироваться с вашим api. Тут на помощь приходит apps script.

Задача решается в несколько шагов:
* Сначала подготавливаем http-ручку на нашем бэкенде, вызов которой делает нужную нам работу.
* В моем случае я завел ещё одну почту, куда с помощью фильтров отправил только нужные мне письма, добавив к каждому из них определенный лейбл и пометив его звёздочкой.
* Затем идём на script.google.com и под нужным аккаунтом, почту которого нужно проверять, пишем обработку наших писем:

function checkEmails() {
const threads = GmailApp.search('is:starred label:"my_label"');

for (const thread of threads) {
const messages = thread.getMessages()

for (const message of messages) {
if (!message.isStarred()) {
continue;
}
...

let response = UrlFetchApp.fetch('https://myapi.com/api/test', options);
...

message.unstar()
}
}
}

* Затем в меню настраиваем интервал запуска этой функции, и на этом задача решена.

Плюсы - это быстро, и работать так можно с многими сервисами из инфры гугла.
Минусы - после определенного дневного лимита выполнение функции станет платным, но стоить это будет сильно дешевле, чем сторонние решения.

#tools #note

dev notes

20 May, 17:47


PGO-оптимизации или как бесплатно ускорить приложение

Узнал про интересную возможность бесплатно и очень быстро ускорить go-приложение на ~10%.

В Go 1.20, релиз которого был чуть больше года назад, добавили PGO - новые возможности компилятора оптимизировать приложение на основе его поведения.
В чем идея: с помощью профилировщика снимаем профиль процессора, затем запускаем go build с флагом -pgo и нужным профилем: go build -pgo ./pgo/profile.pprof

Компилятор на основе данных профилировщика понимает, где можно заинлайнить какие-либо данные, где можно предсказать ветвление по входным данным или где можно реорганизовать данные так, чтобы тратить меньше времени на переключение контекста. На выходе мы получаем тот же билд нашего приложения, но на 2-7% быстрее, чем его аналог скомпилированный без этого флага. В определенных случаях для специфических паттернов можно ускорить приложение на 10 и более процентов.
Так, например, ребята из cloudflare сумели такой бесплатной оптимизацией сэкономили 97 ядер из 3000, на которых было запущено приложение. Если перевести 97 ядер в стоимость облачной инфры, получается очень приятная цифра, которую получилось сэкономить за пару минут.

#go #note

dev notes

24 Mar, 19:25


написал большой и подробный ман о том, как с нуля настроить neovim и зачем в 2024 году это нужно
постарался описать все то, чего не хватало мне, когда я погружался в эту тему

го читать

#vim #nvim #article

dev notes

17 Mar, 18:44


Последний год я активно пользуюсь ChatGPT, и хочу поделиться кейсами, как он помогает мне в работе.

Во-первых, SQL. Каждый раз, когда мне нужно написать запрос, будь то запрос на создание таблицы, запрос на select/insert/update, или мне нужно создать индекс - я копирую запрос, копирую структуру таблиц и кидаю в ChatGPT с вопросом "what can be improved in this query". Например, недавно я закинул запрос на создание таблицы в PostgreSQL, где была стандартная история с расширением для UUID:

create extension if not exists "uuid-ossp";
create table if not exists table (
id uuid primary key default uuid_generate_v4(),
...

И помимо всего прочего, ChatGPT посоветовал использовать не uuid-ossp, а pgcrypto, ссылаясь на документацию. Погуглив, я и правда нашел такой совет от разработчиков - https://www.postgresql.org/docs/10/uuid-ossp.html#idm46428633607040. И как правило, таких примеров - очень много. Помимо типов, GPT подсказывает, какие лучше использовать индексы, как лучше назвать поля и как переписать запрос, чтобы он быстрее работал.

Второй кейс - нейминг. Конечно, переменная, модуль или даже проект будут работать, как ты их не назови, но не зря про то, как лучше называть переменные написано много книг. Просто попробуй закинуть в GPT немного контекста и свое название, и 99%, что он подберет название лучше.

Третий кейс - прочитать условие. Что я понимаю под прочтением условий: берем любую строчку, которая из-за множества отрицаний или плохого нейминга никак не хочет интерпретироваться в голове (пример синтетический, но отлично показывает, как оно работает):

if !(!(price <= discount) && !((!(!(quantity >= maxLimit)) || !!(minOrderValue > 100)) && !(price*quantity-discount <= 200))) {
...
}

Кидаем ее в ChatGPT и просим кратко описать, что тут происходит. Даже в случае общения на русском, ответ получился таким:

Таким образом, условие !(!(price <= discount) && !((!(!(quantity >= maxLimit)) || !!(minOrderValue > 100)) && !(price*quantity-discount <= 200))) можно переформулировать так:

Условие выполнено, если цена товара больше скидки, и либо количество товара меньше максимального лимита, либо минимальная стоимость заказа больше 100, и при этом общая стоимость товара (цена умноженная на количество) минус скидка больше 200.

Все еще неприятно, но уже сильно-сильно проще.

Четвертый кейс - переформулировать или сформулировать. На текущей работе мне приходится много писать на английском, а английский у меня далеко не advanced. Как GPT с этим помогает:
* Сначала я прошу его исправить ошибки и опечатки - тут GPT заменяет Grammarly и любые его аналоги.
* Затем копирую что получилось, прошу упростить и перефразировать (более официально, менее официально, опционально можно накинуть любого контекста).
* Уже на этом этапе скорее всего получится сильно лучше, чем было.
* Если результат не устраивает - повторяем алгоритм.

Помимо английского, четвертая версия хорошо научилась работать и с русским: часто, когда нужно что-то сформулировать по обрывкам контекста, а слова в предложения не выстраиваются, GPT с этим отлично помогает. Скорее всего, потом придется попросить его упростить результат или как-то подправить, но основную мысль получится собрать в текст сильно быстрее.

Есть еще множество примеров, с которыми GPT отлично справляется, например, составление регулярок, написание тестов или в целом помощь с тем, чтобы найти ошибку, которую ты найти не можешь. Единственный минус - вызывает привыкание, так что тут нужно не разучиться думать самому 🙂

dev notes

06 Mar, 23:21


реакции есть, так что кто считает, что ему нужна помощь, пишите: @junsenpub

чтобы пост не был из одной строчки, поделюсь еще своими наблюдениями о собеседованиях

я уже давно собеседовал php-разработчиков на разные грейды, и около года как начал собеседовать go-разработчиков на senior и middle позиции

сейчас популярна такая тема, как хак-собеседований: когда ты не готовишься и разбираешься, а учишься умело наебать интервьюера, ответить на его вопросы с помощью чата таких же хакеров, как и ты, и задорно зателеть на работу, на которой потом работать ты, конечно же, не планируешь - только получать деньги
особенно громко таких ребят слышно в твиттере

да, на рынке есть разные неповоротливые конторы, где (если ты конечно как-то к ним пройдешь) в каком-нибудь отделе тебя просто могут не замечать полгода и платить тебе зарплату
но везде, где я работал (а я много где работал) - такая история не прокатила бы и человека уволили бы на испыте одним днем
в минусе от такого увольнения оказывается не компания - у компании постоянный поток кандидатов, и компания вместо него возьмет следующего, а мамких хакер - абсолютное большинство потратит в итоге на поиски компании столько времени, что можно было бы несколько раз подготовиться, получить знания и пройти собес

я разделяю мнение, что типичный собес плохо оценивает тебя как разраба, и скорее всего ты сможешь перекладывать json как бы ты его не прошел
но
мой опыт, как и опыт большого числа компаний показывает, что есть огромная корреляция между тем, насколько хорошо человек проходит собес (если на этом собесе была не только теория, но и задачи, дающие кандидату возможность показать, как он умеет думать), и тем, насколько хорошо он потом будет работать и делать задачи

сейчас риторика апологетов хака собесов стала меняться на "я просто хочу, чтобы на собесе проверяли знания; сейчас все собесы не работают, и мы это доказываем тем, что мы их хакаем"
как я уже сказал выше, если ты и найдешь собес, который можно наебать, то испытательный срок обойти будет сильно сложнее
ну и вседа держи в голове, что основное, что эти апологеты хотят - это бабки, так как все такие чаты платные

какой тут можно сделать вывод: если у тебя совсем нет знаний, и ты решил таким путем быстро получить работу - волшебной кнопки не бывает, и будь готов, что помимо денег за доступ к чату таких же "хакеров", ты еще потратишь очень много нервов, времени и сил на поиск компании, с которой этот номер пройдет
если у тебя уже есть какие-то знания - вероятно, полезней будет посмотреть примеры прохождения собесов на твоем стеке на youtube - это бесплатно, и очень часто совпадает с реальными собесами

dev notes

23 Jan, 19:26


как человек, работающим с докером только в рамках докеризации небольших кусков приложений, открыл для себя крайне интересную вещь
может быть, для многих очевидную, но как показал опрос коллег - мало кто про это знает :)

unionfs - это слоистая файловая система, 1 из 4-х базовых компонентов любого контейнера
почему система называется слоистой? потому что одно действие, например через директиву RUN в Dockerfile - выполняется на одном слое, затем этому слою выдается hash, который в дальнейшем может быть переиспользован на последующих слоях

так вот докер помечает все ранее выполненные слои как read only, и каждая следующая команда не может изменить данные, оставшиеся на слое выше

иначе говоря, если мы пытаемся скачать архив, затем распаковать его, переместить файлы и удалить, и делаем это 4-мя разными командами:
RUN wget https://releases.hashicorp.com/terraform/0.12.28/terraform_0.12.28_linux_amd64.zip
RUN unzip terraform_0.12.28_linux_amd64.zip
RUN rm terraform_0.12.28_linux_amd64.zip
RUN mv terraform /usr/local/bin/


у нас ничего не получится, в таком случае 3-я команда не сможет удалить данные, а 4-ая не сможет их перенести

чтобы все сработало, нужно сделать это в одну команду:
RUN wget https://releases.hashicorp.com/terraform/0.12.28/terraform_0.12.28_linux_amd64.zip \
&& unzip terraform_0.12.28_linux_amd64.zip \
&& rm terraform_0.12.28_linux_amd64.zip \
&& mv terraform /usr/local/bin/

dev notes

13 Dec, 21:42


пожалуй, лучшее объяснение того, как устроены мапы в golang - это доклад Кейта Рэндалла на GopherCon 2016 - https://www.youtube.com/watch?v=Tl7mi9QmLns
Кейт работает в google, занимается райнтаймом языка и точно знает, о чем говорит

ниже - небольшой конспект первой части доклада - устройство мапы в памяти, за деталями и подробностями советую просмотреть сам доклад

мапа - это структура данных, позволяющая хранить данные в формате ключ-значение
простейшая реализация мапы делается в два действия: создаем структуру полем-ключом и полем-значением, и объявляем массив этих структур
какая основная проблема такой реализации? в случае большого объема данных мы теряем в скорости: для поиска конкретного ключа нам нужно перебрать все данные
как решить? разбить данные на несколько групп
например, по алфавиту мы бы могли разбить на 4 группы:
A-F - первая, G-M - вторая, N-S - третья и T-Z - четвертая
возникает другая проблема - данные могут распределиться неравномерно
например, ключи могут быть ссылками, ссылки начинаются с http, и все данные в таком случае улетят у нас во вторую группу
в качестве решения мы можем взять хорошую hash-функцию, которая равномерно сможет распределить данные по группам
в go такие группы называются buckets
один бакет может содержать максимум 8 пар ключ-значение
в случае, если пачка данных не вмещается в один бакет (что решает hash-функция), структура может содержать указатель на дополнительный бакет

когда мы выделяем мапу через var m map[string]float64 m - это указатель
указывает m на область памяти, называемую map header
header хранит указатель на массив с бакетами, информацию о размерности мапы, информацию о количестве бакетов и другую мета-информацию

dev notes

07 Dec, 21:49


открыл для себя тулзу для интеграционного тестирования gonkey - https://github.com/lamoda/gonkey
если коротко, она позволяет поднять в пару строк моки на все внешние сервисы, в интеграции с которыми будет тестироваться приложение, описать сценарии в yaml-файлах, где можно задать нужные фикстуры и указать их порядок, описать ответы на запросы и проверить, что в итоге залетело в базу
затянул на все свои проекты, и крайне рекомендую, если ты пишешь на go

dev notes

06 Dec, 19:50


в golang есть такая интересная вещь, как netpoller - это пакет, который позволяет преобразовать асинхронный ввод/вывод в блокирующий
зачем это нужно?
golang заточен работать под блокирующие вызовы
например, происходит синхронное чтение из файла, горутина блокируется и ждет, пока чтение завершится
планировщик, через 10 мс выбрасывает ее вниз очереди ожидания, и берет в работу другую горутину
с синхронными вызовами все просто и понятно
а что если вызов асинхронный? в go поступили просто - умеем работать с синхронными? значит сделаем из асинхронного синхронный :)
тут в дело вступает netpoller - компонент рантайма, который умеет блокировать горутину, при этом не блокируя текущий поток выполнения
текущий поток выполнения берет в работу новую горутину из очереди, а netpoller тем временем подписывается на API операционной системы, которое работает с асинхронными вызовами
как только API выбросит событие, что ответ получен - netpoller разбудит горутину и сообщит планировщику, что ей нужно выделить процессорное время
после чего планировщик заберет горутину в один из потоков и возьмет ее на выполнение

второй интересный момент из модуля про планировщик - asynchronous preempation
это механизм, добавленный в go 1.14, позволяющий вытеснить горутину, работающую дольше 10 мс, и дать возможность поработать другим горутинам из локальной очереди
да, до версии 1.14 в случае, если мы работали на одном ядре и запускали там горутину с бесконечным циклом - поток блокировался до явного вызова runtime.Gosched()
более подробно, если тебе интересно, про это можно почитать тут - https://habr.com/ru/post/502506/

dev notes

19 Sep, 06:28


в очередной раз все пошло не по плану :)
план, собственно, был описан выше

предприму еще одну попытку оживить тут активность, и в этот раз у меня есть, что писать
несколько недель назад я сменил работу - полностью перешел на golang и теперь пишу только на нем
сейчас вкатываюсь в процессы, смотрю как тут решаются разные задачи и радуюсь красоте этого языка :)

параллельно решил добить все-таки курс от бывшего mail.ru group на coursera, последний раз я остановился на том, что решил легендарную вторую домашку и дальше забил
курс оплачен, отображается (кстати, надолго ли? или coursera решила все-таки оставить уже начатые курсы?), и надеюсь его получится завершить

пока в планах описывать разное полезное с работы касательно go, архитектуры и процессов
собственно, далеко ходить не буду и отвечу на вопросы, которым я задавался когда менял стек: насколько сильно обычная backend-разработка на go отличается от разработки на php, как отличается реальная структура проекта от описанной в golang-layout, как отличаются паттерны описания сервисов и репозиториев от тех, что можно найти в разных статьях на medium и видосах на youtube?

ответ: почти не отличаются
те примеры, что видел я и базовую структуру которых повторял в своих проектах оказались очень похожими на правду, за исключением некоторых субъективных моментов

так что всем страждущим и желающим перейти на go могу однозначно посоветовать следующие ресурсы:
https://www.youtube.com/c/TheArtofDevelopment - хорошие построения базовой структуры rest-приложения, примеры построения ddd-архитектуры и в целом большое количество видосов и автор, умеющий объяснить

https://www.youtube.com/c/MaksimZhashkevych - примеры построения приложений, выделения структуры сервисов, репозиториев и интеграции всего этого вместе

https://github.com/golang-standards/project-layout - пример структуры приложения, де-факто стандарт
на практике многое отсюда заимствуется, что-то пропускается
кто-то считает этот пример плохим и пилит свой
но ознакомится и попробовать точно стоит

dev notes

12 Apr, 08:37


Вообще, посты у меня и так были не часто, а на фоне всего происходящего очень сложно вести канал и поддерживать какую-либо работу.
С одной стороны - это кажется неуместным, и, вероятно, так и есть.
С другой, я попробую продолжить это делать, и надеюсь, кому-то это будет сейчас полезно: любая такая информация это возможность что-то изучить и что-то в последующем поменять.

Немного скажу про то, что я тут пилил пару недель назад в режиме лайвкодинга.
Зрителей было немного, но основная идея - приложение, которое будет отслеживать реальный уровень инфляции. Источников, которые показывали бы всё кристально чисто - я не нашёл.
Смысл такой: каждый день через определённые интервалы времени я набираю одну и ту же продуктовую корзину, и смотрю, насколько изменилась цена за предыдущий день.
Раз в неделю смотрю, как изменилась за неделю.
И раз в месяц финалим стату за 30 дней.
Собственно, софтина готова, кроме ротации проксей, небольшого количества асинхронщины и интеграции с парой крутых либ - особо интересного там ничего нет, поэтому код пока открывать смысла не вижу.
Изначально идея была настроить автопостинг этого в твиттер, но переписка с dev-саппортом твиттера затягивается, поэтому на днях сделаю автопостинг этого в отдельный канал в telegram. Вероятно, кому-то будет интересно посмотреть, что происходит с ценами, и насколько больше/меньше сегодня нужно будет заплатить, чем вчера.
Затем, если будут заинтересованные, может провести несколько сессий по рефакторингу в режиме лайв-кодинга: есть идея прикрутить дженерики, добавить больше асинхронщины и в целом привести всё к божескому виду.