Как стать автором
Обновить

Комментарии 255

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

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

Да вот хотя бы FastAPI так делает из коробки

Gui - просто сокращение механической работы. Что ворчать на него ?
OpenApi дает тот же самый результат, просто менее удобно

Для ASP.NET Core есть, например, Swashbuckle.

Это генерация из кода, это не Spec-First.

Слушайте, ваш подход spec-first имеет место быть. Но не везде. Я сталкивался с ситуациями, когда требования к API мегялись в процессе разработки и тестирования. Наш фронтендер потребовал сохранить старый контракт на API, и мы получили в итоге очень проблемные баги, которые решали две недели. А ещё, некоторые движки, типа Django, имеют определённые ограничения при разработке обёртки. Движок выбирается по многим причинам, и если фронтенд начнёт создавать для такого движка контракты на апи, то это приведёт к расходам и проблемам. Будем объективны: в абсолютном большинстве ситуаций фронтенд не может делать контракт на API по объективным причинам. Например, потому, что смена схемы вывода данных, инициированная бэком, может ускорить запрос к бд. Или потому, что у движка есть ограничения. Или потому, что фронтендер не является опытным архитектором АПИ. В большинстве случаев, фронтенд реально нуждается только в том, чтобы бэк вернул определённые данные, а форма этих данных важна лишь в минимуме ситуаций. Плюс, вынести часть расчётов на фронт - это нормально. Бэкендер ограничен производительностью сервера, а фронтендер в большинстве ситуаций может не беспокоиться о производительности пары лишних циклов. Поэтому, ваш подход слишком радикален. Да, есть ситуации, когда бэк обязан вернуть ответ по контракту фронта. Но это слишком редкие ситуации, когда реально фронт нельзя переписать. И меня смущает, что вы в своей статье не затронули вопросы ограничений бэка и фронта, которые могли бы вывести ваш подход на более логичные рельсы. Например, как вы собираетесь обходить ограничения движка? Как собираетесь реагировать на необходимость оптимизации запроса к бд посредством смены API схем? Если ваш подход работает в обстоятельствах, где эти детали не критичны, то так и пишите: этот подход работает на лоу-лоаде сервера, когда проблемами бэкенда можно пренебречь.

Я лично использовал вариант, когда опрашивал фронтэнд разработчиков, и они мне кидали образцы json, которые я мог воспроизвести в API. Увы, в том числе, фронтендеры не всегда давали проработанный вариант, и контракт приходилось менять по разным причинам. Были ситуации, когда я программировал и по схеме контрактной разработки АПИ, но контракт прорабатывался и для фронта, и для бэка, с учётом всех возможных ограничений и подводных камней.

Ммм, я думал что созданием контракта должен рулить некто "архитектор". Понимающий, как система в целом будет функционировать. А не только какая-то из её частей. Если, конечно, одна из частей не является анемичной (REST поверх хранилища данных, или наоборот тонкий UI на клиенте).

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

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

Dilbert strips

не вижу противоречия, разве что архитектор только мышкой умеет проектировать)

Вот опять не удержаться от комикса

Похоже, что у вас очень депрессивное рабочее окружение, что за конторка? Меняйте пока не поздно. Развиваться в окружении такого кол-ва болванов, очень сложно ...

тут недопонимание возникло) это сарказм был

Насколько я в теме, архитекторов вещи типа формата json не волнуют от слова совсем и я их отлично понимаю:-)

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

В статье речь про swagger, а это именно что описание протокола, причём не универсального, а отдельная спецификация на каждый эндпоинт.

Я могу ошибаться, но мне кажется, что мы под протоколами разное подразумеваем :-) Вы таки из фронта?)))

Мне всегда казалось, что этап проектирования находится до этапа кодирования.

Визуальная среда, в данном случае, позволяет быть в одинаковом контексте: это уже не сырой ux, для которого нужно API. Фронты готовят draft-контракт, который уже совместно доводится до ума, финализируется. И показывают, почему они видят именно так.

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

-

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

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

Да это просто декларация классов и типов полей, нет там никаких особых трат времени.

А какой процесс предпочитаете Вы?

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

Ну, то же самое, только с другой стороны.

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

А коммуникация в чатах с JSON-чиками?

ссылка на сваггер

Он сгенерирован на базе кода уже или написан в YAML заранее?

автоматически сгенерирован, конечно

А перед кодом, что-то было? Фронты как-то учавствовали в обсуждении того какие данные придут с бэка? Какие параметры при этом нужно передавать?

Или бэк сделал как это пока сам видит?

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

Вот самый главный вопрос как это обсудается? В чатах с JSON? На митинге голосом?

Что если вместе открыть редактор и писать сразу контракт, а потом начать работать паралельно? А потом еще и проверить, что он выполнен правильно? Лишняя не нужная работа? Интересно ваше мнение.

GET /users/{id}

parameters:
- name: id
  in: path
  required: true
  description: Target user
  schema:
    type: integer
    format: int64
    example: 1
responses:
  '200':
    description: OK
    content:
      application/json:
        schema:
          $ref: '#/components/schemas/User'

User

type: object
properties:
  id:
    type: integer
    nullable: false
    format: int64
    example: 1
  name:
    type: string
    nullable: false
    example: Ralph Edwards
  avatar:
    type: string
    nullable: true
    format: URL
    example: https://static.server.com/ralph.jpg

параллельная работа, боюсь вызовет у вас желание написать еще один пост, если вы узнаете, что задачи фронту тоже ставит бэк)

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

Спасибо за комментарий, но аргументы немного странные, извините.

не вижу смысла обсуждать контракт, бэк просто его напишет так, как нужно)

Получается, фронты вообще не нужны. За них все придумает бэк. Вопрос, точно ли он сделает все как нужно. А потом митинги, согласования, изменения и т.д.

Бэк выдает все 20 полей из сущности, а фронты выведут только 5 и эти 15 оставшиеся будут бегать по сети просто так и есть траффик пользователя и время на сериализацию.

Бэк выдает все 20 полей

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

А может вам всем вместе стоит просто один раз все обсудить)

Чтобы он дал необходимое и достаточное, он должен понимать, как будет работать фронт. Но тогда это не чистый бэкенд-разработчик

Очень много если. Почему нельзя отдать на бекенд по-сути ТЗ записанное в виде контрактра на Swagger, а не полагаться на его профессионализм и "понимание фронта"?

Фронт может заниматься своим прямым делом — написанием фронта. Почему я, как бек девелопер, не могу посмотреть дизайн в фигме, и потом отдать фронту готовое апи с достаточными и не излишними данными? А если у нас при этом еще и GraphQL, то вопрос underfetching / overfetching решается сам по себе вообще.

Насколько бекенд разработчик хорошо может разбираться в UI, что бы по нему сделать качественный API?

Я не хочу кидаться шапками и говорить «да фигня ваш фронт», но я не совсем понимаю вопрос — что значит «разбираться в UI»? Вот я смотрю дизайн, вижу что там есть условный дропдаун с выбором customer name — значит, фронту нужен customer name и customer id. Бывают более сложные случаи, конечно, если я в чем-то не уверен — консультируюсь с фронтендерами, они высказывают свои пожелания и я их учитываю. Но, в любом случае, проектирование API — это задача бекенда. В конце концов, это самое API может использоваться приложением на реакте, мобильными приложениями iOS и Android, а еще оно напрямую может использоваться клиентами как public API. И условный frontend react developer будет в этом понимать больше чем бекендер? Почему?

Как вы считаете, а так будет лучше для Вас как для бэка?

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

И бэку не нужно залезать в Фигму, лазить по экранам, разбираться во всей UX/UX специфике приложения.

Нет, не будет лучше. Фронт — это всего-лишь клиент к бекенду. И я этим не пытаюсь унизить фронт, не поймите неправильно — я вполне себе могу представить ситуацию, когда логики и даже алгоритмов там больше чем на бекенде (какая-нибудь онлайн версия фотошопа, например). Но фронт остается клиентом, и (потенциально) одним из многих клиентов. web UI, iOS app, Android app… Для каждого делать отдельный API? Может в этом и есть смысл, но чаще его нет. И кого же мне слушать — реакт девелопера Васю, свифт девелопера Колю, или же котлин девелопера Ваню? У всех у них свои пожелания к API, у всех у них разный интерфейс. Поэтому проектировать API (а это часть бекенда) должны на бекенде. Учитывая желания разработчиков консьюмеров этого самого API, конечно же.

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

И не надо для каждой сущности изобретать свой протокол взаимодействия да ещё и прибитый гвоздями к HTTP.

Достаточно через любую систему контроля версий согласвать схему предметной обасти

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

Покупателю - лишнее, а вот менеджеру уже нет.

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

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

Не подскажите что формат описания?

Есть обратный случай, когда бэк тривиален и состоит из CRUD и перекладывания JSON между БД и фронтом, для реализации такого есть даже кодогенерация из swagger-файлов.
Почему бы в таком случае не воспользоваться?

Но ведь Swagger это же не про генерацию. Я ведь писал:

Многие думают, что Swagger (Open API) – это «UI шкурка», которую генерирует в конечном счете бек из кода, они не понимают, что это в первую очередь – JSON схема описания API.

Не ужели это не так?

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

Мне кажется, что фронтенд не должен проектировать api. Фронтенд должен очень четко описать, что он хочет получить в api. А бэкендер должен очень ответственно и честно объяснить почему лучше сделать по другому.

Собственно, Вы кратко выразили содержание поста: совместное проектирование.

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

В вашем примере меня удивляет квалификация бэка: почему они не спорили? Не выдвигали аргументы?

Ответственность за API всегда должна быть на бэке, но нет никаких проблем построить процессы так, что наброски контрактов готовятся фронтами (которые, в свою очередь определяет ux), а дальше уже валидируются бэками. А ещё можно сразу обсуждать вместе: ux, front, middleware|back, PO. Я и с таким процессом работал.

-

Как фронт, скажу: мне вот нафиг надо делать ещё и работу по проектированию api. Но - надо, бэк не погружается в ux так же как я, у него своей работы море. Поэтому - совместная работа, с уважением к работе друга: фронты - это не формошлепы, а бэки|middleware не crud-ошлепы.

А как же тогда сказать бэку, что вам от него нужно? Чаты? JSON-чики?

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

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

Фронты могут проектировать API

Как мобильный разработчик, ранее затрагивавший БД и бек — кмк, лучше бы фронты не брались действительно за проектирование апи, если у них нет знания кодовой базы бека и бд. Ну либо апи разрабатывалось бы совместно. Ибо без знания какие там индексы, какие субд используются подо что, какие запросы сейчас для бека тяжелые а какие нет — можно дел наворотить.

Только в посте об этом и написано: совместно.

Просто риторика поста должна была быть более чёткой: фронты могут (должны?) принимать участие в проектировании API.

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

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

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

Там еще по тексту есть еще отсылки к совместной работе и улучшению процесса.

Здесь речь описывается уже рабочий процесс, который принят в команде, а не топание ножкой "я не обезьянка".

Вообще, кмк, мы тут видим что-то похожее на DDD

Это не так, вся статья пронизана, что фронты-вносят предложения, а бэк согласовывает.

Да, там есть по совместную работу, но в конце суммируется видение:

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

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

Это кошмар, это обычно приводит к созданию отдельных API под каждый экран, тип клиента (десктоп, телефон, планшет) и т.д.

Обычно всё-таки проектируются use cases, выясняется какой API нужен для их поддержки, а не для конкретного экрана. То есть, в терминах автора, опираясь на use cases, а не конкретный UI (который может очень часто меняются).

Хоть автор и пишет "spec first", но у них явно UI first. А надо API first, и проектировать его должен кто-то понимающий и проектирующий use cases, а не под конкретные экраны.

UI, точнее UX, определяет use case.

Визуальное представление здесь важно, чтобы показать всем участникам процесса как будет использоваться API. Это позволяет предусмотреть граничные случаи и обсуждать вопросы предметно: нет человека, который продумывает use case на 100%, есть наброски, которые уже доводятся до ума коллегиально.

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

Или вы думаете, что там дураки сидят и не думают о планировании развития?

Я не считаю никого дураками, просто так описано - всё после рисования экранов, а не после дизайна use cases. А экраны обычно заметно разные для десктопа, мобильного веба, мобильных приложений, и т.д.

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

Что такое use case в вашем понимании?

В моем схема может быть такая, для ситуации в посте:

  • бизнес даёт требование в виде: нам нужно сделать страницу с аналитикой по каждому пользователю (с кучкой всякой функциональности)

  • PO формирует feature task, в котором будет draft use case

  • Задача уходит к ux-специалистку, промышленному дизайнеру, который строит интерфейсы так, чтобы пользователь был доволен: определяет use cases: мобилки, десктоп

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

  • Бэки валидируют, согласовывают, что-то меняют или полностью рубят.

  • Если есть проблемы, то организовывается общий митинг с PO для поиска решений

  • Если нет, то контракт фиксируется. Дизайнеры, бэки и фронты работают параллельно.

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

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

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

А то, что вместо одного запроса надо отправить три 3, соответсвенно, ошибки каждого требуется обработать и как-то вплести во флоу пользователя — это пустяки.

Заем вы обрабатываете ошибки каждого запроса по отдельности? Напишите уже обобщённый код.

Заем вы обрабатываете ошибки каждого запроса по отдельности?

За тем, что для разных ошибок требуется разная обработка, в зависимости от контекста.

И тут дело не только в обобщенном коде. 3 запроса с клиента — это менее стабильно, сеть может пропасть между запросами, надо решать вопросы, например, консистенции из-за этого.

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

Ну да, а ещё 3 запроса можно запускать параллельно да ещё и к разным серверам и по разному кешировать.

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

Ну, представим ситуацию. Она почти выдуманная (похожее в моей практике было). В мобильном приложении пользователь создает каким-то образом сущности "магазин", "отдел", "полка", которые, конечно же, связаны между собой. Упертый бекенд хочет строго следовать json api и требует отправлять эти сущности тремя разными post-запросами. Как я писал выше, потому что бекенду "так удобнее". Каждый запрос отправляет свои поля, поэтому ошибки валидации могут быть разные.

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

ещё 3 запроса можно запускать параллельно да ещё и к разным серверам и по разному кешировать

Если надо 3 запроса к 3 разным серверам, то это будет 3 запроса. Но мы сейчас говорим немножко не об этом. И опять же если у нас клиент ходит в 3 разных места, то чаще всего мы что-то делаем не так. Логику похода в разные места на бекенд закинуть опять же проще, а не раскрывать такие знания клиенту.

Ошибки валидации просто мёржатся и обрабатываются единоообразно. Ну а если запросы к серверу неидемпотентны, то проблемы будут что с 1, что с 3 запросами. А если идемпотентны, то проблем не будет и так и так.

Поход в разные места - это, например, авторизация на сервере авторизации, получение справочников из cdn и создание профиля на конкретном сервисе.

проблемы будут что с 1, что с 3 запросами

Проблемы разного уровня. Если после одного запроса пропадает сеть и 2 других не доходят, незаконченная сущность будет болтаться на бекенде неопределенное количество времени. Мне что-то кажется, вы не делали мобильных приложений :)

авторизация на сервере авторизации, получение справочников из cdn и создание профиля на конкретном сервисе

Это три разные вещи, непонятно, почему мы о них говорим.

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

А для пользователя это одна вещь - форма регистрации в сервисе.

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

Иронично, что вы перечислили как раз те стороны API, которые не играют никакой роли. Настоящая боль плохого API — в изменяющих запросах.


Допустим, у вас есть сущность foo в коллекции foos, и вам хочется её создать. Казалось бы, логично это делать через POST либо PUT на какой-нибудь URL /foos/create или там /foos/new? Но как только вы включаете такую конечную точку в ваш API — вы тем самым постулируете, что сущность foo является самостоятельной сущностью, и может быть создана в отрыве от остальных. А это совершенно не всегда так. Возможно, что сама возможность создать foo и какой-нибудь bar не парой, а по-отдельности, уже является дырой в безопасности.


Впрочем, бывает и наоборот. Когда за проектирование БД берутся какие-нибудь бизнес-аналитики, они всегда забывают о праве пользователя сделать перерыв при заполнении формы на пару дней — а потом эти требования неизбежно и в API перекочёвывают; так что желание фронтов на процесс проектирования API хоть как-то влиять вполне понятно.

"Казалось бы, логично это делать через POST либо PUT"

что за бред. /foos сам по себе должен являтся ресурсом. GET - view data, POST - create, PUT-update. DELETE - соответственно.

Связь сущьностей foo и bar API не регламинтирует. просто POST /foos шлет лесом запрос в котором отсутствует в data внешний ключ, передовая соответсвующий http status...

что за бред. /foos сам по себе должен являтся ресурсом

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


просто POST /foos шлет лесом запрос в котором отсутствует в data внешний ключ

Тем самым постулируется возможность создать сначала bar, а потом создать (или не создать) foo. Но что делать если они могут быть созданы только парой?

Но что делать если они могут быть созданы только парой?

Как вариант — вводится понятие какого-то FooBarEntity, и потом POST /foobars.

Ну да, разумеется как-то так сделать и надо. Но известно ли это фронтендерам, что требования безопасности не разрешают создавать эти сущности иначе как парами?

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

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

Так то подобные вещи нужно обсудить внутри команды, если будет одобрение - тогда вперед. Если нет - ну можно попробовать в следующем проекте предложить.

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

Честно говоря не понял насчет "проектирования API". Как это всё должно выглядеть и пролезать в транспорт? Это да, тут участие фронта очень часто нужно, а то без этого участия то long в JSON попробуют положить числом, то справочные данные выведут не один раз на ответ, а один раз на каждую из 10000 строк таблицы.
А вот в вопросы "как это всё будет работать" я с фронта и не собираюсь лезть. Тут бэкам сильно виднее, где у них будут узкие места, и как сквозь них всё должно пролезать.

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

А я вижу в этом подходе нечто похожее на предметно-ориентированное программирование.

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

Малый масштаб - Вы про размеры задач? Думаю, тут вопрос конкретных процессов.

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

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

В общем, это один из возможных инструментов, который кому-то подойдёт, а кому-то нет.

Я про масштаб проекта. Вкратце:

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

Интересная мысль возникла по поводу:

В общем, это один из возможных инструментов, который кому-то подойдёт, а кому-то нет.

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

Понял Вас, спасибо.

Беда, коль пироги начнет печи сапожник,

А сапоги тачать пирожник,

И дело не пойдет на лад.

Да и примечено стократ,

Что кто за ремесло чужое браться любит,

Тот завсегда других упрямей и вздорней:

Он лучше дело всё погубит,

И рад скорей

Посмешищем стать света,

Чем у честных и знающих людей

Спросить иль выслушать разумного совета.

И. А. Крылов

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

Угу, а потом прохладные истории о том как бэк переименовал и перетасовал поля в API потому что у него видение БД сменилось а фронт 2 недели ползал по коду чтобы эти переименования правильно заселить.

Работаете вместе ну так работайте вместе, и над API тоже

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

Иначе - когда фронтом является мобильное приложение, и требуется поддерживать старые версии, пока все клиенты не мигрируют на актуальную

 бэк переименовал и перетасовал поля в API потому что у него видение БД сменилось а фронт 2 недели ползал по коду чтобы эти переименования правильно заселить

Частично поменялись точки реста. Я понимаю боль фронта, но как иначе?

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


Как только респонс не соответствует принятому контракту - прерывание работы приложения и запись в лог, что именно не так. В итоге - находится и поправляется всё очень быстро (особенно если код на TS).


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

Если бизнес устраивает двойная валидация, и проброс ошибок в обоих направлениях, то это отличный вариант.

Т.к. по настоящему доверять мы (фронты) можем только своему написанному коду

Да тоже не особо выйдет, в код можно и вмешаться. Как в веб странички, так и в нативный.

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

Как часто меняется определение сапога? Если "сапог" уже депрекейтед, а его замена - "лапоть" всё ещё в стадии MVP, то на что полагаться? На сапоги (которые работают, но deprecated), или на лапти, которые многообещающие, но только в форме обещаний, а сейчас ничего не умеют?

Жизнь в IT нельзя передавать через профессии, в которых правнук учится тому же, чему учился прадед.

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

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

Кстати о сваггере и прочих OpenAPI. Лично мне они не нравятся тем, что сводят весь REST к RPC. Не то чтобы это было плохо — в конце концов, RPC не просто так стало популярной штукой, но остаётся какое-то чувство некрасивости.


Вот я делаю конечную точку для импорта данных в коллекцию, с маршрутом вида /api/{collection}/{version}/import. Именно в таком порядке — ведь я позаботился (пусть меня и не просили) чтобы по пути /api/{collection} можно было увидеть список версий, а по пути /api/{collection}/{version} — список всех возможных операций и их доступность для текущего пользователя; и таким образом получается красивая естественная вложенность ресурсов.


А потом эта конечная точка попадает в OpenAPI под именем ImportDataToCollectionVersion, под тем же именем она попадает в автоматически сгенерированный клиент, и вообще никто не видит итогового URL. С тем же успехом я мог сделать конечную точку /api/import?collection={collection}&version={version}, и ничего бы не изменилось для системы в целом.

При наличии возможности однозначного преобразования URI (из красивого пути со слешами в путь с параметрами и наоборот, как, например, лет 10-15 назад массово делали для проектов на PHP + Apache mod-rewrite) это вообще несущественная деталь. Выше уже сказали, что API, в первую очередь, это про определение набора сущностей, с которыми можно взаимодействовать, и способ взаимодействия (просмотр, изменение, удаление). И эту задачу обычно решает архитектор, видя все ограничения на стадии проектирования.

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

REST — оно как раз про структуру URL и HTTP-методы
RPC — оно про возможность вызвать функцию, которая выполнится на другом хосте


При использовании генератора клиента на основе OpenAPI и любого современного серверного фреймворка сетевое взаимодействие происходит так:


  1. на клиенте вызывается функция, которая делает HTTP-запрос;
  2. на сервере этот запрос приводит к вызову определённого метода у контроллера.

Это в чистом виде RPC, а весь REST становится всего лишь причудой транспортного слоя.


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

И эта задача вообще не имеет никакого отношения к REST. Её как раньше для SOAP решали, как для JSON-RPC решали — так и для REST решают, решения не меняются (разве что REST требует немного более аккуратного решения — и то не всегда).

REST — оно как раз про структуру URL и HTTP-методы

По вашей ссылке, есть пункт 4.1: Идентификация ресурсов. Это, как минимум, показывает, что URL для REST таки интерес представляет.


А холиварить про то, насколько текущее понимание термина "RESTful" большинством программистов соответствует изначальному мне не интересно — потому что swagger сводит к RPC любую из этих интерпретаций с одинаковым успехом. Не взирая на то, что по вашей же ссылке REST и RPC прямо противопоставляются.

С тем же успехом я мог сделать конечную точку /api/import?collection={collection}&version={version}, и ничего бы не изменилось для системы в целом.

Более того, так и стоит делать изначально. А ещё лучше так: /api/import?version={versionId}

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

А кто вам сказал, что versionId однозначно задаёт номер версии в отрыве от кода коллекции?

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

А нахера он нужен в запросе, суррогатный-то ключ? Он же неудобен: становится известен только после деплоя, потенциально различается на проде, стейджинге и в dev-контуре.


В то же время, пара из кода коллекции и номера версии зачастую известна ещё до начала разработки. И вообще весь префикс "http://{домен}/api/{collection}/{version}/" в той системе в большинстве бизнес-процессов можно было бы даже хардкодить в строковых литералах, если бы не сваггер.

Речь, очевидно, про динамические, а не статические параметры.

Чем динамический параметр отличается от статического, и почему вам более очевидно о чём речь чем мне?

Если фронты хорошо знают REST

У фронтов принято гордиться тем, что "хорошо" знаешь REST? Что там знать-то, и тем более "хорошо"? Как послать HTTP-запрос? Кажется, все вам правильно сказали.

НЛО прилетело и опубликовало эту надпись здесь

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

При диссертации и книжки вообще смешно.

А что смешного? REST это вообще-то архитектурный паттерн и таки да, был темой диссертации. HTTP там вообще не при чем, просто удобно оказалось.

Демонстрировать воинствующее невежество на людях не стоит, все же.

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

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

Как-то неправильно этот ваш "коллективный разум" отработал :)

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

Время всё расставило таким образом, что термин REST стал самым заезженным и бесмысленным баззвордом в бекенд-разработке. Модную приставку RESTful к API припысывает даже последняя собака не зависимо от того каким принципам этот API следует или не слеует.

Выше человек все правильно написал, что исходно REST является архитектурным стилем гипертекстового веба от одного из главных авторов HTTP 1.1, который тот сформулировал в процессе стандартизации протокола. За 20 лет не изменилось ничего - в ядре современного веба работают 6 из 6 огранчений REST. Я не знаю, как так вышло, но с какого-то момента этот термин стали противопоставлять SOAP и затем исказили до CRUD over HTTP, хотя методы HTTP напрямую с CRUD даже не сопоставляются.

Раздутый карго-культ о котором вы писали является порождением этого самого "коллективного разума", который работает как сломанный телефон. Никто не занимает факт-чекингом, ни на что не ссылается, никто не заглядывает в первоисточнки. Зачем, если достаточно прочитать первую нагугленную статью от Krishna Srinivasan?

Простите, не удержался :)


Очень похоже )))

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

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

Лучше слушать фронтов с самого начала - требования от клиента приходят в первую очередь им. Клиенту неинтересно слушать что у вас там на бэкенде чистый код, DRY/KISS и stateless запросы - он смотрит как быстро страничка загружается и хочет иметь три разных вида корзины, а через месяц захочет четвертый.

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

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

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

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

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

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

Ну это ж как раз вроде нормальный вариант. Было дело - так и работали: система с ноля, вообще ничего ещё нет, только общее представление о бизнес-сущностях и макеты приложения.
1. Прошлись по макетам- стали понятны клиентские выборки. Добавили в список всякие системные (авторизацию, пуши на обновления итд).
2. Прикинули структуру бэка (сущности, взаимосвязи) - стало понятно, какие выборки и чего будут стоить.
Наложили 1 на 2, подрихтовали заведомо неудобные выборки, написали спеку в apiary, отдали аутсорсерам с приложенькой и ушли пилить бэк под эту спеку. Периодически синкались для тестов.

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

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

Вторая проблема: коммуникации. Разработчики вроде друг другу не враги: взяли тряпки, обоссали и пошли стеной на PM/PO.

Клиенту неинтересно слушать что у вас там на бэкенде чистый код, DRY/KISS и stateless запросы - он смотрит как быстро страничка загружается и хочет иметь три разных вида корзины, а через месяц захочет четвертый

Прямо с языка снято. А вообще можно посмотреть в сторону GraphQL - он позволяет избежать ситуации с пятью разными, но похожими запросами

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

Другими словами - это наличие слоя бизнес-логики (слоя сервисов + БД) и слоя API (контроллеры + трансформеры, которые дергают и склеивают данные из разных сервсов).

Хочу поддержать разумное мнение.

Я сейчас пишу фронт и бэк. И когда встал вопрос взаимодействия, пришлось отталкиваться от фронта, потому что фронт крайне необходимо сделать максимально лёгким. Потому что фронт в браузере, потому что фронт не масштабируется, потому что фронт бывает на дохлых древних смартфонах, потому что у фронта, помимо бизес логики, есть UI логика, которая жрёт (прощай React, пробуем Svelte). И чем "тоньше" фронт, тем плавнее и лучше user experience, следовательно, счастливый пользователь - тучный бизнес.

Тут мне могут возразить разработчики фронта как нативного приложения и разработчики, которые расчитывают только на desktop пользователей. Но будем честны, статистика упрямо показывает отток на мобильные устройства. А универсальность и скорость создания UI с помощью html, css и js выпихивает натив в узкие ниши. Конечно, скорость мобильных soc растёт, но, во-первых, всё равно упирается в батарейку (Snapdragon 8 прозрачно намекает), во-вторых, прирост производительности лучше отдать на логику UI, потому что быстрее разрабатывать и дешевле поддерживать. Вжух, MVP выкатываем...

И если принять как факт, что зайти на сайт совсем не тоже самое, что открыть магазин и установить приложение (а тут ещё тараканы с permissions), станет ясна заинтересованность бизнеса в PWA. В свете изложенного, наличие двух эндпойнтов, отличающихся даже только сортировкой, уже перестают казаться "бредовыми требованиями 'глупого' фронтендера". Ну, в самом деле, на бэке и вся логика под рукой, и лишний эндпойнт это пара строк кода плюс отдельная функция, что способствует лучшей структурируемости проекта.

НЛО прилетело и опубликовало эту надпись здесь

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

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

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

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

Я бы в первую очередь рассмотрел проектирование API в широком смысле, без привязке к какому-либо протоколу передачи данных, будь то http по tcp/ip или обычный вызов функции.

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

В этом смысле условный User GetUser(int id) и GET /users/{id} решают одну и ту же задачу.

Далее у вас есть вполне очевидное требование, что consumer и provider это не части одной программы и даже не находятся на одной машине.

Поэтому вы выбираете последовательно протоколы на 4-7 уровнях OSI. Обычно всё сводится к TCP/IP и HTTP. И в этот самый момент, если у вас есть человек, отвечающий за архитектуру, стоит выбрать какой-то стандарт, который вы будете использовать. Вы можете остановиться на REST, добавить к нему JSON API, или же можете взять GraphQL. Возможно вам нужно своё решение. В редких случаях, стандарт трудно принять или практически невозможно, но частично стандартизировать что-либо можно, например способ именования параметров или ещё что-либо.

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

Если же бэкэнд достаточно сложный, то фронтэнд спректировать апи не может, и всё, что может сделать фронтэнд, это дать бэкэнд разработчикам input и ожидаемый output и попросить апи, которое им предоставят. Вот тут вероятно то, что концептуально выглядит как одна функция на фронтэнде, может превратиться в более чем один вызов функции (а в вашем случае в несколько HTTP запросов), либо, в целях оптимизации, в новый и сложный эндпойнт, который делает то, что вам нужно за один вызов. И вот тут, если вы используете достаточно хороший стандарт, спецификация может оказаться лучшим языком общения. А может и не быть им.

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

Нужно ли для такой коллаборации специальное решение? Не уверен. Но и критиковать ваш проект я не готов.

КПДВ напомнило шикарное видео:

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

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

Это называется, backend for frontend. Его, кстати, не обязательно могут писать разработчики фронтенда. И не обязательно на node :) Но он может лучше отвечать потребностям фронтенда и скрывать внутреннюю кухню.

Да просто тимлид фронтов и тимлид бэков должны быть сопоставимы по квалификации, а не сеньор с одной стороны и малоопытный мид.

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

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

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

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

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

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

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

Я как фулл-стак разраб подтверждаю что фронтендеры это просто макаки. Их максимум кодерами назвать можно.

Бек обычно дальше от бизнес-требований, чем фронт, хуже понимание продукта. Ничем хорошим не заканчивалось, когда беку отдавался API на проектирование, куча времени утекало на коммуникации. Я пока пришел к реверс-схеме. Фронт пишет часть бека - ключевые dto, сразу задавая демо-данные. Фактически - мок сервер. В нашем случае - используется graphql с хорошо именованными резолверами. Где надо - делает комменты. Дальше кодогеренацией из gql-схемы рождается фронт-sdk, чтобы были единые контракты фронта и бека. Бек превращает мок-сервер в реальный, фронт в это время пилит фронт. По дороге вносятся небольшие изменения, но это сразу отражается в контрактах при кодогенерации и если что-то добавилось это сразу палится typescript-ом на фронте.

Бек обычно дальше от бизнес-требований, чем фронт

Это что, шутка такая?

Как обмениваетесь этой документацией?

GraphQL решает большую часть этих всех проблем. Мы уже 4 года только на нем, и я с ужасом вспоминаю всю ту дичь, которая была с REST.

Как решаете проблемы с кэшированием в GraphQL? REST легко закэшировать на уровне nginx искользуя в качестве ключа URL. GraphQL все запросы шлются через POST при этом в одном запросе могут комбинироваться как фетчи так и мутации вместе.

Кеширование можно делать не только на уровне nginx :)

Это верно, вопрос только в скорости кэша в этоге.

На уровне http мы ничего не кешируем. Мне не очень вообще понятно что можно в API кешировать на уровне http. Можно пример какой-то не синтетический? Вот в хабре, например - какие API можно и нужно закешировать?

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

Вот отличная статья https://www.nginx.com/blog/nginx-caching-guide/

На хабре я бы закэшировал https://habr.com/kek/v2/inset/vacancies, а когда нужно сбросил бы кэш на nginx для этого урла.

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

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

И почему же это всегда дорого и медленно?

Потому-что воркер очевидно требует больше ресурсов для запуска и работы, даже если в вашем коде Вы просто забираете данные из memcache например. И Ваш ответ не будет занимать 10 миллисекунд как при nginx кеше, а все 50-100 минимум.

Какой именно воркер и зачем он запускается на каждый запрос?


И да, за счёт какой такой магии файловый кеш может быть быстрее кеша в памяти?

Вы меня минусуете просто так? :-)

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

Один из наших проектов https://www.esanum.de/

Смотрим ендпойнт /api/apps/current/feeds/today/posts?page=1&page_size=14...

C кэшированием nginx ответ 77ms x-cache-status: HIT

Отключеаем кэш https://www.esanum.de/?no-cache=1

C memcache там же 522 ms x-cache-status: BYPASS

Как видим разница в 5-8 раз. И тут в целом все очевидно. Воркеры требуют дополнительных ресурсов. Nginx выдаст это как обычный статический файл.

Долго делали эксперименты c Python касаемо производительности, сверяли с GoLang и т.д. Python - тормозит :-) Жду Ваших минусов.

Ну хорошо, Питон — тормозит (хотя надо бы проверить что там вообще на сервере по-написано). Это что, единственный язык программирования?

Это самый популярный язык программирования в мире. Плох он или хорошо - это предмет отдельной дискуссии.

Видите, вы уже согласны. Уберете минусы :-)?

Вот только исходное обсуждение было не про Питон, а про бэк вообще. Это вы откуда-то решили, что если бэк, значит Питон, а если Питон — то только uwsgi.

Вопрос был к кэшировании graphql и как вывод, что его кэшировать намного сложнее. Его кэш сложно засунуть в статический кэш nginx.

Смешались в кучу кони, люди...

  1. У меня ваш сайт загрузился без кеша (на стороне браузера) в обоих случаях за одинаковое время.

  2. Задача бэка выдавать различный ответ в зависимости от входящих параметров. А ежели вы кэшируете каждый вариант в статику, подразумевая огроменную нагрузку на ваш ресурс с одинаковыми запросами с одинаковыми входящими аргументами, может, стоит пересмотреть сам подход к структуре бэкенда [, фронтенда]. Не знаю как у вас там всё устроено, могу допустить даже, что Python каждый раз вычитывает шаблон с диска, наполняет и отдаёт. Тогда тупо загоните шаблоны при загрузке в удобную структуру данных Python и отдавайте прямо из оперативки, лучшего кэша и не придумать.

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

  4. Мне трудно поверить, что ресурс, который вы указали, трещит по швам от желающих его посетить настолько, что Python становится узким местом. Может, вы не используете asyncio с какой-либо обёрткой (aiohttp), это даст примерно такой же эффект, как замена HDD на SSD на 5-7 летних ноутбуках.

  5. И вообще, на мой беглый взгляд, у вас там БЕДА. У вас ресурсов по сети загружается на 3 метра, картинок из них на 900Kb, распаковывается всё это хозяйство в 12-14 метров. Нет, вы серьёзно?!!! И если там, в недрах сайта есть что-то, что требует 12Mb ресурсов, но я не нашёл, то зачем сразу то всё загружать?!

  6. Если честно, вот прям обидно стало за Python. :(

    Ну да, он не такой быстрый как Go. Но тут... Вы просто не умеете их готовить...

Возможно, я тычу пальцем в небо и чего-то недопонимаю, но я старалсо... Чтобы вам минусов больше не ставили!

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

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

Задите пожалуйста на youtube.com и Вы увидите 12.6 мегабайт загруженных ресурсов - разве это может быть аргументом в неправильной архитектуре?

На платформе проводяться онлайн конференции для докторов с нагрузкой порядка 5 тыс. онлайн пользователей, и если каждый запрос перенаправлять на сервер приложений для обработки Python это становится проблемой. В моем примере nginx выдает ответ в 3-5 раз быстрее, чем Python из memcache - это факт.

Python - прекрасный и самый популярный язык программирования в мире. На нем быстро писать из коробки, но изначальная дискуссия была вообще в другом - в кешировании graphql. Проблема, в том, что, если можно выдать данные из nginx - их лучше выдать оттуда, перенаправление на сервер приложений не может быть быстрее - это тоже факт. В случае с graphql сделать кэш на nginx становиться сложнее, т.к. все запросы по сути это POST с телом с миксом фетчинга и мутаций.

Мне уже просто интересно стало...

  1. Пусть у вас SPA. Я отключил кэш в браузере, поставил slow3G. До того момента, как я увидел простой блог без картинок, "лениво" передалось по сети 2Mb, распаковалось в 10 метров. Ну там как бы нет ничего такого, как на youtube.

  2. Возможно, я просто не понимаю, но зачем вам вообще uWSGI, разве это не дополнительная сущность? В чём преимущество перед reverse_proxy на нужные ендпойнты на Python сервер за nginx?

  3. Неужели такого рода кэш на nginx оказывается быстрее, чем ответ Python сервера, который соберёт всё в памяти, нежели nginx вычитает с диска? Возможно, стоит измерять весь pipeline пользователя, а не отдельные показатели?

Пусть у вас SPA. Я отключил кэш в браузере, поставил slow3G. До того момента, как я увидел простой блог без картинок, "лениво" передалось по сети 2Mb, распаковалось в 10 метров. Ну там как бы нет ничего такого, как на youtube.

У youtube есть Service Side Render Cache, это когда в в первом запросе странице выдается ее полный кэш, после загрузуки SPA ресурсов, начинает работать уже SPA - у нас он еще не реализован, по разным объетивным причинам. Изначально, претензия была в количестве ресурсов, как признаке плохого проектирования. Вы именно так и написали.

Что такое в вашем понимании Python сервер? Кто примет запрос от nginx ? Кто запустит обработку Python в итоге? Разве не сервер приложений? Зачем тогда вообще nginx, почему Python сервер не может выдавать и статику тоже?

Зачем тогда вообще nginx, почему Python сервер не может выдавать и статику тоже?

…и такие решения существуют (наверное, для других языков они существуют совершенно точно).


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

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

детские болячки и привычный инструмент сисадмина

Не ужели в инженерной среде такие аргументы имеют место?

nginx - стал популярен из-за в первую очередь снижения стоимости владения инфраструктурой.

Возьмите статью по оценке производительности nginx

Static Content. NGINX performs 2.5 times faster than Apache according to a benchmark test performed by running up to 1,000 simultaneous connections. Another benchmark running with 512 simultaneous connections, showed that NGINX is about twice as fast and consumed less memory.

Это аргумент?

А что не так с аргументом? У библиотек не бывает детских болячек? Сисадминам на настройку разных серверов требуется одинаковое время (включая те сервера, которые настраиваются только кодом)?


Static Content. NGINX performs 2.5 times faster than Apache

Apache пора закопать уже, а не сравнивать с ним nginx.

А что не так с аргументом? У библиотек не бывает детских болячек? Сисадминам на настройку разных серверов требуется одинаковое время (включая те сервера, которые настраиваются только кодом)?

Эти аргументы - субъективные оценки, объективные аргументы инженера - это цифры.

Apache пора закопать уже, а не сравнивать с ним nginx.

И снова субъективная оценка. Давайте закопаем сервер который работает сейчас на 33% серверов в Интернете https://w3techs.com/technologies/comparison/ws-apache,ws-nginx

Снова минус? Хоть за что? За цифры? Мне просто интересна позиция инженера с такой кармой.

Вы пытаетесь сравнить производительность nginx и сервера приложений, для этого выбираете статью, которая сравнивает его с apache, и правда не понимаете в чём тут разница? Вы идиот или как?

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

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

На последок ответьте тогда на такой вопрос:

Что будет быстрее и дешевле (управлять и масштабировать) выдать статический кэш с nginx или отправить его на сервер приложений с выдачей из memcache на масштабе 100 000 запросов в секунду?

Я надеюсь, вы понимаете, что если даже Apache работает на 33% серверов в интернете, то это не повод его использовать, а повод скорее закапывать?!

Ну, подчёркиваю, это только моё мнение, но я полагаю, что юзеру надо показать первую страницу так мгновенно, как это только возможно технически. Чтоб семантика отрендилась первой, особенно, если это просто блог. Причём, если это относительно лёгкая страница, показать её, а не спиннер. И пока он там думает куда дальше кликнуть, можно догружать остальное. Я понимаю, о чём вы говорите, но первая страница у вас, если без картинок, ну сколько может весить этот кусок html'а со стилями, копейки. А когда юзеру понадобится кусок тяжелого функционала, показать спиннер, если нужно. Я не знаю подноготной, но, на первый взгляд, это напоминает новостной сайт со статьями, мне тяжело представить, что для такого движка требуется сразу тащить в браузер 10-12 метров ресурсов. Возможно, я придираюсь и начинаю чувствовать себя неудобно. Давайте оставим, пожалуйста...

Python сервер, в моём понимании, это программа, которая сама прекрасно умеет в HTTP (websocket если надо), sessions, cookies совершенно без участия посторонних сущностей. И таки, да, прекрасно сможет выдавать и статику. Но это будет медленнее, нежели на статику поставить nginx, или вот Caddy полюбился. Плюс, nginx спереди берёт на себя гемор с безопасностью, а caddy умеет в автосертификаты HTTPS из коробки и простой конфиг. Такая конструкция избавляет от множества забот, позволяя писать в Python только логику. Я как-то прошёл мимо WSGI. Python серверы на aiohttp (TCP socket server, Андрею Светлову респект несомненный) делаю, просто reverse_proxy на нужные эндпойнты API прокидываю, так можно и нагрузку распределить на микросервисы, поднять несколько интерпретаторов (и GIL, внезапно, по-боку становится). Спереди и nginx был, но Caddy, конечно, очень вкусный. Я тут полез смотреть про uWSGI и не понимаю зачем сейчас это... Как я понял, это соглашение для функций Python, универсальный интерфейс, получается, это лишняя сущность из прошлого, когда Python не умел в полноценный сервер...

Ну так все таки, что будет быстрее и дешевле выдать статический кэш с nginx или отправить его на Python с выдачей из memcache на масштабе 100 000 запросов в секунду?

Задите пожалуйста на youtube.com и Вы увидите 12.6 мегабайт загруженных ресурсов - разве это может быть аргументом в неправильной архитектуре?

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

Опять ушли от темы :-(

Потому-что воркер очевидно требует больше ресурсов для запуска и работы

Вы что-то путаете, uWSGI работает в prefork режиме, его воркеры стартуют при запуске сервера однажды и затем параллельно обрабатывают запросы.

Да я согласен, но дополнительный IO требуется для передачи от nginx до uWSGI? Для масштабирования требуется запуск новых воркеров? Жедательно воркеров на разных машинах. Значит их нужно запускать - это ведь дороже в конечном счете чем кэш на nginx. Или нет?

Потому-что воркер очевидно требует больше ресурсов для запуска и работы, даже если в вашем коде Вы просто забираете данные из memcache например. И Ваш ответ не будет занимать 10 миллисекунд как при nginx кеше, а все 50-100 минимум.
Почему воркер nginx'а может работать быстро, а воркер вашего приложения не может? 🤔

Потому-что это дополнительный IO между nginx и сервером приложений, потом между сервером приложений и memcache.

У вас nginx, приложение и memcache находятся в разных датацентрах? Откуда там задержка в сотни мс?

Но ведь вопрос был не в этом. Пускай даже сеть супер-скоростная, пускай даже это все на 1 компьютере, пускай мы ускорим и выиграем 10-30 миллисекунд. Зачем забивать сервер-приложений выдачей статики по сути? Это обязательно выстрелит при масштабе, когда запросов к серверу будет 10 тысяч. Лучше, если 9000 из них обработает сам nginx, а остальные сервер-приложений. Разве нет?

Это может быть и не статика. Например, представим страницу с информацией о популярном товааре в онлайн-магазине. На ней есть:
1. Персонифицированные данные для клиента, с персональными предложениями и прочей маркетологией. Она — для каждого клиента своя, но для одного клиента меняется редко. В общем-то, место ей в кэше.
2. Навигация — она вообще для всех страниц может быть одинаковой. Место ей — в кэше (а то и вообще это статика)
3. Это самая информация о товаре — оно у каждого товара своя, но для всех клиентов — одинаковая. Если товар популярный, то имеет смысл закэшировать, чтобы каждый раз в базу не лазить.
А теперь попробуем все это закэшировать на обратном прокси (nginx или ещё каком). Если бы сайт был сделан по древним канонам — на фреймах — то никаких проблем, каждый кусок из 1-2-3 кэшируется независимо. Но сейчас так не делают, и кэшировать надо всю страницу целиком. И получается, что для каждого пользователя в кэше надо держать свою копию, со всеми вытекающими.
А на стороне веб-сервера можно закэшировать 1,2 и 3 как отдельные фрагменты — а потом быстро собрать из них страницу для выдачи. Не знаю как где, а в ASP.NET Framework эта функциональность есть из коробки, там даже силы тратить на ее реализацию не надо было.

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

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

Ваш ключ на nginx - это URL ендпойна + токен пользователя из куки или заголовка.

Навигация — она вообще для всех страниц может быть одинаковой. Место ей — в кэше (а то и вообще это статика)

Видите, вы уже почти согласны. Конечно статика, зачем тут сервер-приложений?

Вопрос изначально был про кэширование API, мы не говорили не про Server Sider Rendring, мы говорили про SPA.

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

Вы не поняли: вопрос — в количестве этих ключей. Одно дело, когда userID (в любом виде) — отдельно, а itemID — отдельно: число ключей кэширования (и копий в кэше) равно сумме числа разных userID и разных itemID, а совсем другое — когда ключ включает в себя и userID, и itemID: потенциально для кэширования той же информации потребуется число ключей кэширования равное произведению числа разных userID и разных itemID (плюс, сами кэшируемые куски больше, т.к. кэшируется вся страница).
Конечно статика, зачем тут сервер-приложений?
Например, чтобы разделы для навигации создавать в CMS и хранить в БД. Ну и обратный прокси вынужден, в общем случае, хранить копию этих данных для каждой кэшированной копии страницы.
Вопрос изначально был про кэширование API, мы не говорили не про Server Sider Rendring, мы говорили про SPA.

Ну, у меня, когда это все писал, в голове был ASP.NET Framework MVC, как вещь для меня лучше знакомая. Но с API ситуация будет примерно та же, только вместо страниц будет JSON. Он, конечно, объемом поменьше, но его точно так же можно было бы кэшировать по частям на сервере приложения и собирать из этих частей ответ, при том, что на обратном прокси пришлось бы хранить в кше ответы для каждой из используемых комбинаций userID и itemID.

Ну так все таки, что будет быстрее и дешевле выдать статический кэш с nginx или отправить запрос на сервер приложений с выдачей из memcache на масштабе 100 000 запросов в секунду?

Опять вы не хотите рассматривать проблему в общем виде: а почему именно memcache на масштабе 100 000 запросов в секунду; а если реальная нагрузка меньше; а если использовать не memcached с его сетевыми задержками, а локальное кэширование (вы же на его рассмотрение ЕМНИП согласились); а если ещё и ограничения по памяти для кэша рассмотреть — из-за которых промахи будут?
Короче, конкретные цифры надо смотреть для конкретного проекта, а если в общем, то схема с локальным кэшированием фрагментов — она тоже имеет область применимости.

Слишком много если, вместо простого помещения результата ответа API в статический кэш nginx с супер низкой стоимостью владения. На 100 запросах +-1 секунда не будет заметна, а вот 100 000 вот тогда будет важен каждый лишний запрос на сервер приложений.

Какая нахрен плюс минус одна секунда? Откуда вы эту секунду взяли, "инженер"? Последуйте уже своему совету, поищите цифры в интернете!


К примеру, на Web Framework Benchmarks от TechEmpower верхние строчки все менее одной миллисекунды, а медианный результат — где-то 2.5ms. И это как раз на сотнях тысяч запросов в секунду.

Не думал, что примите буквально. +-1 секунда на все 100 запросов имелось ввиду. 2.5ms сюда включен IO между nginx сервером приложений и например memcached?

Там другой сценарий рассматривался, с запросом в БД, но без кешей и без nginx. Но представление о порядке величин должно дать.

Так это просто оценка скорости запроса в БД и все? Это не скорость обработки HTTP запроса с конечной выдачей ответа? Это очень разные вещи, очень.

Это оценка скорости обработки HTTP запроса под нагрузкой без кеширования (кроме как на стороне СУБД).

У вас этот кэш nginx на диск валится?

Но в целом какая разница, ведь и так понятно, что nginx в итоге поместит это в RAM для востребованных запросов и не будет IO с диска. А так тут же статья https://habr.com/ru/post/428127/

В смысле?! А как же это?

https://stackoverflow.com/questions/38813399/cache-a-static-file-in-memory-forever-on-nginx

Из статьи, что вы привели: "Что же из себя представляет этот кэш? На самом деле это обычный файл на сервере". Похоже, только ключи в памяти кэшируются?

https://stackoverflow.com/questions/38813399/cache-a-static-file-in-memory-forever-on-nginx

Здесь говорится о том, что сама OS кэширует часто используемые файлы - в этом случае получается своеобразный inmemory cache. Более того, если уж хочется - nginx может работать с memcached/redis (но только кэш придется для него формировать самостоятельно, но это несложно) - таким образом, при любом раскладе эту будет шустрее работать, чем перекидывать запрос на сервер приложений. Мне как бэкэнд разработчику кажется, что если есть возможность возвращать ответ, не задействуя сервер приложений - то лучше так и делать. Если не устраивает nginx - используйте varnish или что-то подобное. Возможно, для go это не так актуально, но в случае с python выручает (особенно когда используется django)

Именно в случае django это и выручает, потому что django всё ещё синхронный фреймворк, а python медленный язык.


Более современные фреймворки таковой проблемы не имеют.

Да, я прочитал заранее про это. Просто оппонент написал: "Но в целом какая разница, ведь и так понятно, что nginx в итоге поместит это в RAM для востребованных запросов и не будет IO с диска." А мне было непонятно, потому что nginx сам по себе НЕ поместит это в RAM. И, в таком случае, получается, что контроль над кэшем отсутствует, чёрт его знает чего там OS решит, и поведение под нагрузкой станет непредсказуемым. Конечно, в итоге, можно и в RAM диск этот кэш пристроить. Или memcached/redis к nginx прикрутить, или...

И вот со всеми этими загогулинами, для меня совсем не очевидно, что "при любом раскладе это будет шустрее работать, чем перекидывать запрос на сервер приложений". У меня, лично, уже недостаточно информации, чтобы делать такие выводы однозначно. Потому что "сервер приложений", например, прекрасно может хранить у себя в памяти всё, что нужно для ответа, а не терзать memcached/redis. И ещё писали: "Мне как бэкэнд разработчику кажется, что если есть возможность возвращать ответ, не задействуя сервер приложений - то лучше так и делать." Вот не очевидно это для меня совсем, может, весь подвох кроется в формулировке "сервер приложений", что может быть не совсем API?!

Но даже это здесь не главное, с чего всё началось то:

  • "Мне не очень вообще понятно что можно в API кешировать на уровне http."

  • "Кэш на nginx очень дешевый, по сути это статика в памяти."

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

Мне кажется, у вас вышло недопонимание из-за терминологии. Возможно, под "статика" подразумевались не только картинки,..., но и ответы от апи. У нас тоже часть ответов апи кэшируется на nginx (с помощью proxy_cache): регулируется с помощью Cache-Control и "подпиливается" на основе статистики запросов и специфики конкретных апи (например, справочники можно надолго кэшировать), к вопросу о параметрах: формируем cache key на основе урла с параметрами - сразу решаем "формировать ответ на запрос с разными аргументами и значениями этих аргументов" (да, GET запрос может содержать тело со своими параметрами (спецификация этого не запрещает), но это уже другая история). В итоге это позволяет очень снизить нагрузку с серверов приложения django (которая пока еще, увы, в основном синхронная). Почему, это кажется Вам "вундервафля"? Предложите свой вариант решения этой проблемы.

Кстати, вы подняли интересный вопрос: локальный кэш внутри приложения. А что будет, когда приложение будет перезапущено? Кэш же сбросится и потребуется время на прогрев, а это не всегда приемлемо, особенно в k8s, который может перезапускать контейнера довольно часто. Более того, а как масштабироваться? Например, нехватка ресурсов и нужно поднять новые инстансы на других серверах - они будут опять прогревать свой кэш - не проще ли использовать распределенный кэш сразу? Да, кэш в памяти однозначно быстрее, но не помешает ли это в будущем? Мы тоже иногда кэшируем в память приложения, но крайне редко и точно не ответы api.
Открыт к плодотворному диалогу.

Оу, вы добротно растолковали возможные юзкейсы. Спасибо. В целом, диалог оказался для меня плодотворным. Я не знал про такого рода кэш в nginx и стал пытаться пристроить его к своей "картине ландшафта", но, видимо, не обладаю настолько обширной практикой, например, с k8s дел пока не имел. Дело в том, что плотно погружаться в эту тему я начал при уже существующем aiohttp, когда Python пленил меня. Мой первый проект представлял исключительно статику, потом на бэке появился Python и обработка этой статики. После я хотел было начать разбираться с Django, но для меня оказалось - это путь в никуда (не загорелся), ведь Django берёт шаблон, вставляет туда данные и отдаёт как html страницу, что просто следующий шаг от статики. У меня сейчас в голове немного другой подход (через эту призму я и смотрел), по сути SPA (я считаю за этим будущее), где API преимущественно берёт из базы, вертит и отдаёт, а вся семантика заранее загружена как статика или как статика подгружается. Но это не на все случаи жизни, наверное :) И теперь, конечно, я буду иметь ввиду такую возможность nginx, только вижу слабую её применимость в последнем случае.

Что касается прогрева кэша, не думаю, что кэш такого размера, в котором есть смысл, будет долго вычитываться с pci-e накопителя. Но тут я ступаю на зыбкую почву недостаточной компетенции...

Благодарю за ответ. Есть библиотека django rest framework, которая позволяет создавать апи в django. Таким образом, мы получаем мощь админки django и апи, которое можем использовать в spa приложениях (у нас тоже spa приложение). Более того сейчас разработчики django работают над асинхронностью - будем надеяться, что это "омолодит" фреймворк. Хотя, мы сами постепенно некоторые его части выносим в более легкие фреймворки.

По поводу кэша - он может быть очень большой. Особенно если вы кэшируете специфичный для пользователя контент, а пользователей много (например корзина конкретного пользователя или лента новостей, рекомендации). И поэтому в процессе его формирования нагрузка на сервере может подскочить. Можно конечно, вначале перенаправлять только небольшую часть траффика на "холодные" инстансы, постепенно "прогревая" их. Но все таки советовал бы Вам посмотреть в сторону распределенного кэша. "будет долго вычитываться с pci-e накопителя" - немного не понял, Вы имеете в виде что-то вроде multiprocess memory?

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

Поэтому, я думаю, что подход Вашего оппонента имеет место быть и он отлично может решать их проблемы.

Новая дичь, которая подъехала с GraphQL, тоже шедевральна.

Какая-то жесть описана. То ли люди не понимают, что такое командная работа, то ли не понимают, что они в принципе делают (не "пишу бэкэнд на джаве" а "пилим соцсеть для котов", хотя бы в таком ключе)

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

ЗнаЕМ, пишЕМ, умеЕМ, используЕМ... Автор взялся отвечать за абсолютно всех фронтендеров? Это - не серьезно. Это - не профессионально. Так взрослые люди не пишут.

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

Вопрос то ведь был поставлен так и никаки иначе:

Как считаете будущее за Spec-First Development или полный Agile (шутка): митинги, JSON-чики в чатиках и т.д.?

Разве это не для того, что бы обеспечить взаимопонимания? Вы как считаете?

Как считаете будущее за Spec-First Development или полный Agile (шутка): митинги, JSON-чики в чатиках и т.д.?

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

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

Я писал про Spec-First именно (для этого и был сделан Swagger / Open API) про то, как можно согласовать требования заранее к API без "чатиков" и "JSON-чиков", вопрос был только в этом.

Я единственно, правда не совсем понимаю, почему многие пишут и комментируют статью в отрыве от самого текста?

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

Что я предлагал? Я лично ничего не придумал. Есть Swagger - Spec-First - не я это придумал. Я лишь, описал как хорошо писать спецификации на API заранее или нет?

Причем тут ограниченность архитектур?

Напишите контракты, выполните их, проверьте, что все выполнено - разве не хорошо?

Что я предлагал? Я лично ничего не придумал.

Ну, может, не вы лично, а ваша команда. Но вы — таки предлагали:
Мы в команде давно используем Swagger, мы пишем его заранее на фронте, потом передаем на бэк, что бы они реализовали, что нам нужно.

И спустя пару месяцев мы разработали – API Projector — Визуальный Swagger редактор
API projector – это визуальный Swagger редактор с возможностями привязки API к пользовательскому интерфейсу системы (приложения).

То есть, предложили (неявно, описывая ваш процесс работы) создавать описание на стороне фронта (хорошо, с согласованием у бэка, но бэк играет в целом пассивную роль в процессе разработки API), указали формат описания API (если чо, его можно и просто на бумажке написать) и инструмент создания описания в этом формате. То есть вы достаточно детально описали процесс создания спецификации API.
Есть Swagger — Spec-First — не я это придумал.

Вы придумали процесс создания API. Это хорошо, это правильно. Но в его описании все сложили в одну кучу. Spec-First — это концепция, она же паттерн, вещь весьма абстрактная. А Swagger — это весьма конкретный набор средств для работы с конкретным форматом описания API.
Ну, и этот процесс не всем и не всегда может подойти. Например, если для облегчения нагрузки на бэкенд (или на его разработчиков ;-) ) преобразование из модели представления (тот набор сущностей, которые пользователь видит и с которыми работает в приложении) в модель данных предметной области решено вынести на фронтенд. Тогда API будет основан не на модели представления а на модели предметной области, и источником информации для его создания станет бэкенд. И логично, чтобы спецификации API шли от бэка.
Причем тут ограниченность архитектур?

Ограниченность тут — в том смысле, что возможны архитектуры приложения, в которых ваше решение неоптимально. Пример — выше.
Напишите контракты, выполните их, проверьте, что все выполнено — разве не хорошо?

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

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

Многие думают, что Swagger (Open API) – это «UI шкурка», которую генерирует в конечном счете бек из кода, они не понимают, что это в первую очередь – JSON схема описания API.

Вот свежий курс по проектированию API

Теперь поговорим о подходе, основанном на спецификации. Многие считают, что автогенерация, описанная в предыдущем разделе, - не лучший подход. В книге «Undisturbed REST: A Guide to Designing the Perfect API» Майкл Стоу рекомендует командам реализовать спецификацию OpenAPI вручную, а затем рассматривать документ спецификации как контракт, который разработчики используют при фактическом кодировании. Этот подход часто называют «разработкой на основе спецификации».

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

Все выводы вы сдедали сами. Подход не претендовал, на все случаи жизни.

Напишите контракты, выполните их, проверьте, что все выполнено — разве не хорошо?

Именно только она и была, как в вашем случае на бумажке повторить данный процесс?

Подход не претендовал, на все случаи жизни.

В вашей статье так не написано. Или я пропустил нужное место?

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

Хотя бы это:

Многие думают, что Swagger (Open API) – это «UI шкурка», которую генерирует в конечном счете бек из кода, они не понимают, что это в первую очередь – JSON схема описания API.

А этого места нет.

Так сделайте его, напишите про это в явном виде. Иначе многие будут из-за этого считать, что вы претендуете на универсальность (кстати, по комментриям это видно, что немало комментаторов именно так все и поняли).
Или напишите что вы не согласны с тем, что API всегда должен определять бэкенд: отрицанием утвержднения с квантором всеобщности как раз будет утверждение с квантором существования верного обратного утверждения
думал, что вы больше прокомментируете :-(
Хотя бы это:
Многие думают, что Swagger (Open API) – это «UI шкурка», которую генерирует в конечном счете бек из кода, они не понимают, что это в первую очередь – JSON схема описания API.

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

Почему вы сделали вывод, что в этом подходе бэки принимают пассивное участие?

Мы в команде давно используем Swagger, мы пишем его заранее на фронте, потом передаем на бэк, что бы они реализовали, что нам нужно.

Вы падаван софистики?

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

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

А все, что я увидел про роль бекенда — это слово «согласовывают». Согласитесь, это, все-таки, пассивная роль: посмотреть результат разработки API и сказать, пригоден ли он для реализации.
Или я что-то, по-вашему, тут упустил? Тогда приведите цитату — возможно, мне в таком случае, придется переосмыслить свое мнение.
PS Я вижу перед собой только текст, поэтому знать, что автор хотел сказать, я могу только из этого текста. Если он имел в виду что-то другое, то, я считаю, что про это надо было написать явно.

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

А дальше уже вами предложенная цитата:

фронтенд предлагает

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

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

Автор уже в коментах отвечал: совместная работа на API. Просто не аналитик/бэк/архитектор проводит первичный анализ, а фронт.

Пришли за визой? Если рассмотреть пассивную роль, то это - пришли с заказом. Я допускаю, что могут быть пассивные люди, которые не будут думать, а сделают так, как просят. Но я таких за 10 лет не встречал.

Автор уже в коментах отвечал: совместная работа на API. Просто не аналитик/бэк/архитектор проводит первичный анализ, а фронт.

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

Отвечая на вопрос - я действительно верю в spec-first и активно продвигаю его в своих командах

Переходя к тексту статьи.

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

Давайте попробуем обозначить основные компоненты вашего повествования, ими являются бэкэнд и фронтэнд. Какие у них роли? Бэкэнд можно сравнить с поставщиком некой продукции/данных (автопроизводитель, молочная ферма, онлайн ресурс) в свою очередь фронтэнд - это потребитель данной продукции (автовладелец, покупатель в магазине, клиент сервиса), чем же в данной аналогии является спецификация? Все верно спецификация это - "инструкция по эксплуатации" автомобиля. Исходя из предложенных аналогий выходит, что существует конкретный предложенный продукт и множество разнообразных его потребителей. Становится видна на мой взгляд вся абсурдность вашего требования, которое подразумевает обязанность производителя в согласовании инструкции с каждым возможным потребителем. Как вы представляете себе процесс согласования API какого-нибудь Aviasales или Reddit с сайтом-визиткой отображающим цены на последний перелет или количество комментариев reddit, странно звучит, не правда ли?

Переходя к процессу актуализации спецификации тут все тоже становится прозрачнее, стоит лишь определить ее владельца. Кто является владельцем API, ну конечно же сервис который его предоставляет и реализует - бэкэнд. А значит достаточно иметь один файл спецификации (json, yml) в репозитории бэкэнда. Где все внутренние потребители смогут его прочитать, предложить свои комментарии/исправления по средствам merge request.

Ситуация когда конкретному потребителю нужно оптимизировать/кастомизировать некие запросы для удобства восприятия ответов, не является уникальной и для ее разрешения с сохранением ответственностей описан паттерн BFF ( back for front) задачей которого и является удовлетворение потребности конкретного потребителя. Приходя к аналогиям его можно сравнить с тюнинг-анелье, которое на вход получает "голый" продукт от производителя, а на выход выдает то, что попросил отнего конкретный клиент. В этом случае спецификацию bff сервиса может составлять и фронтэнд, ровно в том виде который ему нужен. Причем не обязательно воспринимать bff как отдельный сервис (хотя очень желательно) это вполне может быть и отдельное адресное пространство оригинального бэка.

P.S. сразу попрошу прощения. Неожиданно длинный получился комментарий.

Спасибо за развернутый комментарий.

Но мне несколько странно, что Вы написали:

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

Ведь в моей статье был тезис про разделение слоя бизнес-логи и API.

@breslavsky Мне кажется проблема в том, что некоторые бекенд разработчики, неверно понимают разработку бизнес-логики и разработку интерфейса доступа к ней и к данным. Интерфейс на бекенд может быть HTTP, сокеты ли даже командная строка. Это всего лишь интерфейс. Эти разработчики при проектировании ендпойнта /login часто зашивают в контроллер бизнес-логику, работу с базой, генерацию сессии и т.д. И именно поэтому они связывают проектирование API с разработкой кода функции и именно поэтому когда им нужно добавить, например, GraphQL им нужно дублировать код.

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

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

Где тут проблема?

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

Опять вопрос на вопрос. Мы - есть комманда Reddit - его бекенд и фронтенд. Теперь такой кейс реально существует?

И ответ, то бы на кашу в голове :-)

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

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

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

Если бизнес-логика отдельно почему нельзя предоставить к ней доступ сразу через API: REST, SOAP, командную строку разным клиентам исходя из их потребностей. Где тут все таки каша? Ваш бизней слой идеален, модель данных идеальна. Вы просто педоставляете к ней доступ исходя из потребностей клиентов.

Вот например я как поставщик продукта и выбрал единственный приемлемый для себя ( тот за работу и актуальность которого я готов отвечать головой) способ предоставления доступа, пускай это будет REST. И пускай все возможные потребители сами решают как и в каком виде они будут его потреблять. Кто-то будет слать запросы на прямую, кто-то напишет BFF-сервисы для преобразования запросов/ответов. Кто-то вообще приделает CLI и буде радоваться консоли. Это уже не моя забота как поставщика. Моя задача гарантировать работоспособность того единственного канала, который я предоставил.

На другой стороне сидит точно такой же "царёк", который сделал апи для интеграции, а остальное - не его, как потребителя, забота. В конечном счёте подстраивается тот, кому больше нужно.

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

Вот например я как поставщик продукта и выбрал единственный приемлемый для себя ( тот за работу и актуальность которого я готов отвечать головой)

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

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

просто реализовать это в API для фронта

Вот вы снова упускаете важнейшую деталь. Для какого конкретно фронта нужно реализовать АПИ? каждому фронту нужно свое, уникальное АПИ.

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

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

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

В моей статье было это:

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

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

Основные арументы с обоих сторон уже высказаны.

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

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

Если у бэка есть несколько существенно разных по функциональности фронтов (несколько типов АРМ работников или клиентов), то для каждого фронта можно создаеть свою модель представления (набор отображаемых в ней сущностей и действий с ними) и использовать API, основанный на этой модели. Да, бэку в этом случае придется потрудиться, преобразуя данные из модели предметной области в нужную модель представления и обратно (и программистом бэка — тоже, программируя это преобразование). Но и преимущество в таком подходе есть (и даже для единственного фронта): модель представления для фронта изолируется от модели предметной области, и эти модели (и основаннные на них спецификации API, классы DTO, струтуру БД) можно менять независимо.
В таком подходе предложения автора статьи — вполне годные для использования (особенно, если учесть, что фронт может по жизни являться источником сведений о хотелках пользователей).
А использовать ли такой подход, или какой-либо другой (например, API, прямо отображаемый на модель предметной области, чтобы разгрузить бэк — серверы или программистов) — это зависит от конкретного проекта.

Ну так собственно о таком варианте и шла реч в моём первом сообщении. То что вы описали полностью попадает под описанного мною BFF-пасположенном не в виде отдельного сервиса (приложения) а в виде отдельного адресного пространства того же сервиса.

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

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

А давайте я приведу другую аналогию.

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

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

Да даже в автосалоне заказываешь автомобиль в нужной комплектации, а потом ждёшь, когда ее произведут.

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

-

Каждый подход имеет границы применимости.

Спасибо, за поддержку. Такое ощущение, что разрабочики сразу любят бежать в код и потом договариваться в чатиках и JSON-чиках, вместо того, что бы спроектировать, как это будет выглядить до разработчки, что бы начать работу паралелльно.

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

На самом деле, не так важно кто пишет спецификацию: фронт или бакэнд.

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

Вся индустрии софтостроенния идёт в сторону "текстофикации": asciidoc, PlantUML, развёртывание софта по декларативням описаниям и пр ... . С текстом работать на порядки удобнее, его можно легко мерджить и отслеживать.

Далее: кодогенерация - зло. Всё-таки, API делается в (условно) Java-классах, где прописывается аннотациями аттрибуты и методы.

Прописывать API в XML или yaml файлах - это пустая трата времени, это криво и неэлегантно. Опять же, возврат во времена доклетов и кейс-средств.

Спасибо за комментарий. Разрешите привести в качестве аргумента https://swagger.io/tools/swaggerhub/

The Single Source of Truth for API Development

Join thousands of teams who depend on SwaggerHub to get their products to market, faster 100k+ API Practitioners, 40k+ Organizations, 200k+ API Projects

Складывается ощущение, что на текущий момент такой подход просто еще не пришел на Хабр.

Но, очевидно, она не может рисоваться ни в каком UI — инструменте.

Не очевидно. Потому что ничто не мешает UI-инструменту сохранять результаты работы в текстовом формате. Например, редактор диалогов из состава средств разработки MS программ на Windows с древних времен делал именно так: читал текстовый нескомпилированный файл ресурса диалога (расширение rc), отображал его в GUI (где можно было на все элементы полюбоваться, мышкой их подвигать и т.д.), и потом сохранял результат в тот же самый текстовый файл — со всеми упомянутыми вами преимуществами в плане работы с ним.

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

Сам draft-контракт описывается текстом в итоге: в формате OpenAPI. Подозреваю, можно даже сразу текст писать, а ui будет сгенерирован сам. И, скорее всего, эта спека хранится в гите. Почему OpenAPI - плох, а asciidoc - хорошо?

Также это способ замокать api, пока нет бэка. И это бывает очень полезно: поднять локально за пару минут на ноде мини-сервер, который будет отдавать рандомные данные по типам.

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

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

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

Что касается свагера, то это вторичный формат, как и WSDL. Зачем делать двойную работу? С него генерить классы - получится плохо-поддерживаемый мусор. И работать удобнее с классами и методами, а не с этим птичьим языком, который непонятно даже как по модулям разбить.

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

Я читал wdsl. А Вы не читали OpenAPI. И, видимо, не сталкивались с проблемами, которые решает ТС

Я так понимаю архитектор с вашей гордой шхуны ушел? Попробуйте сначала в confluence пару недель поописывать, то что вы собираетесь делать. Почему-то часто разрабы считают себя выше того, чтоб писать куда-то кроме IDE и не код.

То что сваггер что-то ускоряет это миф. Ведь нельзя что-то ускорить, если вместо 40 спринтов взять 42 и ускорять не нужно, зато сделать SDK с валидацией и у вас не останется бесполезного YMLика. Ди в конце концов у вас не 400 эндпойнтов, будет 20 или около того. Экономия на спичках.

Вот зачем такие голословные оценки? Мы давно используем все возможные иструменты в своей работе.

Почему-то часто разрабы считают себя выше того, чтоб писать куда-то кроме IDE и не код.

Как раз таки Swagger и решает эту проблему. Напиши контракт до кода, напиши код и проверь контракт.

То что сваггер что-то ускоряет это миф. Ведь нельзя что-то ускорить, если вместо 40 спринтов взять 42 и ускорять не нужно, зато сделать SDK с валидацией и у вас не останется бесполезного YMLика. Ди в конце концов у вас не 400 эндпойнтов, будет 20 или около того. Экономия на спичках.

Очень не однозначно. У вас будет 20 ендпойнтов, но в 200 раз больше запросов к бэку. Как это скажеться на производительности?

Почему-то часто разрабы считают себя выше того, чтоб писать куда-то кроме IDE и не код.
Или просто лень) (как мне, например)

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

Вот мне интересно, что вы пишите в конфлюенсе? И чем это принципиально отличается от описания в формате OpenAPI с последующем обсуждением спеки для её финализации?

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

1) спеки вперед - отличная идея. Перед спеками - соглашения о структуре, типах и других глобальных вещах

2) Технический инструмент - в идеале такой, который соответствует коду. Обычно это легче всего достигнуть, если он оттуда генерится. Тогда как минимум код будет соответствовать контракту.

3) Фронт генерит контракт - скорее нет, чем да. Тем более АПИ может быть одно, а фронтов и вообще, его пользователей много :)

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

Имхо тема поднята важная, за это плюс.

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

Нельзя делить то, что не делится. Нужен кто-то кто business requirements обговорит с архитектором/кем-то кто понимает и Frontend и Backend. В итоге фронтенд и бэкенд подкручивают как надо, а не одни сидят и говорят, что мы ничего не меняем, а другие ломают руки и придумывают новые проклятия. Если нет человека, который отвечает и за Frontend и за Backend и за реализацию business logic, вы doomed.

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

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории