Basic Hello World

The best way to learn a new language is still writing the typical Hello World application. I can not count the number of times I started a new project with this simple application. For example here is the simplest Hello World application that can be done in C#:

After starting Visual Studio and done File → New → Project → Windows Console Application, the remaining thing to do is to complete the Main method.

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

hello-worldBut this minimalist version of Hello World is no longer sufficient today. See what is missing in this example to make it more complete.

Prerequisites

 

Here’s what you’ll need to run this tutorial:

  • Visual Studio (Cummunity or Professional)
  • A Visual Studio Online accounte

Le code n’est pas tout

While it is interesting to see this code compiles and runs on our computer, this is only the beginning of the story. Writing and running code on its own development environment is easy. All development tools offer a range of features to facilitate this aspect of software development. The complications come later, often at deployment but sometimes earlier than that.

Let’s look at the full application development cycle.

application-cycleNotre 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.

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 pourront injecter des dépendances pour les tests. Quel est la dépendance à remplacer dans la classe Greeter?

Pour l’instant, la classe Geeter é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 le design orienté 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 peux 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 remplisse 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 que le fichier package.config a été ajouté.

<?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&amp;amp;amp;lt;IReceiver&amp;amp;amp;gt;();
      var greeter = new Greeter(mock.Object);
      greeter.Hello("World");
      mock.Verify(m =&amp;amp;amp;gt; 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 est de faire ces étapes dès que possible dans la réalisation du projet. 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.

Previous post

The Agile startup and the venture capital—Part 2: The ‘wait’

Next post

The distinction between compliance and engagement

éric de carufel

Passionate, concerned, and careful are qualities describing Éric, for whom software development is a constant quest for improvement to strike a balance between perfection and client needs. His architectural approach is simple: to develop an architecture where it is easier to apply good practices than bad ones.

His involvement as a speaker and blogger is recognized by Microsoft, which awarded to him the prize of "Most Valuable Professional in Visual C#" (C# MVP) every year between 2009 and 2015.

No Comment

Leave a reply

Your email address will not be published. Required fields are marked *