JavaRush /Курсы /Go SELF /Личная стратегия роста: портфолио, код‑ревью и чтение std...

Личная стратегия роста: портфолио, код‑ревью и чтение stdlib

Go SELF
72 уровень , 4 лекция
Открыта

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

Портфолио начинающего разработчика часто выглядит так: десять репозиториев, в каждом final_final2.go, а в README гордо написано “My cool project”. На собеседовании это даёт ноль очков к доверию, потому что не видно главного: как ваш код ведёт себя, какие у него контракты, и можно ли ему верить. Портфолио — это не про количество, а про демонстрацию качества.

Представьте, что ваш проект — это маленький прибор. Пользователь не обязан знать, как внутри устроены шестерёнки. Ему важно: включается ли он, что показывает дисплей, что будет при ошибке, и не взорвётся ли он от неправильной кнопки. В софте “дисплей” — это CLI/HTTP контракт, а “не взорвётся” — это тесты, аккуратные ошибки и предсказуемость.

Чтобы у портфолио была «форма», полезно держать в голове тройку: демо → гарантии → воспроизводимость. Демо отвечает на вопрос «что это делает и зачем», гарантии — «почему этому можно доверять», воспроизводимость — «как это запустить и проверить». В хорошем проекте это видно за 2–3 минуты, не включая режим археолога.

Мини-скелет демо для учебного приложения

Возьмём условный итоговый проект курса — менеджер задач (пусть называется tasker), у которого есть CLI и HTTP API. В демо вы почти всегда показываете одно и то же: happy-path и один-два error-path, но через контракты.

Небольшой фрагмент “правильного” входа в CLI, который хорошо смотрится в портфолио, потому что поведение централизовано и объяснимо:


package main

import (
	"os"
)

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

И рядом — точка, где вы сознательно управляете “внешним контрактом” CLI (аргументы → код выхода):

package main

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

var ErrUsage = errors.New("usage")

func run(args []string) int {
	if len(args) == 0 {
		fmt.Fprintln(os.Stderr, "usage: tasker <command>")
		return 2
	}
	return 0
}

Это маленький пример, но он показывает зрелость: вы не раскидываете os.Exit по всему коду, а держите внешний контракт в одном месте.

2. README как интерфейс проекта

README — это не сочинение на тему «как я провёл лето с Go». Это инструкция, которая помогает человеку быстро ответить на четыре вопроса: что делает проект, как запустить, как проверить качество, где посмотреть примеры. Если README не отвечает на эти вопросы, то это не README, а декоративная открытка.

В портфолио особенно важна «скорость понимания»: чем быстрее проверяющий сможет получить сигнал “проект аккуратный”, тем больше шансов, что он вообще будет читать код. Ирония в том, что хороший README часто важнее изящной архитектуры, потому что архитектура без читателя — это как шутка без аудитории: у автора смешно, у остальных тишина.

Хороший приём — писать README в стиле “quickstart + контракт”. Ниже пример фрагмента, который можно держать как ориентир (это текст, но структура важнее конкретных слов):

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

Quickstart:
  go test ./...
  go run ./cmd/tasker help

CLI contract:
  stdout — данные
  stderr — ошибки/usage
  exit codes: 0 ok, 2 usage, 1 runtime

HTTP contract:
  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. Код‑ревью как навык

Код‑ревью многие новички воспринимают как экзамен: “сейчас меня будут ругать”. На практике код‑ревью — это способ уменьшить риск ошибок и повысить качество коммуникации. Это совместное проектирование. Иногда оно действительно неприятное, но чаще всего неприятно не ревью, а отсутствие привычек: непонятный дифф, хаотичные изменения, нет тестов, нет объяснения “зачем”.

Хорошая новость: код‑ревью — это навык, который прокачивается. Ещё лучшая новость: вы можете начать делать ревью уже сегодня, даже если у вас нет команды, потому что существует мощная техника — саморевью. Вы делаете PR “для себя”, проходите чек качества, и только потом показываете кому-то. Это резко снижает количество замечаний в стиле “ну gofmt-то можно было сделать?”.

В портфолио код‑ревью видно косвенно: по истории коммитов, по тому, насколько изменения атомарны, по наличию тестов и по тому, как вы оформляете ошибки. Даже если никто не оставлял вам комментарии в GitHub, проект может выглядеть как “прошёл ревью у взрослого инженера”.

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

Допустим, вы добавили валидацию заголовка задачи. Плохая версия часто выглядит так: функция “на месте”, ошибки разные по стилю, тестов нет, а валидация размазана по трём слоям.

Аккуратная версия начинается с маленькой функции, которую легко тестировать:

package tasker

import "errors"

var ErrTitleEmpty = errors.New("title is empty")

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

Да, это простая функция. Но именно такие вещи формируют “вкус” к коду: маленькие, читаемые, тестируемые кусочки.

И рядом — маленький table-driven тест, который закрепляет контракт:

package tasker

import "testing"

func TestValidateTitle(t *testing.T) {
	if err := ValidateTitle(""); err == nil {
		t.Fatalf("expected error")
	}
	if err := ValidateTitle("buy milk"); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}

В ревью такой код обычно комментируют мало. Не потому что он “идеальный”, а потому что он не требует догадок.

Чек качества как привычка

Важно, чтобы качество не зависело от настроения (“сегодня я молодец, завтра устал”). Поэтому большинство команд превращают качество в ритуал. Вы уже знаете инструменты: форматирование, тесты, анализаторы. Дальше вопрос не “что запускать”, а “как сделать это привычкой”.

Тут полезна одна простая мысль: чем меньше ручных действий, тем выше шанс, что вы их реально сделаете. Даже в одиночном проекте можно завести одну команду, которую вы запускаете перед пушем. Иногда это делают через Makefile, иногда через скрипт, иногда через IDE-run configuration — не принципиально. Принципиально, чтобы “проверить себя” было так же легко, как открыть браузер и отвлечься.

4. Чтение исходников стандартной библиотеки

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

Читать stdlib нужно не с мыслью “я сейчас всё пойму”, а с мыслью “я сейчас пойму один маленький кусок и украду оттуда одну хорошую привычку”. Это как спортзал: вы не приходите туда один раз и не становитесь супергероем. Вы приходите регулярно, и через пару месяцев внезапно замечаете, что ваш код стал спокойнее и чище.

Есть ещё один бонус: когда вы читаете stdlib, вы перестаёте верить мифам. Увидели в реальном коде, что ошибки оборачивают с контекстом, что интерфейсы маленькие, что много внимания к границам ввода — и всё, “магическое мышление” начинает умирать.

Как найти исходники пакета

В Go это делается довольно прямолинейно: у вас есть GOROOT, и там лежит стандартная библиотека. Если вы используете IDE, чаще всего можно просто “Go to definition” по 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("bytes:", cw.N) // bytes: 6
}

Да, пример игрушечный. Но он учит трём взрослым вещам: интерфейсам, композиции и наблюдаемости. И в stdlib таких маленьких “кирпичиков” очень много — именно поэтому чтение её исходников так хорошо прокачивает мозг.

5. Ритм роста

Почти все планы развития ломаются об одно и то же: человек ставит себе цель “выучить всё”, и через неделю ненавидит себя и Go. Чтобы не повторять эту классическую трагикомедию, полезно принять простую идею: развитие должно быть маленьким, регулярным и измеримым. Не в смысле “метрики KPI”, а в смысле “я могу честно сказать, что сделал шаг”.

Очень удобный формат — недельный ритм, где у вас есть несколько повторяющихся активностей: чуть-чуть улучшить проект (портфолио), чуть-чуть потренировать ревью, чуть-чуть почитать хороший код. Важно не количество, а устойчивость. Если вы делаете по 20 минут, но каждую неделю — это лучше, чем один “марафон на выходных” раз в два месяца.

Ниже пример ритма, который хорошо ложится на реальность, даже если вы учитесь параллельно работе/учёбе:

Привычка Время Что считается “сделал”
Мини-улучшение проекта 30–60 мин/нед один PR: тест, багфикс, мелкая фича
Саморевью 10–15 мин/PR прогнал проверки, перечитал дифф
Чтение stdlib 20–30 мин/нед один файл/одна функция + заметка
Документация 15 мин/нед улучшил README или добавил Example

Обратите внимание: здесь нет пункта “выучить Kafka”. Не потому что Kafka плоха, а потому что без ритма вы не выучите даже fmt.Printf — будет только чувство вины и вкладка с курсом, открытая “на потом”.

И ещё одна важная мысль: следите за изменениями платформы. Go развивается, инструменты меняются, появляются новые дефолты. Например, в Go 1.25 изменилось поведение GOMAXPROCS в контейнерах: рантайм стал учитывать CPU limits по умолчанию, чтобы избежать неприятной троттлинг-латентности. Вам не нужно прямо сейчас “учить контейнеры глубоко”, но полезно иметь привычку читать такие заметки и понимать, что платформа живая.

6. Типичные ошибки в личной стратегии роста

Ошибка №1: делать портфолио “про количество”, а не “про доверие”.
Когда у вас много репозиториев, но ни один не имеет понятного quickstart, тестов и ясных контрактов, проверяющему трудно поверить в ваш уровень. Гораздо сильнее выглядит один проект, который запускается с первой попытки, имеет стабильные ошибки, тесты и понятный README.

Ошибка №2: воспринимать код‑ревью как наказание.
Если вы ждёте ревью “как приговор”, вы начинаете прятать изменения, делать их мелкими и бессмысленными, или наоборот — заливать огромные коммиты “пока не передумал”. Здоровая модель другая: ревью — это совместное снижение риска. Саморевью перед отправкой — лучший способ сделать ревью спокойным и полезным.

Ошибка №3: читать stdlib как роман (и страдать).
Попытка понять сразу весь net/http или encoding/json может демотивировать. Гораздо эффективнее читать маленькими порциями: один тип, одна функция, один тест. Смысл в накоплении привычки и “профессионального вкуса”, а не в разовом подвиге.

Ошибка №4: путать “знаю” и “могу показать”.
На собеседовании и в работе ценится не то, что вы “примерно понимаете”, а то, что вы можете быстро воспроизвести: запустить тесты, показать демо, объяснить контракт ошибок. Поэтому портфолио должно быть демонстрируемым: команды запуска, сценарий, ожидаемый результат.

Ошибка №5: улучшать качество “когда будет время”.
Если качество не встроено в процесс, оно не появится. В какой-то момент проект начинает жить, баги копятся, и вы откладываете тесты “на потом”. Гораздо дешевле — маленький ритуал: форматирование, тесты, статический анализ, и только потом коммит.

1
Задача
Go SELF, 72 уровень, 4 лекция
Недоступна
Диспетчер команд
Диспетчер команд
1
Задача
Go SELF, 72 уровень, 4 лекция
Недоступна
Отчёт ревью
Отчёт ревью
1
Задача
Go SELF, 72 уровень, 4 лекция
Недоступна
Пример поведения
Пример поведения
1
Задача
Go SELF, 72 уровень, 4 лекция
Недоступна
Счётчик записи
Счётчик записи
1
Опрос
Итоги курса, 72 уровень, 4 лекция
Недоступен
Итоги курса
Итоги курса
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ