Столкнулся с тем, что часто в системах объявляют интерфейсы для каждого класса из слоёв service or repository. Соответственно каждый интерфейс имеет только одну реализацию. Так вот, как мне кажется, это overhead. Хотелось бы узнать о том когда же все таки следует использовать интерфейсы, а точнее стоит ли их использовать вот в таких вот случаях. Возможно, есть какие-то хорошие практики или умные статьи по этому поводу.
Возможно, в разных языках разные практики, интересует ситуация с Java
Проект: средних размеров enterprize монолит с двумя базами, интерфейсы общения с базами никак не пересекаются, тесты - только юнит и спокойно (как мне кажется) можно обходится моками реализаций
Ответ
Не раз встречался с практикой описанной в вопросе, когда например для всех сервисов или DAO объектов или стратегий, независимо от необходимости, создавался интерфейс и его единственная имплементация.
С точки зрения OOP это правильный подход (см. Dependency inversion principle), т.к. в результате модули использующие описываемый интерфейсом функционал не имеют 'design time' зависимости на какую то конкретную имплементацию.
С практической точки зрения интерфейсы, также как и другие возможности языка, нужно использовать только если в этом есть реальная, а не гипотетическая необходимость. В большинстве случаев чем меньше кода, тем лучше. Тем проще разобраться в коде и навигировать по нему, что в свою очередь влияет на скорость разработки, багфиксинга, что в свою очередь влияет на стоимость расширения и поддержки.
Случаи когда использование интерфейсов необходимо уже перечислены в других ответах.
Первый очевиден - необходимость иметь несколько имплементаций.
Второй менее очевиден до тех пор пока в нем не возникает необходимость и специфичен для Java: для поддержки множественного наследования. В Java нет нативной поддержки для этого и единственный выход это имплементация нескольких интерфейсов одним классом.
Одна из псевдопричин использования интерфейсов это возможность подмены имплементаций для организации тестирования. Наверняка есть случаи когда это действительно необходимо. Для большинства же проектов это контр продуктивно, так как создает дополнительные зависимости в коде тестов на конкретные имплементации интерфейсов. Гораздо более эффективно использование зрелого Mock-фреймворка (Mockito и/или PowerMock для Java). Этот подход требует значительно меньше кода и является более гибким и наглядным, т.к. описание поведения реализуемого 'затычкой' :) находится прямо в тесте, а не где то еще, в третьем классе также используемом в 42 других тестах.
Использование интерфейсов добавляет хоть и минимальную, но сложность. В тоже время операция extract interface в современных IDE является стандартной, полностью автоматизированной и занимает секунды, что делает определение интерфейсов "на всякий случай для будущих поколений" бессмысленным.
Комментариев нет:
Отправить комментарий