Я бы не стал относиться к интерфейсам как к "костылю". Просто другой подход, отличный от классического ООП.
В Go нет иерархии типов, вся модель типов плоская. И если хочется иметь несколько типов (Simple, Extended) и какой-то общий для них код, то этот код делается в виде отдельной функции. Если он будет методом одного из типов, то он не сможет работать с другими типами.
И интерфейсы нужны как раз для возможности обобщать, некий аналог утиной типизации.
type Утка interface {
Крякнуть()
}
Про крупные проекты: да, в Go нет кучи возможностей из других языков (неявный вызов деструкторов, наследование, возможность частично переопределить функции базового класса и заставить старые функции неявно использовать новый код, тьюринг-полные макросы, переопределение операторов и возможность получить от них исключение, и т.п.), но смотря на Kubernetes я очень этому рад. Перейдя в любое место программы можно хотя бы понять какой код задействован и как он будет выполняться.
Из толковых материалов: код. Go это не про красивую теорию, Go это про решение проблем.