Что такое интерфейс в программировании
Перейти к содержимому

Что такое интерфейс в программировании

  • автор:

Лекция №21 Интерфейсы в программировании

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

Интерфейс — ключевое понятие в задаче интеграции. При разработке любой программы непременно приходится использовать «чужие» компоненты, такие как встроенная библиотека типов и стандартных функций или сторонние библиотеки. Более сложные приложения могут сами состоять из многих компонентов, которые надо интегрировать между собой; зачастую эта задача усложняется тем, что взаимодействующие модули написаны на различных языках программирования и функционируют в различных операционных средах.

Выделяют две категории программных интерфейсов:

  • API (application programming interface) описывает принципы взаимодействия на уровне исходного кода приложений. Пример такого описания — декларации структур данных и функций (или объектов / классов в ООП).
  • ABI (application binary interface) специфицирует взаимодействие на уровне машинного кода. Например, ABI может задавать особенности вызова функций (размещение операндов в стеке / регистрах), размеры базовых типов данных и тому подобное.

Языки программирования высокого уровня (Java, Python, C#) скрывают от разработчиков пользовательских приложений особенности ABI, перекладывая ответственность за соблюдение стандартов на компилятор или интерпретатор языка. С другой стороны, роль ABI чрезвычайно велика при написании системных программ.

Интерфейсы могут использоваться как в пределах одного языка программирования, так и при интеграции модулей, реализованных на различных языках. Самый базовый тип интерфейсов первого рода — описание функций и типов данных. В большинстве языков программирования существуют средства для разделения интерфейса и реализации (например, файлы заголовков в C/C++), interface в Java или утиная типизация. Еще один способ интеграции — инверсия управления, при которой под интерфейсами подразумеваются точки перехвата контроля управления разрабатываемым приложением.

Взаимодействие компонентов, реализованных на различных ЯП, отличается большей сложностью. В случаях, если компоненты выполняются в пределах одной среды (например, Java Virtual Machine или Common Lanuguage Runtime), интеграция по своей сути не отличается от интеграции компонентов на одном ЯП. Например, большинство сред выполнения задают общую для всех поддерживаемых языков систему типов данных, принципы управления памятью и так далее. Еще один способ взаимодействия — интерфейс внешних функций — обычно используется для вызова низкоуровневых утилит (это позволяет повысить скорость работы или использовать специфичный для платформы код). Наконец, для связи между ЯП высокого уровня могут использоваться программы-посредники (middleware), такие как CORBA.

В чем суть интерфейсов в программировании?

Не совсем ясно, для чего именно предназначены интерфейсы. Зачем мне в одном месте описывать методы, а в другом реализовывать? Зачем именно нужно дополнительное место для описания, если я могу это сделать сразу в классе? Или же это сделано для удобства восприятия кода? Например, если вижу, что класс наследуется от интерфейса, то знаю, каким функционалом он обладает? Если да, то почему бы не придумать имя класса, из которого будет ясна функциональность? Что первично — интерфейс, или класс? По возможности, приведите примеры кода(желательно не из объектной области, желательно на Java), где будет показано, что в данной ситуации необходимо использовать интерфейс, или что его использование удобнее, чем не использование. В книгах везде приводят примеры того, что может делать интерфейс, но в примерах из книги я не вижу крайней необходимости его использования. Спасибо!

  • Вопрос задан более трёх лет назад
  • 54009 просмотров

Комментировать
Решения вопроса 1

Я делаю систему контроля яркости.
Я хочу настраивать яркость всего (гирлянды, люстры, фонарика, экрана телефона).
В коде выглядит примерно так

class BrightControl public void setDefaultBright(Object obj) < obj.setBright(10); >>

Метод setDefaultBright принимает любой объект. Ведь мне всё равно яркость чего настраивать.
Мой код используют другие разработчики, я не могу контролировать их.
Как мне убедиться, что у объекта, который мне пришел в качестве аргумента, есть метод setBright?
Я пишу интерфейс, и говорю, что метод setDefaultBright принимает только объекты, которые реализуют этот интерфейс.

Если кроме меня самого никто не будет использовать эту систему контроля яркости. То я просто буду держать у себя в голове, что в метод setDefaultBright можно отправлять только объекты, у которых есть метод setBright, но поддержка кода усложняется, через год и не вспомнишь.

Ответ написан более трёх лет назад
Нравится 33 3 комментария
Спасибо за нормальное объяснение) целый день разбирался)

Спасибо за нормальное пояснение!
Правильно я понимаю что в случае использования утиной типизации (как в Ruby) необходимость использывать интерфейсы отпадает? Или у них есть ещё какое-то прикладное применение?

Александр Краснов @Pompeius_Magnus

Rozello, необходимость остается, но ЯП не будет вас ограничивать этим. Интерфейсы — это прием проектирования, а не особенность конкретного инструмента

Ответы на вопрос 8

ptchol

Linux system administrator

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

«Придумать класс с правильным именем» — так вы не сможете заставить «наследников» реализовывать функционал.

Интерфейсы располагаются на уровень выше классов, если можно так выразиться. Они неявно «объединяют» классы схожие по каким то общим признаком, и которые обязаны (по логике вашего приложения) реализовывать те или иные методы.

interface Instruments < final static String key = "До мажор"; public void play(); >class Drum implements Instruments < public void play() < System.out.println("бум бац бац бум бац бац"); >> class Guitar implements Instruments < public void play() < System.out.println("до ми соль до ре до"); >>

p.s: программисты дополнят и поправят.

Ответ написан более трёх лет назад
Нравится 19 2 комментария
syntax @syntax Автор вопроса

«В интерфейсе вы описываете лишь сигнатуры методов, то есть вы указываете что класс наследник должен уметь делать, но как он будет это делать, тот решает сам.
Таким образом вы уверенны, что если класс реализует тот или иной интерфейс, все объекты данного класса имеют определенный набор методов.»

Почему я не могу сделать это прямо в классе? Зачем интерфейс? Я же и без него могу быть уверенным, что объекты будут обладать функционалам, описав методы в самом классе. Зачем мне кто то(интерфейс) должен говорить, какие мне методы реализовать? Если я знаю, что должен описать play(), то я могу это сделать прямо в классе, не используя интерфейс. И так могу сделать со всеми, кому нужен play(). Не понятно, в чём конкретно выгода?

ptchol

Посмотрите на это с другой стороны.
Вы отдаете кому то решение и позволяете его «расширять». Но для того чтобы обеспечить совместимость на вашей стороне вы должны быть уверены, что все что будет сделано ниже с использованием того интерфейса который Вы дали, будет иметь набор методов (все объекты).
Если вы их опишите в классе и отнаследуете — то может случиться так что для данного объекта даная конкретная реализация метода не подходит. Вы не можете никак регламентировать то что должен делать метод. Интерфейс как раз и нужен для этого регламента.

Я же говорю интерфейсы нужны не для тех кто «снизу», а для тех кто «сверху».
Это договор с одной стороны вам дают функционал и интерфейс, со своей стороны вы обязуетесь реализовать интерфейс для использования этого функционала.

Косвеннным плюсом во всем этом является предсказуемость поведения объекта. Зная какой интерфейс он реализует, вы уже знаете что то о его поведении.

rEAcT1oNmanT1s

rEAcT1oNmanT1s @rEAcT1oNmanT1s

Да, это сделано именно для восприятия человеком кода. Легкие программы, где не особо много строк кода, не сильно сложны для восприятия человека, а программы которые имеют тысячи строк кода, уже соответственно нужно разделять на файлы в одних файлах лежат условия «что нужно сделать?», а в других «как это сделать?».

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

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

P.S. Даже когда пишите что-то или задаете вопросы, можете разделять на блоки текста, как написал я, так воспринимается легче чем то, что написано в куче , не правда ли?

Ответ написан более трёх лет назад
Комментировать
Нравится 4 Комментировать

leventov

Без интерфейса (как концепции) немыслимы три из четырех основных понятий ООП.

Конкретно в Java интерфейсы как отдельные сущности нужны, потому что нет множественного наследования. В C++ и многих других языках с поддержкой множественного наследования интерфейсов как отдельной сущности нет (чисто виртуальный класс — частный случай обычного абстрактного класса).

Ответ написан более трёх лет назад
Комментировать
Нравится 3 Комментировать

Для начала нужно сразу понять, что интерфейс это частный случай класса. Но в Java оно имеет отдельное ключевое слово, а в C++ это просто класс без реализации. Поэтому интерфейс просто задает некий стандарт для работы с кучей разнообразных реализаций.

Например, интерфейс Iterable говорит, что классы реализующие данный интерфейс имеют элементы и их можно перебирать в цикле вызывая метод next(). А значит, если создаете какой-то контейнер или коллекцию, то можно реализовать Iterable. Не выдумывая свои методы для работы с контейнером. Тем самым появляется некий общий стандарт — интерфейс для работы с контейнерами.

А если вы делаете игру, то можете создать интерфейс Unit, тем самым задав классам определенное поведение. Например, unit должен обязательно иметь метод atack(), isDead() и т.д.

А дальше, в цикле делаете проверку всех юнитов:
loop(. ) if (unit.isDead())
removeFromMap(unit);
>

Ну и конечно Unit может быть и просто классом или абстрактным классом, в котором реализованы atack и isDead, а может быть только isDead, потому что attack у каждого типа юнита индивидуально и требует собственной реализации. Т.е. приходим к тому, что интерфейс это также частный случай абстрактного класса.

Т.е. тут уже вступает в действие полиформизм, т.е. интерфейсы по сути дают полиформизм. Ну, а в Java они еще позволяют делать множественное наследование или другими словами задать классу несколько свойств поведения, например Unit может быть также и Iterable, тем самым можно дать юнитам инвентарь и перебирать элементы в нем.

И соответсвенно если Unit у вас будет классом или абстрактным классом, то унаследовав Unit в Java, вы просто не сможете дать наследнику еще и Iterable поведение, если Iterable будет тоже классом.

OrcWarrior implements Unit, Iterable — так можно

OrcWarrior extends Unit, Iterable — так в Java нельзя, но можно в С++, а Unit и Iterable тогда всегда будут объявляться как class.

Из-за этого, в Java приветствуется не наследование, а композиция. Т.е. нафига каждый раз реализовывать Unit.isDead, если он стандартный? Поэтому, создается скажем класс UnitAI и делается следующее:

class OrcWarrior implements Unit, Iterable UnitAI ai;

interface Unit void attack();
UnitAI getAI();
>

Вот это называется композиция, т.е. в OrcWarrior, HumanWarrior вы подмешиваете UnitAI, в котором уже реализовано isDead, и тем самым не нужно каждый раз его реализовывать одним и тем же кодом. В С++ такого можно не делать, там есть поддержка множественного наследование, но оно имеет свои минусы. Впрочем, как и композиция имеет плюсы/минусы.

Что такое интерфейс? Объясняем простыми словами

Пишем про дизайн и искусство. Всё, что вы хотели знать о настоящем, прошлом и будущем визуальной культуры.

Интерфейс — это термин, который встречается и в дизайне, и в айти. Он означает одно и то же? Или в каждой области подразумевается своё значение?

Простыми словами объясняют, что такое интерфейс, эксперт в UX/UI Евгений Князев и эксперт в web-разработке Михаил Малышев.

Евгений Князев

CEO Antro, арт-директор, продуктовый дизайнер. Спикер Product Sense, спикер ECOM Expo. Автор курса «Логомашины» по мобильным интерфейсам, член жюри Russian Drupal Awards.

Евгений Князев об интерфейсе на дизайнерском и глобальном

Что такое интерфейс

В самом слове «интерфейс» для человека, который немного знает английский, уже есть подсказки. Явно видно, что это про interaction ― взаимодействие ― и про face ― лицо. Правда, если подглядеть в какую-нибудь «Википедию» и прочитать там определения, то можно ничего не понять.

Всё достаточно просто: интерфейс — это какая-то штука, которая помогает взаимодействовать двум системам или, условно говоря, двум другим штукам.

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

Интерфейс — это система интерфейсов

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

Есть кружка. Это тоже интерфейс — взаимодействия рук с кока-колкой и другими напитками. И вот получается уже система, которую можно декомпозировать :

  • Мозг хочет напиток.
  • Он для этого использует руки. Но только руки для колы — так себе интерфейс, поэтому…
  • Он придумывает, как сделать с помощью рук какую-то штуку в зависимости от контекста и среды, в которой он находится. Например, делает кружку из каких-нибудь листьев и веток или покупает керамическую в магазине.
  • И вот руки берут кружку — получается уже достаточно хороший интерфейс: кока-колка не проливается, мозг получает удовольствие от сахара.

Разным контекстам разные интерфейсы

Кружка может быть с ручкой, без ручки, состоять из стакана с подстаканником, который этому гладкому стакану добавляет ручку.

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

Если ты будешь из кружки для эспрессо пить вино, то любители вина посмотрят косо — у них абсолютно другие требования к интерфейсу. Ёмкость для напитка, помимо утилитарной подачи напитка из среды в ЖКТ, должна соответствовать эстетическим требованиям и, например, позволять вину «раскрыться».

Какими интерфейсами занимаются дизайнеры

На языке продуктовых дизайнеров интерфейс — это, в первую очередь, видимая часть системы web-сервиса или мобильного приложения (браузера, игры, онлайн-магазина), с которой взаимодействует пользователь. Его задача — передавать информацию от юзера.

С дизайнерской точки зрения разница между веб- и мобильным интерфейсом есть, но в конечном счёте это всегда некоторый макет в Figma.

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

Заметка: с разделением UI и UX ситуация непроста. Во-первых, среди дизайнеров нет консенсуса на этот счёт. Во-вторых, у нас внутри компании он есть: UI — часть UX, так как user interface (UI) является частью пользовательского опыта (UX) и отделять один от другого, на наш взгляд, некорректно.

Слово design с английского переводится как «проектирование». Так что дизайн интерфейсов — это в первую очередь проектирование удобного приспособления, а не рисование и раскрашивание.

Проектировщику интерфейсов надо заботиться не только о том, чтобы его работа была красивой, но и как этим будут пользоваться — то есть о UX. Такой дизайнер должен смотреть шире, чем только на «лицо»: надо представлять и проектировать, как будет происходить взаимодействие. Поэтому в работе есть не только статичные картинки, но и анимации, проектирование переходов и откликов от системы.

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

Сделать удачный интерфейс, а не лакать воду из ладошек, поможет знание 10 эвристик по Нильсену.

Михаил Малышев

Веб-разработчик, работал в «Рокетбанке» и «Яндексе». Frontend Tech Lead в Timestripe, Fullstack TypeScript Developer в Playdex. Ведёт телеграм-канал про фронтенд и веб 3.0.

Михаил Малышев об интерфейсе на айтишном

Что такое интерфейс в программировании

Простыми словами, интерфейс ― это соглашение, по которому компоненты компьютерной системы обмениваются информацией.

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

Давайте рассмотрим несколько примеров интерфейсов, от самых высокоуровневых до низкоуровневых (речь идёт об уровнях абстракции: чем ниже уровень, тем глубже погружение в детали реализации и тем более подробно требуется описывать программу; например, zero-code-программирование находится на более высоком уровне по сравнению с обычным, потому что когда мы сами пишем код, то должны явно описывать каждую деталь).

Какие есть виды интерфейсов

Давайте рассмотрим три вида интерфейсов, с которыми взаимодействуют пользователи и разработчики.

Хардверные

Hardware-интерфейсы нужны для подключения физических устройств друг к другу.

— Подскажите, какой интерфейс у этой MIDI-клавиатуры?

— Она может работать и по MIDI, и по USB.

Сюда относятся как проводные интерфейсы вроде USB или Thunderbolt, так и беспроводные — WiFi и Bluetooth.

Программные

Эта аббревиатура расшифровывается как Application Programming Interface — интерфейс программирования приложения.

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

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

Апишка — так разработчики часто называют API.

Эндпоинт — один из доступных методов в API, например эндпоинт для добавления песни в плейлист в API Spotify.

Ручка — так эндпоинт называют в «Яндексе».

  • В объектно-ориентированном программировании

Интерфейс в объектно-ориентированном программировании — это описание структуры объекта, без деталей реализации.

Пользовательские

Пользовательские интерфейсы предназначены для работы человека с программой.

Все интерактивные элементы на экране компьютера — части графического пользовательского интерфейса (GUI — Graphical User Interface).

Но не все пользовательские интерфейсы графические. Например, существует вид пользовательских интерфейсов, который называется CLI — Command Line Interface. Это консольный интерфейс для программы, для работы с которым нужно вводить команды в терминал. Программы, созданные для разработчиков, часто используют CLI вместо GUI, потому что его гораздо проще создать и развивать. Кроме того, CLI используют для автоматизации, потому что консольные команды можно выполнять внутри собственных программ. Таким образом, консольные интерфейсы одновременно являются и пользовательскими, и программными.

Больше интересного про дизайн в нашем телеграм-канале. Подписывайтесь!

Интерфейсы — важнейшая концепция в разработке ПО

image

Интерфейс можно считать своеобразным договором между системой и внешним окружением. В рамках компьютерной программы «система» — рассматриваемая функция или модуль, а «окружение» — весь остальной проект. Интерфейс формально описывает, какие данные могут передаваться между системой и окружением. А «реализацию» можно охарактеризовать как «система минус интерфейс». В языках наподобие Haskell интерфейсы могут быть крайне специфическими. А в языках вроде Python они, напротив, очень обыденны. Выбранный тип интерфейса может повлиять на размер созданного технического долга и производительность программиста. О том, как это посчитать, написано ниже. Также будет предложен метод для оценки и сравнения разных интерфейсов. На основании этих сравнений вы сможете сами понаблюдать за способами использования языка или программного инструмента.

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

Что такое интерфейс?

Большинству из нас знакомы две краткие формулировки:

Интерфейс — это договор между системой и внешним окружением.
Интерфейс — это сопряжение системы с внешним окружением.

Интерфейс = Система ∩ Окружение

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

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

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

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

unsigned int add_numbers(unsigned int, unsigned int); void other_function(void) < add_numbers(3,4); >unsigned int add_numbers(unsigned int a, unsigned int b) < return a + b; >int main(void)

Применим ту же методику цветовой дифференциации штанов для описания окружения, системы add_numbers и интерфейса:

Рассматриваемая здесь «система» состоит из функции add_numbers . Если вы скажете, что можно рассматривать как отдельную систему основной метод — other_function , — то будете правы. Но для простоты мы считаем функцию add_numbers изолированной системой. Также целесообразно считать частью интерфейса обращения к add_numbers .

Как видите, здесь добавлена четвёртая концепция: «реализация». Довольно сложно дискутировать на тему интерфейсов без учёта конкретных реализаций. Давайте определим этот термин:

Реализация — это система минус интерфейс.

Implementation = System ∖ Interface
Implementation = System ∖ (System ∩ Environment)

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

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

Интерфейс как договор

Если рассматривать интерфейс функции add_numbers в виде договора, то гарантии будут такие:

  • Функция add_numbers существует.
  • add_numbers имеет только два параметра, каждый из которых является unsigned int .
  • add_numbers возвращает лишь один unsigned int .
  • о прерывании выполнения add_numbers ;
  • об асимптотической сложности рантайма add_numbers ;
  • о количестве свободной памяти, необходимой для запуска add_numbers ;
  • о конкретной реализации unsigned int ;
  • о побочных эффектах (выделение памяти, модифицирование глобальных переменных).

unsigned int add_numbers();

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

С компьютерными программами всё то же самое. Модули и функции говорят, что им нужно и (иногда) что они дадут взамен. Нарушение этого договора приведёт к ошибке компиляции, к ошибке выполнения, к сбою приложения, системы, средств контроля качества кода и к выговору от руководства. Я бы даже сказал, что определение интерфейса как договора не метафорическое. Здесь используются те же принципы, что и в коммерческом договоре, хотя он и не столь детализирован.

Патенты, авторские права и интерфейсы

Я не буду давать вам советы в области права. Возможно, что-то из мною сказанного даже будет противоречить законам. Всё нижеследующее — лишь частное мнение автора.

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

Следует ли патентовать интерфейс? Учитывая его определение как договора между системой и окружением, я считаю, что использование патентов было бы ошибкой. И, судя по всему, существующее прецедентное право поддерживает мою позицию. Но имейте в виду, что слово «интерфейс» используется очень широко, и зачастую совсем не в том смысле, как я описал выше.

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

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

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

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

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

def foo(): print("asdf") def foo(abc): print(abc) foo("lol") 

Все эти разговоры о законах напомнили мне дело Oracle против Google. По приведённой ссылке вы можете найти интересные для разработчиков подробности, так что я буду опираться на них в своём анализе. Учитывая все аспекты, не вижу причин не соглашаться с решением дела в пользу Oracle. Не могу сказать, что безоговорочно их поддерживаю, поскольку нам доступно не так много деталей разбирательства.

Думаю, многие переживали, что будет создан прецедент, позволяющий защищать патентом или авторскими правами элементы интерфейса. Как раз тот случай, при котором не был бы пройден мой тест. Окружной суд принял решение: «Структура, последовательность и архитектура API могут быть защищены авторским правом». Не думаю, что это проблема, поскольку «структура, последовательность и архитектура» по своему определению вполне пройдут мой тест. Приведу пару выдержек из статьи по приведённой выше ссылке:

«Окружной суд заключил, что „есть лишь один способ написания“ объявлений для взаимодействия с Java. Если это так, то использование одинаковых объявлений не подлежит защите авторским правом. В Google не оспаривают тот факт, что они могли бы написать свои собственные API для доступа к Java, за исключением трёх». И наконец, «В Google признали, что они дословно скопировали объявления».

Думаю, суд принял верное решение, заключив, что уникальные по сути свойства интерфейса не должны подвергаться защите. К тому же в Google признали «дословное» копирование. Если под этим подразумевается копипастинг, включая все пробелы и орфографические ошибки в комментариях, то я считаю это нарушением прав. Даже если нельзя защищать интерфейс, то это не должно мешать защите индивидуального творческого самовыражения.

Об этой тяжбе я знаю лишь из открытых сетевых источников, но, судя по всему, в Google полностью скопировали исходный Java-код, включая интерфейсы. Похоже, они и сами считали, что нужно лицензировать своё использование Java, поскольку это было предметом переговоров по лицензионным соглашениям с Sun ещё до 2010 года. Но эти соглашения потерпели неудачу после того, как Sun была приобретена Oracle. Тем не менее Google продолжала использовать «дословные» копии кода, что явно не пошло ей на пользу при судебном разбирательстве. Подозреваю, что их адвокаты знали о слабости своей позиции, поэтому выбрали стратегию защиты, основанную на законном требовании о нераспространении авторского права на интерфейсы. Надеялись выиграть дело за счёт представления интерфейса в виде исходного кода и его объединения с более философской концепцией.

Что такое «модуль», или «абстракция»?

При слове «модуль» у меня в голове возникает заглавная картина поста. Эта иллюстрация хорошо демонстрирует важность границ модуля и его взаимодействия с окружением. Интерфейс кубика жёстко ограничивает взаимодействие внешней среды с содержимым кубика. Вы не сможете обойти интерфейс, так что придётся соблюдать навязанные им «правила игры». Наконец, внутри кубика ничего нет, но это неважно: важно не его содержимое, а интерфейс.

Другой пример: строение клеточной мембраны. Различные компоненты обеспечивают прохождение через мембрану только необходимых веществ и только тогда, когда это нужно.

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

Вы можете считать отдельную функцию модулем в языке С, «модулем» — в Python, классом или пакетом — в Java. Чем угодно, лишь бы оно имело внешний интерфейс и «скрытую» реализацию. Причём «скрытость» может быть следствием правил языка или даже решения программиста.

Дырявые абстракции

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

Перебор отсортированных данных может дать совсем другой результат по сравнению с перебором случайных данных. Допустим, нужно найти минимальное значение в списке:

min = null; list = map.getMapKeys(); for (item in list)< if ( min == null )< min = item >else if (item < min)< min = min; /* This line has a bug */ >> 

Ветка else if никогда не будет выполнена, если данные отсортированы по возрастанию. Даже если вы начнёте проверку со случайного места списка, программа никогда не столкнётся с этой строкой. И это огромная проблема, поскольку если вы поменяете реализацию карты и она не будет возвращать отсортированные ключи, то ваш код неожиданно станет выполняться по ветке с багом. А к тому моменту вы совершенно забудете об этом коде и скрытой внутри него бомбе.

Хочу предложить своё собственное определение утечки абстракций.

Утечкой абстракций (abstraction leak) называется ситуация, когда реализация может влиять на окружение так, как не было предусмотрено интерфейсом.

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

Идея дырявости большинства абстракций не является необоснованной. Это подразумевал и Джоел Сполски в своём «The Law of Leaky Abstractions»:

«Все нетривиальные абстракции являются дырявыми до определённой степени».

Раз все абстракции дырявые, то о чём говорить? Проблемы возникают только тогда, когда часть окружения начинает опираться на один из непредусмотренных способов воздействия системы на окружение. Именно о таких утечках все и говорят.

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

Каждая физическая реализация криптосистемы уязвима к атакам по сторонним каналам.

Учитывая всё сказанное выше, эту идею можно распространить не только на физические, но и на эмулированные реализации.

Оценка и сравнение интерфейсов

Как мы уже видели выше, в интерфейсах на С задаются такие вещи, как тип возвращаемого значения и количество параметров, которые могут быть переданы функции. А что насчёт Python? Я использую термин «интерфейс» в соответствии с контекстом статьи, то есть в более широком понимании по сравнению с тем, что пишут в книгах об «интерфейсах» в Python.

def add_numbers(a,b): return a + b print(add_numbers(3,1)) print(add_numbers("abc","def")) 

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

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

Через интерфейс В обход интерфейса
Описание характеристики Кол-во возможных состояний Описание характеристики Кол-во возможных состояний
Тип параметра 1 1 (unsigned int) Состояния глобальной переменной (кол-во глобальных переменных) * (кол-во состояний глобальных переменных)
Тип параметра 2 1 (unsigned int) Файловая система Кол-во состояний файловой системы
Тип возвращаемого значения 1 (unsigned int) Время использования процессора Не ограничено
Значение параметра 1 2^(кол-во бит в unsigned int) Состояние кучи Кол-во состояний кучи
Значение параметра 2 2^(кол-во бит в unsigned int) Многие другие. .
Возвращаемое значение 2^(кол-во бит в unsigned int)

И есть ряд вещей, которые могут коммуницировать с add_numbers через интерфейс Python.

Передача информации через интерфейс Python Передача информации в обход интерфейса Python
Описание характеристики Кол-во возможных состояний Описание характеристики Кол-во возможных состояний
Тип параметра 1 Практически бесконечное Состояния глобальной переменной Кол-во состояний файловой системы
Тип параметра 2 Практически бесконечное Файловая система Не ограничено
Тип возвращаемого значения Практически бесконечное Время использования процессора Кол-во состояний кучи
Значение параметра 1 Практически бесконечное Состояние кучи .
Значение параметра 2 Практически бесконечное Многие другие. (кол-во глобальных переменных) * (кол-во состояний глобальных переменных)
Возвращаемое значение Практически бесконечное

А теперь взгляните на количество типов интерфейсов, которые мы можем описать в Haskell:

add_numbers :: Int > Int -> Int add_numbers 3 4 = 7 main = print (add_numbers 3 4) 

Учитывая этот код, интерфейс add_numbers может получить следующую информацию:

Передача информации через интерфейс Haskell Передача информации в обход интерфейса Haskell
Описание характеристики Кол-во возможных состояний Описание характеристики Кол-во возможных состояний
Тип параметра 1 1 (Int) Время использования процессора Не ограничено
Тип параметра 2 1 (Int) Влияние на кэши процессора/памяти Не ограничено
Тип возвращаемого значения 1 (Int) Прочие. .
Значение параметра 1 1 (значение 3)
Значение параметра 2 1 (значение 4)
Возвращаемое значение Как минимум 2^30[1]

Для конкретного интерфейса на выбранном вами языке можно оценить ещё и количество уникальных способов передачи информации:

  • через интерфейс;
  • в обход интерфейса через утечки абстракций.
  • сколько ограничений вы можете использовать в рамках этого языка с точки зрения минимального и максимального количества информации, передаваемой через интерфейс;
  • какие инструменты предоставляет этот язык для предотвращения взаимодействия в обход интерфейса.

image

Передача информации через GUI Передача информации в обход GUI
Описание характеристики Кол-во возможных состояний Описание характеристики Кол-во возможных состояний
Клик по Папке 1 Кол-во пикселей на экране, занимаемых Папкой 1 * кол-во кликов Скрытые возможности UI Не ограничено
Клик по Папке 2 Кол-во пикселей на экране, занимаемых Папкой 2 * кол-во кликов Нестандартные комбинации быстрого вызова Кол-во пикселей на экране, занимаемых Кнопкой 2
Наведение курсора на Папку 1 Кол-во пикселей на экране, занимаемых Папкой 1 Прочие неожиданные возможности UI .
Наведение курсора на Папку 2 Кол-во пикселей на экране, занимаемых Папкой 2
Время между наведением и кликом Бесконечно
Стандартные клавиатурные события Кол-во стандартных комбинаций клавиш
Площадь экрана, занимаемая GUI Кол-во пикселей, используемых для отображения GUI

А теперь рассмотрим ту же задачу смены папки с помощью командной строки и cd :

Передача информации через GUI Передача информации в обход GUI
Описание характеристики Кол-во возможных состояний Описание характеристики Кол-во возможных состояний
Кол-во названий папок, которые можно набрать Не ограничено Переменные окружения Не ограничено

В предыдущие две таблицы я не включил такие данные, как количество шума в сигнале. Если сравнить сложность повторения одной и той же последовательности при нажатии клавиш (одна за другой) и движении мыши (пиксель за пикселем), то очевидно, что во втором случае ошибок гораздо больше. В графических интерфейсах это компенсируется благодаря принятию менее строгой семантики. Представьте, если бы на кнопках «OK» и «Cancel» доступная для кликов зона была шириной всего 1 пиксель.

Можно ещё больше усложнить анализ, если оценивать изменение доли ошибок у пользователей с физическими отклонениями.

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

  • Люди предпочитают интерфейсы, которые не слишком строги при приёме информации, особенно если интерфейс незнакомый.
  • Не слишком строгие интерфейсы чаще используют неправильно.
  • Всеобъемлющие интерфейсы, принимающие большие объёмы информации, выглядят мощными, но часто используются неправильно.
  • Если взаимодействие становится утомительным, люди стараются передавать информацию в обход интерфейса.
  • При взаимодействии в обход интерфейса, через утечки абстракций, крайне вероятно возникновение неприятных неожиданностей.

Дырявые и ограниченные интерфейсы

Я опишу несколько наблюдений на основании анализа из предыдущего раздела. Но сначала приведу пару определений:

Дырявый интерфейс (leaky interface) — интерфейс, который игнорируется в ходе любых взаимодействий между системой и окружением.

Ограниченный интерфейс (specific interface) — интерфейс с относительно небольшим количеством возможных входов и выходов.

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

Если вы можете обоснованно оценить «дырявость» или «ограниченность» интерфейсов, то имеет смысл очертить диапазон, на одном конце которого будут очень ограниченные и недырявые интерфейсы, а на другом — неограниченные и дырявые.

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

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

Асимптотическая сложность технического долга

Начну с заявления:

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

В самом начале проект содержит один-два модуля, и для проработки договора хорошего интерфейса вам понадобится выполнить объём работы О(1). Если ваш интерфейс плох, то объём технического долга тоже будет равен О(1), так что вам не придётся потратить слишком много времени на приведение в порядок договора интерфейса. Но при линейном росте количества модулей объём межмодульных связей может достигать О(N^2). Следовательно, при плохом интерфейсе, если каждый модуль взаимодействует со всеми остальными модулями, количество обращений к интерфейсу в худшем случае будет пропорционально N^2.

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

Обычно уровень межмодульного взаимодействия растёт медленнее, чем О(N^2), но определённо быстрее, чем О(N). Также есть один фактор, сдвигающий начало быстрого роста в будущее: это человеческая память. Даже когда в вашем проекте 20 модулей, вы, вероятно, ещё помните, что делает каждый из них. Так, из всех договоров вам нужны лишь туманные названия функций и эзотерические соглашения. Но как только проект становится достаточно большим, то многие детали забываются, или когда в проект приходят новые люди — и начинается степенной рост трудовых затрат.

Почему всё ещё пользуются командной строкой?

На этот вопрос вы получите от людей разные ответы, ни один из которых мне не кажется самым важным:

  • Командная строка гибкая и даёт много возможностей.
  • Она потребляет меньше ресурсов.
  • Это позволяет лучше понимать, как всё работает.

Хотя мы и могли бы внедрять автоматизацию через кликанье и экранные грабберы, нельзя забывать о том, что такой тип взаимодействия с машиной придуман для людей. Он подразумевает использование нестрогого интерфейса, не требующего высокой точности. Поэтому ваш автоматизированный кликер наверняка будет сбоить, если окно вдруг сдвинется со своей позиции или поменяется системный шрифт. С GUI связано слишком много переменных. А командная строка позволяет действовать гораздо точнее, вы взаимодействуете через очень строгий интерфейс. Поэтому многие люди его не любят, в отличие от компьютерных программ.

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

Выбор правильного языка

После раздела про асимптотическую сложность технического долга вы могли подумать, что любой проект нужно писать на языке с очень строгими условиями договоров интерфейса, вроде Haskell или Java. Но это не совсем то, что я хотел донести. Ответ на следующий вопрос может помочь вам сделать правильный выбор.

Насколько вероятно изменение требований к вашему проекту?

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

Если вы ответили «очень вероятно», то используйте язык, который позволит терять меньше времени при уточнении договоров интерфейса: они наверняка будут работать против вас в случае изменения требований. Но главная задача здесь — получить не идеальную реализацию требований, а идеальные требования, позволяющие вам начать создавать финальную реализацию. Исключением может быть ситуация, когда ваш MVP представляет собой огромную систему с сотнями модулей. Если в проект вовлечено немало народу, то хороший интерфейс просто необходим для того, чтобы они не наступали друг другу на ноги.

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

Когда-то было сломано немало копий относительно того, что Twitter начали создавать на Ruby on Rails, а потом это стало причиной затруднений при масштабировании проекта. Позднее Twitter был переведён на Scala. Кто-то может считать, что разработчики совершили ошибку и им следовало сразу выбрать Scala. Я так не думаю. В основе Twitter’а лежит очень простая идея, и в условиях большого количества конкурентов им нужно было завоевать доминирующую позицию на рынке. Им требовалось расти как можно быстрее, невзирая на расходы. Циклы разработки новых возможностей должны были проходить максимально быстро, поскольку это позволяет в кратчайшие сроки понять, что именно нужно пользователям, какой продукт они хотят в результате получить. Трудности масштабирования – это признак не неудачи, а успеха. Было сформулировано видение Twitter’а как готового продукта, и оставалось только реализовать его. С точки зрения разработчиков, это просто нирвана, все о таком мечтают, но мало кому удаётся поработать в таких условиях: «Перепиши это дерьмо с нуля на своём любимом языке, как тебе удобно, лишь бы в будущем с ним было легче работать». Гораздо проще переписывать что-то с нуля, имея перед глазами более слабую реализацию, чем пытаться нащупать облик продукта, который позволит компании взлететь. К сожалению, большинство участников рынка идут только путем избегания «ненужных» расходов на создание с нуля и тратят массу сил и времени на масштабирование того, что изначально не предполагало масштабирования.

Почему так популярен Python?

В разделе про дырявые и строгие интерфейсы я говорил о способе классифицирования интерфейсов в зависимости от их склонности к утечкам абстракций, а также о том, как строги могут быть определения интерфейса. И я указал на тот факт, что более «дружелюбные» и «продуктивные» интерфейсы куда более склонны к утечкам, чем другая часть спектра интерфейсов.

Я считаю, что популярность Python проистекает из того, что это прекрасный вводный язык, предоставляющий крайне простые договоры интерфейса. По той же причине с увеличением проекта на Python поддерживать его становится всё труднее.

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

Почему корпоративное ПО обычно пишут на Java/C++?

В разделе про дырявые и строгие интерфейсы я говорил о компромиссах, связанных с разными типами интерфейсов. Java и С++ относятся больше к строгой части спектра, в отличие от Python или Ruby. Да, в них могут возникать утечки, и есть более строгие языки (тот же Haskell), но зато Java и С++ более сбалансированы с точки зрения масштабируемости, дружелюбности и продолжительности итерирования. Кроме того, эти два языка позволяют гибче управлять дырявостью интерфейсов в зависимости от проектных соглашений. Например, делая переменные или функции частными, публичными или защищёнными.

Как эффективнее срезать углы

Если вы хотите вынести из этой статьи что-то одно, пожалуйста: когда вам нужно срезать углы в проекте, делайте это внутри реализации и оборачивайте в очень хороший интерфейс. Даже если реализация не слишком хороша и её проблемы перетекают в другие части системы, то это проблема плохого интерфейса! Чтобы не было недопонимания, позвольте привести список того, что я подразумеваю под интерфейсами:

  • Прототипы функций.
  • «Интерфейсы» Java.
  • Общедоступные методы классов.
  • Переменные общедоступных компонентов.
  • Заголовочные файлы (.h) в C/C++.
  • Конечные точки RESTful API.
  • Маршрутизация URL.
  • Общедоступные аспекты «моделей» или «пакетов».
  • Логическая структура баз данных (DDL).
  • И многое другое.

Заключение

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

  • Блог компании VK
  • Веб-разработка
  • Программирование
  • Анализ и проектирование систем

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *