- PVSM.RU - https://www.pvsm.ru -

Что можно найти в чужом коде? Подборка полезных материалов по .NET

Привет! Наш коллега, Скотт Хансельман, считает, что в рамках изучения языка программирования важно не только кодить и практиковаться в написании, но и изучать чужой код. «Читайте чужой код» говорит Скотт и приводит полезные материалы, которые он нашел в наработках своего коллеги. Подробнее под катом!

Что можно найти в чужом коде? Подборка полезных материалов по .NET - 1

Передаю слово Скотту Хансельману [1]. А вы согласны с ним?

Лучший подход к изучению языка программирования – не только писать больше кода, но и знакомиться с его примерами [2]! Не всегда это будут примеры образцового кода, и многое из увиденного вам не пригодится, но это отличный способ расширить кругозор.

Я считаю, что на самом деле чтению кода не уделяют должного внимания. Возможно, не хватает чистых баз кода.

Поэтому я был приятно удивлен, когда обнаружил базу кода, названную Джимми Богардом Contoso University [3].

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

Это вовсе не упрек. Мы все со временем накапливаем шаблоны, формируем библиотеки и разрабатываем собственные архитектурные стили. Мне нравится, что Джимми собрал интересные наработки, сделанные им самим или при его участии за многие годы, и подготовил хороший материал для чтения. Джимми отмечает, что на ContosoUniversityDotNetCore-Pages [4] есть много полезного:

Клонирование и сборка работают довольно хорошо

Вы удивитесь, насколько низко я иногда опускаю планку. Очень часто я клонирую чей-либо git-репозиторий, который нигде не тестировался. И получаю бонус для загрузки в build.ps1 всего, что необходимо. В моей системе уже установлен .NET Core 2.x [14], build.ps1 получает нужные пакеты и полностью строит код.

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

  • Build.ps1 использует стиль скрипта сборки, взятый из PSake [15], инструмента автоматизации сборки PowerShell.
  • Он помещает сборку в папку со стандартным именем ./artifacts.
  • В build.ps1 применяется Roundhouse [16]— утилита миграции базы данных для .NET, которая использует SQL-файлы и версии, созданные при помощи инструмента управления версиями projectroundhouse [17].
  • Он настроен для непрерывной интеграции в AppVeyor [18], прекрасную систему CI/CD, которую я использую сам.
  • Она применяет инструмент Octo.exe [19] из OctopusDeploy для упаковки артефактов.

Упорядоченный и понятный код

По-моему, весь код читается очень легко. Я начал с Startup.cs, чтобы просто понять, какое промежуточное ПО используется.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMiniProfiler().AddEntityFramework();
 
    services.AddDbContext<SchoolContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
 
    services.AddAutoMapper(typeof(Startup));
 
    services.AddMediatR(typeof(Startup));
 
    services.AddHtmlTags(new TagConventions());
 
    services.AddMvc(opt =>
        {
            opt.Filters.Add(typeof(DbContextTransactionPageFilter));
            opt.Filters.Add(typeof(ValidatorPageFilter));
            opt.ModelBinderProviders.Insert(0, new EntityModelBinderProvider());
        })
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
        .AddFluentValidation(cfg => { cfg.RegisterValidatorsFromAssemblyContaining<Startup>(); });
}

Здесь я вижу используемые библиотеки и помощники, например, AutoMapper, MediatR и HtmlTags. Далее я могу переходить в отдельные разделы и изучать каждый инструмент.

MiniProfiler

Мне всегда нравился инструмент MiniProfiler [20]. Это тайное сокровище .NET создано уже давно и всегда полезно в работе. Я упоминал о нем еще в 2011 году! [21] Он незаметно присутствует на вашей веб-странице и предоставляет ДЕЙСТВИТЕЛЬНО полезные данные о поведении сайта и ключевых значениях времени выполнения.

Что можно найти в чужом коде? Подборка полезных материалов по .NET - 2

Целесообразно использовать его с EF Core, чтобы видеть также сгенерированный код SQL. И все встраивается в сайт по мере его создания.

Что можно найти в чужом коде? Подборка полезных материалов по .NET - 3

Просто замечательно!

Понятные модульные тесты

Джимми использует XUnit, и я вижу в списке файл IntegrationTestBase. [22] Некоторые моменты я не понимаю, например, работу файла SliceFixture [23]. Взял его на заметку, чтобы досконально во всем разобраться. Вряд ли здесь запускается создание новой тестовой вспомогательной библиотеки: слишком универсальный и серьезный подход, чтобы использовать его в этом шаблоне.

Джимми применяет шаблон CQRS [5] (Command Query Responsibility Segregation). В начале создается и запускается команда Create, затем выполняется запрос для подтверждения результатов. Все предельно четко, мы получаем очень изолированный тест.

[Fact]
public async Task Should_get_edit_details()
{
    var cmd = new Create.Command
    {
        FirstMidName = "Joe",
        LastName = "Schmoe",
        EnrollmentDate = DateTime.Today
    };
 
    var studentId = await SendAsync(cmd);
 
    var query = new Edit.Query
    {
        Id = studentId
    };
 
    var result = await SendAsync(query);
 
    result.FirstMidName.ShouldBe(cmd.FirstMidName);
    result.LastName.ShouldBe(cmd.LastName);
    result.EnrollmentDate.ShouldBe(cmd.EnrollmentDate);
}

Fluentvalidation

fluentvalidation [24]— полезная библиотека для создания четких правил проверки со строгим контролем типов. Джимми использует ее повсюду и получает предельно понятный код проверки.

public class Validator : AbstractValidator<Command>
{
    public Validator()
    {
        RuleFor(m => m.Name).NotNull().Length(3, 50);
        RuleFor(m => m.Budget).NotNull();
        RuleFor(m => m.StartDate).NotNull();
        RuleFor(m => m.Administrator).NotNull();
    }
}

Полезные решения

Давайте посмотрим, какие методы расширения C# проекта использует автор. Это показывает, чего, по его мнению, не хватает в базовом функционале. Метод позволяет возвращать данные в формате JSON из Razor Pages.

public static class PageModelExtensions
{
    public static ActionResult RedirectToPageJson<TPage>(this TPage controller, string pageName)
        where TPage : PageModel
    {
        return controller.JsonNet(new
            {
                redirect = controller.Url.Page(pageName)
            }
        );
    }
 
    public static ContentResult JsonNet(this PageModel controller, object model)
    {
        var serialized = JsonConvert.SerializeObject(model, new JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        });
 
        return new ContentResult
        {
            Content = serialized,
            ContentType = "application/json"
        };
    }
}

PaginatedList

Я всегда задавался вопросом, что же делать со вспомогательными классами типа PaginatedList. Слишком маленький для упаковки, слишком специфичный для встраивания. Что вы думаете?

public class PaginatedList<T> : List<T>
{
    public int PageIndex { get; private set; }
    public int TotalPages { get; private set; }
 
    public PaginatedList(List<T> items, int count, int pageIndex, int pageSize)
    {
        PageIndex = pageIndex;
        TotalPages = (int)Math.Ceiling(count / (double)pageSize);
 
        this.AddRange(items);
    }
 
    public bool HasPreviousPage
    {
        get
        {
            return (PageIndex > 1);
        }
    }
 
    public bool HasNextPage
    {
        get
        {
            return (PageIndex < TotalPages);
        }
    }
 
    public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source, int pageIndex, int pageSize)
    {
        var count = await source.CountAsync();
        var items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
        return new PaginatedList<T>(items, count, pageIndex, pageSize);
    }
}

Я продолжаю изучать любые источники кода, которые удается найти. Беру на заметку понравившиеся вещи, отмечаю то, что не знаю или не понимаю, и составляю список тем для чтения. Я бы посоветовал вам делать то же самое! Спасибо, Джимми [25], за то, что написал такой большой шаблон кода [3], который мы можем читать и изучать!

Автор: sahsAGU

Источник [26]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/programmirovanie/288728

Ссылки в тексте:

[1] Скотту Хансельману: https://www.hanselman.com/

[2] знакомиться с его примерами: https://www.hanselman.com/blog/GivenILikeReadingSourceCodeByTheFireWithMySmokingJacketAndBrandySnifterAListOfBooks.aspx

[3] Contoso University: https://github.com/jbogard/ContosoUniversityDotNetCore-Pages?WT.mc_id=-blog-scottha

[4] ContosoUniversityDotNetCore-Pages: https://github.com/jbogard/ContosoUniversityDotNetCore-Pages

[5] CQRS : https://www.hanselman.com/blog/ExploringCQRSWithinTheBrighterNETOpenSourceProject.aspx

[6] MediatR: https://github.com/jbogard/MediatR?WT.mc_id=-blog-scottha

[7] AutoMapper : https://automapper.org/

[8] Архитектура вертикальных срезов: https://jimmybogard.com/vertical-slice-architecture/

[9] Razor Pages: https://docs.microsoft.com/en-us/aspnet/core/razor-pages?WT.mc_id=-blog-scottha

[10] Fluent Validation: https://fluentvalidation.net/

[11] Shouldly: http://shouldly.readthedocs.io/en/latest/

[12] HtmlTags: https://github.com/HtmlTags/htmltags?WT.mc_id=-blog-scottha

[13] Ядро Entity Framework: https://docs.microsoft.com/en-us/ef/core/?WT.mc_id=-blog-scottha

[14] системе уже установлен .NET Core 2.x: https://www.dot.net/

[15] PSake: https://github.com/psake/psake?WT.mc_id=-blog-scottha

[16] Roundhouse : https://github.com/chucknorris/roundhouse?WT.mc_id=-blog-scottha

[17] projectroundhouse: http://projectroundhouse.org

[18] AppVeyor: https://www.hanselman.com/blog/AppVeyorAGoodContinuousIntegrationSystemIsAJoyToBehold.aspx

[19] Octo.exe: https://github.com/OctopusDeploy/OctopusClients?WT.mc_id=-blog-scottha

[20] MiniProfiler: https://miniprofiler.com/

[21] Я упоминал о нем еще в 2011 году!: https://www.hanselman.com/blog/NuGetPackageOfTheWeek9ASPNETMiniProfilerFromStackExchangeRocksYourWorld.aspx

[22] IntegrationTestBase.: https://github.com/jbogard/ContosoUniversityDotNetCore-Pages/blob/master/ContosoUniversity.IntegrationTests/IntegrationTestBase.cs?WT.mc_id=-blog-scottha

[23] SliceFixture: https://github.com/jbogard/ContosoUniversityDotNetCore-Pages/blob/1c2e0e524221fac702d6e7e8027b046cbe031bd2/ContosoUniversity.IntegrationTests/SliceFixture.cs?WT.mc_id=-blog-scottha

[24] fluentvalidation : https://fluentvalidation.net

[25] Джимми: https://twitter.com/jbogard/

[26] Источник: https://habr.com/post/418519/?utm_campaign=418519