Pull to refresh
10
0
Виктор Николаев @Veikedo

.net developer

Send message

Кажется, теорема Гёделя математически доказывает, что не всё можно доказать математически

В первой части статьи вы так расписывали удобство Mapster'a что в нём не надо явно конфигурацию прописывать. Но ведь в продакшене в любом случае эти правила должны быть явно прописаны, чтобы иметь возможность вызвать AssertConfigurationIsValid.
Да и про киллер-фичу с генерацией моделек у мапстера ни слова.

Не знаю, я вот очень люблю джунов и стажёров.

Это же идеальные исполнители на огромную кучу мелких задач и мелкого техдолга.

Зачем вы так про GraphQL?


Graphql это язык запросов к вашему приложению, он никак не зависит от IQueryable или чего-то ещё — вы сами выбираете (=реализуете) какую фильтрацию поддерживаете.
То есть, он не течёт*, там строгая схема, которую вы сами обязались реализовать.


В HotChocolate (реализация gql для дотнет) 11 версии ребята вообще отказались от IQueryable.


(*может течь, если уровень вложенности select'a становится больше какого-то, задаваемого разработчиком, уровня)

Для фильтров хорошо подходит спецификация (но согласен, там тоже текучесть).


При должном усилии можно подружить с чистым sql.

Мсье знает толк

Лучше тогда $appsettings.{Environment.MachineName}.json и его в .gitignore.


appsettings.Development.json всё-таки шарить удобно внутри команды.

Я возможно чего-то не понимаю, но как при правильно настроенном CSP можно слить JWT из local storage на сторонний сервер?

В целом положительные.
Но у нас не как у Джими Богарда с его vertical features.


У нас "почти clean" — сборка с апп сервисами и в ней свои фичи, сборка презентейшн — либо напрямую юзает классы (дто) из апп сервисов, либо добавляет свои фичи (например, для graphql).


Кроме размещения фич в одном файле, не стесняемся пользоваться nested классами — меньше проблем с придумыванием имён и меньше нейм-конфликтов. Если класс получается большим из-за nested-классов, то делаем класс partial и выносим в отдельный файл.


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


Заголовок спойлера
  public class CreateAccount
  {
    public class Command : MediatR.IRequest<Result>
    {
      public string Name { get; }
    }

    public class Result
    {
      public Account Account { get; set; }
    }

    // dto
    public class Account
    {
    }

    public class Mappings : Profile
    {
    }

    public class Validation : AbstractValidator<Command>
    {
    }

    public class Handler : IRequestHandler<Command, Result>
    {
    }
  }

Плюсы медиатра в том, что очень легко решать cross cutting concerns, у marshinov хорошие статьи были на эту тему.

Сейчас используем такой извращённый интересный подход:


Какая-нибудь 'фича' или app service
namespace Vendor.Features.Statistics
{
  public class GetAutomationStatisticsQuery : IRequest<GetAutomationStatisticsResult>
  {
    public DateTime? FromDate { get; set; }
    public DateTime? ToDate { get; set; }
    public string TaskArn { get; set; }
  }

  public class GetAutomationStatisticsResult
  {
    public long TotalAutomations { get; set; }
    public long ErrorsReported { get; set; }
    public long WarningsReported { get; set; }
  }

  internal class GetAutomationStatisticsHandler :
    IRequestHandler<GetAutomationStatisticsQuery, GetAutomationStatisticsResult>
  {
    private readonly GetAutomationsLogTotalCount _getAutomationsLogTotalCount;
    private readonly GetAutomationsTotalCount _getAutomationsTotalCount;

    public GetAutomationStatisticsHandler(
      // Это делегаты на другие фичи (этакая инкапсуляция над медиатром)
      GetAutomationsLogTotalCount getAutomationsLogTotalCount,
      GetAutomationsTotalCount getAutomationsTotalCount)
    {
      _getAutomationsLogTotalCount = getAutomationsLogTotalCount;
      _getAutomationsTotalCount = getAutomationsTotalCount;
    }

    public async Task<GetAutomationStatisticsResult> Handle(GetAutomationStatisticsQuery query, CancellationToken ct)
    {
      // some logic
    }
  }

  public delegate Task<GetAutomationStatisticsResult> GetAutomationStatistics(
    GetAutomationStatisticsQuery query, CancellationToken ct = default);
}

В каждом файле "фичи" лежат классы для реквеста, респонса, хендлера и делегат (GetAutomationStatistics в примере).


Затем этот делегат через рефлексию регистрируется в IoC с помощью такого класса:


MediatorForwarderForDelegates
    private sealed class MediatorForwarderForDelegates<TRequest, TResponse> where TRequest : IRequest<TResponse>
    {
      private readonly IMediator _mediator;

      public MediatorForwarderForDelegates(IMediator mediator)
      {
        _mediator = mediator;
      }

      public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken)
      {
        return _mediator.Send(request, cancellationToken);
      }
    }

Ну и эти делегаты потом уже можно инжектировать в другие хендлеры/сервисы.

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

ViennaNET.Mediator.*
Такой подход позволяет сократить количество DI-инъекций до одной, например, в контроллерах.

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


Если да, то есть мнение, что это тот же service locator.

react-admin хорош, если все формы простые и одинаковые.
Чуть шаг в сторону и начинаются костыли и баги

Почему не воспользовались AppMetrics?

Извиняюсь, я кажется чего-то не понял — а где хоть какой-то репозиторий birma.net или gorp.net?


За статью спасибо, не знал про реверсивные шаблоны.

А какие потребности решаются прометеусом? Хранение метрик, да решаются

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


Только не надо писать про Task, он нужен когда создается множество тредов через тредпул(под капотом) и с удобным управлением

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


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

Разве такие потребности не решаются тем же прометеусом?
А у вас здесь кроме неподдерживаемого кода ещё и создание тредов руками (ещё и без try..catch, что может привести к краху всего процесса) и динамики непонятно зачем и это на первый взгляд только.
Ну и ещё вопросы — кто будет ваш тред останавливать, учитывая, что при завершении процесса в очереди могут быть ещё задачи?
и BlockingCollection был бы здесь более подходящим вариантом с его семафорами и GetConsumingEnumerable, а не Thread.Sleep в цикле как у вас.

У эластика есть ИИ для анализа логов.
Вообще было бы интересно почитать историии про его использование

1
23 ...

Information

Rating
Does not participate
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Date of birth
Registered
Activity