JavaRush /Курси /Go SELF /Особиста стратегія зростання: портфоліо, код-ревʼю та чит...

Особиста стратегія зростання: портфоліо, код-ревʼю та читання stdlib

Go SELF
Рівень 72 , Лекція 4
Відкрита

1. Портфоліо як вітрина довіри

Портфоліо розробника-початківця часто виглядає так: десять репозиторіїв, у кожному final_final2.go, а в README гордо написано «Мій класний проєкт». На співбесіді це не додає довіри, бо не видно головного: як поводиться ваш код, які в нього контракти і чи можна йому довіряти. Портфоліо — це не про кількість, а про демонстрацію якості.

Уявіть, що ваш проєкт — це маленький прилад. Користувач не зобов’язаний знати, як усередині влаштовані шестерні. Йому важливо, чи вмикається прилад, що показує дисплей, що станеться у разі помилки і чи не зламається він через неправильну кнопку. У програмному забезпеченні «дисплей» — це контракт CLI/HTTP, а «не зламається» — це тести, акуратні помилки й передбачуваність.

Щоб портфоліо мало «форму», корисно тримати в голові трійку: демонстрація → гарантії → відтворюваність. Демонстрація відповідає на запитання «що це робить і навіщо», гарантії — «чому цьому можна довіряти», відтворюваність — «як це запустити й перевірити». У хорошому проєкті це видно за 2–3 хвилини, без режиму археолога.

Мінімальний каркас демо для навчального застосунку

Візьмемо умовний підсумковий проєкт курсу — менеджер задач (нехай називається tasker), у якого є CLI та HTTP API. У демо ви майже завжди показуєте один сценарій успіху і один-два сценарії помилки, але через контракти.

Невеликий фрагмент правильного входу в CLI, який добре виглядає в портфоліо, бо поведінка зосереджена в одному місці й легко пояснюється:


package main

import (
	"os"
)

func main() {
	os.Exit(run(os.Args[1:]))
}

І поруч — точка, де ви свідомо керуєте зовнішнім контрактом CLI: аргументи → код виходу:

package main

import (
	"errors"
	"fmt"
	"os"
)

var ErrUsage = errors.New("використання")

func run(args []string) int {
	if len(args) == 0 {
		fmt.Fprintln(os.Stderr, "використання: tasker <command>")
		return 2
	}
	return 0
}

Це маленький приклад, але він показує зрілість: ви не розкидаєте os.Exit по всьому коду, а тримаєте зовнішній контракт в одному місці.

2. README як інтерфейс проєкту

README — це не твір на тему «як я провів літо з Go». Це інструкція, яка допомагає людині швидко відповісти на чотири запитання: що робить проєкт, як його запустити, як перевірити якість, де подивитися приклади. Якщо README не відповідає на ці запитання, то це не README, а декоративна листівка.

У портфоліо особливо важлива швидкість розуміння: чим швидше людина, яка перевіряє, побачить сигнал «проєкт акуратний», тим більша ймовірність, що вона взагалі читатиме код. Іронія в тому, що хороший README часто важливіший за витончену архітектуру, бо архітектура без читача — це як жарт без аудиторії: автору смішно, решті — тиша.

Хороший прийом — писати README у стилі «quickstart + контракт». Нижче приклад фрагмента, який можна тримати як орієнтир (це текст, але структура важливіша за конкретні слова):

tasker — мінімальний менеджер задач (CLI + HTTP).

Швидкий старт:
  go test ./...
  go run ./cmd/tasker help

Контракт CLI:
  stdout — дані
  stderr — помилки/використання
  коди виходу: 0 — ok, 2 — використання, 1 — виконання

Контракт HTTP:
  JSON, Content-Type: application/json
  помилки: { "error": { "code": "...", "message": "...", "fields": {...} } }

Зверніть увагу: тут немає «ми використали мікросервісну архітектуру з квантовими енумами». Є те, що можна перевірити вручну за хвилину.

Example-тести як частина портфоліо

Звичайний приклад у README швидко старіє. Example-тест компілюється і може перевірятися через go test, тому він є «живим прикладом». Це один із найбільш недооцінених способів показати якість: ви не переконуєте словами — ви показуєте перевірюваний сценарій.

Наприклад, ви хочете, щоб функція парсингу ID була зрозуміла і людині, і тестовому раннеру:

package tasker

import (
	"fmt"
	"strconv"
)

func ExampleParseID() {
	id, err := strconv.Atoi("42")
	fmt.Println(id, err == nil) // 42 true
	// Output: 42 true
}

У портфоліо це працює як маленька гарантія: «я не тільки написав код, я зафіксував поведінку так, що вона не „попливе“».

3. Код-ревʼю як навичка

Код-ревʼю багато новачків сприймають як іспит і думають: «зараз мене сваритимуть». На практиці код-ревʼю — це спосіб зменшити ризик помилок і підвищити якість комунікації. Це спільне проєктування. Іноді воно справді неприємне, але найчастіше неприємне не ревʼю, а відсутність звичок: незрозумілий diff, хаотичні зміни, немає тестів, немає пояснення «навіщо».

Хороша новина: код-ревʼю — це навичка, яку можна прокачувати. Ще краща новина: ви можете почати робити ревʼю вже сьогодні, навіть якщо у вас немає команди, бо існує дієва техніка — саморевʼю. Ви робите PR «для себе», проходите чек якості, і лише потім показуєте його комусь. Це різко знижує кількість зауважень у стилі «Ну, gofmt-то можна було зробити?».

У портфоліо код-ревʼю видно опосередковано: за історією комітів, за тим, наскільки зміни атомарні, за наявністю тестів і за тим, як ви оформлюєте помилки. Навіть якщо ніхто не лишав вам коментарів на GitHub, проєкт може виглядати так, ніби «пройшов ревʼю у досвідченого інженера».

Маленький ритуал саморевʼю на прикладі зміни в tasker

Припустімо, ви додали валідацію заголовка задачі. Поганий варіант часто виглядає так: функція є, помилки різного стилю, тестів немає, а валідація розмазана по трьох шарах.

Акуратна версія починається з маленької функції, яку легко тестувати:

package tasker

import "errors"

var ErrTitleEmpty = errors.New("заголовок порожній")

func ValidateTitle(title string) error {
	if title == "" {
		return ErrTitleEmpty
	}
	return nil
}

Так, це проста функція. Але саме такі речі формують смак до коду: маленькі, читабельні, тестовані шматочки.

І поруч — невеликий табличний тест, який закріплює контракт:

package tasker

import "testing"

func TestValidateTitle(t *testing.T) {
	if err := ValidateTitle(""); err == nil {
		t.Fatalf("очікували помилку")
	}
	if err := ValidateTitle("купити молоко"); err != nil {
		t.Fatalf("неочікувана помилка: %v", err)
	}
}

У ревʼю такий код зазвичай коментують мало. Не тому що він «ідеальний», а тому що він не потребує здогадок.

Чек якості як звичка

Важливо, щоб якість не залежала від настрою («сьогодні я молодець, завтра втомився»). Тому більшість команд перетворюють якість на ритуал. Ви вже знаєте інструменти: форматування, тести, аналізатори. Далі питання не «що запускати», а «як зробити це звичкою».

Тут корисна одна проста думка: чим менше ручних дій, тим вищий шанс, що ви їх справді зробите. Навіть в одиночному проєкті можна завести одну команду, яку ви запускаєте перед пушем. Іноді це роблять через Makefile, іноді через скрипт, іноді через налаштування запуску в IDE — не принципово. Принципово, щоб «перевірити себе» було так само легко, як відкрити браузер і відволіктися.

4. Читання вихідного коду стандартної бібліотеки

Читати вихідний код стандартної бібліотеки звучить як щось, що роблять люди в темних плащах, коли компілятор вередує. Насправді це дуже практична звичка. Стандартна бібліотека Go — це величезний збірник рішень: як оформлювати помилки, як проєктувати API навколо інтерфейсів, як писати код, який житиме роками, і чому простота іноді досягається не магією, а дисципліною.

Читати stdlib треба не з думкою «я зараз усе зрозумію», а з думкою «я зараз зрозумію один невеликий шматок і візьму з нього одну хорошу звичку». Це як спортзал: ви не приходите туди один раз і не стаєте супергероєм. Ви приходите регулярно, і за кілька місяців раптом помічаєте, що ваш код став спокійнішим і чистішим.

Є ще один бонус: коли ви читаєте stdlib, ви перестаєте вірити міфам. Побачили в реальному коді, що помилки обгортають контекстом, що інтерфейси маленькі, що багато уваги до меж вхідних даних, — і магічне мислення починає зникати.

Як знайти вихідні коди пакета

У Go це робиться доволі прямолінійно: у вас є GOROOT, і там лежить стандартна бібліотека. Якщо ви використовуєте IDE, найчастіше можна просто перейти до визначення для net/http або encoding/json і потрапити у вихідний код. Якщо ви любите термінал (або IDE показує шлях), можна орієнтуватися на GOROOT.

Якщо ви хочете «відчути», що Go — це не лише мова, а й інструментальна екосистема, корисно знати, що в команди go багато режимів і файлів навколо проєкту. Наприклад, workspaces (go.work) — один зі способів керувати кількома модулями разом; він не обов’язковий новачку щодня, але сам факт, що це задокументовано й підтримано інструментами, — частина «культури Go».

А ще корисно пам’ятати, що деякі команди — це окремі кроки процесу. Наприклад, go generate існує, але він не «вбудований магічно» у збірку: його потрібно запускати явно, і це принципово для відтворюваності. Навіть якщо ви не використовуєте go generate просто зараз, розуміння цієї філософії допомагає писати проєкти без прихованої магії.

Що читати в stdlib, якщо ви новачок

Не потрібно починати з runtime. Починати краще з пакетів, які ви вже використовували в курсі: errors, fmt, io, bufio, net/http, encoding/json, context, sync. Там ви побачите знайомі ідеї в ідеальній подачі.

Дуже корисна техніка читання: йти від інтерфейсу до реалізації. Спочатку дивитеся, як виглядає контракт (наприклад, io.Reader), потім — хто його реалізує, потім — які обгортки й декоратори навколо нього побудовані. Це повторює наш курс: спочатку контракт, потім реалізація, потім тестованість.

Мініпрактика: декоратор у стилі stdlib

Коли ви читаєте stdlib, особливо пакети навколо io, виникає відчуття: «та вони все загорнули в щось, що реалізує інтерфейс». І це правда: у Go дуже люблять маленькі обгортки, які нічого не ламають, а додають поведінку. Це ідеальне тренування для розвитку: ви вчитеся розширювати систему не переписуванням, а композицією.

Зробімо невеликий крок у нашому tasker: додамо обгортку над io.Writer, яка рахує, скільки байтів ми записали. Це корисно, наприклад, для логів, метрик або тестів, і це рівно той стиль мислення, який ви постійно зустрічатимете в стандартній бібліотеці.

package tasker

import "io"

type CountingWriter struct {
	W io.Writer
	N int
}

func (cw *CountingWriter) Write(p []byte) (int, error) {
	n, err := cw.W.Write(p)
	cw.N += n
	return n, err
}

Тепер ви можете використати це в будь-якому місці, де у вас є writer (stdout, файл, буфер). І це дуже «по-Go»: мінімум магії, максимум прозорості.

Наприклад, ви хочете в CLI порахувати, скільки байтів ви вивели користувачу:

package main

import (
	"fmt"
	"os"

	"example.com/tasker"
)

func main() {
	cw := &tasker.CountingWriter{W: os.Stdout}
	fmt.Fprintln(cw, "hello")   // hello
	fmt.Println("байти:", cw.N) // байти: 6
}

Так, приклад іграшковий. Але він вчить трьох дорослих речей: інтерфейсів, композиції та спостережуваності. І в stdlib таких маленьких «цеглинок» дуже багато — саме тому читання її вихідного коду так добре прокачує мозок.

5. Ритм зростання

Майже всі плани розвитку ламаються об одне й те саме: людина ставить собі ціль «вивчити все», а за тиждень починає ненавидіти і себе, і Go. Щоб не повторювати цю класичну трагікомедію, корисно прийняти просту ідею: розвиток має бути маленьким, регулярним і вимірюваним. Не в сенсі «метрики KPI», а в сенсі «я можу чесно сказати, що зробив крок».

Дуже зручний формат — тижневий ритм, де у вас є кілька повторюваних активностей: трохи покращити проєкт (портфоліо), трохи потренувати ревʼю, трохи почитати хороший код. Важлива не кількість, а стійкість. Якщо ви робите по 20 хвилин, але щотижня — це краще, ніж один «марафон на вихідних» раз на два місяці.

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

Звичка Час Що вважається «зробив»
Мініпокращення проєкту 30–60 хв/тиждень один PR: тест, виправлення багу, маленька фіча
Саморевʼю 10–15 хв/PR прогнав перевірки, перечитав diff
Читання stdlib 20–30 хв/тиждень один файл / одна функція + нотатка
Документація 15 хв/тиждень покращив README або додав Example-тест

Зверніть увагу: тут немає пункту «вивчити Kafka». Не тому що Kafka погана, а тому що без ритму ви не вивчите навіть fmt.Printf — буде лише відчуття провини й вкладка з курсом, відкладена «на потім».

І ще одна важлива думка: стежте за змінами платформи. Go розвивається, інструменти змінюються, з’являються нові дефолти. Наприклад, у Go 1.25 змінилася поведінка GOMAXPROCS у контейнерах: рантайм почав враховувати CPU limits за замовчуванням, щоб уникнути неприємних затримок через throttling. Вам не потрібно просто зараз «глибоко вивчати контейнери», але корисно мати звичку читати такі нотатки й розуміти, що платформа жива.

6. Типові помилки в особистій стратегії зростання

Помилка № 1: робити портфоліо «про кількість», а не «про довіру».
Коли у вас багато репозиторіїв, але жоден не має зрозумілого quickstart, тестів і ясних контрактів, людині, яка перевіряє, важко повірити у ваш рівень. Набагато переконливіше виглядає один проєкт, який запускається з першої спроби, має передбачувані помилки, тести й зрозумілий README.

Помилка № 2: сприймати код-ревʼю як покарання.
Якщо ви чекаєте на ревʼю «як на вирок», ви починаєте ховати зміни, робити їх дрібними й беззмістовними або, навпаки, заливати величезні коміти «поки не передумав». Здорова модель інша: ревʼю — це спільне зниження ризику. Саморевʼю перед відправленням — найкращий спосіб зробити ревʼю спокійним і корисним.

Помилка № 3: читати stdlib як роман і мучитися.
Спроба зрозуміти одразу весь net/http або encoding/json може демотивувати. Набагато ефективніше читати маленькими порціями: один тип, одна функція, один тест. Сенс у накопиченні звички й професійного смаку, а не в разовому подвигу.

Помилка № 4: плутати «знаю» і «можу показати».
На співбесіді та в роботі цінується не те, що ви «приблизно розумієте», а те, що ви можете швидко відтворити: запустити тести, показати демо, пояснити контракт помилок. Тому портфоліо має бути показовим: команди запуску, сценарій і очікуваний результат.

Помилка № 5: покращувати якість «коли буде час».
Якщо якість не вбудована в процес, вона не з’явиться. У якийсь момент проєкт починає жити, баги накопичуються, і ви відкладаєте тести «на потім». Набагато дешевше — маленький ритуал: форматування, тести, статичний аналіз, і вже потім коміт.

1
Опитування
Підсумки курсу, рівень 72, лекція 4
Недоступний
Підсумки курсу
Підсумки курсу
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ