Проектирование интерфейсов в Go
Вопрос
Расскажите, как вы проектируете интерфейсы в Go-сервисе. Чем подход отличается от Java или C#?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Неявная реализация: интерфейс объявляет потребитель
Маленькие интерфейсы на 1-3 метода, композиция через встраивание (io.ReadWriter)
Принимай интерфейсы, возвращай конкретные типы
Не вводить интерфейс заранее, пока нет второй реализации или потребности в моке
Ловушка nil-интерфейса с typed nil
Стоимость: косвенный вызов, побег значений в кучу
Что могут спросить следом
- Когда всё-таки возвращать интерфейс?
- Как тестировать код, который зависит от внешнего HTTP API?
Разбор
В Go интерфейсы реализуются неявно, поэтому их объявляет тот, кто использует. Сервису заказов нужно получить пользователя: он объявляет type UserGetter interface { Get(ctx, id) (User, error) }, а реализация в пакете базы про это не знает. Интерфейсы держу маленькими, как io.Reader и io.Writer, а большие собираю встраиванием. Функции принимают интерфейсы и возвращают конкретные структуры, чтобы вызывающий получил все методы и мог выбрать нужный ему интерфейс. Интерфейс заранее не ввожу: если реализация одна и мок не нужен, лишняя абстракция только мешает навигации. Исключения, когда возвращаю интерфейс: error, или когда реализаций действительно несколько и они скрыты (например, хранилище в памяти и в базе). Помню про ловушку typed nil при возврате интерфейса и про то, что вызов через интерфейс косвенный и мешает инлайнингу, а значения в интерфейсе часто убегают в кучу. В горячем коде это бывает заметно.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Ещё по теме «Структуры, методы и интерфейсы»
- LRU-кеш на Go: map и двусвязный список
- Очередь с приоритетом через container/heap на Go
- Площади фигур через интерфейс Shape на Go
- Сортировка структур по нескольким ключам на Go
- Что выведет Go: встраивание и вызов метода
- Что выведет Go: интерфейс хранит копию значения
- Что выведет Go: method value и defer копируют ресивер
- Что выведет Go: nil-указатель в интерфейсе error