Роли, интерфейсы и правила именования

роли и интерфейсы

Я решил написать коротенькую статью на непривычную для этого блога тему. Тема касается интерфейсов, ролей и правил их именования. Дело в том, что современные подходы к написанию кода все больше склоняют нас к настоящему объектно-ориентированному подходу. Это делает и популярный шаблон дизайна Dependency Injection, и TDD, да и вообще модульное тестирование с использованием Mock Objects. Благодаря им дизайн приложения должен напоминать сеть объектов с определенными ролями, которые взаимодействуют между собой по определенным протоколам. Такие приложения относительно легко поддерживать благодаря модульности кода и заложенной тестируемости.

И вот тут появляется очень интересная “проблемка”. Вы создаете интерфейс A и делаете к нему реализацию B. Вам нужно выбрать имена для A и B. Долгое время под воздействием примеров кода для библиотеки Spring многие не задумывались и просто лепили к A суффикс Impl, получая AImpl. Данная практика очень вредна по нескольким причинам. Во-первых код становится “замусоренным” лишней информацией, которая абсолютно ничего в себе не несет. Во-вторых, данный подход позволяет не тратить время на выдумывание правильных доменных имен для классов, что затрудняет понимание дизайна приложения на высоком уровне. В-третьих, нарушается понимание модели “интерфейс -> роль -> реализации”. Ведь если будет еще одна реализация, то как ее выделить по названию? И как по названию понять чем она будет отличаться от AImpl? А что если объект будет играть сразу две роли в приложении (реализовывать два интерфейса)?

В действительности интерфейсов должно быть ровно столько, сколько ролей вы придумали в доменной модели. Причем сама роль не должна включать в себя ничего от возможных реализаций. Этот принцип очень легко проверить. Сделайте интерфейс и подумайте как будет называться реализация, которая видится вам на данный момент. Если вы не можете выдумать ей название и вас тянет приписать суффикс Impl, то это явный признак того, что вам не удалось придумать новую удачную роль. Вернитесь еще раз к интерфейсу и подумайте над ним. Или задумайтесь чем ваша реализация будет выделяться среди возможных других реализаций. Если возможна единственная реализация роли, то роль попросту надумана и вводится только с целью удобства тестирования. А это свидетельствует о плохом дизайне.

В завершение, приведу пример правильной роли. Возьмем InputStream. Представьте себе класс InputStreamImpl. Как он работает? Что от него ожидать? Вам придется каждый раз заглядывать в документацию (если вам повезло и она есть) или лезть в код класса, чтобы понять как он работает. Вместо этого существует множество реализаций с понятными вменяемыми именами: ByteArrayInputStream, ZipInputStream, TelnetInputStream, FixedLengthInputStream и т.д. Да и если посмотреть в код самой библиотеки Spring, то они очень редко пользуется “классическим” именованием с суффиксом Impl. Единственное место, где это использование хоть немного уместно – слой высокоуровневых API сервисов к вашей системе. Просто там по умолчанию c вероятностью 99% будет единственная реализация. Да и то не факт.

Думайте хорошенько при написании кода и ваши усилия многократно окупятся в будущем!

Обсуждение (0)

Leave a Reply

Your email address will not be published. Required fields are marked *