Interfaces

Начну с самого важного. ВСЕГДА используйте интерфейсы . Ну или хотя бы в большинстве случаев, когда пишете программу или создаёте проект. Чем больше, тем лучше. Интерфейсы — это по большому счёту единственный настолько эффективный инструмент, который будет в вашем арсенале. Это достаточно серьёзное утверждение, и я бы не стал использовать его без полагающегося уважения 🙂

Что и как — это ещё простые вопросы. Выяснить, как всё работает, нетрудно. Непонятный для многих момент кроется в главном вопросе “почему?”. Долгое время у меня было так же. И действительно, почему вы должны захотеть использовать все эти странные штуки?

И вот, что я выяснил в поисках ответов.

1. Абстрактное программирование

Интерфейсы помогут вам сделать кое-что очень важное для процесса разработки классного кода. Они позволят программировать абстрактными методами. Чистая абстракция! Почему вы должны выбрать их, а не путь реализаций? Вот короткий ответ: интерфейс — это наименьшая, тончайшая и минимально сложная вещь, которую вы можете “приклеить” к коду. Надеюсь, вы уже осознаёте, что слабо связанный код — это хорошая идея.

Конечно же, если ваш код вообще не связан с чем-либо, он совсем ничего не сможет выполнить. Код должен быть привязан к чему-то, чтобы обеспечить какую-то полезную функциональность. Поэтому оптимальное решение — идеально несвязанный код. 

Разберёмся в слабо связанном коде, который вам пригодится во многих случаях. Он должен быть связан настолько слабо, насколько это вообще возможно с точки зрения человека. Если вы никогда ни к чему не привязывали код кроме интерфейсов, то это ваш вариант. Оказывается, вы всегда работали с самым слабо связанным кодом, который только может быть.

В конце концов, основная причина, по которой стоит использовать интерфейсы: они обеспечивают очень тонкую, но при этом очень мощную абстракцию вашему коду. Относитесь к своей разработке, как к деталям LEGO: у них есть штырьки с одной стороны и отверстия с другой. Вот с таким слабо привязанным интерфейсом вы можете соединить один любой блок с любым другим и создать всё, что захотите. Было бы очень ограниченно, если бы у красных блоков были отверстия другого размера, чем штырьки зелёных блоков, не правда ли?

Хороший разработчик пишет методами абстракции, а не идёт путём реализаций. Интерфейсы для этого — мощнейший инструмент. 

2. Подключаемые реализации

Если вы программируете методами абстракции, то вы не можете привязываться к конкретной реализации. Интерфейсы позволяют вам связывать классы в очень свободной форме. Их (классы) нужно разрабатывать и тестировать отдельно от внешних зависимостей или же с их минимальным количеством, если невозможна полная изоляция. Они почти всегда зависят хотя бы от чего-то одного как минимум. И, несомненно, когда у вас будет готова толковая библиотека классов, вам понадобится собрать их все вместе, чтобы построить систему, которую вы хотите. Совсем как ребенку, который может построить из кубиков почти всё, что он захочет.

Итак, интерфейс — самый простой и тонкий элемент, от которого может зависеть класс. Мне понравилось связывать код с интерфейсами, я обозначаю это действие метафорой “ухватиться за дым”. Так что, если для вас в приоритете программирование с интерфейсами, то вы в любом случае напишете очень слабо связанный код. И, как мы уже все усвоили, это замечательно. Именно так интерфейсы помогают создавать качественный код. 

Скажу кое-что ещё. Интерфейсы предлагают вам альтернативу реализациям, даже в ходе исполнения кода. Когда вы работаете с интерфейсами, вы можете запросто выбрать ту реализацию, какую хотите и когда хотите. Например, сможете написать вот такой код:

function EncryptSomething(aSuperSecretStuff: any[], aIWantToBeSafe: Boolean) {
  var encryptor: IEncrypt;

  if (aIWantToBeSafe) {
    encryptor = new superDuperPowerfulEncryption();
  } else {
    encryptor = new whoCaresHowSafe();
  }
  encryptor.Encrypt(aSuperSecretStuff);
}

Это простейший пример, но на нём можно убедиться, как интерфейсы могут приносить пользу. У вас может быть один единственный интерфейс и, если понадобится, выбор подходящей реализации во время выполнения. Я бы еще добавил, что если не получится выбрать реализацию при выполнении, значит вы написали слишком сильно связанный код. 

Более практический пример возможен с интерфейсом ICreditCardProcessor: тут показанные на примерах реализации разных кредитных карт основаны на выборе клиента. Можете пользоваться одним интерфейсом ICreditCard, ведь вы не привязаны к конкретной реализации. А так будет проще создать альтернативный выбор среди реализаций. Если хотите добавить новый обработчик кредитных карт, то можете просто реализовать новый класс и добавить его к средствам, которые используете для выбора обработчика. При этом не нужно менять основной код, который обрабатывает кредитные карты. В этом случае уже не важно, какую реализацию вы будете использовать.

Конечно, вы можете считать, что реализация вашего интерфейса самая лучшая, но всегда может появиться и лучший вариант. Возможно, вы захотите в любой момент добавить и эту новую реализацию без радикальных изменений своего кода. С интерфейсами это реально и просто. Вот вам толковое эмпирическое правило:

Перевод: всегда программируйте с интерфейсами и пишите код так, будто бы потом вы напишете еще одну реализацию намного лучше.

3. Межмодульное взаимодействие

У меня есть ещё кое-что для вас! Интерфейсы также хороши для коммуникации между модулями, например, если у вас большая система с разными командами разработчиков, которые работают над важными модулями. Эти команды отвечают за функциональность своих модулей и соответственно за интеграцию и качество кода только своих модулей. 

Допустим, вы в команде разработки виджетов, а надо, чтобы команда спрокетов сделала кое-что для вас. Вы идёте к ним и говорите: “привет, ребята, мне нужно добавить несколько вещей в ваш код так, чтобы мы смогли делать в своём виджете всякие спрокет-штуки.” Думаете, они посмеются над вами, потому что не особо хотят пускать вас в свою продуманную систему?

А вот и нет. Они спросят, что именно вам нужно, создадут функции, вручат вам некоторый код с интерфейсом и шаблоны для примеров реализации этого интерфейса. Они и близко не подпустят вас к своему коду, но зато поделятся интерфейсом, который будет с ним связан. Вы получите, что просили, —  доступ к функциональности другого модуля, а они смогут держать всё остальное в своих руках, не рассказывая вам подробностей. 

И позже, когда они полностью изменят архитектуру своего кода, то вы об этом можете и не узнать. Интерфейс будет работать, даже если они полностью поменяют внутреннюю реализацию. Звучит, как отличный способ разработки — с интерфейсами возможно всё!

4. Тестируемый код

На этом всё ещё не заканчивается. Интерфейсы сделают ваш код также лучше поддающимся тестированию. Помните, мы говорили выше, если вы пользуетесь интерфейсами, то сможете легко заменить любую реализацию? Вот пример: вы проводите тестирование и не хотите подключаться к реальной базе данных? Тогда можно устроить фейковую реализацию своего интерфейса с подключением к базе данных. Оно будет выглядеть как БД и будет возвращать какие-то старые данные. И вот так вы сможете протестировать свой код отдельно без реального подключений к базе данных. 

5. Паттерны

Наконец-то, интерфейсы сделали так, что реализовывать дизайн-паттерны стало проще, как и делать вещи вроде внедрения зависимостей. Большинство новых паттернов и практик, включая фреймворки внедрения зависимости, включены в это благодаря мощности и гибкости интерфейсов. Паттерны разработки и архитектуры, такие как модель-представление-контроллер (MVC) и модель-представление-представление модели (MVVM), более просты в реализации и применении благодаря интерфейсам. 

Заключение

Если вы решаете не использовать интерфейсы, то также откажетесь и от новых и эффективных программных фреймворков и методов. Всё еще не убедились? Скажу иначе: все крутые программисты создают интерфейсы, а вы ведь хотите быть крутым разработчиком, верно?

Спасибо, что прочли! 

Надеюсь, было полезно!

Читайте также:


Перевод статьи Nick Hodges: 5 Reasons Why You Should Be Coding With Interfaces