Suivi qualité
    avec Sonar pour PHP




Gabriele Santini
PHPTour Lille - 25/11/2011
WhoAmI
• Gabriele Santini
• Consultant – Architecte Logiciel
• Indépendant -> Zend Technologies


• Sonar pour PHP


                                     Passions professionnelles
                                          - Modélisation métier
                                             - Bonnes pratiques
                                                  - Suivi qualité
(Ex) PlanDuTalk
• Prendre un applicatif de mauvaise qualité
• Le placer sous surveillance Sonar
• Utiliser Sonar comme guide qualité
• Améliorer la qualité de l’applicatif
• Suivre les progrès avec Sonar
PlanDuTalk
• Prendre un applicatif de mauvaise qualité
• Le placer sous surveillance Sonar
• Montrer Sonar
• Préparer l’applicatif pour le refactoring
• Paramétrer Sonar pour le refactoring
• Début du refactoring
• Afficher les amélioration dans Sonar
(Ex) ButsDuTalk
• Introduire Sonar pour PHP
• Parler bonnes pratiques XP
• Montrer des techniques pour le « legacy code »
(Ex) ButsDuTalk
• Introduire Sonar pour PHP
• Parler bonnes pratiques XP
• Montrer des techniques pour le « legacy code »


• … s’amuser avec l’exemple de « revamping »
ButsDuTalk
• Introduire Sonar pour PHP 
• Parler bonnes pratiques XP 
• Montrer des techniques pour le « legacy code » 


• … s’amuser avec l’exemple de « revamping » 
Exemple
• Petit projet (3-6k LOC)
• Vieux code (à la « PHP3/4 »)
 • Recherche Sourceforge de projets s’arretant ~2006
• Intéressant pour moi


• And the winner is…
PHPRiSK !
Démo
OpeningTheBox
class class_mysql{                       // PSR0 ? 
        function class_mysql() {
                  global $CONFIG;
                  $this->host = $CONFIG['mysql']['host'];
                  $this->user = $CONFIG['mysql']['user'];
                  $this->pass = $CONFIG['mysql']['pass'];
                  $this->dbase = $CONFIG['mysql']['dbase'];
                  return true;
        }
        function db_con(){
                  $db = mysql_connect($this->host, $this->user, $this->pass)
                  or die ("verbindung $this->user@$this->host fehlgeschlagen");
DidYouSayDecoupled?
#status 0: Offline
# ...
# status: 10 Running Game


class class_risk{


           function get_soapobject() {
                     global $CONFIG;
                     require_once 'SOAP/Client.php'; // aucun répertoire “SOAP”…


           function soapUpdateNumOnline($numonline) {
                     global $CONFIG;
DidYouSaySRP?
Méthodes de class_risk :
• 7 méthodes contenant« soap »
• 21 méthodes contenant « display »
• ~15 méthodes d’action
• 4 méthodes contenant « By »
• …


• 57 méthodes au total
• 1648 LOC au total
DidYouSaySoC?
function display_win() {
           $cdb = new class_mysql;
           $cdb->select("SELECT CurrentGame FROM risk_config");
           $row = $cdb->fetchArray();
           if ($row['CurrentGame'] != "Complete") {
                        header("Location: index.php");
           }
           $cdb->select("SELECT username, color FROM risk_players WHERE
                     status='10'");
           $row = $cdb->fetchArray();
           $r = "<h2>Game Over</h2><center><br><br><br><font color='".$row['color']."'
           class="wintext">".$row['username']."wins!<br><br><br></font></center>";
           return $r;
}
DidYouSaySecure?
function display_gameManager() {
        global $PHP_SELF, $CONFIG;
[…]
<form method="post" name="msg" action="$PHP_SELF">




Heureusement nous sommes en PHP 5…
DidYouSayNormalizedDB?
CREATE TABLE `risk_players` (
 `num` smallint(5) unsigned NOT NULL auto_increment,
 `username` varchar(16) NOT NULL default '',
 `password` varchar(32) NOT NULL default '',
  ……)
INSERT INTO `risk_players` VALUES
(1, 'Allies', '2e970e822e1a8834203d06abb60f59ec', '', 1, ''
, 0, 0, 0, NULL, NULL, 1, 1, 0, 0, 0, 0, 0, 'notmyturn.php'
, 0, 0);
BoxOpened
Moralité


           Qualité externe

                !=
           Qualité interne
EnterSonar
• Install !
 • 2 minutes coté Sonar (Ok, + téléchargement de Java)
  • http://docs.codehaus.org/display/SONAR/Install+Sonar#InstallS
    onar-The2minutestutorial
  • Localhost:9000
 • 2 minutes coté PHP (à tester)
  > pear config-set auto_discover 1
  > pear install pear.phpqatools.org/phpqatools


 • 30 secs Plugin Sonar pour PHP via l’UI Sonar
  • Update Center => Available Plugins
SonarDontImpliesMaven
• Depuis la 2.6, Java Runner
 • Installation en 2 minutes
    http://docs.codehaus.org/display/SONAR/Analyse+with+a+simple+Java+
    Runner

• Fichier sonar-project.properties
  # required metadata
  sonar.projectKey=my:risk
  sonar.projectName=PHP Risk
  sonar.projectVersion=0.3
  # path to source directories (required)
  sources=source
  # path to test source directories (optional)
  tests=test
  # The value of the property must be the key of the language
  sonar.language=php
  # PHP plugin specific parameters
  sonar.phpUnit.shouldRun=false
  sonar.dynamicAnalysis=false
FirstSonarRun
• Lancer « sonar-runner » à la racine du projet




• Le projet apparait dans l’interface web
FirstVerdict
AutomaticDeployment
FunctionalCasting
FastFunctionalTesting
Au début le calque remplacera les TUA
Dans le cycle TDD!
                        Doit être

                     RAPIDE
Selenium ne convient pas
Les solutions spécifiques à un framework non plus
BehatMink
Behat : Framework BDD (style Cucumber)
Mink : Framework pour les tests de recette
 • Abstraction du navigateur et du driver
 • Drivers disponibles :
 • Goutte (headless HTTP)
 • Sahi, Selenium (navigateur)
 • Zombie (headless javascript!)
GoutteScenario
 Feature: Register
         In order to play the risk game when I want
         As a site visitor
         I need to become a site user


         Scenario: Register as a new user
                     Given I am on "register.php"
                     When I fill in "username" with "blacksun"
                     And I fill in "password" with "password"
                     And I fill in "confirmpassword" with "password"
                     And I fill in "email" with "toto@example.com"
                     And I press "Register"
                     Then I should see "added"
ZombieScenario
 Feature: Register
         In order to play the risk game when I want
         As a site visitor
         I need to become a site user
         @mink:zombie
         Scenario: Register as a new user
                     Given I am on "register.php"
                     When I fill in "username" with "blacksun"
                     And I fill in "password" with "password"
                     And I fill in "confirmpassword" with "password"
                     And I fill in "email" with "toto@example.com"
                     And I press "Register"
                     Then I should see "added"
CodeCoverage
PHP_CodeCoverage dans PHPUnit
Aucune solution prête à l’emploi en TFA
Il est très important pour diriger la couverture

=> Je fais exécuter Behat dans PHPUnit
PHPCodeCoverageASolution



                                          PHPCC init or deserialize
                                          Start cc
     Tests loop


                                          Stop cc
                                          PHPCC serialize




    PHPCC deserialize, merge and report
PHPRiskInitialDemo
DynamicAnalysis
• Retour sur sonar-project.properties
  # required metadata
  sonar.projectKey=my:risk
  sonar.projectName=PHP Risk
  sonar.projectVersion=0.3

  # path to source directories (required)
  sources=source
  # path to test source directories (optional)
  tests=test

  # The value of the property must be the key of the language
  sonar.language=php

  # PHP plugin specific parameters
  sonar.phpUnit.mainTestClass=test/functional/BehatTest.php
  sonar.dynamicAnalysis=true
Adjusting
• Je fixe les EOL dans class_risk.php
• Je sépare le composant xajax dans un répertoire xajax/
• Je mets les contrôleurs de page et les assets dans www/
SonarImprove
SonarDelta
Components&Treeview

 PHPRisk          PHPRisk > [root]
SourcesDetail
• Coverage pour xajaxFunctionsDefinition.php
WhatNowDemo
Un example : les Hotspots
SonarPHPState
Version 0.6 : hier !
• Introduction des profils par défaut
• Prise en compte de toute propriété PHPCS
Version 0.7 : décembre
• Prise en compte de toute règle PHPCS et PHPMD
• Correction d’un problème très gênant sur le nommage
  des fichiers
• Automatisation Import/Export des règles
BarackObamaFeatures
Version 1.0 et +
• Gestion des fichiers « plats »
• Synchronisation avec Eclipse (plugin Eclipse)
• Compatibilité avec d’autres plugins Sonar
• Utilisation automatique avec un service ci-clould
• Nemo pour php
SonarPHPPointers
• Les documents d’installation déjà cités
• Documentation officielle du plugin
 • http://docs.codehaus.org/display/SONAR/PHP+Plugin



• Billets de blog et articles (certains « historiques »)
 •   « Continuous Integration with Sonar » S. Marek php|architect Avril 2011
 •   http://www.phparch.com/magazine/2011-2/april/
 •   http://www.blacksun.fr/2009/12/sonar-for-php-is-on-its-way/
 •   http://akrambenaissi.wordpress.com/2011/02/23/le-plugin-sonar-php
 •   http://criticallog.thornet.net/2010/11/22/sonar-for-php-coming/
PHPRiskState?
Court terme
• Continuer le refactoring
 • (en faire la présentation)
• Publier
• Améliorer l’usabilité
Moyen terme?
• Plus de paramètres (règles, cartes, …)
• Nouvelles mappes
• Plusieurs AI
• Les AI peuvent jouer à distance via REST
Thank you

Suivi qualité avec sonar pour php

  • 1.
    Suivi qualité avec Sonar pour PHP Gabriele Santini PHPTour Lille - 25/11/2011
  • 2.
    WhoAmI • Gabriele Santini •Consultant – Architecte Logiciel • Indépendant -> Zend Technologies • Sonar pour PHP Passions professionnelles - Modélisation métier - Bonnes pratiques - Suivi qualité
  • 3.
    (Ex) PlanDuTalk • Prendreun applicatif de mauvaise qualité • Le placer sous surveillance Sonar • Utiliser Sonar comme guide qualité • Améliorer la qualité de l’applicatif • Suivre les progrès avec Sonar
  • 4.
    PlanDuTalk • Prendre unapplicatif de mauvaise qualité • Le placer sous surveillance Sonar • Montrer Sonar • Préparer l’applicatif pour le refactoring • Paramétrer Sonar pour le refactoring • Début du refactoring • Afficher les amélioration dans Sonar
  • 5.
    (Ex) ButsDuTalk • IntroduireSonar pour PHP • Parler bonnes pratiques XP • Montrer des techniques pour le « legacy code »
  • 6.
    (Ex) ButsDuTalk • IntroduireSonar pour PHP • Parler bonnes pratiques XP • Montrer des techniques pour le « legacy code » • … s’amuser avec l’exemple de « revamping »
  • 7.
    ButsDuTalk • Introduire Sonarpour PHP  • Parler bonnes pratiques XP  • Montrer des techniques pour le « legacy code »  • … s’amuser avec l’exemple de « revamping » 
  • 8.
    Exemple • Petit projet(3-6k LOC) • Vieux code (à la « PHP3/4 ») • Recherche Sourceforge de projets s’arretant ~2006 • Intéressant pour moi • And the winner is…
  • 9.
  • 10.
  • 11.
    OpeningTheBox class class_mysql{ // PSR0 ?  function class_mysql() { global $CONFIG; $this->host = $CONFIG['mysql']['host']; $this->user = $CONFIG['mysql']['user']; $this->pass = $CONFIG['mysql']['pass']; $this->dbase = $CONFIG['mysql']['dbase']; return true; } function db_con(){ $db = mysql_connect($this->host, $this->user, $this->pass) or die ("verbindung $this->user@$this->host fehlgeschlagen");
  • 12.
    DidYouSayDecoupled? #status 0: Offline #... # status: 10 Running Game class class_risk{ function get_soapobject() { global $CONFIG; require_once 'SOAP/Client.php'; // aucun répertoire “SOAP”… function soapUpdateNumOnline($numonline) { global $CONFIG;
  • 13.
    DidYouSaySRP? Méthodes de class_risk: • 7 méthodes contenant« soap » • 21 méthodes contenant « display » • ~15 méthodes d’action • 4 méthodes contenant « By » • … • 57 méthodes au total • 1648 LOC au total
  • 14.
    DidYouSaySoC? function display_win() { $cdb = new class_mysql; $cdb->select("SELECT CurrentGame FROM risk_config"); $row = $cdb->fetchArray(); if ($row['CurrentGame'] != "Complete") { header("Location: index.php"); } $cdb->select("SELECT username, color FROM risk_players WHERE status='10'"); $row = $cdb->fetchArray(); $r = "<h2>Game Over</h2><center><br><br><br><font color='".$row['color']."' class="wintext">".$row['username']."wins!<br><br><br></font></center>"; return $r; }
  • 15.
    DidYouSaySecure? function display_gameManager() { global $PHP_SELF, $CONFIG; […] <form method="post" name="msg" action="$PHP_SELF"> Heureusement nous sommes en PHP 5…
  • 16.
    DidYouSayNormalizedDB? CREATE TABLE `risk_players`( `num` smallint(5) unsigned NOT NULL auto_increment, `username` varchar(16) NOT NULL default '', `password` varchar(32) NOT NULL default '', ……) INSERT INTO `risk_players` VALUES (1, 'Allies', '2e970e822e1a8834203d06abb60f59ec', '', 1, '' , 0, 0, 0, NULL, NULL, 1, 1, 0, 0, 0, 0, 0, 'notmyturn.php' , 0, 0);
  • 17.
  • 18.
    Moralité Qualité externe != Qualité interne
  • 19.
    EnterSonar • Install ! • 2 minutes coté Sonar (Ok, + téléchargement de Java) • http://docs.codehaus.org/display/SONAR/Install+Sonar#InstallS onar-The2minutestutorial • Localhost:9000 • 2 minutes coté PHP (à tester) > pear config-set auto_discover 1 > pear install pear.phpqatools.org/phpqatools • 30 secs Plugin Sonar pour PHP via l’UI Sonar • Update Center => Available Plugins
  • 20.
    SonarDontImpliesMaven • Depuis la2.6, Java Runner • Installation en 2 minutes http://docs.codehaus.org/display/SONAR/Analyse+with+a+simple+Java+ Runner • Fichier sonar-project.properties # required metadata sonar.projectKey=my:risk sonar.projectName=PHP Risk sonar.projectVersion=0.3 # path to source directories (required) sources=source # path to test source directories (optional) tests=test # The value of the property must be the key of the language sonar.language=php # PHP plugin specific parameters sonar.phpUnit.shouldRun=false sonar.dynamicAnalysis=false
  • 21.
    FirstSonarRun • Lancer «sonar-runner » à la racine du projet • Le projet apparait dans l’interface web
  • 22.
  • 23.
  • 24.
  • 25.
    FastFunctionalTesting Au début lecalque remplacera les TUA Dans le cycle TDD! Doit être RAPIDE Selenium ne convient pas Les solutions spécifiques à un framework non plus
  • 26.
    BehatMink Behat : FrameworkBDD (style Cucumber) Mink : Framework pour les tests de recette • Abstraction du navigateur et du driver • Drivers disponibles : • Goutte (headless HTTP) • Sahi, Selenium (navigateur) • Zombie (headless javascript!)
  • 27.
    GoutteScenario Feature: Register In order to play the risk game when I want As a site visitor I need to become a site user Scenario: Register as a new user Given I am on "register.php" When I fill in "username" with "blacksun" And I fill in "password" with "password" And I fill in "confirmpassword" with "password" And I fill in "email" with "toto@example.com" And I press "Register" Then I should see "added"
  • 28.
    ZombieScenario Feature: Register In order to play the risk game when I want As a site visitor I need to become a site user @mink:zombie Scenario: Register as a new user Given I am on "register.php" When I fill in "username" with "blacksun" And I fill in "password" with "password" And I fill in "confirmpassword" with "password" And I fill in "email" with "toto@example.com" And I press "Register" Then I should see "added"
  • 29.
    CodeCoverage PHP_CodeCoverage dans PHPUnit Aucunesolution prête à l’emploi en TFA Il est très important pour diriger la couverture => Je fais exécuter Behat dans PHPUnit
  • 30.
    PHPCodeCoverageASolution PHPCC init or deserialize Start cc Tests loop Stop cc PHPCC serialize PHPCC deserialize, merge and report
  • 31.
  • 32.
    DynamicAnalysis • Retour sursonar-project.properties # required metadata sonar.projectKey=my:risk sonar.projectName=PHP Risk sonar.projectVersion=0.3 # path to source directories (required) sources=source # path to test source directories (optional) tests=test # The value of the property must be the key of the language sonar.language=php # PHP plugin specific parameters sonar.phpUnit.mainTestClass=test/functional/BehatTest.php sonar.dynamicAnalysis=true
  • 33.
    Adjusting • Je fixeles EOL dans class_risk.php • Je sépare le composant xajax dans un répertoire xajax/ • Je mets les contrôleurs de page et les assets dans www/
  • 34.
  • 35.
  • 36.
  • 37.
    SourcesDetail • Coverage pourxajaxFunctionsDefinition.php
  • 38.
  • 39.
    SonarPHPState Version 0.6 :hier ! • Introduction des profils par défaut • Prise en compte de toute propriété PHPCS Version 0.7 : décembre • Prise en compte de toute règle PHPCS et PHPMD • Correction d’un problème très gênant sur le nommage des fichiers • Automatisation Import/Export des règles
  • 40.
    BarackObamaFeatures Version 1.0 et+ • Gestion des fichiers « plats » • Synchronisation avec Eclipse (plugin Eclipse) • Compatibilité avec d’autres plugins Sonar • Utilisation automatique avec un service ci-clould • Nemo pour php
  • 41.
    SonarPHPPointers • Les documentsd’installation déjà cités • Documentation officielle du plugin • http://docs.codehaus.org/display/SONAR/PHP+Plugin • Billets de blog et articles (certains « historiques ») • « Continuous Integration with Sonar » S. Marek php|architect Avril 2011 • http://www.phparch.com/magazine/2011-2/april/ • http://www.blacksun.fr/2009/12/sonar-for-php-is-on-its-way/ • http://akrambenaissi.wordpress.com/2011/02/23/le-plugin-sonar-php • http://criticallog.thornet.net/2010/11/22/sonar-for-php-coming/
  • 42.
    PHPRiskState? Court terme • Continuerle refactoring • (en faire la présentation) • Publier • Améliorer l’usabilité Moyen terme? • Plus de paramètres (règles, cartes, …) • Nouvelles mappes • Plusieurs AI • Les AI peuvent jouer à distance via REST
  • 43.