Стоит ли писать свой бэкэнд как API?


322

Сегодня у меня была горячая дискуссия о нашем приложении MVC. У нас есть веб-сайт, написанный на MVC ( ASP.NET ), и он обычно следует шаблону «сделать что-то» в представлении -> нажать на контроллер -> контроллер строит модель (вызывает менеджера, который получает данные, строит модель в Сам метод контроллера) -> модель идет на просмотр -> промыть и повторить.

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

Он сказал, что решение и лучшая практика - это создать API, а затем создать свой сайт поверх вашего API, а затем создать настольное приложение, мобильное приложение и т. Д. Очень просто.

Это кажется плохой идеей для меня по разным причинам.

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

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

  • Это слишком абстрактно, чтобы запускать свой бэкэнд из API. Вы пытаетесь сделать его слишком гибким, что сделает его неуправляемым беспорядком.

  • Все вещи, встроенные в MVC, кажутся бесполезными, например, роли и аутентификация. Например, [Авторизовать] атрибуты и безопасность; Вы должны будете катиться самостоятельно.

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

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

  • Вы теряете все виды инструментов, таких как интерфейсы и абстрактные классы, когда дело доходит до API. Такие вещи, как WCF, имеют очень слабую поддержку интерфейсов.

  • У вас есть метод, который создает пользователя или выполняет какую-то задачу. Если вы хотите создать 50 пользователей, вы можете просто позвонить 50 раз. Когда вы решите использовать этот метод в качестве API, ваш локальный веб-сервер может подключиться к ним по именованным каналам, и это не проблема - ваш настольный клиент тоже может поразить его, но внезапно ваше массовое создание пользователя будет включать в себя 50 ударов API по Интернету, что не не хорошо Таким образом, вы должны создать массовый метод, но на самом деле вы просто создаете его для настольных клиентов. Таким образом, вам в конечном итоге придется: а) модифицировать свой API в зависимости от того, что с ним интегрируется, и вы не сможете просто напрямую интегрироваться с ним, б) проделать гораздо больше работы для создания дополнительной функции.

  • ЯГНИ . Если вы специально не планируете писать два одинаково функционирующих приложения, например, одно веб-приложение и одно приложение Windows, это огромный объем дополнительной разработки.

  • Отладка намного сложнее, когда вы не можете пройти сквозной.

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

  • Вероятно, есть еще несколько причин, по которым это просто не в моей голове.

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


Изменить: некоторые отличные ответы, действительно начинают понимать, что все это значит сейчас. Итак, чтобы расширить мой вопрос, как бы вы структурировали приложение MVC, чтобы следовать этой структуре API?

Например, у вас есть веб-сайт, который отображает информацию о пользователе. Под MVC у вас есть:

View - (CS) HTML-страница, на которой отображается контроллер UserViewModel. Вызывает GetUser () и создает UserViewModel, который он передает классу View Manager (своего рода API), в котором есть метод GetUser.

Контроллер выполняет GetUser (), но вам также нужно приложение для настольного компьютера. Это означает, что ваш GetUser должен быть представлен через какой-то API. Возможно, вам понадобится TCP-соединение, либо WCF, либо, возможно, Remoting. Вы также хотите мобильное приложение, которое будет RESTful, поскольку постоянные соединения ненадежны.

Итак, не могли бы вы написать API для каждого из них, веб-сервис WCF, у которого есть метод GetUser (), а код просто есть return new UserManager().GetUser()? И метод веб-API MVC 4, который делает то же самое? Продолжая вызывать GetUser непосредственно в методе контроллера MVC?

Или вы выбрали бы решение, которое будет работать для всех трех (REST-сервис веб-API), и построите все на этом, чтобы все три приложения выполняли вызовы API (mvc для локальной машины).

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


Редактировать 2: После прочтения большего количества вещей, я поместил комментарий ниже, который, я думаю, может объяснить это. Я думаю, что это вопрос с подвохом. Если вы пишете свой бэкэнд в качестве API, я бы запутался, думая, что должен быть один веб-сервис, который все (mvc-приложение, приложение для ПК, мобильное приложение) вызывает, чтобы что-то делать.

Я пришел к выводу, что на самом деле вы должны убедиться, что ваш уровень бизнес-логики правильно отделен. Глядя на мой код, я уже делаю это - контроллер вызовет GetUser()менеджера, а затем создаст из него модель представления для визуализации с помощью представления. Итак, действительно, уровень бизнес-логики - это API. Если вы хотите вызвать его из настольного приложения, вам нужно написать что-то вроде службы WCF, чтобы облегчить вызов. Было бы достаточно просто вызвать метод WCF GetUser(), содержащий код return MyBusinessLayer.GetUser(). Таким образом, API - это бизнес-логика, а WCF / web api и т. Д. - всего лишь кусочки кода, позволяющие внешним приложениям вызывать его.

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

Надеюсь, эта интерпретация верна. Спасибо за все обсуждения / комментарии, которые он вызвал.


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

12
@SLC: Когда вы говорите API, вы имеете в виду API веб-сервиса, такой как интерфейс SOAP или REST? Потому что вы должны сделать бэкэнд API, но не должны делать это веб-сервисом.
JacquesB

7
@IanNewson «мобильное приложение, например, у них меньше функций». Я никогда не слышал убедительной причины, по которой мобильные приложения должны быть гражданами второго сорта ... (хотя, похоже, все так делают)
Майкл

3
@IanNewson, может быть, это только я ... но я всегда чувствую себя подавленным из-за того, что не могу делать то или иное на мобильном телефоне до такой степени, что я очень мало делаю на мобильном телефоне
Майкл

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

Ответы:


282

Да, ты должен.

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

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

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


Изменить: ОК, я вижу вашу проблему. Вы думаете об API как об удаленной библиотеке. Это не. Думайте об услуге как об услуге предоставления данных. Вы вызываете службу для получения данных, а затем выполняете операции с этими данными локально. Чтобы определить, вошел ли пользователь в систему, вы должны вызвать « GetUser», а затем, например, посмотреть 'logged on'значение. ( YMMV с этим примером, конечно).

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

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

Отладка также проста - вы можете тщательно протестировать API в отдельности, чтобы вам не нужно было отлаживать его (и вы можете отлаживать сквозное, Visual Studio может подключаться к нескольким процессам одновременно).

Такие вещи, как дополнительная работа по внедрению безопасности - это хорошо. В настоящее время, если вы вложите весь код в свой веб-сайт, если хакер получит к нему доступ, он также получит доступ ко всему, включая БД. Если вы разделите его на API, хакер может очень мало сделать с вашим кодом, если только он также не взломает уровень API - что будет для них невероятно сложно (когда-нибудь задумывались, как злоумышленники получают обширные списки всех пользователей сайта или подробности о cc?) они взломали ОС или веб-сервер, и у него было прямое соединение с БД, где они могли select * from usersлегко " " работать ).

Я скажу, что я видел много веб-сайтов (и клиент-серверных приложений), написанных так. Когда я работал в индустрии финансовых услуг, никто никогда не писал веб-сайт «все в одном», отчасти потому, что это слишком рискованно для безопасности, а отчасти потому, что большая часть разработки - это довольно GUI, а не стабильная (то есть унаследованная) внутренняя обработка данных. системы. Систему DP легко представить как веб-сайт с использованием архитектуры стиля обслуживания.

2-е редактирование: некоторые ссылки по теме (для ОП):

Обратите внимание, что, когда речь идет об этом в контексте веб-сайта, веб-сервер следует рассматривать как уровень представления, поскольку именно клиент вызывает другие уровни, а также потому, что он создает представления пользовательского интерфейса, которые отправляются в браузер для рендеринга. Это большая тема, и есть много способов разработать ваше приложение - ориентированное на данные или ориентированное на домен (я обычно считаю, что ориентированное на домен является «более чистым», но YMMV ), но все сводится к тому, чтобы придерживаться логического уровня между ваш клиент и ваша БД. Это немного похоже на MVC, если вы считаете, что средний, API, уровень эквивалентен вашей модели, только модель не является простой оболочкой для БД, она более богата и может делать гораздо больше (например, собирать данные из 2 источников данных, после -обработка данных для соответствия API, кеширование данных и т. д.):


2
Это да с точки зрения астронавта архитектуры? Я могу понять ваши 2-й и 3-й абзацы с точки зрения обслуживания, но мы говорим о GetUser, CreateUser, IsUserLoggedIn и сотнях крошечных функций, которые ранее были отдельными строками кода, преобразованными в вызовы API.
NibblyPig

12
Представьте, что вы пишете это как веб-сайт - все эти крошечные функции не могут быть такими интерактивными, как вы себе представляете, поэтому вам придется получать данные и кэшировать их локально, пока вы создаете свою страницу (или передавать их как потенциально устаревшие данные в клиент, в зависимости от системы). В большинстве случаев вы должны изменить свой дизайн с «реагировать по требованию» на «предвидеть заранее», но большая часть вашей системы будет выполнять вызовы API. Создайте свой API-интерфейс так, чтобы он был менее детализированным и более ориентированным на данные, поэтому IsUserLoggedOn не обязательно должен быть вызовом API, вам нужен только «GetUserDetails», как только вы затем проверяете его локально.
gbjbaanb

5
Мы использовали этот метод на моем последнем месте работы, и он работал прекрасно. Нашим основным продуктом было веб-приложение, но мы смогли создать настольное приложение и даже листы Excel, которые могли бы обращаться к тем же веб-сервисам, что и наше веб-приложение, для всех его данных, и дополнительно предоставлять сервисы нашим клиентам, чтобы они могли программа против них.
Кик

2
Вот еще одно преимущество: вы можете предоставить бэкэнд-API клиентам вашего сайта. Мы сделали это в нашей компании, и некоторые крупные заказчики программного обеспечения (после того, как опробовали бэкэнд на нашем хосте) заплатили за то, чтобы бэкэнд был упакован как самостоятельный продукт. В зависимости от продукта, некоторые клиенты меньше интересуются внешним интерфейсом и гораздо больше заинтересованы в том, что на самом деле делает ваш продукт - бэкэнд. Это еще один продукт для продажи.
Рейд

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

87

Вы не можете избежать создания API . Даже если вы создаете «просто сайт», ему все равно нужно каким-то образом получать данные из вашего бэкэнда. Однако вы решите это сделать, это ваш де-факто API.

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

Тем не менее, как вы указываете, это вызывает определенные опасения. Для их решения:

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

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

Все вещи, встроенные в MVC, кажутся бесполезными, например, роли и аутентификация. Например, [Авторизовать] атрибуты и безопасность; Вы должны будете катиться самостоятельно.

Признаюсь, мне очень трудно сочувствовать людям, которые отказываются изучать свои инструменты. То, что вы не понимаете, как они используются, не означает, что они бесполезны, и, конечно же, это не значит, что вы должны сами бросить . Наоборот; вам не следует переходить на собственные инструменты, пока вы не поймете альтернативы, чтобы вы могли быть уверены, что решите те же проблемы, что и они (даже если только по-своему).

Вспомните Линуса Торвальдса , который наиболее известен благодаря написанию Linux , но также написал git : сейчас одна из самых популярных систем контроля версий в мире. Одним из движущих факторов в его дизайне была глубокая оппозиция Subversion (еще один чрезвычайно популярный VCS , и, возможно, самый популярный в то время, когда был написан git); он решил взять все, что мог Subversion, и, насколько это было возможно, решить эти проблемы по-другому. Чтобы сделать это, он должен был стать экспертом по Subversion сам по себе , именно для того, чтобы он мог понимать одни и те же проблемные области и использовать другой подход.

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

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

Да. Так и должно быть.

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

Не обязательно. Именно здесь в игру вступают такие архитектуры, как REST . Вы определяете ресурсы, с которыми работает ваше приложение, и операции, которые имеют смысл применять к этим ресурсам, а затем реализуете их, не беспокоясь о других .

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

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

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

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

ЯГНИ . Если вы специально не планируете писать два одинаково функционирующих приложения, например, одно веб-приложение и одно приложение Windows, это огромный объем дополнительной разработки.

Нет, ЯНИ (тебе это уже нужно). Я изложил это, как указано выше. Вопрос только в том, сколько дизайнерских работ вложит в это.

Отладка намного сложнее, когда вы не можете пройти сквозной.

Почему вы не смогли бы пройти сквозной?

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

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

REST решает эту проблему, работая над законченными объектами ( ресурсами , используя термины теории REST), а не над отдельными свойствами объектов . Чтобы обновить имя пользователя, вы получаете пользовательский объект, меняете его имя и возвращаете пользователя обратно. Вы можете внести другие изменения одновременно с изменением имени пользователя. Более общую проблему легче решить, потому что вы можете исключить все эти отдельные вызовы для обновления отдельных свойств объекта: вы просто загружаете его и сохраняете.

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

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

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

Дальнейшее чтение:

  1. REST API Design - моделирование ресурсов

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

7
Это делает действительно плохой API: настолько бедным, что многие даже не думают о нем как об API. Но он по-прежнему определяет способ взаимодействия внешнего интерфейса с внутренним, каким бы грубым он ни был. Думая об этом как о API, вы понимаете, насколько важно делать это хорошо.
Самый ложный

1
Я думаю, что Линус сделал git, потому что сообщество Linux восстало против использования коммерческой Bitkeeper DVCS, которая использовалась для ядра.
gbjbaanb

2
Ваше первое предложение рассеивает все мое замешательство. Я связал термин API с веб-сервисом, и это главная причина, по которой я так растерялся.
NibblyPig

4
@IanNewson: есть способ взаимодействия с кодом, он называется http. Он может иметь много несоответствующих требований и возвращать много несоответствующих данных, но это то, что делает его паршивым API.
Jmoreno

63

Я знаю, что микросервисы сейчас в моде, но они не всегда стоят того. Да, слабосвязанный код - это цель. Но это не должно происходить за счет более болезненного цикла разработки.

Хорошим промежуточным решением было бы создать отдельный проект данных в вашем решении. Проект данных будет библиотекой классов .NET. Ваш проект ASP.NET MVC затем добавит ссылку на библиотеку данных, и все модели будут извлечены из проекта данных. Затем, когда пришло время создать настольное или мобильное приложение, вы могли ссылаться на тот же код. Так что это может быть не официальный API, но он будет функционировать как один. Если вы хотите сделать его доступным в виде API, вы можете создать простой веб-проект, который действует как оболочка для проекта данных.

Microsoft продвигает эту концепцию, которую они называют Portable Class Libraries .


13
Мне пришлось поддерживать проект, в котором логика была помещена на уровень пользовательского интерфейса, вызывая те же общие структуры данных. Из-за этого мне пришлось исправлять одну ошибку тридцать раз («если нам снова понадобится та же логика, мы скопируем и вставим! API-интерфейс не нужен»). Если бы существовал логический слой (теперь он есть), этого было бы достаточно только с одним исправлением.
SJuan76

1
Этот ответ, помимо упаковки этой библиотеки в собственный пакет NuGet и размещения собственного фида / сервера пакетов NuGet, также является хорошим способом. Вам не нужно беспокоиться о привередливых сетях, и вы можете делать все вызовы локальными для потока (и, следовательно, быстрее), плюс добавление правильной версии в вашу библиотеку классов с помощью NuGet дает другим командам гибкость при обновлении.
Грег Бургхардт

34

Нет, ты не должен . Если у вас нет непосредственных планов создания альтернативных внешних интерфейсов (таких как мобильные или настольные приложения или отдельное веб-приложение), которые обращаются к одному и тому же внутреннему интерфейсу, то вам не следует вводить слой веб-службы. ЯГНИ .

Слабая связь всегда желательна (наряду с высокой связностью), но это принцип конструкции, который не означает, что вам нужно физически разделять объекты на разных серверах! А плохо спроектированный сервисный API может создать тесную связь через границы сервера, поэтому наличие API не гарантирует слабой связи.

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


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


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

9
@Bartdude: Представить ненужную сложность ради «будущего» для будущего, которое не наступит, - просто трата ресурсов.
JacquesB

6
@Bartdude добавление API определенно больше времени. Понятия не имею, как вы думаете, вы можете требовать иначе.
Ян Ньюсон

13
API "слой веб-сервиса" не следует вводить! = веб-сервис. Если у вас есть бизнес-логика за API, то вы можете в какой-то момент представить этот API как веб-сервис. Это не предварительное требование, хотя.
Селос

2
@JacquesB: ... так что вы действительно не разрабатываете функции, если не уверены, что они вам понадобятся. Вот что я понимаю из ЯГНИ. Тем не менее, архитектура не является особенностью, и неправильный выбор архитектуры может (и, скорее всего, приведет) к печальному провалу. Еще раз, я полагаю, что эта дискуссия может даже состояться, что иногда не относится к бюджету, времени выхода на рынок, ресурсам или причинам отсутствия знаний ... Я думаю, что мы можем полностью согласиться с этим не согласиться, хотя Я понимаю вашу точку зрения, поскольку у меня часто было то же самое обсуждение с собой ^ _ ^
Лоран С.

29

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

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

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

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


22

Это зависит от типа приложения и типа рынка, в котором вы находитесь.

Есть компромиссы и преимущества для этого пути. Это не однозначный ответ, что один путь лучше другого.

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

Выгоды

  • Гибкость. Будь то запрос на создание мобильного приложения для расширения возможностей рабочего стола или запрос на интеграцию с серверной частью SAP, все становится проще, когда у вас уже есть API для вызова. Когда вы получите достаточно этих запросов, вы будете органично развиваться в сторону API, и единственный вопрос заключается в том, имеет ли он перед собой стандартный веб-сервис или является внутренним API, для которого веб-сервисы создаются индивидуально.

  • Масштабируемость (команды). В нашем случае у нас много разных групп разработчиков, все они опираются на этот API. У нас даже есть специальные команды API, которые общаются с различными группами, обобщают потребности и создают из них универсальный API. Дошло до того, что нам даже больше не говорят, что люди строят вещи поверх API, и не все, кто это делает, работают в нашей компании.

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

Компромиссы

  • Гибкость. Вы должны сделать работу, чтобы «правильно» встроить что-то в API. Невозможно быстро выполнить запрос к БД из кода пользовательского интерфейса, чтобы решить конкретную проблему. Кроме того, API, которые на самом деле можно использовать повторно, должны учитывать столько вариантов использования, что быстрое решение обычно является неправильным решением. API становится менее гибким, чтобы развиваться, особенно с учетом того, что уже существует так много клиентского кода (по этой причине мы переходим к API с поддержкой версий).

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

Красная сельдь

Вы упомянули кучу из них. Они на самом деле не имеют значения на практике.

  • Абстракция. Ваш API становится достаточно абстрактным, чтобы охватить все варианты использования, которые должен обслуживать ваш продукт, и не более того. Даже без веб-сервисов у вас либо будет внутренний API, который делает это, либо много дублирующего кода. Я предпочитаю абстракцию, а не дублирование.

  • Отказ от серверного стека MVC. В наши дни почти каждой системе через некоторое время понадобится мобильное приложение. Затем, когда вы создадите веб-службы для этого мобильного приложения, вам все равно придется выяснить, как выполнять аутентификацию и авторизацию в контексте API. Это на самом деле меньше работы, когда у вас есть только один способ сделать это, как вы делаете это в своих веб-сервисах.

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

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

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

В итоге

В системе, которая используется в достаточно разных контекстах, API будет естественно развиваться, поскольку это самый простой способ удовлетворить все потребности. Но, безусловно, происходит дело ЯГНИ. Есть компромиссы, и это не имеет смысла, пока это не имеет смысла. Ключевым моментом является то, чтобы не быть догматичным и иметь открытый взгляд на различные подходы в архитектуре для удовлетворения растущих потребностей продукта.


Интересное чтиво, можете ли вы рассказать о том, что вы сделали неправильно при разработке API, и что вы узнали?
aaaaaaaaaaaa

3
Тремя основными ошибками были: (1) адаптация API к потребностям основного пользовательского интерфейса, (2) создание состояния по нескольким запросам с использованием сессий (мы постепенно становимся безсессионными) и (3) поддержка только сгенерированного db id в качестве идентификатора, где настраиваемый пользователем код часто является лучшим идентификатором (для интеграции с внешними системами обычно они хотят загрузить идентификаторы в нашу систему для последующего использования в API, а не наоборот). Эти три вместе со слабой документацией и бесполезными сообщениями об ошибках сделали API невозможным использование без посторонней помощи.
Джоери Себрехтс

10

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

У SOA есть несколько существенных преимуществ, которые я попытаюсь перечислить:

Масштабируемость

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

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

способность быть свидетелем в суде

MVC обычно начинается с чистого листа, но на практике контроллеры редко остаются сосредоточенными на одном ресурсе. Чем больше вещей ваши методы контроллера делают, тем менее проверяемыми они становятся.

API обходит эту проблему. Каждый вызов API тянет ресурс и обслуживает его. Чистый и проверяемый.

Гарантированное разделение интересов

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

Downsides

Есть, конечно, некоторые недостатки. Монолит часто быстрее, чем начать. Это может быть то, что вы привыкли. Это может лучше вписаться в ваш стек. Ваши инструменты могут быть оптимизированы для создания монолита.

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


Это самый ясный ответ на данный момент.
Тони Эннис

7

Здесь есть много хороших ответов, поэтому я просто добавлю свой опыт реализации.

Вот как я делаю вещи:

  • Создайте слой доступа к базе данных, который обрабатывает все / только взаимодействие с БД (обычно для скорости и контроля используется ручной SQL, без ORM) . Вставить, Обновить, Удалить, Выбрать ...
  • Создайте interface( virtual class), который предоставляет / реализует нужные мне функции API. При реализации они будут использовать узкоспециализированные функции DBAL для достижения результатов. Это также помогает мне применять API на уровне компилятора, поэтому я уверен, что реализация Server + API имеет все встроенные функции.
  • Создайте второй уровень, который реализует интерфейс (это фактический API) и применяет ограничения безопасности. Вы также взаимодействуете с внешними API здесь.
  • Веб-сайт будет использовать второй уровень напрямую (для повышения производительности), не используя удаленно доступный API (например, SOAP, JSON) .
  • Автономный Сервер - это сборка, которая реализует интерфейс и предоставляет Второй Уровень в качестве фактического удаленно доступного API для внешних настольных / мобильных клиентов (без доступа к веб-сайту) . Все, что он делает, это декодирует запросы и кодирует ответы и управляет / отключает клиентов. Он также поддерживает возможности возврата для массового уведомления клиентов о событиях, генерируемых другими подключенными партнерами (функциональность, которая обычно не требуется веб-сайту) .

Технически, API - это Второй уровень. Вы используете его непосредственно на веб-сайте и предоставляете его удаленным клиентам через сервер. Код используется повторно, и ни один фрагмент кода многократного использования не может быть встроен. (живи и умри по этому правилу, и все замечательно) Помогает с ремонтопригодностью, тестированием ... всем.

Вы никогда не подключаете веб-сайт к настольному / мобильному API-серверу (если ваш сайт не является AJAX и работает на JSON) . Но если сайт отображает динамический контент в разметке, использование промежуточного API снизит вашу производительность. Сайт должен быть быстрым! Удаленный доступ к клиенту может быть немного медленнее.

PS : Да, обслуживание немного сложнее, так как большее количество колес работает вместе, но это легче в долгосрочной перспективе. Поэтому, если ваш проект рассчитан на некоторое время и немного сложен, всегда используйте API. Также намного проще протестировать каждый слой отдельно.


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

6

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

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

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

пример

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

Число вызовов API, которое может потребоваться для достойного API, вероятно, будет равно 1. Да, это негибко, но почему вы хотите, чтобы оно было гибким?


4

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

Ну а ты? Если нет, то это довольно неуместное утверждение.

Я бы сказал, если бы вы собирались создать новое приложение в 2015 году, а затем серьезно заняться чем-то с пользовательским интерфейсом, который включает API, а не сгенерированные сервером HTML-страницы. Есть явные затраты, но также и явные выгоды.

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


4

Короткая версия: Ваш контроллер эффективно API независимо от того, что; хотя ASP.NET может скрывать это.

Более длинная версия:

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

/sign_in
/sign_out
/beer
/beer/{beer_name}
/order
/order/{order_number}

В обычном веб-приложении есть несколько вспомогательных маршрутов, таких как:

/beer/new
/beer/{beer_name}/edit
/beer/{beer_name}/delete
/order/new
/order/{order_number}/edit
/order/{order_number}/delete

В веб-API они не требуются, так как выводятся из метода HTTP.

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

После некоторых копаний я определил, что это может быть для вас ситуацией в зависимости от того, какую версию ASP.NET вы используете. В старых MVC 5 и более ранних версиях отсутствуют соглашения и интерфейс для разумного объединения двух реализаций. В старых версиях возврат Web App заполняет представление, тогда как API дает HttpResponse. В любом случае, однако, они генерируют точно такой же ответ семантически.

Если вы используете MVC 6, вы получаете оба в унифицированном классе контроллера, который может быть умным в отношении того, что он возвращает. Я не нашел хорошего примера кода ASP для этой модели, но нашел код Rails с тем же шаблоном. Рассмотрим этот контроллер для «лайков» из проекта диаспоры . Каждый метод управления имеет маршруты , определенные в «изобретательной конвенции» здесь эту сумму к LCRUD в качестве API.

Однако, если вы читаете реализации, каждая из них может ответить на HTML, Mobile HTML или JSON. Это в сочетании с соглашением о поиске представлений полностью объединяет веб-приложение и веб-API. Вы также заметите, что не все методы на самом деле предоставляют каждый ответ (что имеет смысл, поскольку для пользовательского интерфейса могут потребоваться методы, которых API не будет, и наоборот).

Это несоответствие импеданса, потому что ASP.NET вроде бы все это выяснил поздно, тогда как Rails уже некоторое время воспринимает симметрию и делает это очень ясным.

Спекуляция:

Ваш коллега, вероятно, прав и неправ, в зависимости от того, какую версию ASP вы используете. В старой версии MVC различие между API и приложением, вероятно, делало его «наилучшей практикой» для создания API заранее, потому что модель ASP.NET действительно не допускала хорошего повторного использования кода.

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

В любом случае, однако, Контроллер по сути является API.


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

Чем больше ответов, тем лучше, они помогают получить всестороннюю оценку того, что другие люди думают об этом.
NibblyPig

2

Когда я начал свою карьеру в 2006 году, этот тип архитектуры был в моде в мире .NET. Я работал над 3 отдельными проектами, задуманными в середине 2000-х годов с веб-сервисом между уровнем бизнес-логики и веб-интерфейсом. Конечно, в наши дни веб-сервисы были SOAP, но это все та же архитектура. Предполагаемые преимущества заключались в возможности переключаться на передний или задний план и даже разрабатывать настольные программы. В конечном итоге ЯГНИ подтвердилось. Я никогда не видел, чтобы это случилось. Все это время я видел только стоимость разделения проекта таким образом. Я даже закончил тем, что вырывал веб-сервис из одного из проектов (ушло полгода, чтобы удалить его шаг за шагом, делая другие вещи), и вся команда была счастлива. С тех пор я никогда не пробовал такой подход, и я не буду, если не будет дана очень конкретная причина. 5 лет опыта работы с этой архитектурой научили меня, что она мне не понадобится, и никакое количество экспертов, говорящих мне об обратном, не убедит меня в этом. Только проект, в котором я нуждаюсь, может сделать это.

Теперь, как говорится, я очень стараюсь создать слой между бизнес-логикой и контроллерами / докладчиками. Например, у меня есть сервисный уровень, я никогда не выставляю запросы, использую интерфейсы для всех моих сервисов и внедряю их в контроллеры с IoC. Если мне когда-нибудь понадобится веб-сервис в моей архитектуре, я смогу внедрить его с разумной стоимостью. Я просто не хочу платить эту стоимость заранее.

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


2

Третьи лица будут использовать это? Да, ты должен .

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

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

Фронтенд никогда не увидит свет из-за причин? Да, ты должен .
Я добавил эту причину, потому что, ну, это случилось со мной много.
И, по крайней мере, у меня остались компоненты для повторного использования, перераспределения и т. Д.


1

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

Нельзя утверждать, что YAGNI - причина не создавать API.

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.