Le Hello World de base

La meilleure façon d’apprendre un nouveau langage reste encore d’écrire l’application typique Hello World. Je ne compte plus le nombre de fois que j’ai commencé un nouveau projet par cette simple application. Par exemple, voici la plus simple application Hello World qui peut être faite en C# :

Après avoir démarré Visual Studio et fait FileNew Project WindowsConsole Application, il ne reste qu’à compléter la méthode Main.

using System;
namespace HelloWorld
{
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Hello World!");
    }
  }
}

hello-world

Mais cette version minimaliste du Hello World n’est plus suffisante aujourd’hui. Voyons ce qui manque à cet exemple pour le rendre plus complet.

Prérequis

Voici ce dont vous aurez besoin pour exécuter ce tutoriel :

  • Visual Studio (Community ou Professional);
  • un compte Visual Studio Online.

Le code n’est pas tout

Bien qu’il soit intéressant de voir ce code se compiler et s’exécuter sur notre poste de travail, ce n’est que le début de l’histoire. Écrire et faire fonctionner du code sur son environnement de développement est une chose facile. Tous les outils de développement offrent une panoplie de fonctionnalités pour faciliter cet aspect du développement logiciel. Les complications arrivent plus tard, souvent au moment du déploiement, mais parfois un peu avant.

Regardons le cycle complet de développement d’une application.

Notre exemple Hello World ne concerne que la partie développement de ce processus, mais le plus souvent, les problèmes complexes surviennent au cours des autres étapes. Il est donc impératif de bonifier notre Hello World avec ces étapes.

Pour l’instant, laissons de côté les étapes préalables au développement et concentrons nos efforts sur les sous-étapes du développement : conception, construction et tests.

Du code qui sent mauvais

Dans cet exemple de code, si simple soit-il, il y a déjà du code qui sent mauvais. Ce qu’on appelle communément des code smells. Voyez-vous ce qui ne va pas? Comment pouvons-nous tester ce code?

Vers une version entreprise du Hello World

Pour moi, une première étape serait de sortir la logique d’affaires du Main. Dans ce cas-ci, c’est assez simple :

using System;
namespace HelloWorld
{
  class Program
  {
    static void Main(string[] args)
    {
      var greeter = new Greeter();
      greeter.Hello("World");
    }
  }
}
using System;
namespace HelloWorld
{
  public class Greeter
  {
    public void Hello(string name)
    {
      Console.WriteLine($"Hello {name}!");
    }
  }
}

Ce changement ne semble pas significatif, mais il nous permet d’avancer vers l’ajout de tests. En plaçant le code dans une classe et une méthode non statique, nous pourrons injecter des dépendances pour les tests. Quelle est la dépendance à remplacer dans la classe Greeter?

Pour l’instant, la classe Greeter écrit directement dans la console. Bien qu’il soit possible d’intercepter la sortie vers la console, ce n’est pas idéal pour les tests. Allons-y plutôt avec une injection de dépendance. Définissons l’interface à injecter.

namespace HelloWorld
{
  public interface IReceiver
  {
    void Say(string text);
  }
}

Ensuite, il faut créer une implémentation de cette interface :

using System;
namespace HelloWorld
{
  class ConsoleReceiver : IReceiver
  {
    public void Say(string text)
    {
      Console.WriteLine(text);
    }
  }
}

On peut maintenant remplacer l’implémentation dans la classe Greeter :

namespace HelloWorld
{
  public class Greeter
  {
    private readonly IReceiver _receiver;
    public Greeter(IReceiver receiver)
    {
      _receiver = receiver;
    }
    public void Hello(string name)
    {
      _receiver.Say($"Hello {name}!");
    }
  }
}

Une chose à noter dans la conception orientée objet : il faut bien identifier le type d’objet et sa relation avec les autres. Dans le cas présent, la classe Greeter est clairement une classe de traitement dont la responsabilité est de « saluer ». Mais la classe Greeter ne peut fonctionner toute seule. Elle ne peut pas saluer dans le vide. Il lui faut un récepteur du message. On doit donc lui ajouter cette dépendance pour que le système fonctionne.

Pour garder la fonctionnalité d’origine, on lui injecte une instance de ConsoleReceiver :

namespace HelloWorld
{
  class Program
  {
    static void Main(string[] args)
    {
      var greeter = new Greeter(new ConsoleReceiver());
      greeter.Hello("World");
    }
  }
}

Tout est maintenant en place pour faire notre premier test. Dans Visual Studio, on choisit File à Add New Project… à Test à Unit Test Project et on nomme le projet « HelloWorld.Tests ».

Pour tester la classe Greeter, il faut se créer un mock. Un mock est un objet qui peut prendre la place d’un autre et grâce auquel on peut vérifier le comportement attendu. Donc, voici le mock de IReceiver :

namespace HelloWorld.Tests
{
  public class ReceiverMock : IReceiver
  {
    private string _text;
    public void Say(string text)
    {
      _text = text;
    }
    public string Text
    {
      get { return _text; }
    }
  }
}

On peut maintenant écrire le test :

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace HelloWorld.Tests
{
  [TestClass]
  public class GreeterTests
  {
    [TestMethod]
    public void Reveiver_should_be_greeted()
    {
      var receiver = new ReceiverMock();
      var greeter = new Greeter(receiver);
      greeter.Hello("World");
      Assert.AreEqual("Hello World!" + Environment.NewLine, receiver.Text);
    }
  }
}

Bien que notre mock accomplisse la tâche, ce n’est pas ce qu’on utilise habituellement. Il serait trop coûteux d’écrire tous les mocks nécessaires pour tous les scénarios possibles. On utilise habituellement des librairies. Pour cet exemple, nous utiliserons Moq. Pour ajouter une librairie à notre projet de test, la façon conseillée est d’utiliser Nuget. Nuget est un gestionnaire de dépendances qui utilise un fichier pour conserver la liste des dépendances ajoutées. Ce fichier servira par la suite à réinstaller ces mêmes dépendances lorsque nous compilerons le code sur une autre machine.

Dans Visual Studio, avec un clic droit sur le projet de test, sélectionnez Manage nuget packages… à Browse à Search : moq à Moq by Daniel Cazzulino à Install. Vous remarquerez l’ajout du fichier package.config.

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Castle.Core" version="3.3.3" targetFramework="net461" />
  <package id="Moq" version="4.5.21" targetFramework="net461" />
</packages>

Maintenant, nous pouvons supprimer le fichier ReceiverMock.cs et réécrire le test comme suit :

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace HelloWorld.Tests
{
  [TestClass]
  public class GreeterTests
  {
    [TestMethod]
    public void Reveiver_should_be_greeted()
    {
      var mock = new Mock<IReceiver>();
      var greeter = new Greeter(mock.Object);
      greeter.Hello("World");
      mock.Verify(m => m.Say("Hello World!"), Times.Once);
    }
  }
}

Maintenant que nous avons un projet complet avec tests (au moins un), la prochaine étape est d’ajouter ce projet à un système de contrôle de version. Nous utiliserons Git. Avec Visual Studio 2015, il est très facile de créer son repo Git. En bas à droite de la fenêtre, sélectionnez Publish à Git. Cette opération va :

  • créer un fichier .gitattributes pour modifier la configuration de Git;
  • créer un fichier .gitignore pour exclure tous les fichiers indésirables;
  • ajouter ces deux fichiers dans un commit;
  • ajouter tous les fichiers du projet dans un autre commit.

Ensuite, pour rendre ces changements disponibles aux autres développeurs et surtout au serveur de build (à venir), il faut publier le repo. Visual Studio propose de publier sur Visual Studio Team Services ou sur GitHub. Nous utiliserons Visual Studio Team Services pour l’instant.

En cliquant sur Publish Git Repo, Visual Studio prend en charge la création d’un repo sur Visual Studio Team Services, il pousse les changements et associe ce repo remote au repo local en tant que origin. Maintenant, si vous allez voir la section code du projet, vous devez voir votre code à jour sur le serveur TFS Online. On peut alors définir un build. Suivez les instructions suivantes :

Une fois le build créé, on peut demander un nouveau build en cliquant sur Queue new build…

Si tout s’est bien passé, vous devriez avoir un build terminé avec succès. Vous pouvez explorer les différents onglets du résultat de build pour voir des statistiques sur votre projet.

Conclusion

Faire un HelloWorld aujourd’hui demande de réfléchir à tout le processus du cycle de développement logiciel. Cet exemple simple illustre les différentes étapes à réaliser pour y arriver. Le plus important pour assurer la réussite d’un projet, c’est de faire ces étapes le plus tôt possible. Si elles sont bien intégrées au processus de développement, vous réduirez les problèmes à long terme et vous éviterez plus facilement le fameux « Works on my machine ».

Billet précédent

La distinction entre conformité et engagement

Billet suivant

La « startup » Agile et le capital de risque — Partie 3 : La réalité frappe de plein fouet

éric de carufel

Passionné, impliqué et minutieux sont des qualités qui décrivent bien Éric pour qui le développement logiciel est une quête constante d'amélioration pour atteindre un équilibre entre la perfection et les besoins du client. Son approche architecturale est simple : élaborer une architecture où il est plus facile d'appliquer les bonnes pratiques que les mauvaises.

Son implication en tant que conférencier et blogueur est reconnue par Microsoft, qui lui a décerné le prix de "Most Valuable Professional in Visual C#" (MVP C#) chaque année entre 2009 et 2015.

Pas de commentaire

Laissez un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *