Хабрахабр

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

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

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

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

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

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

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

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

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

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

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

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

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

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

public void ConfigureServices(IServiceCollection services)
) .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) .AddFluentValidation(cfg => { cfg.RegisterValidatorsFromAssemblyContaining<Startup>(); });
}

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

MiniProfiler

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

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

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

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

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

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

[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 — полезная библиотека для создания четких правил проверки со строгим контролем типов. Джимми использует ее повсюду и получает предельно понятный код проверки.

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); }
}

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

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»