Комментарии 84
Чистые бэкендеры на C# втягивались в ноду около 2-х месяцев. Но зато сразу после этого могли решать задачи, не связанные с версткой, на фронте.
максимально облегченная VS Code по сравнению с мощной VSЧто мешает использовать PhpStorm?
PHPStorm — IDE с уклоном на PHP
WebStorm — IDE с уклоном на JS
PHPStorm — это WebStorm (все возможности) плюс PHP
Возможности WebStorm есть и в PyCharm.
Момент в том, что разработчику, который не пишет на этих языках вряд ли нужно более захламленное рабочее пространство, чем оно могло бы быть.
Стоит упомянуть, что WebStorm включает предустановленные плагины, которых изначально нет ни в PHPStorm, ни в PyCharm.
И стоит WebStorm в полтора раза дешевле.
Можно пример таких плагинов? Особенно тех, что доступны только в WebStorm и Idea, а в PhpStorm даже поставить нельзя.
… а почему у вас в заголовке .net Core, а в тексте — про "обычный" .net? Хотя вот как раз у Core сильно меньше проблем с кроссплатформенностью (да и с IDE)?
заголовок взят из предыдущей статьи.
про кросс платформенность, да в .Net Core с этим ok
но основной смысл перехода на node.js был именно в унификации стека, а не кросплатформенности, поэтому как не называй статью, смысл не поменяется)
И тем не менее, заголовок вводит в заблуждение.
Кроме Xamarin.Forms tcnm есть еще и Mobile Blazor
Announcing Experimental Mobile Blazor Bindings May
Да это пока все на эксперементальной стадии.
Кроме того нужно упомянуть и про Blazor Desktop
blog.stevensanderson.com/2019/11/01/exploring-lighter-alternatives-to-electron-for-hosting-a-blazor-desktop-app
gunnarpeipman.com/blazor-on-desktop-webwindow-experiment
visualstudiomagazine.com/articles/2020/05/19/blazor-webassembly-3-2.aspx
channel9.msdn.com/Events/dotnetConf/Focus-on-Blazor/Blazor-Futures-WebAssembly-PWAs-Hybrid-Native 28 минута
github.com/dotnet/aspnetcore/issues/21514
github.com/aspnet/Blazor.Docs/blob/master/community.md
github.com/Daddoon/BlazorMobile]BlazorMobile
github.com/ElectronNET/Electron.NET]Electron.NET
Задачи разработки пользовательского интерфейса и бэкенда
Как ни странно, большая часть задач на фронте и на бэкенде абсолютно одинаковые.
Мы берем данные (из СУБД или кэша в случае с бэком и из бэкенда или хранилища состояния (redux/mobx/rxJs) в случае с фронтом), выполняем некоторые преобразования и отдаем их потребителю (фронту в случае с бэком или компоненте визуализации в случае с фронтом). Специфичные регулярно возникающие задачи — это проектирование СУБД и интерфейсов — для бэка и верстка — для фронта.
Как сделать, чтобы крутой бэкендер не залип на несколько дней с верстальной задачей?
достаточно хорошо декомпозировать задачу (чтобы занимала не больше дня) и прийти на помощь разработчику, если в ожидаемый срок результата нет
у кого лучше получается, тот и берет как бороться со специализацией?
постепенно. Сначала давать небольшой объем несвойственных задач, потом контролировать результат и удовлетворенность разработчика от того, что он делает. Если совсем не его, то не давать такой тип задач. Но у нас разве что верстку не все любят, а с остальным таких проблем я не замечаю
Все это в купе с переходом от типизации C# должно сказаться на процессах обеспечивающих качество
от типизации C# мы перешли к типизации typescript
Измеряли ли вы (а потом сравнивали) показатели качества?
Для нас показатели качества всегда были в приоритете. К нам возвращаются наши Клиенты за разработками нового ПО, для меня это самый главный показатель. Говорят, что им очень нравится наша скорость работы и недельные спринты с понятным результатом
у вас все разработчики фулл-стеки, а значит дороже
Фулстеки бывают разные. Джуны, мидлы, сеньоры. З/п зависит от общего уровня
Кто-то может выполнять задачу, в которой не является специалистом (например, мобильная разработка), а значит будет делать дольше, а значит дороже
Это так, но мы идем на эти потери (надо сказать, очень небольшие) сознательно. У нас соотношение серверной/WEB/мобильной разработки часто меняется. Поэтому нужны надежные резервы во всех направлениях.
Код-ревью подразумевает, что все будут либо распыляться на три платформы (фронт, бэк, мобилки)
Я предпочитаю формулировку «набираться опыта в трех платформах»
сделали как сделали, а потом тянем деньги на суппорт
Нет, у нас не такая бизнес модель. У нас есть бесплатная тех-поддержка для наших решений (от полу года до года в зависимости от проекта). Поэтому для нас траты на тех. поддержку — это минус и мы стремимся делать так, чтобы Клиенты возвращались с запросами на новые фичи или системы, а не за исправлением багов.
Стоит указать что Node.js однапоточна и красиво распараллеливать как в .NET не получится.
swagger-описание REST API должно автоматически генерироваться из исходного кодаЭто в корне не верно. OpenApi — пром. стандарт описания сервисов, соответственно пишутся сервисы на сваггере, и из сваггер-описания генерируются заглушки с исходным кодом с готовым транспортом и валидацией. А не наоборот.
2.
Тимлиды не разруливают споры между бэкендерами и фронтендерами;Во только при чём тут выбор ЯП для бэка? Вообще ни как не связано. Есть огромное количество бэкендов, написанных на ЯП, отличных от js/ts и C#, в которых тимлиды и близко ничего такого не разруливают, да и разруливать нечего ввиду отсутствия споров.
3. Из предыдущего
чтобы загрузить все ядра сервера придется воспользоваться модулем “Cluster” или внешним управлением процессами.Опять таки решение не имеет ничего общего с задачей. «чтобы загрузить все ядра сервера», нужно оптимизировать CPU-bound вычисления. Cluster к этому ни каким боком
Это в корне не верно. OpenApi — пром. стандарт описания сервисов, соответственно пишутся сервисы на сваггере, и из сваггер-описания генерируются заглушки с исходным кодом с готовым транспортом и валидацией. А не наоборот.
Не работал с таким потоком, работал с указанным автором source -> spec (причём в .NET с этим было ноль проблем).
Что, в вашем варианте, происходит при обновлении сервиса? Скажем, я добавляю поле в модель. Я должен добавить его в спецификации и у меня автоматически обновится соответствующая модель в исходном коде?
Я должен добавить его в спецификации и у меня автоматически обновится соответствующая модель в исходном коде?Разумеется так, иначе нафиг оно всё это было бы нужно
Не работал с таким потокомхз как это сделано в net (и сделано ли). Но в том яп, который я использую, это всё на достаточно рабочем уровне
Ну так и читайте спеку OpenApi! Какая при этом разница что на основе чего было сгенерировано?
Разумеется так, иначе нафиг оно всё это было бы нужно
И миграции базы сгенерируются, со всеми "дефолтными" связями?
Фронт на typescript + react, бэк на java + spring, подход к контракту API — api spec first.
По спеке API генерируется клиент API с DTO для фронта и интерфейсы для контроллеров и DTO для бэка.
Если в API что-то поменять, то при сборке будут заново сгенерированы клиент, интерфейсы контроллеров и DTO, и на этапе компиляции typescript или java покажут сломанные места.
Главный плюс такого подхода: фронтенд-разработчик может менять спеку API так, как нужно ему, не зная java, бэкенд-разработчик может менять спеку не зная typescript. Естественно, этот плюс пропадает, если на фронте и бэке один язык.
Главный минус: официальные генераторы кода. Некоторые вещи сложно выразить, например streaming больших файлов. Некоторые вещи, описанные в документации swagger, поддерживаются не всеми генераторами или поддерживаются неправильно. В принципе качество кода этих генераторов ужасно (видел, когда улучшал поддержку некоторых нужных вещей).
Если бы на фронте и на бэке был typescript, то я бы использовал подход code first, выделив контракт API в модуль, который бы переиспользовался и на фронте и на бэке, руками написав реализацию этого контракта. По большому счету swagger нужен или в проекте с солянкой технологий или для публичного API.
Если в API что-то поменять, то при сборке будут заново сгенерированы клиент, интерфейсы контроллеров и DTO
Самописного кода у вас там нет? Боюсь, как бы генератор его не потерял.
Главный плюс такого подхода: фронтенд-разработчик может менять спеку API так, как нужно ему, не зная java
Абстрактно соглашусь, но на практике как часто вам нужно менять модель и не менять сам код АПИ? Грубо говоря, если я добавил новое поле к условному заказу, то мне и обрабатывать его надо, так что бекенд работа всё равно присутствует.
Самописного кода у вас там нет? Боюсь, как бы генератор его не потерял.
Это одно из ограничений подхода с генерацией кода, если не устраивает сгенерированный код — или переделать генератор или написать еще слой абстракции поверх или смириться с тем, что есть. Использую все три варианта в зависимости от задачи. Но код для обычного CRUD вполне нормальный.
как часто вам нужно менять модель и не менять сам код АПИ? Грубо говоря, если я добавил новое поле к условному заказу, то мне и обрабатывать его надо, так что бекенд работа всё равно присутствует.
Я имел в виду, что если используется подход code first, и спека API создается из аннотаций на java-классах бэкенда, то фронтенд-разработчик должен каждый раз на пальцах объяснять бэкенд-разрабочику, что он хочет поменять. В подходе же spec first они оба могут вносить изменения сразу в спеку. Да, изменения в спеке сломают проект и оба разработчика должны будут исправить свою часть проекта.
В идеале, конечно, иметь команду из фуллстеков, которые внесут изменения сразу и на фронт и на бэк, но так бывает не всегда. Я видел проект, где фуллстеков не было, причем разработка спеки API шла от фронта. В таком проекте code first со стороны бэка не подходил, возможно есть инструменты для code first со стороны фронта, тут я не в курсе.
Вообще, самое главное, по моему мнению, обеспечить типобезопасность для API, для этого нужны статически типизированные языки на фронте и бэке и единый источник правды, из которого потом будут сгенерированы клиенты API / интерфейсы для серверов. А что будет этим источником правды — спека swagger или классы с аннотациями — не так важно и определяется скорее структурой команды и/или проекта.
1.
проект, где фуллстеков не было, причем разработка спеки API шла от фронтаВ этом проекте бэкенд-разработчик спеку вообще не трогал, можно было бы использовать code first
2. Проект, который я пишу сейчас, состоит из нескольких модулей, один занимается обработкой данных и спеку его API я писал от бэкенда, второй модуль — админка (формы / визарды на фронте), спеку его API я писал от фронта. Поэтому я использовал подход spec first, это позволило единообразно собирать оба модуля.
Вообще, я время от времени сталкиваюсь с тем, что спека написанная мной от бэкенда не полностью устраивает фронтенд-разработчика, так как я что-то не учел. Не вижу ничего плохого в том, что фронтенд-разработчик предложит правки к спеке, и сам их внесет после обсуждения. Мне кажется, что так будет быстрее, чем построчно объяснять мне, что и где поменять.
Вообще, самое главное, по моему мнению, обеспечить типобезопасность для API, для этого нужны статически типизированные языки на фронте и бэке и единый источник правды, из которого потом будут сгенерированы клиенты API / интерфейсы для серверов. А что будет этим источником правды — спека swagger или классы с аннотациями — не так важно и определяется скорее структурой команды и/или проекта.
Абсолютно согласен, в идеале докинуть сверху consumer-driven contracts.
Спасибо за обсуждение.
«Главный минус: официальные генераторы кода» — я так понимаю это для всех языков. В го ни кто не пользуется офиц. генератором, есть годная сторонняя либа
«Если бы на фронте и на бэке был typescript, то я бы использовал подход code first» — ага, и фротендеру, чтобы править спеку, пришлось бы учить какой нибудь лютый expressjs и прочее node-специфическое г-но, ломая при этом проект бекенда. Человек занят важным делом — пиксили подгоняет, flexbox-ы выравнивает. И тут ему — фигакс! — внезапно надо лезть в серверный код.
Во-2, сильно сомневаюсь, что спека из кода генерируется адекватно. Что правильно прописывает валидацию, например. Правильно понимает схемы авторизации. Это всё не тривиально.
И вообще притягивать за уши nodejs чтобы всё писать на одном языке — это бред. Нет конкаренси, нет праллелизма, код изуродован асинхронщиной, npm этот дебильный с миллиардам node_modules — чего ради? На рынке труда полно соискателей со знанием js/ts(react) + ЯП бекенда. Ориентироваться на тупых, ниасиливших второй ЯП? если только
«swagger нужен или в проекте с солянкой технологий» — ну то есть везде где есть веб. Вот и я говорю — пром. стандарт
фротендеру, чтобы править спеку, пришлось бы учить какой нибудь лютый expressjs и прочее node-специфическое г-но
Я вижу контракт API в виде отдельного модуля, который состоит из набора DTO и интерфейсов. В нем не должно быть ничего специфичного для клиента или сервера. DTO описывают, какие данные передаются в API, интерфейсы описывают, какие методы API доступны. Потом интерфейсы реализуются на фронте, чтобы получить клиент и на бэке, чтобы получить контроллер. Таким образом фронтенд-разработчик меняет именно контракт, не трогая реализацию бэкенда, бэкенд-разработчик — контракт, не трогая фронтенда. В этом же модуле можно сделать валидацию, ведь DTO не будут генерироваться через swagger, а будут переиспользоваться.
Для общения между модулями на java я использовал такой подход без swagger вообще.
сильно сомневаюсь, что спека из кода генерируется адекватно. Что правильно прописывает валидацию, например
Теоретически, springfox, который превращает java-классы в спеку, должен работать с JSR 303: Bean Validation, но практически я не видел поддержки валидации в генераторах фронта, хотя библиотеки c валидаторами на аннотациях для фронта я видел. Это основная проблема swagger — очень фрагментарная реализация фишек.
притягивать за уши nodejs чтобы всё писать на одном языке — это бред
Я думаю, что автор статьи привел хороший пример того, когда это удобно — проект, в котором одинаковые бизнес-правила нужны и на фронте и на бэке.
Я вижу контракт API в виде отдельного модуля, который состоит из набора DTO и интерфейсовАвторы OpenApi к счастью видят это по другому, поэтому добавили в сваггер много чего ещё, см. обзор фич сваггера. Сразу же возникает куча вопросов — как задать в ваших модулях методы аутентификации, схемы AND|OR авторизации, доп. форматы(base64 string, date-time, bsonobjectid и т.п.), доп. валидацию «через интиерфейс». Я понимаю, что какие-то ответы у вас могут быть, но могу заверить — они точно не понравятся любому, кто не пишет регулярно на java, особенно фронтендерам
Вы предлагаете фронтенд разработчику слегка подучить джаву и ваши гайдланы, которые вам кажутся простыми. Но у него своих гайдлайнов хватает. Потом ему предложат написать ui для бекенда на рубях — ror учить? едва ли это кому-то понравится. Проще изучить OpenApi вместо специфических гайдлайнов и ЯП. Зачем фронтендеру вникать что можно и что нельзя делать в вашем проекте, если есть де факто стандартный язык компактного и декларативного описания сервисов?
В этом же модуле можно сделать валидацию, ведь DTO не будут генерироваться через swagger, а будут переиспользоваться.Не проще ни разу, это довольно нудный бойлерплейт, особенно если нужен канонический RESTfull и требуется выбирать нужные коды ошибок хттп. На много проще валидацию описать декларативно в сваггере, и пусть себе генерируется.
Для общения между модулями на java я использовал такой подход без swagger вообще.для такого есть другая универсальная технология — grpc. Используется чуть более чем везде .
Я думаю, что автор статьи привел хороший пример того, когда это удобно.Да не сказал бы. Автор привёл пример примитивного круд сервиса, коих сотни тысяч на любых языках.
«проект, в котором одинаковые бизнес-правила нужны и на фронте и на бэке» — к сожалению такая формулировка мне не понятна
Вы предлагаете фронтенд разработчику слегка подучить джаву и ваши гайдланы
Нет, я писал про ситуацию, в которой и фронт и бэк написаны на одном языке, на typescript, а не на java. Для систем, написанных на разных языках я не вижу альтернативы swagger.
Не проще ни разу, это довольно нудный бойлерплейт
Язык описания схемы в swagger более многословен, чем java + lombok, kotlin или typescript, так что в на swagger бойлерплейта будет больше. Плюс swagger менее удобен, когда спеку пора разбить на несколько файлов, не все инструменты экосистемы swagger нормально работают с $ref, ведущими в другой файл.
На много проще валидацию описать декларативно в сваггере, и пусть себе генерируется.
Валидация точно так же декларативно делается аннотациями на полях класса. Только в swagger кастомную аннотацию сложно добавить, а в код на java / typescript — просто.
см. обзор фич сваггера
И исходники генераторов, чтобы понять, какие из них реально поддерживаются.
Давайте я вам проясню мою позицию по swagger:
Идея технологии хорошая, но как и любая другая имеет свою область применения. В случае swagger еще добавляются особенности реализации — не все заявленные фичи поддерживаются для всех языков, поэтому нужно обязательно это иметь в виду, когда принимаешь решение о его использовании. В своих проектах я его использую, в основном spec first, но с удовольствием бы поменял на что-то более удобное и лучше сделанное.
Для систем, написанных на разных языках я не вижу альтернативы swaggerНу вот автор утверждает, что у него всё на ts, и тем не менее из кода генерируется спека сваггера в качестве документации. Получается, даже написав всё на одном языке сваггер всё равно нужен. Вот только, как мы выяснили, такая документация не соответствует апи или не является полной. Поскольку, например, декларативную валидацию из кода на ts едва ли адекватно воспроизведёт тулза, генерирующая спеку сваггера (аналогично другие фичи).
swagger менее удобен, когда спеку пора разбить на несколько файлов, не все инструменты экосистемы swagger нормально работают с $ref, ведущими в другой файл.ну это значит экосистема совсем никудышная, раз таки мелочи не осиливает
Вот только, как мы выяснили, такая документация не соответствует апи или не является полной. Поскольку, например, декларативную валидацию из кода на ts едва ли адекватно воспроизведёт тулза, генерирующая спеку сваггера
Мне вот интересно. Значит, сделать спеку, которая соответствует коду, тулинг не может… а код, который соответствует спеке — сможет?
Значит, сделать спеку, которая соответствует коду, тулинг не можетНе видел таких и сомневаюсь в их существовании — слишком сложная задача в моём представлении. Приведите пример если есть желание.
а код, который соответствует спеке — сможет?Должен мочь. Иначе экосистема не годится для апи, не адекватна и не нужна — не поддерживает пром. стандарт.
Не видел таких и сомневаюсь в их существовании — слишком сложная задача в моём представлении. Приведите пример если есть желание.
"Должен мочь. Иначе экосистема не годится для апи, не адекватна и не нужна — не поддерживает пром. стандарт."
Должен мочь. Иначе экосистема не годится для апи, не адекватна и не нужна — не поддерживает пром. стандарт.
"Не видел таких и сомневаюсь в их существовании — слишком сложная задача в моём представлении. Приведите пример для C# если есть желание."
Значит, сделать спеку, которая соответствует коду, тулинг не может… а код, который соответствует спеке — сможет?
Ну, вообще, да. "Баловался" я одно время DSL-ами для спек разного уровня с кодогенерацией, спеки декларативные, код — ООП или ПП вообще. Максимум что получалось — внедрение каких-то незначимых для кода декларативных аннотаций, за синхронизацию которых с императивным кодом отвечает программист.
Вот любопытно мне. Как вы из спеки, которая говорит, что "такой-то ресурс возвращает такие-то HTTP-коды", сгенерите соответствующий код? Ну, в смысле, который других кодов не возвращает, а эти возвращает в описанных случаях?
Маппинг кодов на исключения в генераторе. Один нормальный код — 2хх, а остальное по исключениям типа ResourceNotFound — 404 и т. п.
Маппинг кодов на исключения в генераторе.
Угу, а преобразовывать исключения в коды вы где в коде будете?
В сгенерированном "водопроводном" контроллере :) типа try {} catch (ResourceNotFound e) { return new Response(404) }
Угу. А теперь давайте вспомним, что бывают коды, которые не-исключения. Вот 201 и 202, скажем. Которые еще и Location
возвращают.
Кстати, а что будет в try
этого метода?
Как раз в try что-то вроде return new Response(201, {'Location': ${generateUri(resource)}}).
Там несколько кодов, откуда генератор знает, какой при каких условиях?
(и откуда resource
берется?)
Есть некоторые ограничения, в частности упомянутый:
Один нормальный код — 2хх
То есть у каждого "роута" один нормальный, успешный код возврата.
resource возвращается сервисом. Реализовать сервис — ответственность разработчика
Есть некоторые ограничения
Ну вот и все, собственно. Согласно определению выше, "экосистема не годится для апи, не адекватна и не нужна — не поддерживает пром. стандарт".
Потому что стандарт позволяет больше одного "нормального" кода.
Можно бы сделать больше, но в виду того, что к обратной задаче (генерации спеки по коду) даже не понятно было как лучше подступать, то забили, пользовались всё реже, а потом вообще удалили.
потом вообще удалили
Вот.
Что вот? Тулинг, который только код по спеке генерировал, нам не подошёл, нам и обратный процесс нужен был. А вот задача генерации кода ("болванок") по спеке вполне решаема. Напомню, что обсуждаем
Значит, сделать спеку, которая соответствует коду, тулинг не может… а код, который соответствует спеке — сможет?
А вот задача генерации кода ("болванок") по спеке вполне решаема.
В полном объеме? Или "с ограничениями"?
Задача генерация спеки из кода тоже решаема — при условии, конечно, что код написан с соблюдением неких правил.
Ограничения, о которых я говорил, были на стадии типа MVP. Все выявленные при "промышленной эксплуатации" недостатки было понятно как решать при одном условии: сгенерированный код руками не меняется. Но только для направления спека->код
Ну так давайте вернемся к примеру с возвращаемыми кодами (и соответствующими им ответами, и это мы еще даже к Content-Type
не переходили). Как вы предлагаете решать озвученную проблему?
Не предлагаю, а собирался анализом/маппингом возвращаемого сервисом результата, возможно с использование какого-то ResultStatus контейнера или прослушиванием событий, синхронных.
Хочу уточнить, у нас не было цели создать универсальный тулинг для обработки всего, что соответствует swagger спецификации, нам нужно было решать наши задачи интеграции фронта и бэка. Сделали MVP, который позволял фронту вносить изменения в спеку, которые приводили к перегенерации части фронта и бэка. Обратную задачу решить не смогли быстро, оставили как есть, но оказалось непрактичным. Бэк не хотел руками синхронизировать свой код со схемой.
Хочу уточнить, у нас не было цели создать универсальный тулинг для обработки всего, что соответствует swagger спецификации
Это значит, что утверждение "тулинг может создать код, который соответствует спеке [в полном объеме спецификации]" вы не проверяли.
А я говорю именно об этом.
.NET Core vs Node.js. Аргументы и факты