Pull to refresh
15
0

User

Send message
Ваше предложение? Убить всех джунов, «не совсем професионалов с большим опытом работы» и индусов?
Напоминает service locator, не находите?

Не совсем понял что имеется виду. Можете уточнить?
Предположим, что вот вам нужно починить багу. Вы нашли роут с которым не все в порядке. Открываем контролер и видим следующий конструктор.
    public SomeController(
        ISearchResultManager searchResultManager, 
        IStorageManager storageManager, 
        IMediaManager mediaManager, 
        ISearchResultsExportManager searchResultsExportManager, 
        IElasticSearchManager elasticSearchManager, 
        IElasticSearchService elasticSearchService, 
        ISearchHistoryService searchHistoryService, 
        IAgentManager agentManager, 
        IElasticSearchOptionsCreator elasticSearchOptionsCreator, 
        ISearchResultCreator searchResultCreator, 
        IWorkInProgressManager workInProgressManager, 
        ICommonManager commonManager)
    {
        this.searchResultManager = searchResultManager;
        this.storageManager = storageManager;
        this.mediaManager = mediaManager;
        this.searchResultsExportManager = searchResultsExportManager;
        this.elasticSearchService = elasticSearchService;
        this.searchHistoryService = searchHistoryService;
        this.agentManager = agentManager;
        this.elasticSearchOptionsCreator = elasticSearchOptionsCreator;
        this.searchResultCreator = searchResultCreator;
        this.workInProgressManager = workInProgressManager;
        this.commonManager = commonManager;
        this.elasticSearchManager = elasticSearchManager;
    }


Вам понятно что делает следующий контроллер? Я бы сказал что он может делать что угодно. Ладно, посмотрим сам обработчик нужного роута, там одна строка:
searchResultManager.GetSearchesByAgentId(agentId);

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

С медиатором ты знаешь что нужно смотреть сам вызов медиатора и если там нет ничего http специфичного, то в обработчике будет одна строка.
Как по мне, найти грань очень просто. Если это REST API, то это все, что может работать без веб сервера. Это та часть приложения что может жить в сфечисеком вакуме. Ты только дай ей данные и она сделает с ними все необходимое.

Исходя из этого, редактирование справочников это точно бизнес логика. REST API получает запрос, преобзовывает его согласно принятым протоколам, отдает на откуп бизнес логике.
Меня тоже терзали эти мысли, но больше не терзают. Намучался называется…
У контролера и сервиса с бизнес логикой разные задачи. Задача контролера заключается в обработки запроса. Не важно это http или grpc. Для этого у него есть все необходимые данные. Тело запроса, параметры, куки и все остальное. Он их анализурует и решает что делать дальше. Сервис же обрабатывает бизнес задачу. Для этого у него есть свои инструменты. Это две разные абстракции. Смешивание двух абстракций в одном методе точно увеличивает его размер(нужно писать логику для двух сразу), что увеличивает вероятность что-то недопонять когда ты к нему вернешся. Если же используются отдельные сервисы, то будет фигурировать как минимум один метод с логичным названием, что существено упростит понимание и поиск это места в будущем(что наверно даже болие важно).

Сам все больше склоняюсь к использованию библиотек по типу MediatR. С ними искать и писать можно еще более точечно и весь контекст для выполнения задачи находится в одном месте. При этом исключается возможность случайно создать контролер с 10 зависимостями в конструкторе, что происходит почти всегда в особо больших проектах.
Проверял и он там не работает. Баг в трекере есть, но когда его починят не известно.
youtrack.jetbrains.com/issue/RIDER-31659
Все просто, им нужны разработчики, но их количество ограничено. Нужно постоянно показывать насколько ты хорош чтобы привлеч к себе винимание. Если этого не делать, то ты будеш в проиграше, поскольку это делают другие.
Ну так уже много раз сказано и написано статей(даже на хабре), что синглтон нужно использовать очень осмотрительно, а лучше вообще не использовать. Сначала он выглядит просто и красиво, а чуть поже начинаются приседания. Что ваша статья добавляет ко всему сказаному?
Ох, трюк конечно прикольный, я такого ещё не видел, спасибо что показали, но если бы я увидел такое в реальном проэкте у меня бы возникло много вопросов и смущений.

С таким подходом часть данных доставляется магическим/неявним образом. В итоге просто задебажить контролер не получиться, всегда нужно это учитывать. Кроме того, как писать тесты с такой магией? Запускать весь asp net core runtime чтобы магия начала работать?

Тут было бы логичней вынести все это в отдельные сервисы. Первый отвечает за роботу с другим API, делая все необходимые валидации. Второй уже успользует его и делает свой набор валидаций. Он же пакует все вместе и возвращает. В случае ошибки делать исключение или Maybe<> с кодом ошибки.
А значит миграция с одного хромобраузера на другой для пользователя может оказаться весьма хлопотной — закладки, пароли придется переносить вручную и нарушится

Именно с этим проблем не будет. Microsoft Edg-у можно сказать заимпортить все данные с уже установленного Google Chrome при настройке аккаунта. Сам так сделал когда он только вышел.
Но это наглядно показвает реальный расброс в 10%, а не 60%.

Mono конечно) но если ещё проще то https://github.com/chrisdunelm/DotNetAnywhere

Была бы ссылка на оригинал можно было бы проверить…
Есть AspNet Core, но он не совместим с обычным AspNet. Много старого легаси осталось фреймворке. Все новое уже на core.
Половина(если не больше) топ игор в appstore и google play написаных на Unity. Разные красивые AR демки от Google и Apple сразуже имеют поддержку Unity или вообще написаны на ей. Все это так, фигня.
Ну не вижу ничего особенного. Цель моно была быть максимально совместимым с .Net framework. Там даже некоторые баги пришлось копировать, чтобы ничего не сломать. .Net Core же сделан с «нуля» без груза обратной совместимости.

Еще немного оптимизаций. Вынес вывод в консоль из замеров. Стало работать за 0.54-0.53. ТОже самое для rust стало 0.47-0.48
using System;
using System.Diagnostics;
using System.Linq;
using System.Text;

public class Program
{
    public static Int32 LevDist(string s1, string s2)
    {
        if (s1.Length == 0)
        {
            return s2.Length;
        }
        else if (s2.Length == 0)
        {
            return s1.Length;
        }

        var v0 = new int[s2.Length + 1];
        var v1 = new int[s2.Length + 1];
        for (int i = 0; i < v0.Length; i++)
        {
            v0[i] = v1[0] = i;
        }

        for (var i = 0; i < s1.Length; i++)
        {
            v1[0] = i + 1;

            for (var j = 0; j < s2.Length; j++)
            {
                var substCost = (s1[i] == s2[j]) ? v0[j] : (v0[j] + 1);
                var delCost = v0[j + 1] + 1;
                var insCost = v1[j] + 1;

                v1[j + 1] = Math.Min(Math.Min(substCost, delCost), insCost);
            }

            (v0, v1) = (v1, v0);
        }

        return v0[s2.Length];
    }

    public static void Main()
    {
        string s1 = new String('a', 15000);
        string s2 = s1;
        string s3 = new String('b', 15000);

        for (var i = 0; i < 5; i++)
        {
            Stopwatch execTimer = new Stopwatch();
            execTimer.Start();

            var levDist1 = LevDist(s1, s2);
            var levDist2 = LevDist(s1, s3);

            execTimer.Stop();
            
            Console.WriteLine(levDist1);
            Console.WriteLine(levDist2);
            double execTime = execTimer.ElapsedMilliseconds / 1000.0;

            Console.WriteLine($"Finished in {execTime.ToString():0.000}s");
        }
    }
}

Эта верия работает еще быстрее
using System;
using System.Diagnostics;
using System.Linq;
using System.Text;

public class Program
{
    public static Int32 LevDist(string s1, string s2)
    {
        if (s1.Length == 0)
        {
            return s2.Length;
        }
        else if (s2.Length == 0)
        {
            return s1.Length;
        }

        var v0 = new int[s2.Length + 1];
        var v1 = new int[s2.Length + 1];
        for (int i = 0; i < v0.Length; i++)
        {
            v0[i] = v1[0] = i;
        }

        for (var i = 0; i < s1.Length; i++)
        {
            v1[0] = i + 1;

            for (var j = 0; j < s2.Length; j++)
            {
                var substCost = (s1[i] == s2[j]) ? v0[j] : (v0[j] + 1);
                var delCost = v0[j + 1] + 1;
                var insCost = v1[j] + 1;

                v1[j + 1] = Math.Min(substCost, delCost);
                if (insCost < v1[j + 1])
                {
                    v1[j + 1] = insCost;
                }
            }

            (v0, v1) = (v1, v0);
        }

        return v0[s2.Length];
    }

    public static void Main()
    {
        string s1 = new String('a', 15000);
        string s2 = s1;
        string s3 = new String('b', 15000);

        for (var i = 0; i < 5; i++)
        {
            Stopwatch execTimer = new Stopwatch();
            execTimer.Start();

            Console.WriteLine(LevDist(s1, s2));
            Console.WriteLine(LevDist(s1, s3));

            execTimer.Stop();
            double execTime = execTimer.ElapsedMilliseconds / 1000.0;

            Console.WriteLine($"Finished in {execTime.ToString():0.000}s");
        }
    }
}


Тут Enumerable.Range(...) заменен на обычный масив и для красоты сделал (v0, v1) = (v1, v0). Выполняться стало за 0.55 вместо 0.65. Запускал на .NET Core SDK (3.1.100), следующим образом dotnet run -c release

На той же машине раст отрабатывает за 0.490. Запускался через cargo run --release
Тоже самое с C#.
Доберусь домой сравню у себя на машине с растом.

Information

Rating
Does not participate
Registered
Activity