Лучший способ улучшить код — понять и исправить ошибки, сделанные при его написании. В этой уникальной книге проанализированы 100 типичных ошибок и неэффективных приемов в Go-приложениях. Вы научитесь писать идиоматичный и выразительный код на Go, разберете десятки интересных примеров и сценариев и поймете, как обнаружить ошибки и потенциальные ошибки в своих приложениях. Чтобы вам было удобнее работать с книгой, автор разделил методы предотвращения ошибок на несколько категорий, начиная от типов данных и работы со строками и заканчивая конкурентным программированием и тестированием. Для опытных Go-разработчиков, хорошо знакомых с синтаксисом языка.
https://github.com/teivah/100-go-mistakes
Author(s): Тейва Харшани
Series: Для профессионалов
Publisher: Питер
Year: 2024
Language: Russian
Pages: 480
City: СПб.
Tags: go
Краткое содержание
Оглавление
Предисловие
Благодарности
Об этой книге
Для кого эта книга
Структура книги
О коде в книге
Форум liveBook
Об авторе
Иллюстрация на обложке
От издательства
1. Go: просто научиться, но сложно освоить
1.1. Go: основные моменты
1.2. Просто не означает легко
1.3. 100 ошибок в Go
1.3.1. Баги
1.3.2. Излишняя сложность
1.3.3. Плохая читаемость
1.3.4. Неоптимальная или неидиоматическая организация
1.3.5. Отсутствие удобства в API
1.3.6. Неоптимизированный код
1.3.7. Недостаточная производительность
Итоги
2. Организация кода и проекта
2.1. Ошибка #1: непреднамеренно затенять переменные
2.2. Ошибка #2: лишний вложенный код
2.3. Ошибка #3: неправильно использовать функцию инициализации
2.3.1. Концепция
2.3.2. Когда использовать функции init
2.4. Ошибка #4: злоупотреблять геттерами и сеттерами
2.5. Ошибка #5: загрязнять интерфейсы
2.5.1. Концепции
2.5.2. Когда использовать интерфейсы
Общее поведение
Снижение связанности (decoupling)
Ограничение поведения
2.5.3. Загрязнение интерфейса
2.6. Ошибка #6: интерфейсы на стороне производителя
2.7. Ошибка #7: возврат интерфейсов
2.8. Ошибка #8: any не говорит ни о чем
2.9. Ошибка #9: путаница в использовании дженериков
2.9.1. Концепция
2.9.2. Общие случаи использования и злоупотребления
2.10. Ошибка #10: не знать о возможных проблемах со встраиванием типов
2.11. Ошибка #11: не использовать паттерн функциональных опций
2.11.1. Структура Config
2.11.2. Паттерн Строитель
2.11.3. Паттерн функциональных опций
2.12. Ошибка #12: неорганизованность проекта
2.12.1. Структура проекта
2.12.2. Организация пакета
2.13. Ошибка #13: создавать пакеты утилит
2.14. Ошибка #14: игнорировать коллизии имен пакетов
2.15. Ошибка #15: не писать документацию по коду
2.16. Ошибка #16: не использовать линтеры
Итоги
3. Типы данных
3.1. Ошибка #17: путаница с восьмеричными литералами
3.2. Ошибка #18: игнорировать целочисленные переполнения
3.2.1. Концепции
3.2.2. Обнаружение целочисленного переполнения при инкрементировании
3.2.3. Обнаружение целочисленного переполнения при сложении
3.2.4. Обнаружение целочисленного переполнения при умножении
3.3. Ошибка #19: не понимать проблем, связанных с плавающей точкой
3.4. Ошибка #20: не понимать особенностей, связанных с длиной среза и его емкостью
3.5. Ошибка #21: неэффективная инициализация среза
3.6. Ошибка #22: путать пустые и нулевые срезы
3.7. Ошибка #23: неправильно проверять пустоту среза
3.8. Ошибка #24: неправильно создавать копии срезов
3.9. Ошибка #25: неожиданные побочные эффекты при использовании append в операциях со срезами
3.10. Ошибка #26: срезы и утечки памяти
3.10.1. Утечки емкости
3.10.2. Срез и указатели
3.11. Ошибка #27: неэффективно инициализировать карты
3.11.1. Концепции
3.11.2. Инициализация
3.12. Ошибка #28: карты и утечки памяти
3.13. Ошибка #29: некорректное сравнение значений
Итоги
4. Управляющие структуры
4.1. Ошибка #30: игнорировать то, что элементы в цикле range копируются
4.1.1. Концепция
4.1.2. Копия значения
4.2. Ошибка #31: игнорировать то, как в циклах range вычисляются аргументы
4.2.1. Каналы
4.2.2. Массив
4.3. Ошибка #32: игнорировать влияние, которое оказывает использование элементов указателя в циклах range
4.4. Ошибка #33: делать неверные допущения во время итераций карты
4.4.1. Упорядочивание
4.4.2. Вставка карты во время итераций
4.5. Ошибка #34: игнорировать особенности работы оператора break
4.6. Ошибка #35: использовать defer внутри циклов
Итоги
5. Строки
5.1. Ошибка #36: не понимать концепции рун
5.2. Ошибка #37: неточная итерация строк
5.3. Ошибка #38: неправильно использовать функции обрезки
5.4. Ошибка #39: недостаточная степень оптимизации при конкатенации строк
5.5. Ошибка #40: бесполезные преобразования строк
5.6. Ошибка #41: подстроки и утечки памяти
Итоги
6. Функции и методы
6.1. Ошибка #42: не знать, какой тип получателя использовать
6.2. Ошибка #43: не использовать именованные параметры результата
6.3. Ошибка #44: побочные эффекты от именованных параметров результата
6.4. Ошибка #45: возврат получателя nil
6.5. Ошибка #46: использовать имя файла в качестве входных данных функции
6.6. Ошибка #47: игнорировать то, как вычисляются аргументы и получатели оператора defer
6.6.1. Вычисление аргументов
6.6.2. Получатели значений или указателей
Итоги
7. Обработка ошибок
7.1. Ошибка #48: паника
7.2. Ошибка #49: игнорировать оборачивание ошибки
7.3. Ошибка #50: неточная проверка типа ошибки
7.4. Ошибка #51: неточная проверка значения ошибки
7.5. Ошибка #52: двойная обработка ошибки
7.6. Ошибка #53: не выполнять обработку ошибки
7.7. Ошибка #54: не выполнять обработку ошибки оператора defer
Итоги
8. Конкурентность: основы
8.1. Ошибка #55: путать конкурентность и параллелизм
8.2. Ошибка #56: полагать, что конкурентность быстрее
8.2.1. Планирование в Go
8.2.2. Параллельная сортировка слиянием
8.3. Ошибка #57: путаться в том, когда использовать каналы, а когда мьютексы
8.4. Ошибка #58: не понимать проблем гонки
8.4.1. Гонка данных и состояние гонки
8.4.2. Модель памяти Go
8.5. Ошибка #59: не понимать влияние типа рабочей нагрузки на конкурентность
8.6. Ошибка #60: неверно понимать контексты Go
8.6.1. Крайний срок
8.6.2. Сигналы отмены
8.6.3. Значения контекстов
8.6.4. Перехват отмены контекста
Итоги
9. Конкурентность: практика
9.1. Ошибка #61: передавать неподходящий контекст
9.2. Ошибка #62: запускать горутину и не знать, когда ее остановить
9.3. Ошибка #63: неосторожно обращаться с горутинами и переменными цикла
9.4. Ошибка #64: ожидать детерминированное поведение при использовании select и каналов
9.5. Ошибка #65: не использовать каналы уведомлений
9.6. Ошибка #66: не использовать нулевые каналы
9.7. Ошибка #67: гадать насчет размера канала
9.8. Ошибка #68: забывать о возможных побочных эффектах при форматировании строк
9.8.1. Гонка данных в etcd
9.8.2. Взаимоблокировка
9.9. Ошибка #69: создавать ситуацию гонки данных из-за оператора append
9.10. Ошибка #70: неверно использовать мьютексы со срезами и картами
9.11. Ошибка #71: неправильно использовать sync.WaitGroup
9.12. Ошибка #72: забывать о sync.Cond
9.13. Ошибка #73: не использовать errgroup
9.14. Ошибка #74: копировать тип sync
Итоги
10. Стандартная библиотека
10.1. Ошибка #75: неправильно задавать промежуток времени
10.2. Ошибка #76: time.After и утечки памяти
10.3. Ошибка #77: типичные ошибки при обработке JSON
10.3.1. Неожиданное поведение из-за встраивания типов
10.3.2. JSON и монотонные часы
10.3.3. Карта типа any
10.4. Ошибка #78: типичные ошибки, связанные с SQL
10.4.1. Не знать, что sql.Open не всегда устанавливает соединение с базой данных
10.4.2. Забывать о пуле соединений
10.4.3. Не использовать подготовленные операторы
10.4.4. Неправильная обработка нулевых значений
10.4.5. Не обрабатывать ошибки итерации строк
10.5. Ошибка #79: не закрывать временные ресурсы
10.5.1. Тело HTTP
10.5.2. sql.Rows
10.5.3. os.File
10.6. Ошибка #80: забывать об операторе return после ответа на HTTP-запрос
10.7. Ошибка #81: использовать стандартные HTTP-клиент и сервер
10.7.1. HTTP-клиент
10.7.2. HTTP-сервер
Итоги
11. Тестирование
11.1. Ошибка #82: не распределять тесты по категориям
11.1.1. Теги сборки
11.1.2. Переменные среды
11.1.3. Короткий режим
11.2. Ошибка #83: не включать флаг -race
11.3. Ошибка #84: не использовать режимы выполнения тестов
11.3.1. Флаг parallel
11.3.2. Флаг -shuffle
11.4. Ошибка #85: не использовать табличные тесты
11.5. Ошибка #86: задержки в юнит-тестах
11.6. Ошибка #87: неэффективная работа с API времени
11.7. Ошибка #88: не использовать пакеты утилит для тестирования
11.7.1. Пакет httptest
11.7.2. Пакет iotest
11.8. Ошибка #89: писать неточные бенчмарки
11.8.1. Не сбрасывать или не ставить на паузу таймер
11.8.2. Делать неверные предположения о микробенчмарках
11.8.3. Небрежное отношение к оптимизациям компилятора
11.8.4. Эффект наблюдателя
11.9. Ошибка #90: не изучать все возможности тестирования в Go
11.9.1. Покрытие тестами
11.9.2. Тестирование из другого пакета
11.9.3. Вспомогательные функции
11.9.4. Настройка и демонтаж
Итоги
12. Оптимизация
12.1. Ошибка #91: не понимать устройство кэша CPU
12.1.1. Архитектура CPU
12.1.2. Кэш-линия
12.1.3. Срез структур и структура срезов
12.1.4. Предсказуемость
12.1.5. Стратегия размещения кэша
12.2. Ошибка #92: писать конкурентный код, который приводит к ложному совместному использованию
12.3. Ошибка #93: не учитывать параллелизм на уровне инструкций
12.4. Ошибка #94: не знать о выравнивании данных
12.5. Ошибка #95: не понимать различий между стеком и кучей
12.5.1. Стек и куча
12.5.2. Эскейп-анализ
12.6. Ошибка #96: не знать, как сократить число выделений памяти
12.6.1. Изменения API
12.6.2. Приемы оптимизации компилятора
12.6.3. sync.Pool
12.7. Ошибка #97: не полагаться на встраивание
12.8. Ошибка #98: не использовать диагностический инструментарий Go
12.8.1. Профилирование
Запуск pprof
Профилирование CPU
Профилирование кучи
Профилирование горутин
Профилирование блокировок
Профилирование мьютексов
12.8.2. Трассировщик выполнения
12.9. Ошибка #99: не понимать, как работает сборщик мусора
12.9.1. Концепции
12.9.2. Примеры
12.10. Ошибка #100: не понимать особенностей запуска Go внутри Docker и Kubernetes
Итоги
Заключение