Pull to refresh

Comments 18

Походу, вы невнимательно прочитали статью. Автор призывает применять интерфейсы в 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 по очевидным причинам есть проблемы с явными обозначениями и проверками контрактов

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

Очень слабое определение (впрочем хорошо что оно вообще есть). Действительно, пусть есть программа, в которой одну конкретную реализацию надо заменить другой, тогда берем и заменяем


Тут, похоже, нужны какие-то ограничения на процент изменяемого кода и т.п. — подобные метрики были бы реально интересны


А то что надо (удобно в перспективе) писать так чтобы легко менялось и дополнялось — это и так все знают

А то что надо (удобно в перспективе) писать так чтобы легко менялось и дополнялось — это и так все знают

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

но большинство не знают как

Вот именно, поэтому определение в статье несодержательное получается, все равно что


Программирование на уровне интерфейса — это спроектировать свою программу так, чтобы не было плохо и было хорошо

Я решил начать с чего-нибудь простого и понятного людям) а дальше попробую развить идею)

Инверсия зависимостей является лишь инструментом программирования на уровне интерфейсов. Это статья скорее направлена на то чтобы люди мыслить начали чуть иначе. А когда захотят имплементить свои идеи, тогда и инверсия зависимостей пригодится

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

я все же придерживаюсь идеи, что "программировать на уровне интерфейсов" это идея, а инверсия зависимостей, это конкретный прием, помогающий воплатить тот или иной интерфейс. Я конечно могу ошибаться :)

Sign up to leave a comment.

Articles