Knowledge-base
  • Home
  • Samman Technical Coaching
  • Software craftsmanship
    • Practices
      • Pair Programming
      • Code Review
      • Co-designs
      • Design sessions
      • Interview Domain Experts
      • Dev ethics
    • The Software Craftsman
    • Egoless Crafting
    • Technical debt workshop
    • Functional Programming made easy in C# with Language-ext
    • F# for OO programmers
    • Domain Modeling Made Functional
    • Testing
      • Clean Tests
      • Improve the design and testing of your micro-services through CDC Tests
        • CDC testing made simple with Pact
        • Pact broker : the missing piece of your Consumer-Driven Contract approach
      • Improve your test quality with Mutation testing
      • How to name our Unit Tests
      • How to write better assertions
    • Katas
      • TDD
        • Stack kata
        • Fizzbuzz
        • Outside-in TDD (London Style)
      • Improve your software quality with Property-Based Testing
        • A journey to Property-Based Testing
      • Clean Code
      • Clean Architecture
      • Write S.O.L.I.D code
      • Mocking
      • Gilded Rose (Approval Testing)
      • Mikado method
        • Mikado kata
      • Pure functions
      • Theatrical players refactoring Kata
        • Let's refactor (OOP style)
        • Let's refactor (FP style)
      • Functional Programming made easy in Java & C#
      • Refactoring journey
      • Refactoring du Bouchonnois
        • 1) Se faire une idée du code
        • 2) "Treat warnings as errors"
        • 3) Let's kill some mutants
        • 4) Améliorer la lisibilité des tests
        • 5) "Approve Everything"
        • 6) Définir des propriétés
        • 7) Tests d'architecture
        • 8) Use Cases
        • 9) Tell Don't Ask
        • 10) "Avoid Primitives" - Commands
        • 11) "Avoid Exceptions"
        • 12) "Event Sourcing"
    • Software Design X-Rays
      • Workshop
    • The Programmer's Brain
      • How to read code better
  • Software Architecture
    • Fundamentals of Software Architecture
    • Aligning Product & Software Design
    • DDD re-distilled
    • Test your architecture with Archunit
    • NoSQL
  • Agile coaching
    • How to run a Community of Practices (COP)
    • The developers — the forgotten of agility
      • The secrets to re-on-board the devs in agility
    • Coaching toolbox
      • Echelle
      • Learning expedition
    • How to improve Team Decision making ?
      • Decision Making Principles and Practices
    • Learning 3.0
    • Retrospectives
      • Back to the Future
      • Mission Impossible
      • Movie themes
      • Rétro dont vous êtes le héros
      • Sad/Mad/Glad
      • Speed boat
      • Star wars theme
      • Story cubes
    • Technical Agile Coaching with the Samman Method
    • Xanpan - a team centric agile method story
    • XTREM WATCH — Découvrez la puissance de la veille collective
    • Become a better speaker through peer feedback
    • Project-to-Product Principles
  • Leadership
    • Bref. J'ai pris une tarte dans la gueule (et ça fait extrêmement de bien)
    • Forward Summit 2020
    • Learn leadership from the Navy SEALs
    • Learn to lead and help your team(s) to be successful
    • Towards a learning organization and beyond
    • Leadership is language
  • Serious games
    • My serious games
    • Libérez vos entretiens d’embauche avec la gamification
    • How to create a game
    • How to debrief a game ?
    • Lego Serious Play (LSP)
      • LSP in your job interviews
  • Xtrem Reading
    • Cultivate Team Learning with Xtrem Reading
    • My Book Infographics
    • How to make book infographics
    • En route vers l’apprenance avec Xtrem Reading
    • Resources
      • Book notes
        • Agile People: A Radical Approach for HR & Managers
        • Agile testing : A Practical Guide for Testers and Agile Teams
        • Boite à outils de l'intelligence émotionnelle
        • Building a better business using Lego Serious Play method
        • Building evolutionary architectures
        • Code that fits in your head
        • Culture Agile
        • Culture is everything
        • Domain-Driven Design: The First 15 Years
        • Dynamic Reteaming - The Art and Wisdom of Changing Teams
        • How to avoid a Climate Disaster
        • La liberté du commandement
        • Réaliser ses rêves, ça s'apprend
        • Refactoring at Scale
        • Succeeding with OKRs in Agile
        • Team Topologies
        • The Good Life
        • Tu fais quoi dans la vie
        • Who Does What By How Much?
  • My Activity
    • Retour sur mon année 2020
Powered by GitBook
On this page
  • Configurer la compilation
  • Ligne de commande
  • Configurer nos projets
  • Jeu des 7 erreurs
  • Bouchonnois
  • Fixer les tests
  • Reflect

Was this helpful?

  1. Software craftsmanship
  2. Katas
  3. Refactoring du Bouchonnois

2) "Treat warnings as errors"

Previous1) Se faire une idée du codeNext3) Let's kill some mutants

Last updated 1 year ago

Was this helpful?

Prendre quelques instants pour découvrir la page .

Configurer la compilation

Pour ce faire nous avons 2 options.

Ligne de commande

On peut spécifier à dotnet de traiter les warnings comme erreur de compilation via la ligne de commande suivante :

dotnet build -warnaserror

On a dès lors 7 erreurs de compilation :

Le problème ici, c'est que cette ligne de commande n'est pas partagée entre tous les devs travaillant sur le système :

  • IDE Build

  • Continuous Integration

Ainsi, la volonté de traiter tous les warnings comme des erreurs peut être facilement "oubliée" en compilant via son IDE ou en omettant de spécifier l'argument passer ici.

On va dès lors privilégier l'option ci-dessous qui permet de partager la configuration de compilation quelque soit la manière de faire.

Configurer nos projets

Pour configurer chaque projet on peut éditer le fichier csproj à la main et y ajouter :

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

Ou le configurer via notre IDE :

Jeu des 7 erreurs

On doit maintenant résoudre les 7 erreurs. On commence par le projet du code de production Bouchonnois.

Bouchonnois

Nous avons plusieurs options pour résoudre les erreurs de compilation comme présenté par Rider :

Ici, nous allons privilégier l'initialisation de la propriété par le constructeur.

Cela permet de :

  • Renforcer l'encapsulation

    • Si nous n'avons pas besoin d'exposer le champ Nom de manière public nous pourrons le rendre private

  • Forcer / exposer ce qui est requis lors de l'instantiation de nos objets

  • Renforcer les règles métiers

    • Initialiser des valeurs par défaut (Status par exemple) depuis le constructeur

    • Ne plus "diluer" cette responsabilité dans le système

public class Terrain
{
    public Terrain(string nom)
    {
        Nom = nom;
    }

    public string Nom { get; init; }
    public int NbGalinettes { get; set; }
}

On va pouvoir se laisser driver par notre compilateur à chaque modification.

On va également pouvoir renforcer l'encapsulation et rendre des champs init-only :

On va améliorer la qualité du code en même temps :

public PartieDeChasse(Guid id, Terrain terrain)
{
    Id = id;
    // La liste de chasseurs ne sera jamais null
    Chasseurs = new List<Chasseur>();
    Terrain = terrain;
    // Initialiser le Status depuis le constructeur afin qu'à l'instanciation le status soit le bon
    Status = PartieStatus.EnCours;
    // La liste d'events ne sera jamais null
    Events = new List<Event>();
}

Fixer les tests

Après les modifications sur le projet de production, on doit fixer les tests -> l'instantiation des objets du Domain.

[Fact]
public void QuandLaPartieVientDeDémarrer()
{
    var id = Guid.NewGuid();
    var repository = new PartieDeChasseRepositoryForTests();
    var service = new PartieDeChasseService(repository, () => DateTime.Now);

    // Changer l'instantiation
    repository.Add(new PartieDeChasse
    {
        Id = id,
        Chasseurs = new List<Chasseur>
        {
            new() {Nom = "Dédé", BallesRestantes = 20},
            new() {Nom = "Bernard", BallesRestantes = 8},
            new() {Nom = "Robert", BallesRestantes = 12, NbGalinettes = 2},
        },
        Terrain = new Terrain
        {
            Nom = "Pitibon sur Sauldre",
            NbGalinettes = 3
        },
        Status = PartieStatus.EnCours,
        Events = new List<Event>
        {
            new(new DateTime(2024, 4, 25, 9, 0, 12),
                "La partie de chasse commence à Pitibon sur Sauldre avec Dédé (20 balles), Bernard (8 balles), Robert (12 balles)")
        }
    });

    var status = service.ConsulterStatus(id);

    status.Should()
        .Be(
            "09:00 - La partie de chasse commence à Pitibon sur Sauldre avec Dédé (20 balles), Bernard (8 balles), Robert (12 balles)"
        );
}

En essayant de corriger les tests on se rend compte qu'on a besoin d'un nouveau constructeur... ou d'une manière simple d'ajouter des chasseurs / events dans la PartieDeChasse. Pour le moment et afin de pouvoir compiler, nous allons créer un nouveau constructeur.

[Fact]
public void QuandLaPartieVientDeDémarrer()
{
    var id = Guid.NewGuid();
    var repository = new PartieDeChasseRepositoryForTests();
    var service = new PartieDeChasseService(repository, () => DateTime.Now);

    repository.Add(new PartieDeChasse(id, new Terrain("Pitibon sur Sauldre"){ NbGalinettes = 3 }, 
    new List<Chasseur>
    {
        new("Dédé") {BallesRestantes = 20},
        new("Bernard") {BallesRestantes = 8},
        new("Robert") {BallesRestantes = 12, NbGalinettes = 2},
    },
    new List<Event>
    {
        new(new DateTime(2024, 4, 25, 9, 0, 12),
            "La partie de chasse commence à Pitibon sur Sauldre avec Dédé (20 balles), Bernard (8 balles), Robert (12 balles)")
    }));

    var status = service.ConsulterStatus(id);

    status.Should()
        .Be(
            "09:00 - La partie de chasse commence à Pitibon sur Sauldre avec Dédé (20 balles), Bernard (8 balles), Robert (12 balles)"
        );
}

A la fin notre classe PartieDeChasse ressemble à celà:

using Bouchonnois.Service;

namespace Bouchonnois.Domain
{
    public class PartieDeChasse
    {
        public Guid Id { get; }
        public List<Chasseur> Chasseurs { get; }
        public Terrain Terrain { get; }
        // Toujours in problème d'encapsulation ici
        public PartieStatus Status { get; set; }
        public List<Event> Events { get; init; }
        
        public PartieDeChasse(Guid id, Terrain terrain)
        {
            Id = id;
            Chasseurs = new List<Chasseur>();
            Terrain = terrain;
            Status = PartieStatus.EnCours;
            Events = new List<Event>();
        }

        // Nous avons ajouté 3 constructeurs pour les tests...
        public PartieDeChasse(Guid id, Terrain terrain, List<Chasseur> chasseurs)
            : this(id, terrain)
        {
            Chasseurs = chasseurs;
        }


        public PartieDeChasse(Guid id, Terrain terrain, List<Chasseur> chasseurs, List<Event> events)
            : this(id, terrain, chasseurs)
        {
            Events = events;
        }

        public PartieDeChasse(Guid id, Terrain terrain, List<Chasseur> chasseurs, PartieStatus status)
            : this(id, terrain, chasseurs)
        {
            Status = status;
        }
    }
}

Reflect

  • Comment aurait-on pu faire en sorte que les tests soient moins résistants aux refactorings du code de prod ?

  • Quelles autres problèmes avions nous identifier et devrions nous corriger avant d'aller plus loin ?

Nouveau rapport SonarCloud disponible .

ici
Treat warnings as errors
Step 2 - "Treat warnings as errors"
Erreurs de compilation
Configurer la compilation
Erreurs du Bouchonnois
Renforcer l'encapsulation