Bonjour, Habr! Notre collègue, Scott Hanselman, estime que dans le cadre de l'apprentissage d'un langage de programmation, il est important non seulement de coder et de pratiquer l'écriture, mais aussi d'apprendre le code de quelqu'un d'autre. "Lisez le code de quelqu'un d'autre", dit Scott, et cite des informations utiles qu'il a trouvées dans le travail de son collègue. Plus de détails sous la coupe!
Je passe la parole à Scott Hanselman . Êtes-vous d'accord avec lui?
La meilleure approche pour apprendre un langage de programmation n'est pas seulement d'écrire plus de code, mais aussi de
se familiariser avec ses exemples ! Ce ne seront pas toujours des exemples de code exemplaire, et une grande partie de ce que vous voyez ne vous sera pas utile, mais c'est un excellent moyen d'élargir vos horizons.
Je crois qu'en fait la lecture du code n'est pas accordée à l'attention voulue. Peut-être qu'il n'y a pas assez de bases de code propres.
J'ai donc été agréablement surpris lorsque j'ai découvert une base de code appelée Jimmy Bogard
Contoso University .
Ce référentiel contient beaucoup de bons documents, mais je ne dirai pas que j'ai tout lu et aussi soigneusement que nous le souhaiterions. Pour tout étudier en détail, vous devez passer toute la journée. Cependant, j'ai aimé certains points et en ai pris note. Les différents morceaux de code sont clairement faits dans le style de Jimmy, comme il les a écrits pour lui-même.
Ce n'est pas du tout un reproche. Au fil du temps, nous accumulons tous des modèles, créons des bibliothèques et développons nos propres styles architecturaux. J'aime le fait que Jimmy ait recueilli des développements intéressants faits par lui-même ou avec sa participation au fil des ans, et préparé un bon matériel de lecture. Jimmy note que
ContosoUniversityDotNetCore-Pages a beaucoup de choses utiles:
Le clonage et l'assemblage fonctionnent plutôt bien
Vous serez surpris de voir à quel point j'abaisse parfois la barre. Très souvent, je clone le dépôt git de quelqu'un d'autre qui n'a été testé nulle part. Et je reçois un bonus pour télécharger dans build.ps1 tout ce qui est nécessaire.
.NET Core 2.x est déjà installé sur mon
système , build.ps1 reçoit les packages nécessaires et construit complètement le code.
Il existe de nombreuses opinions sur ce projet. Et c'est génial, car c'est ainsi que j'apprends des méthodes et des outils que je n'ai jamais utilisés auparavant. Si quelqu'un utilise une approche non standard, alors parmi les outils standard, il n'est pas nécessaire!
- Build.ps1 utilise un style de script de construction tiré de PSake , un outil d'automatisation de génération PowerShell.
- Il place l'assemblage dans un dossier portant le nom standard ./artifacts.
- Build.ps1 utilise Roundhouse , un utilitaire de migration de base de données pour .NET qui utilise des fichiers SQL et des versions créées à l'aide de l' outil de contrôle de version de projectroundhouse .
- Il est configuré pour une intégration continue dans AppVeyor , l'excellent système CI / CD que j'utilise moi-même.
- Elle utilise l'outil Octo.exe d'OctopusDeploy pour emballer les artefacts.
Code ordonné et clair
À mon avis, tout le code est très facile à lire. J'ai commencé avec Startup.cs pour simplement comprendre quel middleware est utilisé.
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>(); }); }
Ici, je vois les bibliothèques et les assistants utilisés, par exemple, AutoMapper, MediatR et HtmlTags. Ensuite, je peux aller dans des sections séparées et étudier chaque outil.
Miniprofiler
J'ai toujours aimé l'outil
MiniProfiler . Ce trésor .NET secret a été créé depuis longtemps et est toujours utile au travail.
Je l'ai mentionné en 2011! Il est invisible sur votre page Web et fournit des données VRAIMENT utiles sur le comportement du site et les valeurs d'exécution clés.

Il est conseillé de l'utiliser avec EF Core pour voir également le code SQL généré. Et tout est intégré au site lors de sa création.

Tout simplement génial!
Des tests unitaires clairs
Jimmy utilise XUnit et je vois le fichier
IntegrationTestBase dans la liste
. Je ne comprends pas certains points, par exemple le fonctionnement du fichier
SliceFixture . Je l'ai pris à une note pour bien comprendre tout. Il est peu probable que la création d'une nouvelle bibliothèque auxiliaire de test soit lancée ici: approche trop universelle et sérieuse pour l'utiliser dans ce modèle.
Jimmy utilise le modèle
CQRS (Command Query Responsibility Segregation). Au début, la commande Créer est créée et exécutée, puis une requête est exécutée pour confirmer les résultats. Tout est très clair, nous obtenons un test très isolé.
[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); }
Validation des fluides
fluentvalidation est une bibliothèque utile pour créer des règles de validation claires avec un contrôle de type fort. Jimmy l'utilise partout et obtient un code de vérification extrêmement clair.
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(); } }
Solutions utiles
Voyons quelles méthodes l'extension de projet C # utilise par l'auteur. Cela montre ce qui, à son avis, fait défaut dans les fonctionnalités de base. La méthode vous permet de renvoyer des données au format JSON à partir de 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" }; } }
Liste paginée
Je me suis toujours demandé quoi faire avec des classes d'assistance comme PaginatedList. Trop petit pour l'emballage, trop spécifique pour l'incorporation. Qu'en penses-tu?
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); } }
Je continue d'explorer toutes les sources de code que je peux trouver. Je prends note des choses que j'aime, note ce que je ne sais pas ou ne comprends pas, et fais une liste de sujets à lire. Je vous conseille de faire de même! Merci,
Jimmy , d'avoir écrit
un si bon modèle de code que nous pouvons lire et apprendre!