82
Qualité logicielle Cyril Gandon

Qualité logicielle

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Qualité logicielle

Qualité logicielleCyril Gandon

Page 2: Qualité logicielle

Introduction

Vous savez coder : lire et écrire un fichier, afficher un résultat à l’écran,

lancer plusieurs Threads, manipuler des listes, etc.

Etes vous attentifs à la qualité de votre code ?

Un logiciel ne se résume pas à ses fonctionnalités

Son potentiel de croissance est au moins aussi important que ses

fonctionnalités

Un code de qualité est tourné vers le futur : maintenable, modulable

Page 3: Qualité logicielle

Objectifs

Etre capable de reconnaitre le manque de qualité d’un code

Etre capable d’appliquer les méthodes de refactoring pour augmenter la

qualité

Comprendre les enjeux de la qualité logicielle

Connaitre les outils applicables pour écrire un code de qualité

Page 4: Qualité logicielle

Sommaire

1. Mesure de la qualité

2. Le Refactoring

3. Les principes S.O.L.I.D.

4. Initiation à la programmation fonctionnelle

5. Analyse statique

6. Programmation par contrat

Page 5: Qualité logicielle

1. Mesure de la qualité

Page 6: Qualité logicielle

La théorie : Norme ISO 9126 Software

engineering — Product quality

Functionality : The existence of a set of functions and their specified properties. The functions are those that satisfy stated or implied needs.

Suitability, Accuracy, Interoperability, Security, Functionality Compliance

Reliability : The capability of software to maintain its level of performance under stated conditions for a stated period of time.

Maturity, Fault Tolerance, Recoverability, Reliability Compliance

Usability : The effort needed for use, and on the individual assessment of such use, by a stated or implied set of users.

Understandability, Learnability, Operability, Attractiveness, Usability Compliance

Efficiency : The relationship between the level of performance of the software and the amount of resources used, under stated conditions.

Time Behaviour, Resource Utilization, Efficiency Compliance

Maintainability : The effort needed to make specified modifications.

Analyzability, Changeability, Stability, Testability, Maintainability Compliance

Portability : The ability of software to be transferred from one environment to another.

Adaptability, Installability, Co-Existence, Replaceability, Portability Compliance

Source : http://en.wikipedia.org/wiki/ISO/IEC_9126

Page 7: Qualité logicielle

En pratique

Fonctionnel

Maintenable

KISS : Keep It Simple Stupid

YAGNI : You Ain’t Gonna Need It

DRY : Don’t Repeat Yourself

Performant (Théorie de la complexité)

Robuste (Parallélisable, Portable)

Testable (Via les tests unitaires)

Page 8: Qualité logicielle

Fonctionnel

Développer les fonctionnalités demandées

Page 9: Qualité logicielle

Maintenable

Simplicité, simplicité, simplicité

Lisibilité

Pas de code spaghetti

Ne soyez pas un « Astronaute Architecte » = Ne surdésigner pas le model

Ne vous répétez pas, n’écrivez jamais deux fois le même code

Page 10: Qualité logicielle

Performant

Soyez conscient de la complexité de votre algorithme

O(1) > O(log n) > O(n) > O(n log n) > O(n²)

Page 11: Qualité logicielle

Robuste

Comment réagi votre logiciel « au bord »

Et si le réseau tombe ?

Et si l’utilisateur rentre de mauvaises données ?

Et si les données reçues sont dans un mauvais format ?

Fail fast => Valider toujours et échouer rapidement

Page 12: Qualité logicielle

Testable

La couverture des tests unitaires doit approcher les 100%

Réduit les dépendances

Diminue les régressions

Page 13: Qualité logicielle

2. Le Refactoring

Page 14: Qualité logicielle

Le refactoring, c’est quoi ?

Définition : la modification du code d’un logiciel dans le but de le rendre

plus simple à comprendre et à modifier, sans changer son comportement

observable

Simplifier le code

Accroitre sa lisibilité

Un code est écrit 1 fois et lu 10 fois

80% du temps est passé à la maintenance, donc la relecture

Gagner en robustesse

Du temps investi aujourd’hui pour une maintenance plus simple demain

Ne modifie pas les fonctionnalités existantes

Page 15: Qualité logicielle

(Re)Factorisation d’une identité

remarquable

a² + 2ab + b²

a = 2, b = 4

2² + 2 * 2 * 4 + 4² = ?

(a + b)²

a = 2, b = 4

(2 + 4)² = 36

Page 16: Qualité logicielle

Références

http://refactoring.com

http://sourcemaking.com/refactoring

Page 17: Qualité logicielle

Quelques principes

1. Renommage

2. Découper les fonctions

3. Réduire les paramètres

4. Réduire le scope des variables

5. Rendre les objets immutables

6. Eviter les négations et supprimer les doubles négation

7. Introduire des variables temporaires pour des expressions complexes

8. Ne pas utiliser la même variable pour autres chose

9. Séparer les niveaux (layers) d’abstraction

10.Loi de Demeter

Page 18: Qualité logicielle

1. Renommage

Un bon nom doit être dicible par téléphone

Notation PascalCase pour les classes et méthodes, camelCase pour les

variables (en C#)

Doit décrire précisément l’action ou l’état représenté

Suivre les conventions de nommages de son langage (Java != C# != PHP),

ou de son entreprise si elles existent

The name of a method does not reveal its purpose.

Change the name of the method.

Page 19: Qualité logicielle

2. Découper les fonctions

Diviser pour régner, mieux vaut plusieurs petites fonctions qu’une seule

grosse

Une fonction ne devrait jamais dépasser quelques dizaines de lignes

void printOwing()

{

printBanner(); //print details

System.out.println ("name: " + _name);

System.out.println ("amount " +

getOutstanding());

}

void printOwing()

{

printBanner();

printDetails(getOutstanding());

}

void printDetails (double outstanding)

{

System.out.println ("name: " + _name);

System.out.println ("amount " + outstanding);

}

Page 20: Qualité logicielle

3. Réduire le scope des variables

Une variable doit être déclarer au plus proche de son utilisation, dans le

scope (contexte) le plus faible

Permet de suivre l’algorithme plus facilement. Le cerveau ne peut pas

retenir plus de 6-7 variables

Implique d’éviter au maximum les variables static qui ont un scope global à

toute l’application

Page 21: Qualité logicielle

3. Réduire le scope des variables

Scope de iScope de i

public int Foo(int j){

int i = 2;int a;if (j > 3){

a = i * i;}else{

a = 0;}return a;

}

public int Foo(int j){

int a;if (j > 3){

int i = 2;a = i * i;

}else{

a = 0;}return a;

}

Page 22: Qualité logicielle

4. Réduire le nombre de paramètres

Le nombre de paramètres d’une méthode ne devrait jamais dépasser 3 ou

4

Grouper ensemble les paramètres qui ont un sens commun

You have a group of parameters that naturally go together.

Replace them with an object.

Page 23: Qualité logicielle

5. Rendre les objets immutables

Un objet sans setters (immutable) est plus simple à manipuler et plus

sécurisant (CF la programmation fonctionnelle)

Peut être passer à des tiers sans effet de bords

Laisser les mutants à la science fiction, pas à la science informatique

Page 24: Qualité logicielle

5. Rendre les objets immutables

public class MyPoint{

private double _x;

public double X{

get { return _x; }set { _x = value; }

}private double _y;

public double Y{

get { return _y; }set { _y = value; }

}

public MyPoint(double x, double y){

this.X = x;this.Y = y;

}}

public class MyPoint{

private readonly double _x;

public double X{

get { return _x; }}private readonly double _y;

public double Y{

get { return _y; }}

public MyPoint(double x, double y){

this._x = x;this._y = y;

}}

Page 25: Qualité logicielle

6. Eviter les négations et les doubles

négation

La lecture est toujours plus simple dans le sens positif que dans le sens

négatif

if(!this.NotFound())

double foo;if(this.HasValue == false)

foo = 0;else

foo = 1;

double foo;if(this.HaveValue)

foo = 1;else

foo = 0;

if(this.Found())

Page 26: Qualité logicielle

7. Introduire des variables temporaires

pour des expressions complexes

Condenser un trop plein d’informations dans une variable nommée

if ( (platform.toUpperCase().indexOf("MAC") > -1) &&

(browser.toUpperCase().indexOf("IE") > -1) &&

wasInitialized() && resize > 0

)

{

// do something

}

final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;

final boolean isIEBrowser = browser.toUpperCase().indexOf("IE") > -1;

final boolean wasResized = resize > 0;

if (isMacOs && isIEBrowser && wasInitialized() && wasResized)

{

// do something

}

Page 27: Qualité logicielle

8. Ne pas utiliser la même variable pour

2 concepts différents

Garder en tête la signification d’une variable est difficile, encore plus si elle

change en cours de route

Mieux vaut créer une nouvelle variable

L’idéal est qu’une variable doit être assignée une seule fois (paradigme de

la programmation fonctionnelle)

double temp = 2 * (_height + _width);

System.out.println (temp);

temp = _height * _width;

System.out.println (temp);

final double perimeter = 2 * (_height + _width);

System.out.println (perimeter);

final double area = _height * _width;

System.out.println (area);

Page 28: Qualité logicielle

9. Séparer les niveaux (layers)

d’abstraction

Identifier et séparer les différentes couches de l’application

Généralement se sont les suivantes

Couche métier (algorithme, logique = BML, Buisness Model Layer)

Couche de présentation (Vue/View)

Couche d’accès aux données (DAL, Data Access Layer)

Voir le Pattern MVC pour un tel découpage (Model Vue Controller)

Page 29: Qualité logicielle

10. Loi de Demeter

L’antipattern : Feature Envy

var c = a.GetB().GetC();

Augmente le couplage

Définition : Ne parlez qu’à vos amis directs

Vous pouvez jouer avec vous même

Vous pouvez jouer avec vos jouets

Vous pouvez jouer avec les jouets que l’on vous donne

Vous pouvez jouer avec les jouets que vous avez fabriqués

Page 30: Qualité logicielle

10. Loi de Demeter

var employees = someObject.GetEmployeeList();employees.AddElementWithKey(employee.GetKey(), employee);

someObject.AddToEmployees(employee);

Définition : soit la méthode M de l’objet O. La méthode M à la droit

d’invoquer les méthodes de :

O lui-même

Des attributs / propriétés de O

Des paramètres de M

Des objets instanciés dans M

Page 31: Qualité logicielle

Conclusion & Problématique

Le refactoring n’ajoute pas de fonctionnalité, ne corrige pas de bugs

Comment vendre du temps d’improductivité à votre entreprise ?

Source : http://dilbert.com/strips/comic/2007-11-26/

Page 32: Qualité logicielle

Conclusion

Le refactoring est un investissement toujours payant, à vous de savoir le

vendre

Le refactoring est une partie importante des méthodes agiles => Coder

vite, livrer vite, refactoriser, boucler

Fonctionne de pair avec les tests unitaires

Page 33: Qualité logicielle

3. Les principes S.O.L.I.D.

Page 34: Qualité logicielle

C’est quoi SOLID ?

Les pratiques SOLID permettent d’avoir des outils pour construire des

logiciels de qualité

Introduites par Robert C. Martin en 2000 dans son article « Design Principles

and Design Patterns »

SOLID est un acronyme de cinq lettres représentant pour chaque lettre 1

principe à respecter

Page 35: Qualité logicielle

S.O.L.I.D.

Single responsibility principle

Open/closed principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Page 36: Qualité logicielle

Single responsibility principle

Un objet doit avoir une seule responsabilité

Un objet doit avoir une seule raison de changer

Page 37: Qualité logicielle

Mauvais exemple

Lit un fichier

Parse et valide les données

Non testable unitairement

public class Fruit{

public int Id { get; set; }public string Name { get; set; }

public static IEnumerable<Fruit> FruitsFromFile(string path){

// 0;Apple// 1;Orange// 2;Bananausing (var reader = new StreamReader(path)){

string line;while ((line = reader.ReadLine()) != null){

var words = line.Split(';');int id = Convert.ToInt32(words[0]);string name = words[1];yield return new Fruit() { Id = id, Name = name };

}}

}}

Page 38: Qualité logicielle

Séparer les responsabilités

// Représente un fruit dans un fichierpublic class FruitFile{

public string Id { get; set; }public string Name { get; set; }

public static IEnumerable<FruitFile> FruitsFromFile(stringpath)

{using (var reader = new StreamReader(path)){

string line;while ((line = reader.ReadLine()) != null){

var words = line.Split(';');yield return new FruitFile()

{ Id = words[0], Name = words[1] };}

}}

}

public class Fruit{

public int Id { get; set; }public string Name { get; set; }

// Valide les données d'une ligne fruitpublic static Fruit Build(FruitFile fruitFile){

int id = Convert.ToInt32(fruitFile.Id);string name = fruitFile.Name;return new Fruit() { Id = id, Name = name };

}

public static IEnumerable<Fruit> FromFile(string path){

return FruitFile.FruitsFromFile(path).Select(fruitFile => Build(fruitFile));

}}

La validation des données devient testable unitairement

Page 39: Qualité logicielle

Open/closed principle

Un objet doit être ouvert à l’extension mais fermer à la modification

Page 40: Qualité logicielle

Open/closed principle

Ouvert à l’extension = Possibilité de rajouter des fonctionnalités

Fermé à la modification = Ajout des fonctionnalités sans changer le code

existant

Mécanisme : Héritage, Polymorphisme, Interface (Abstraction)

Page 41: Qualité logicielle

Mauvais exemple

public class Rectangle{

public double Width { get; set; }public double Height { get; set; }

public double Area { get { return this.Width * this.Height; } }}

public class Circle{

public PointF Center { get; set; }public double Radius { get; set; }

public double Area{

get { return this.Radius * this.Radius * Math.PI; }}

}

public class Shapes{

public double AreaOf(List<object> shapes){

double total = 0;foreach (var shape in shapes){

if (shape is Rectangle){

total += ((Rectangle)shape).Area;}else if (shape is Circle){

total += ((Circle)shape).Area;}

}return total;

}}

Obligation de modifier la fonction si on ajoutait un triangle

Page 42: Qualité logicielle

Ajout d’un niveau d’abstraction

// Abstract the Shape conceptpublic interface IShape { double Area { get; } }

public class Rectangle : IShape{

public double Width { get; set; }public double Height { get; set; }

public double Area { get { return this.Width * this.Height; } }}

public class Circle : IShape{

public PointF Center { get; set; }public double Radius { get; set; }

public double Area{

get { return this.Radius * this.Radius * Math.PI; }}

}

public class Shapes{

// Can run with abstract list of shapespublic double AreaOf(IEnumerable<IShape> shapes){

double total = 0;foreach (var shape in shapes){

total += shape.Area;}return total;

}}

Le code est extensible pour n’importe quel forme

Page 43: Qualité logicielle

Liskov substitution principle

Une classe doit pouvoir être remplacée par une instance d'une des ses

sous-classes, sans modifier la validité du programme

Page 44: Qualité logicielle

Liskov substitution principle

Une sous classe ne doit pas être plus contraignante que sa super classe

Ce qui peut rentrer dans la sous classe doit être moins contraignant que ce

qui peut rentrer dans la super classe

Ce qui peut sortir de la sous classe doit être plus contraignant que ce qui

peut sortir de la super classe

Page 45: Qualité logicielle

Mauvais exemple

public class Fish { }public class Duck{

public virtual void Give(Fish food){

Console.WriteLine("Eating the fish");}

public virtual int LegCount { get { return 2; } }}

public class RubberDuck : Duck{

public override void Give(Fish food){

throw new InvalidOperationException("Rubber Duckdoesn't need fishes");

}

public override int LegCount { get { return 0; } }}

Le canard en plastique ne sait pas manger un poisson, il est plus

contraignant sur ce qui rentre

Les canards devrait toujours avoir des pattes

Page 46: Qualité logicielle

Mauvais exemple

Un canard en plastique n’est pas un canard

La modélisation est incorrecte, et viole le principe de Liskov

On ne peut pas supposer un comportement si le principe de Liskov n’est

pas respecté

public class Test{

public void Main(){

var duck = new RubberDuck();var fish = new Fish();this.GiveFood(duck, fish);

}

public void GiveFood(Duck duck, Fish fish){

// we are expecting that is will never fail// unless we violate the Liskov Principleduck.Give(fish);

}}

Page 47: Qualité logicielle

Interface Segregation Principle

Il vaut mieux avoir plusieurs interfaces spécifiques plutôt qu'une seule

grande interface

Page 48: Qualité logicielle

Mauvais exemple

// Big interface, so much workpublic interface ICommunicate{

void Send(object data);object Receive();

}

// Phone is ok, can communicate both wayspublic class Phone : ICommunicate{

public void Send(object data){

Console.WriteLine("Composingnumber...");

}

public object Receive(){

return "Dring!";}

}

public class Printer : ICommunicate{

public void Send(object data){

Console.WriteLine("Printing datas...");}

// Printer has to define the Receive methodpublic object Receive(){

// But printer can't receive anythingthrow new InvalidOperationException("Printer

are not receiving.");}

}

Page 49: Qualité logicielle

Bon exemple

// make it two interfaces instead of onepublic interface ISender { void Send(object data); }public interface IReceiver { void Send(object data); }public class Phone : ISender, IReceiver{

public void Send(object data){

Console.WriteLine("Composing number...");}

public object Receive(){

return "Dring!";}

}

public class Printer : ISender{

public void Send(object data){

Console.WriteLine("Printing datas...");}

}

Page 50: Qualité logicielle

Dependency Inversion Principle

Les modules de haut niveau ne doivent pas dépendre des modules de bas

niveau. Les deux doivent dépendre des abstractions

Page 51: Qualité logicielle

Mauvais exemple

// Low level modulepublic class Logger{

public void Log(string text){

Console.WriteLine(text);}

}

// High level module, depend on low level modulepublic class DatabaseReader{

public Logger Logger { get; set; }public void ReadData(){

this.Logger.Log("Reading datas...");}

}

Page 52: Qualité logicielle

Bon exemple

// Low level modules, depend on abstractionpublic class ConsoleLogger : ILogger{

public void Log(string text){

Console.WriteLine(text);}

}

// Low level modules, depend on abstractionpublic class FileLogger : ILogger{

private readonly string _path;public FileLogger(string path){

this._path = path;}public void Log(string text){

using (var file = newStreamWriter(this._path))

{file.WriteLine(text);

}}

}

// High level module, depend on abstractionpublic class DatabaseReader{

public ILogger Logger { get; set; }public void ReadData(){

this.Logger.Log("Reading datas...");}

}

// Abstractionpublic interface ILogger{

void Log(string text);}

Page 53: Qualité logicielle

Conclusion

Appliquer ces principes ne garantissent pas un code sans faille, mais au

moins un meilleur code

Il faut savoir pondérer ces bonnes pratiques lorsque les délais sont courts et

les résultats pressants

Les définitions des principes sont simples, mais leurs mises en place

complexe sur des problèmes réels

Page 54: Qualité logicielle

4. Initiation à la

programmation fonctionnelle

Page 55: Qualité logicielle

Historique

Programmation procédurale : Fortran, C, Basic…

A base de fonction qui s’appelle les unes les autres

Ensemble d’étape à exécuter pour arriver au résultat

Programmation orientée objet : C++, Java, C#

Définition d’un ensemble d’objet interagissant entre eux

Un objet est définit par ses états (variables) et ses comportements (méthodes)

Grande mode à partir des années 80, adopté en masse par les entreprises dans

les années 90

Page 56: Qualité logicielle

Historique

Aujourd’hui : le marché est toujours dominé par la programmation orienté

objet, et les langages procéduraux gardent une bonne place

Source : http://www.tiobe.com

Page 57: Qualité logicielle

Historique de la programmation

fonctionnelle

Programmation fonctionnelle : Lisp (1958), puis Scheme (1975), Haskell

(1987), ou récemment F# (2002) et LINQ (2007)

N’a jamais réussi à pénétrer le marché malgré son ancienneté

Peu enseigné, peu pratiqué, peu utilisé

Page 58: Qualité logicielle

A quoi ça sert alors ?

Simple à écrire, condensé

Puissant

Pas d’effet de bords par nature

Les principes de la programmation fonctionnelle sont applicables à la

programmation orienté objet

Rend toute fonction parallélisable

Rend possible la mise en cache de manière automatique

Page 59: Qualité logicielle

Paradigmes

Aucun état n’est modifiable, on parle d’Immutabilité

Un objet est instancié une fois, puis ne peux plus jamais être modifié

Les fonctions sont Pures, pas d’effet de bords = aucune modification d’état

Une fonction pure est une fonction qui ne modifie aucun état, et qui retourne

une seule valeur

La valeur retournée est toujours la même pour les mêmes arguments d’entrée.

Contrexemple : Date date = new Date(); // Impur

Page 60: Qualité logicielle

Immutabilité

Sur des objets, l’initialisation passe par le constructeur

public class ImmutablePoint{

private readonly double _x;public double X { get { return _x; } }

private readonly double _y;public double Y { get { return _y; } }

public ImmutablePoint(double x, double y){

this._x = x;this._y = y;

}}

Page 61: Qualité logicielle

Immutabilité

Sur des conteneurs de données, chaque ajout retourne une nouvelle

instance du conteneur

var empty = new ImmutableList<double>();var onlyTwo = empty.Add(2);var twoAndThree = onlyTwo.Add(3);

Page 62: Qualité logicielle

Avantage de l’immutabilité

Les variables ne pourront jamais être modifié par un code tiers

public void EvilCode(List<int> ints){

ints.Clear();}

var primes = new List<int>() { 2, 3, 5, 7};EvilCode(primes);// ergh, primes is empty!

Page 63: Qualité logicielle

La programmation multi thread est simplifiée

Pas de Lock, Mutex, et autres joyeusetés

Les accès aux données sont automatiquement en lecture seule

Avantage de l’immutabilité

Page 64: Qualité logicielle

Exemple : un tas immutable

public interface IStack<T> : IEnumerable<T>{

IStack<T> Push(T value);IStack<T> Pop();T Peek();bool IsEmpty { get; }

}

Page 65: Qualité logicielle

Exemple : un tas immutablepublic sealed class Stack<T> : IStack<T>{

private sealed class EmptyStack : IStack<T>{

public bool IsEmpty { get { return true; } }public T Peek() { throw new Exception("Empty stack"); }public IStack<T> Push(T value) { return new Stack<T>(value, this); }public IStack<T> Pop() { throw new Exception("Empty stack"); }public IEnumerator<T> GetEnumerator() { yield break; }IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }

}private static readonly EmptyStack empty = new EmptyStack();public static IStack<T> Empty { get { return empty; } }private readonly T head;private readonly IStack<T> tail;private Stack(T head, IStack<T> tail){

this.head = head;this.tail = tail;

}public bool IsEmpty { get { return false; } }public T Peek() { return head; }public IStack<T> Pop() { return tail; }public IStack<T> Push(T value) { return new Stack<T>(value, this); }public IEnumerator<T> GetEnumerator(){

for (IStack<T> stack = this; !stack.IsEmpty; stack = stack.Pop())yield return stack.Peek();

}IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }

}

Page 66: Qualité logicielle

Exemple : un tas immutable

IStack<int> s1 = Stack<int>.Empty;IStack<int> s2 = s1.Push(10);IStack<int> s3 = s2.Push(20);IStack<int> s4 = s2.Push(30); // shares its tail with s3.

Source : http://blogs.msdn.com/b/ericlippert/archive/2007/12/04/immutability-in-c-part-two-a-simple-immutable-stack.aspx

Page 67: Qualité logicielle

LINQ : Application au monde réel

LINQ arrive en 2007 avec le Framework .NET 3.5

Ensemble de fonctions inspiré de la programmation fonctionnelle qui agit

sur des types IEnumerable (basiquement, des List)

Page 68: Qualité logicielle

Un peu de LINQ : filtrer les éléments

d’une liste

Avant

public List<int> MutableEvens(List<int> ints){

var evens = new List<int>();foreach (var item in ints){

if (item % 2 == 0){

// mutation of the listevens.Add(item);

}}return evens;

}

Après

public List<int> ImmutableEvens(List<int> ints){

return ints.Where(i => i % 2 == 0).ToList();}

Aucune mutation, sans effet de bords

Page 69: Qualité logicielle

Un peu de LINQ : sélectionner une

propriété

Avant Après

public List<int> MutableGetXs(List<Point> points){

var xs = new List<int>();foreach (var point in points){

xs.Add(point.X);}return xs;

}

public List<int> ImmutableGetXs(List<Point> points){

return points.Select(p => p.X).ToList();}

Page 70: Qualité logicielle

Exercice

Refactoriser le code suivant pour le rendre immutable

public class MyPoint{

public double X { get; set; }public double Y { get; set; }

public static void Translate(List<MyPoint> points, double dx, double dy)

{foreach (var point in points){

point.X += dx;point.Y += dy;

}}

public override bool Equals(object obj){

var point = (MyPoint)obj;return point.X == this.X && point.Y ==

this.Y;}

}

[TestClass]public class MyPointTests{

[TestMethod]public void TestTranslate(){

var points = new List<MyPoint>() { new MyPoint() { X = 1, Y = 2 }, new MyPoint() { X = -1, Y = 0 }

};MyPoint.Translate(points, 1, 2);

var expected = new List<MyPoint>() { new MyPoint() { X = 2, Y = 4 }, new MyPoint() { X = 0, Y = 2 }

};CollectionAssert.AreEqual(expected, points);

}}

Page 71: Qualité logicielle

Correctionpublic class MyPoint{

private readonly double _x;public double X { get { return _x; } }

private readonly double _y;public double Y { get { return _y; } }

public MyPoint(double x, double y){

this._x = x;this._y = y;

}

public static List<MyPoint> Translate(List<MyPoint> points, double dx, double dy)

{return points.Select(p => new MyPoint(p.X + dx,

p.Y + dy)).ToList();}

public override bool Equals(object obj){

var point = (MyPoint)obj;return point.X == this.X && point.Y == this.Y;

}}

[TestClass]public class MyPointTests{

[TestMethod]public void TestTranslate(){

var points = new List<MyPoint>() {

new MyPoint(1, 2), new MyPoint(-1, 0)

};var actual = MyPoint.Translate(points, 1, 2);

var expected = new List<MyPoint>() {

new MyPoint(2, 4), new MyPoint(0, 2)

};

CollectionAssert.AreEqual(expected, actual);}

}

Page 72: Qualité logicielle

Conclusion

Les concepts de pureté et d’immutabilité proviennent de la

programmation fonctionnelle

Concepts puissants qui empêchent beaucoup d’erreurs et d’effet de bords

Demande des ajustements dans la façon de coder, et dans l’approche

des problèmes

Ces concepts sont applicables dans tous les langages, objets ou

procéduraux

Page 73: Qualité logicielle

5. Analyse statiqueL’analyse du code par des systèmes tiers

Page 74: Qualité logicielle

La revue du code

Via des personnes : camarade, collègues, forums

Extreme Programming (XP) pratique le Pair programming : deux paires d'yeux valent mieux qu'une. Se passe pendant l’écriture, couteuse en ressource humaine

Code review : Se passe à postériori de l’écriture, moins couteuse

http://www.developpez.net/forums/; http://stackoverflow.com/; http://codereview.stackexchange.com/

Via des logiciels

ReSharper, NDepend, Coverity, etc.

http://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis

Page 75: Qualité logicielle

Un exemple

Capture d’écran d’un rapport NDepend

Page 76: Qualité logicielle

Purity – Immutability – Side-Effects

Capture d’écran d’un rapport NDepend

Page 77: Qualité logicielle

Les outils d’analyse statique

Analyse du code basé sur un ensemble de règles

Propose des avertissements dans les domaines : convention de nommage,

design, architecture, code mort, etc.

Permet la modification et l’ajout de nouvelles règles

Disponible dans tout les langages, du gratuit au plus cher

Page 78: Qualité logicielle

Programmation par contrat

Permet de définir des pré conditions, des post conditions et des invariants

pour chaque fonction

Provient du langage Eiffel (1986) qui le supporte nativement

Supporté à base de plugin dans Visual Studio (Code Contracts) de

manière statique

Plusieurs implémentations existe dans les autres langages, analyse

dynamique uniquement

Java : Cofoja, SpringContracts

PHP : Praspel

CF http://en.wikipedia.org/wiki/Design_by_contract

Page 79: Qualité logicielle

Vérification statique à base de Warning

Vérification dynamique = lancement d’Exception

Générateur de documentation

Code Contracts

Page 80: Qualité logicielle

Exemple Code Contractspublic class Test{

private object _value2 = "";

public object TestMethod(object value, object value2){

Contract.Requires(value != null); // Static Warning && Runtime Exception en entréeContract.Ensures(Contract.Result<object>() != null); // Static Warning && Runtime Exception en sortie

this._value2 = value2;

return null; // Static Warning}

[ContractInvariantMethod]private void ObjectInvariant(){

Contract.Invariant(this._value2 != null); // Static Warning && Runtime Exception en sortie}

}

static void Main(string[] args){

var test = new Test();test.TestMethod(null, null); // Static Warning

}

Page 81: Qualité logicielle

Qualité logicielle

Conclusion

Avoir en tête les fonctionnalités demandées, c’est bien

Avoir en tête la qualité et les fonctionnalités, c’est mieux

Des efforts aujourd’hui pour des effets demain

La qualité en informatique est comme la qualité en général, un

investissement à long terme

La qualité demande du temps. « Vite fait bien fait » n’existe pas, fast code

= dirty code

Page 82: Qualité logicielle

Bibliographie

Code Complete de Steve McConnell

Refactoring: Improving the Design of Existing Code de Martin Fowler

Learn You a Haskell for Great Good!: A Beginner's Guide de Miran Lipovaca

Clean Code: A Handbook of Agile Software Craftsmanship de Robert C.

Martin