18/06/2026
“Код повільний” — це ще не діагноз.
Це симптом.
І в цей момент дуже легко почати вгадувати.
Може, проблема в базі.
Може, в JSON.
Може, в циклі у Go-коді.
Може, у новому релізі.
Кожна версія може звучати правдоподібно.
Але без вимірювання всі ці версії однаково слабкі.
Оптимізація починається не з редагування підозрілого місця.
Вона починається з питання:
де саме програма витрачає час або ресурси?
Benchmark допомагає відповісти на одне питання: як поводиться конкретний маленький шматок коду.
Profile відповідає на інше питання: куди реально йде час або пам'ять під час роботи програми.
Це різні питання, тому й інструменти різні.
Пастка в тому, що без вимірювання можна витратити день на оптимізацію, яка майже нічого не змінить.
Переписати цикл, хоча проблема була в запиті до бази.
Прибрати одну алокацію, хоча основний час ішов у мережу.
Додати кеш, хоча причина була в зайвому повторному виклику.
Тому перед тим як прискорювати код, варто спершу знайти місце, яке справді впливає на поведінку програми.
Оптимізуйте не те, що здається підозрілим.
Оптимізуйте те, що підтверджено вимірюванням.
Якщо корисно — підписуйся, буде ще.
29/05/2026
Найнебезпечніший код від AI — не той, який одразу виглядає погано.
З поганим кодом усе простіше.
Він дивний.
Не компілюється.
Ламається на очевидному місці.
Або просто одразу викликає питання.
Найнебезпечніший код від AI — той, який виглядає правильним.
Він може мати нормальні назви.
Чистий стиль.
Логічну структуру.
Впевнене пояснення.
Може навіть пройти базові тести.
І саме через це його легко прийняти занадто швидко.
Але охайний код ще не означає доречне рішення.
Код може виглядати добре і все одно вирішувати трохи не ту задачу.
Може не врахувати важливий edge case.
Може обійти доменне правило, яке не видно з одного файлу.
Може створити технічний борг, який вилізе не сьогодні, а через місяць.
Тому AI-код я б читав не як готову відповідь.
А як сильну чернетку.
Чернетку, яку треба перевірити, приземлити на контекст і пропустити через інженерне мислення.
Питання не в тому, чи код красиво написаний.
Питання в тому, чи він справді вирішує потрібну задачу в нашій системі.
Якщо корисно — підписуйся, буде ще.
27/05/2026
AI може дуже швидко написати код.
Іноді навіть хороший код.
Але є нюанс: він не живе у вашому проєкті.
Він не пам'ятає всі домовленості команди, старі баги, технічні борги і причини, чому деякі речі в системі зроблені саме так.
Контекст — це не тільки файл, який ви показали AI.
Це ще й історія рішень.
Edge cases, які вже ламали production.
Бізнес-правила, які не очевидні з назви функції.
Обмеження інфраструктури.
Домовленості в коді, які команда давно не проговорює вголос, але всі їх враховують.
Саме тому нормальний на вигляд фрагмент коду може бути поганим рішенням для конкретної системи.
Не тому, що AI "дурний".
А тому, що система завжди більша за один запит.
На мій погляд, робота з AI у 2026 — це не просто "прийняти відповідь".
Це більше схоже на парне програмування.
AI швидко пропонує варіант.
А інженер перевіряє, чи цей варіант вписується в реальну систему: у її правила, обмеження, борги і майбутню підтримку.
Ось чому контекст стає однією з головних навичок програміста.
Якщо корисно — підписуйся, буде ще.
25/05/2026
Навіщо вчитись програмуванню у 2026?
Не для того, щоб набирати код швидше за AI.
Цю гру вже немає сенсу вигравати. AI справді може швидко написати функцію, пояснити помилку, накидати структуру пакета або запропонувати кілька варіантів рішення.
І це не треба заперечувати.
Код стало легше отримати.
Але не стало легше зрозуміти, чи цей код доречний.
Бо робочий фрагмент коду і нормальне інженерне рішення — це не одне й те саме.
AI може видати код, який виглядає переконливо. Але він не завжди знає, які домовленості вже є в проєкті, які edge cases боліли минулого місяця, де лежить технічний борг і чому ця частина системи написана саме так.
Ось тут і потрібна база.
Не як набір синтаксису, який треба пам'ятати напам'ять.
А як здатність читати код, бачити припущення, ставити правильні питання і розуміти, що станеться після merge.
На мій погляд, у 2026 програміст — це вже не просто людина, яка руками пише кожен рядок.
Це людина, яка розуміє контекст, перевіряє рішення і відповідає за систему.
Тому вчитись програмуванню все ще потрібно.
Не тому, що AI не вміє писати код.
А тому, що хтось має розуміти, чи цей код взагалі варто запускати.
Якщо корисно — підписуйся, буде ще.
11/05/2026
Помилка, яка нічого не пояснює.
Сьогодні розберемо ситуацію, яка на перший погляд виглядає простою: ви відкриваєте лог і бачите багато помилок з однаковим текстом:
sql: no rows in result set
З цього зрозуміло, що додаток звернувся до бази, але не знайшов очікуваний рядок.
Проблема в іншому: незрозуміло, який саме рядок він шукав і в якій частині коду це сталося.
У проєкті можуть бути GetUser, GetOrder, GetPayment, GetInvoice, GetSubscription. Усі вони ходять у базу і всі можуть повернути ту саму помилку.
І тоді питання вже не "що сказала база?".
База сказала чесно: рядка немає.
Питання інше: яка саме функція не змогла отримати свої дані?
Окремо такий код не здається проблемою.
Але коли зверху прилітає та сама помилка, з неї не видно, для якого id шукали користувача, хто викликав цю функцію і під час якої дії все зламалося.
Ми передали помилку далі, але не передали разом із нею дію, параметри й місце виклику.
У логах лишився технічний факт без прив'язки до конкретної операції.
Цього тижня розберемо, як писати код так, щоб помилка не просто доходила до логів, а допомагала відповісти на два практичні питання: де це сталося і чому.
Помилка без контексту доходить до логів, але не допомагає зрозуміти, що саме сталося.
У вас частіше траплялись помилки, де незрозуміло "що зламалось", чи помилки, де незрозуміло "де саме зламалось"?
Детальніше розбираю такі теми в Telegram — посилання в профілі.
23/04/2026
Запит уже завершився, а goroutine все ще лишилась у процесі.
Для мене це один із найнеприємніших типів багів у Go, бо він часто не виглядає як баг у звичному сенсі.
Нема panic.
Нема зрозумілого stack trace в очі.
Нема моменту, де система "явно впала".
Є інше: кількість goroutine повзе вгору, сервіс поступово деградує, а причина ховається десь у concurrency-логіці.
Один із типових сценаріїв такий:
1. Основний код чекає або результат, або ctx.Done()
2. По timeout чи cancel він завершується
3. Фонова goroutine трохи пізніше доходить до send у канал
4. Receiver уже пішов
5. Sender блокується й лишається висіти
Саме тому я в таких місцях перевіряю не тільки happy path, а й шлях завершення:
- що станеться після cancel;
- хто ще може чекати на канал;
- чи є в goroutine реальний спосіб завершити роботу без вічного блокування.
На мій погляд, корисне базове правило тут просте: якщо goroutine щось чекає або щось відправляє, у неї має бути зрозумілий вихід і для неуспішного сценарію теж.
Саме з таких дрібних на вигляд деталей і складається передбачуваність у Go.
Якщо корисно — підписуйся, буде ще.
19/04/2026
Що виведе цей код з range по каналу?
На перший погляд відповідь очевидна: 1, 2, 3 і кінець.
Саме так багато хто і мислить про range: якщо всі значення вже "віддали", то цикл має просто завершитись.
Але для каналу в Go це працює не так.
Receiver не знає, що sender уже закінчив роботу. Для нього це лише пауза між повідомленнями. Сигнал завершення з'являється тільки тоді, коли канал закрили.
Тому в реальності цей код:
1. Надрукує 1
2. Надрукує 2
3. Надрукує 3
4. І після цього зависне в очікуванні наступного значення
Саме через це range по каналу часто виглядає простішим, ніж є насправді.
Пастка не в самому range.
Пастка в тому, що ми подумки переносимо на канал логіку slice або масиву, де "кінець" визначається автоматично.
У каналу такого "кінця" нема, поки хтось явно не сказав: значень більше не буде.
Практичне правило тут просте: канал закриває той, хто в нього пише. Receiver не повинен вгадувати, коли все завершилось.
На мій погляд, це одна з базових ідей, без яких concurrency в Go починає приносити дуже дивні сюрпризи.
Детальніше розбираю такі теми в Telegram — посилання в профілі.
15/04/2026
Коли select без default у Go уже стає багом?
Це одна з тих ситуацій, де код виглядає дуже акуратно, але поводиться не так, як багато хто інтуїтивно очікує.
Є select.
Є канал із задачами.
Є ctx.Done().
На вигляд усе зібрано правильно.
Але якщо жоден case не готовий і default немає, select просто блокує поточну горутину.
Саме тут і важливо поставити правильне інженерне питання: це блокування в цій точці справді задумане чи ми просто не помітили, що код може зависнути?
Бо одне діло, коли worker чесно чекає нову задачу.
І зовсім інше, коли handler, coordinator або control-loop тихо зупиняється в очікуванні й ви потім довго шукаєте, чому система "ніби жива", але нічого не робить.
На мій погляд, проблема зазвичай не в самому select.
Проблема в тому, що ми не проговорили явно модель очікування:
1. Тут треба чекати безкінечно
2. Тут треба швидко вийти
3. Тут потрібен default
4. Тут потрібен таймаут
Якщо це не визначено явно, дуже легко отримати тихе зависання замість передбачуваної поведінки.
Хочеш більше таких нюансів у Go — заходь у Telegram, посилання в профілі.
13/04/2026
Чому в Go nil інколи не nil?
На практиці це одна з найнеприємніших тем, бо баг виглядає дуже нелогічно.
Ви дивитесь на код і бачите nil.
Функція ніби повертає "помилки нема".
А зовні перевірка err != nil раптом каже, що помилка є.
Саме в цей момент починаєш менше довіряти коду, хоча проблема не в магії мови, а в тому, як ми мислимо про значення в Go.
Дуже часто причина така: всередині interface уже лежить конкретний тип, навіть якщо його значення nil.
Тобто проблема не в самій перевірці:
1. Не в if err != nil
2. Не в логері
3. Не в handler
4. А в тому, що ми повернули не "чистий" nil
Через це в реальному коді з'являються дивні наслідки:
1. Пишуться зайві логи
2. Запускається fallback
3. Ламається очікувана гілка обробки
4. Ви витрачаєте час на дебаг того, що виглядає очевидним
На мій погляд, це одна з найважливіших практичних ідей у Go: якщо функція повертає error, то в гілці "помилки нема" треба повертати саме nil, а не typed nil pointer.
Цього тижня в Telegram якраз розбираю цю тему далі: interface + nil pointer, коли err != nil бреше, реальні приклади багів і як правильно повертати помилки без сюрпризів.
08/04/2026
Що станеться, якщо в Go handler не перевіряє ctx.Done()?
Дуже багато хто інтуїтивно очікує таку поведінку: якщо запит скасовано, значить код теж має автоматично зупинитися.
Але context.Context у Go працює інакше.
cancel() не перериває виконання примусово. Він лише сигналізує: ця робота більше не потрібна. І якщо ваш handler цей сигнал не перевіряє, він спокійно допрацює до кінця.
Саме тут і ховається практична пастка.
Клієнт уже закрив вкладку або таймаут запиту давно сплив, а код усе ще:
1. Робить запит у БД
2. Тримає ресурси
3. Викликає зовнішній сервіс
4. Пише дані, які вже нікому не потрібні
Тобто проблема не в аварійному падінні. Проблема в тихій, зайвій роботі, яка потім вилізає в навантаженні, дивних логах і витрачених ресурсах.
На мій погляд, це одна з найважливіших ідей у Go: context не магія, а домовленість між частинами системи.
Якщо хочете, щоб скасування реально працювало, треба або передавати `ctx` далі в усі залежності, які вміють його поважати, або явно перевіряти ctx.Done() чи ctx.Err() у довгих операціях.
Цього тижня я якраз глибше розбираю тему context у Telegram, бо тут дуже багато дрібних пасток, які красиво виглядають у коді, але боляче б’ють у проді.