Как стать автором
Обновить
88
2.4
Вадим Мартынов @Vadimyan

Программист

Отправить сообщение

Про идемпотентность — да, есть решения с отдельным идентификатором типа requestId/operationId, которые требуют дополнительного механизма, и иногда могут усложнять композитную операцию, которую можно перевыполнить частично. В общем случае такой отдельный идентификатор полезен хотя бы потому, что не во всех запросах могут быть реальные идентификаторы, при этом такой подход ведь не исключает поддержку возможности повтора на уровне БД, когда Upsert должен корректно сработать при повторе вставки.

Про SQL insert — видимо, я тут как-то неточно сформулировал предложение. Вставка не усложниться, клиент, если надо, попросит, проблема тут в том, что клиенту обычно надо и он обычно просит, на столько, что ORM типа EF Core это "попросит" включает в запрос вставки, сразу делая insert + select. И в случае с микроорм и абстркатным REST клиент ожидает на вставку или сущность с идентификатором целиком, или сам идентификатор.

С последней частью статьи как-то хотелось подвести к тому, что решение нужно, библиотеки сущетсвуют, но вот нет сейчас чего-то "стандартного" из коробки или почти из коробки где-нибудь в либах EF Core, в BCL хотя бы известной community-библиотеки про RFC 4122. Чаще всего задачу решают ULIDом (для которого есть несколького надежных либ), но, учитывая некоторую хитрую "частично лексикографическую" сортировку ключей в SQL Server, это возможно только с сменой типа данных для хранения, что может оказаться очень значительным переходом.

Изначально я смотрел именно на NewId и надеялся проверить результаты на MySQL как более распространенную (субъективно по моим ощущениям) БД, но так и не нашёл нужного инструмента под неё, зато решил поискать другие реализации для генерации UUID version 1 и был сильно озадачен небольшим выбором.

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

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

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

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

Да, всё так, что-то пошло не так и статус стандарта сейчас вот такой:

C# VERSION    ECMA STANDARD   ISO/IEC STANDARD
V1.0          ECMA-334:2003   ISO/IEC 23270:2003
V2.0          ECMA-334:2006   ISO/IEC 23270:2006
V3.0          none            none
V4.0          none            none
V5.0          ECMA-334:2017   ISO/IEC 23270:2018
V6.0          TBD             TBD
V7.0          TBD             TBD

Даже шестая версия считается черновиком.

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

Под пользовательским кодом я имел в виду код конечного приложения, условная бизнес-логика как противопоставление инфраструктурному коду, где оптимизации уровня "делегат не кэшируется, поэтому перепишем менее кратко или менее понятно, зато быстрее" или "избавимся от замыкания" важны. Те же Span<T> могут быть не так актуальны в каждом месте клиентского кода, а для поиска в словаре ключа, который является подстрокой полного имени машины, если это часть кода ServiceDiscovery и используется на каждом запросе — вполне.

Если те же params ReadOnlySpan<T> помогут забустить логирование для случаев с string.Format — отлично же будет. Надо смотреть бенчмарки будущих версий того же asp.net и других либ чтобы оценить значимость изменений.

Это "иногда" касается по большей части пользовательского кода — во внутренней реализации утилитарных библиотек это может использоваться довольно часто. Например, при работе с вебом utf8-литералы заменят большое количество конвертаций в рантайме, а изменения для generic math улучшат разработку новых типов, связанных с математикой.

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

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

Если речь о новых мажорных версиях библиотеки (а делать такое изменение в рамках текущей мажорной версии немного странно) — то тут breaking changes могут служить усилением безопасности. Для первичных конструкторов с большой вероятностью типы и так были спроектированы для использования конструктора базового типа (как в DbContext с options).

А вот обязательные члены меняют принцип инициализации объекта, ещё и требуют нужной области видимости, сейчас даже непонятно, как их хорошо встроить в контейнеры, чтобы те искали и инициализировали required -члены так же из контейнера. Мне сейчас кажется, что required — это больше история про модели и их безопасное использование, так что любой breaking change будет подсвечивать существующую в коде проблему инициализации. И учитывая движение к неизменяемым объектам (с помощью того же init) код уже готов к этому, а init-only свойства достаточно безопасно помечать required.

Это правда, хотя часть из описаных фич уже доставлена в C# 11 preview и много находятся в разработке или ревью уже сейчас. С большой вероятностью большая часть из описаного успеется к выходу C# 11 или по крайней мере не будут выброшены совсем.

Но при этом для некоторых фич всё ещё идут обсуждения дизайна и конечный вариант реализации может поменяться. Например, мне кажется, что params IEnumerable<T> всё-таки не завезут из-за избыточности, а модификатор уровня доступа для области видимости в пределах файла вообще болтает — то ли он будет private, то ли всё-таки file, а ещё там в комментах сразу думают над модификатором уровня доступа в пределах неймспейса.

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

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

required действительно выглядит как потенциальная смена парадигмы инициализации объектов, к которой нужно будет допиливать экосистему ещё. Потому что, например, record выглядит прекрасной фичей, но с AutoMapper сочетается довольно плохо. Если PostInit  конструкторы хорошо встроятся в DI, первичные конструкторы и другие фичи с полями и свойствами, то это будет интересное изменение. Это будет довольно сложно успеть к C# 12, так что пока значимость фичи не так понятна.

Если речь о том, что на самом деле таймаут общий и StopAsync последовательный, поэтому когда 1 HostedService потратил на остановку 4 секунды, то второму осталась всего одна, то да, тут я поправлю статью, это тонкий и важный момент.

Что касается второй части — не совсем вижу тут проблему. Если в моем коде приложение стартовало и сработал lifetime.ApplicationStarted.Register, то проблемы нет. Если приложение не стартовало и сработал stoppingToken.Register, то в моем коде всё равно вернется корректный результат WaitForAppStartup без ошибок, а в вашем внутри ExecuteAsync будет исключение System.Threading.Tasks.TaskCanceledException: A task was canceled. — почему этот сценарий лучше?

Да! И скоро даже будет очередная. На 24 апреля запланирована Krasnodar Frontend miniConf 2022 с 4 докладами:

  1. Feature sliced architecture (на русском я до этого докладов почти не встречал на эту тему)

  2. Виртуальная реальность\

  3. Универсальные UI элементы на Web Components в мультистековой команде

  4. Как бороться с энтропией в css

Анонсы по Краснодару можно смотреть в каналах krd.dev/news и Инфо-канал ИТ-сообщества ITKRD.

Да, async/await работает именно так. Вижу здесь 2 возможных разреза вопроса. Но для начала хочу показать код запуска HosterService внутри класса Host:

foreach (IHostedService hostedService in _hostedServices) 
{   
  // Fire IHostedService.Start    
  await hostedService.StartAsync(combinedCancellationToken).ConfigureAwait(false);       

  if (hostedService is BackgroundService backgroundService)
    _ = TryExecuteBackgroundServiceAsync(backgroundService);
}


1. Выполняет ли HostedService разовую работу при инициализации приложения или же он запускает периодическое выполнение задачи как в примере из статьи.
1.1. Если выполняет разовую работу при инициализации, то важным для await будет вопрос о том можно ли начать обработку запросов ДО завершения работы HostedService.
1.1.1. Если нет, то мы должны ожидать асинхронных вызовов внутри StartAsyncчтобы сработал внешний await в Host. В этом случае await hostedService.StartAsync получит задачу, которую будет ожидать.
1.1.2. Если да, то чтобы хост смог запуститься понадобится не ожидать асинхронные вызовы внутри hostedService.StartAsync, и отдать из метода Task.CompletedTask чтобы выполнение старта хоста продолжилось.
1.2. Если HostedService запускает периодическое выполнение задачи, то мы не можем ждать внутри StartAsync, иначе хост просто никогда не начнет обрабатывать вызовы потому что будет ждать завершения StartAsync.

Но на самом деле сценарии 1.2 или 1.1.2 означают, что нам вообще не нужно использовать свою реализацию IHostedService, а достаточно будет отнаследоваться от BackgroundService.

2. Может ли приложение продолжить работать при ошибке в HostedService.
2.1. Если да (например, HostedService подчищал старые кэши, отправлял дополнительную необязательную телеметрию), то какой-то особенной обработки исключений нам не нужно.
2.2. Если нет, то для gracefully shutdown стоит использовать упомянутый в статье IHostApplicationLifetime.

Но на самом деле в .net 6 хост будет останавлён при возникновении исключения в ExecuteAsync. Именно за это отвечает метод TryExecuteBackgroundServiceAsync, который был в начале комментария. Вот статья об этом изменении: Breaking changes / Unhandled exceptions from a BackgroundService. Чтобы переопределить это поведение и не останавливать хост в случае исключений в BackgroundService нужно сконфигурировать хост для игнорирования таких исключений:

Host.CreateBuilder(args)
    .ConfigureServices(services =>
    {
        services.Configure<HostOptions>(hostOptions =>
        {
            hostOptions.BackgroundServiceExceptionBehavior = BackgroundServiceExceptionBehavior.Ignore;
        });
    });

Сам IHost при запуске IHostedService делает awaitи будет ждать завершения метода StartAsync. То есть, если внутри сервиса заэвейтит задачу await DoSomeWorkEveryFiveSecondsAsync(cancellationToken);, то IHost будет бесконечно ждать старта сервиса и никогда не запустит остальные.

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

Речь как раз о том, что если нам не нужно блокировать дальнейший запуск хоста, то внутри StartAsync достаточно запустить задачу без ожидания и следить за переданным CancellationToken . В этом случае await StartAsync получит Task.CompletedTask и продолжит дальнейшую инициализацию.

Добавлю интересных фактов про собеседование в Яндекс — у меня был занятный опыт собеседования туда в течение пары месяцев и 14 собеседований общей продолжительностью 12+ часов, за время которых я успел решить 20 задач подобных тем, что есть в посте (наверное, проверяли какие-то базовые вещи). И даже успел один раз пообщаться с человеком, который планировал рефакторить эту систему (но, видимо, не очень успешно) собеседований.

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

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

Образование, мне кажется, в Тагане прямо неплохое — есть и обычное среднее, и дополнительное (посмотрите на Школу кода хотя бы). ВУЗ сам по себе неплох, по олимпиадному программированию он на голову выше всех остальных в регионе (но всё ещё на голову ниже топовых ВУЗов страны), и активно старается взаимодействовать с компаниями. + у нескольких компаний есть свои учебные центры и курсы.
Таганрог очень специфичный, согласен. Он очень хорош для slow-life и, возможно, для жизни с детьми — достаточно тихий, у него есть своя архитектурная красота, много зелени. Сфера услуг отстает, но это всё-таки не деревня и можно найти что-нибудь под потребность. Есть ещё приятные акценты — виндсёрф в черте города, аэропорт не очень далеко (а до 2014 был приятный бонус в виде аэропорта Донецка рядом).

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

В общем, он какой-то особенный, это не обычный just another one райцентр, но и не мегаполис с его бонусами.
Я бы хотел поспорить с аргументом «В случае оффлайн конференции негативное впечатление от низкого уровня докладов могло бы быть сглажено за счет новых знакомств и общения с интересными умными людьми». Мне кажется, это только один из способов интерпретации вашего результата. Можно тот же результат привязать к способу потребления информации.

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

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

И в онлайне добирать знания через коммуникацию значительно сложнее потому что установление контакта достаточно биологично (групповая динамика, свой-чужой) и завязано на эмпатию. Так что, с выводами я согласен, но вижу причину проблем онлайн-конференций не столько в том, что плохой контент нельзя скрасить хорошим общением, а именно в том, что «хороший контент» получить практически невозможно и это, к сожалению, не сильно зависит от спикеров. Можно попробовать починить проблему изменением формата, но ИМХО биологию довольно сложно переломить (что я для себя подтверждаю наблюдением поведения людей во время пандемии и их стремлением к встречам).
Да, мне тоже очень грустно по этому поводу потому что Саша очень хорош. Провайдер подвёл буквально за час до эфира и не починился даже к Zoom-созвону после эфира.
Есть доклад примерно полугодовой давности от него же с хорошим обзорным ИМХО как раз про кроссплатформу: "Кроссплатформенная мобильная разработка в 2019: путь C++ — Александр Ефременков | Mobile". В диалоге оно интереснее, но доклад мне очень нравится своей последовательностью и шириной.
Ухх, дискуссионно :) Что такое «более комфортные условия»? Разогретый рынок и высокие зарплаты? Такое уже есть. Большое скопление продуктовых компаний и интересные проекты? Тоже знаю такой город. Компании с свободой в выборе задач и направления развития? Большой общий уютный IT-кампус? Комфортный климат и развитая инфраструктура?

Всем ведь нужно разное — невозможно быть лучшим работодателем для всех, можно быть только лучшим работодателем для тех людей, для которых ты хочешь быть лучшим работодателем :) А это уже про культуру.
Привет.
Всё-таки у нас много разработки веб-сервисов. Хардварой занимаются ребята, которые работают с железом в кионтеатрах (Киноплан), есть разработка медицинского оборудования (например, мониторы и ML в МРТ) и несколько НИИ. Самый большой, наверное, это РНИИРС, но что там делают сложно сказать, а ещё ребята оттуда редко приходят в IT-сообщество и делятся знаниями именно про hardware и Embedded. Если посмотреть то же исследование, то C/C++ на седьмом месте и далеко не факт, что все отметившие эти языки занимаются встраиваемыми устройствами.

Информация

В рейтинге
1 313-й
Откуда
Ростов-на-Дону, Ростовская обл., Россия
Дата рождения
Зарегистрирован
Активность

Специализация

Backend Developer, Community manager
Lead
C#
.NET Core
Database
High-loaded systems
Designing application architecture
Database design
C++
Python
SRE