Комментарии 18
Поздравляю, вы только что изобрели API.
:)
Походу, вы невнимательно прочитали статью. Автор призывает применять интерфейсы в JS, что, кстати, не такая уж простая задача, т.к. в JS пока отсутствует инструмент для этого (планируется protocol).
Лично мне это направление мыслей в сообществе нравится - интерфейсы нужны в сложных приложениях. Значит JS дорос до того, чтобы на нём массово создавались сложные приложения.
Кажется, это вы невнимательно прочитали статью.
Автор призывает создавать код с применением хороших абстракций и качественно декомпозировать его.
Для этого не нужны интерфейсы как языковая фича, любой объект имеет интерфейс в абстрактном смысле - это список его доступных публичных методов и полей.
То есть речь как раз про API в широком смысле.
Более того, применение к месту и не к месту протоколов/интерфейсов как языковой фичи может наоборот навредить боилерплейтом.
Мне кажется вы все говорите об одном и том же, только разными словами)
"API в широком смысле" - это правила взаимодействия на межпрограммном уровне (Application Programming Interface). А интерфейсом обладает не только "приложение", но и утюг. Интерфейс - это и есть эта самая "хорошая абстракция" объекта/класса/приложения/утюга. И если есть инструмент для абстрагирования от, то абстрагироваться от значительно проще, чем когда такого инструмента нет.
У меня создалось впечатление, что вы утверждаете, что наличие такого инструмента (выделение интерфейсов на уровне языка - как в typescript, java, php, c, ...) "может навредить бойлерплейтом". Интересная точка зрения.
Вы правы, я невнимательно прочитал статью. Но мне не показалось, что автор "придумал API", о чём я и не преминул заметить. Если же вы аргументировано докажете, что автор в статье всё-таки "придумал API", то я охотно изменю свой мнение и даже извинюсь перед коллегой @Racheengel.
Нет, тут скорее я не прав про API. У API есть строгое определение, я говорил про интерфейс в абстрактном смысле.
По поводу интерфейсов/протоколов/абстрактных классов могу пояснить свою точку зрения. Я говорю с точки зрения C#, Java, Delphi и похожих языков, так как хорошо знаком в основном с ними, но в typescript, к примеру, проблема обстоит так же.
Хорошо спроектированный класс с ограниченной областью видимости реализацией представляет хорошую абстракцию в виде своих публичных методов и полей, по сути сам содержит свой интерфейс.
Даже когда ты используешь этот класс напрямую - его реализация скрыта в нем, класс остается простым снаружи и сложным (или непонятным) внутри, можно изменить детали реализации независимо от потребителей, это и есть сокрытие деталей. Плохо спроектированный класс в общем аналогично содержит абстрактный интерфейс, просто плохой. Если добавить к нему протокол, это не поможет - через плохую абстракцию в протоколе так же будет протекать.
Можно создавать по интерфейсу на каждую связь и каждый класс. Я видел такой код, он ужасен. Это создает много лишнего кода, затрудняет навигацию по классам и понимание кода и не решает никаких проблем, потому что не вводит абстракций. Любое изменение приводит к каскадному изменению класс - интерфейс - класс - интерфейс так же, как если бы это просто были просто использующие один другой классы.
Оправданные причины использования интерфейсов - полиморфизм и управление зависимостями. В этом смысле они работают похоже на абстракции при создании классов, но позволяют задать контракт в потребителе, что очень ценно в библиотеках и развязывании кода бизнес логики от кода реализации.
Ну и нужно понимать, что вообще за весь код придется заплатить когнитивной нагрузкой. Даже за хорошо написанный. Поэтому введение абстракций просто так все же плохая практика - эта абстракция должна что-то упрощать (хотя бы на текущем уровне), разделять или структурировать, иначе эта стоимость будет заплачена просто так.
Я тоже не сторонник лепить на каждый класс отдельный интерфейс (который у него и так есть по факту), но бывают случаи, когда один класс имплементирует несколько интерфейсов. Вот для таких случаев и нужна отдельная конструкция (interface
, а не class
). Про инъекцию зависимостей вы уже упомянули - в ней наиболее ярко отражается смысл интерфейса. Объект декларирует, какой интерфейс он ожидает получить в качестве зависимости (это на PHP пример):
interface IDep1 {}
interface IDep2 {}
class Main {
public function __construct(IDep1 $dep1, IDep2 $dep2) {}
}
В статье хорошо сказано про суть интерфейса - это граница, по которой можно единое разделять на части. Если в приложении есть интерфейсы, как отдельные элементы (interface
), то они указывают на места, в которых одни компоненты могут заменяться другими. Или задают правила, по которым сторонние приложения/модули могут "включаться" в данное приложение.
Для меня "интерфейс" это даже не то, чем обладает какой-то объект (все конкретные программные объекты обладают каким-то интерфейсом), а скорее требования объекта-потребителя к другим, "подключающимся" к нему, объектам, сформулированные максимально абстрактно (набор методов с описанием входных-выходных параметров). То, что вы называете "контрактом". Другими словами, интерфейс - это электрическая розетка в стене, а имплементация - это вилка от утюга. Или два гвоздя прикрученных к проволоке того же утюга - другая имплементация. Если же у нас "монолит", то мы можем утюг напрямую соединить с генератором тока. Это как раз и будет "приложение без интерфейсов".
Это безотносительно интерфейса как языковой фичи, она безусловно очень хороша как способ абстрагирования контракта.
В JS по очевидным причинам есть проблемы с явными обозначениями и проверками контрактов
Программирование на уровне интерфейса — это спроектировать свою программу так, чтобы она не зависела от конкретных реализаций и их можно было заменить на другие в случае необходимости
Очень слабое определение (впрочем хорошо что оно вообще есть). Действительно, пусть есть программа, в которой одну конкретную реализацию надо заменить другой, тогда берем и заменяем
Тут, похоже, нужны какие-то ограничения на процент изменяемого кода и т.п. — подобные метрики были бы реально интересны
А то что надо (удобно в перспективе) писать так чтобы легко менялось и дополнялось — это и так все знают
А то что надо (удобно в перспективе) писать так чтобы легко менялось и дополнялось — это и так все знают
Да все знают, что так надо делать, но большинство не знают как) большинство не знают, как выглядит инверсия зависимости в коде) Поэтому это первая статья из цикла, про то что это важно (следующее видео на эту тему уже опубликовано, а расшифровка опубликуется позже), а немного позже будет и статья полный разбор реальной задачи
но большинство не знают как
Вот именно, поэтому определение в статье несодержательное получается, все равно что
Программирование на уровне интерфейса — это спроектировать свою программу так, чтобы не было плохо и было хорошо
Сабж про букву D в SOLID?
Инверсия зависимостей является лишь инструментом программирования на уровне интерфейсов. Это статья скорее направлена на то чтобы люди мыслить начали чуть иначе. А когда захотят имплементить свои идеи, тогда и инверсия зависимостей пригодится
Инверсия зависимостей - как раз не инструмент, и идея, способ мышления, когда вместо монолита зависящих друг от друга реализаций пишем отдельные, "сферические в вакууме" куски логики.
[js] Программируйте на уровне интерфейсов