update: ajout et rangement des tests unitaire et fonctionnels GHERKIN, amélioration et rangement des commandes, ajout d'une documentation dans les docs, ajout du dossier build, ajout de l'api de génération de doc pdfs

This commit is contained in:
Emmanuel ROY 2021-04-19 16:23:22 +02:00
parent c238bfdcb3
commit a09f93cddc
147 changed files with 43144 additions and 21 deletions

View file

@ -243,4 +243,18 @@ class Url
}
return $url . BASE_SERVER_DIRECTORY;
}
/**
* Obtiens le fragment depuis une variable serveur,
* ce qui est selon moi possible avec une bonne configuration serveur
* sauf si le fragment est bloqué au niveau du navigateur (rétention d'informations)
*
* Selon QASTACK
* => https://qastack.fr/programming/2317508/get-fragment-value-after-hash-from-a-url-in-php
* ce n'est pas possible avec HTTP "standard" car cette valeur n'est jamais envoyée au serveur
* (par conséquent, elle ne sera pas disponible dans $_SERVER["REQUEST_URI"]ou similaire variables prédéfinies)
*/
public static function getFragment(){
$fragment = parse_url($_SERVER['REQUEST_URI'],PHP_URL_FRAGMENT);
return $fragment;
}
}

Binary file not shown.

BIN
build/bin/phpcpd-6.0.3.phar Normal file

Binary file not shown.

20310
build/bin/phpdcd-1.0.2.phar Normal file

File diff suppressed because it is too large Load diff

BIN
build/bin/phploc-7.0.2.phar Normal file

Binary file not shown.

BIN
build/bin/phpmd.phar Normal file

Binary file not shown.

8
build/composer.json Normal file
View file

@ -0,0 +1,8 @@
{
"config": {
"bin-dir": "bin/"
},
"require": {
"pdepend/pdepend": "^2.9"
}
}

46
command_usefull Normal file
View file

@ -0,0 +1,46 @@
# PHP METRICS
#composer global require 'phpmetrics/phpmetrics'
phpmetrics --report-html=./data/phpmetrics ./ --exclude="vendor","build","tests","data","console/skel","application/modules","application/include/vues/cache"
# PHP DOCUMENTOR
php ./build/bin/phpDocumentor.phar -d ./application -d ./console/ -d ./domain --ignore "vendor/*,build/*,data/*,tests/*,console/skel/*,application/modules/*,application/inculde/vues/cache/*" -t ./data/api-docs/
# PHP MESS DETECTOR
php ./build/bin/phpmd.phar ./ html codesize,design,naming,unusedcode --exclude '*vendor*' --exclude '*tests*' --exclude '*build*' --exclude '*data*' --exclude '*skel*' --exclude '*modules*' --exclude '*cache*' > data/phpmd.html
# CHARTS OF PROJECTS
./build/bin/pdepend --jdepend-chart=data/jdepend-chart.svg --overview-pyramid=data/jdepend-overview.svg --summary-xml=data/jdepend-summary.xml --ignore=vendor,tests,build,data,console/skel,application/modules,application/inculde/vues/cache ./
# TEXT METRIC OF PROJECT
php ./build/bin/phploc-7.0.2.phar ./ --exclude ./vendor --exclude ./build --exclude ./tests --exclude ./data --exclude ./console/skel --exclude ./application/modules --exclude ./application/include/vues/cache > data/phploc.txt
# DUPLICATED LINES OF PROJECT
php ./build/bin/phpcpd-6.0.3.phar --exclude ./vendor --exclude ./build --exclude ./build --exclude ./data --exclude ./console/skel --exclude ./application/modules --exclude ./application/include/vues/cache ./ > data/phpcpd.txt
# DEAD CODE DETECTOR
php ./build/bin/phpdcd-1.0.2.phar --exclude="./vendor" --exclude="./build" --exclude="./build" --exclude="./data" --exclude="./console/skel" --exclude="./application/modules" --exclude="./application/include/vues/cache" --recursive ./ > data/phpdcd.txt
# BEHAT Behavior Driven Developpement Initialisation
#cd tests/behat
#./bin/behat --init
# PHPUNIT Testing
./tests/phpunit/bin/phpunit ./test/phpunit/tests/Tests.php
# GENERATION OF DOCUMENTATION BOOK
php ./data/book sand print
# OBFUSCATION DU CODE (not working at all)
#git clone https://github.com/pk-fr/yakpro-po.git
#cd yakpro-po
#git clone https://github.com/nikic/PHP-Parser.git
#chmod a+x yakpro-po.php
php ./yakpro-po/yakpro-po.php --no-shuffle-statements --no-obfuscate-namespace-name --no-obfuscate-class-name --no-obfuscate-method-name --no-obfuscate-property-name --no-obfuscate-constant-name --no-obfuscate-string-literal --no-strip-indentation './MyAwesomeProjectDirectory' -o './MyAwesomeObfuscatedProjectDirectory'

View file

@ -20,7 +20,29 @@ if (isset($argv[1])) {
\MVC\Classe\Logger::logCommandErrors($errors);
}
} else {
print "Command not found !\n";
$command_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . "command" . DIRECTORY_SEPARATOR . "app" . DIRECTORY_SEPARATOR. ucfirst($option[0]) . ".php";
if (is_file($command_file)) {
$class = "\MVC\Command\\App\\" . ucfirst($option[0]);
$static_method = $option[1];
$errors = $class::$static_method();
if ($errors !== null) {
\MVC\Classe\Logger::logCommandErrors($errors);
}
}else {
$command_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . "command" . DIRECTORY_SEPARATOR . "sand" . DIRECTORY_SEPARATOR. ucfirst($option[0]) . ".php";
if (is_file($command_file)) {
$class = "\MVC\Command\\Sand\\" . ucfirst($option[0]);
$static_method = $option[1];
$errors = $class::$static_method();
if ($errors !== null) {
\MVC\Classe\Logger::logCommandErrors($errors);
}
}else {
print "Command not found !\n";
}
}
}
} else {
print "No command was specified !\n";

View file

@ -0,0 +1,38 @@
<?php
namespace MVC\Command\App;
/**
* Class Log
* Commande Console permettant de manipuler les logs de la base de donnée
* @package MVC\Command\GPeX
*/
class Log
{
/**
* Méthode permettant d'afficher l'aide de la commande
*/
public static function help()
{
print "help ?";
}
/**
* Méthode permettant de nettoyer les logs dont la date est iinférieur à aujourd'hui moins $nbMonth mois
*
* @param int $nbMonth
*/
public static function clearOlderThan($nbMonth = 1)
{
$ajh = new \DateTime('now');
$olderThan = $ajh->modify('-1 month');
$olderThan = $olderThan->format('Y-m-d');
//connection à la base de données
/*$bdd = new \MVC\Classe\Bdd('bdd1');
$sql = "DELETE FROM logs WHERE date_creation < {$olderThan};";
$bdd->faireSQLRequete($sql);*/
print "Log older than $nbMonth month cleared ! \n\n";
}
}

View file

@ -1,10 +1,10 @@
<?php
namespace MVC\Command;
namespace MVC\Command\Sand;
/**
* Class Action
* Commande Système du Framework permettant de gérer les actions
* @package MVC\Command
* @package MVC\Command\Sand
*/
class Action
{

View file

@ -1,10 +1,10 @@
<?php
namespace MVC\Command;
namespace MVC\Command\Sand;
/**
* Class Cache
* Commande Système du Framework permettant de gérer le cache
* @package MVC\Command
* @package MVC\Command\Sand
*/
class Cache
{

View file

@ -1,10 +1,10 @@
<?php
namespace MVC\Command;
namespace MVC\Command\Sand;
/**
* Class Conduit
* Commande Système du Framework permettant de gérer les conduits
* @package MVC\Command
* @package MVC\Command\Sand
*/
class Conduit
{

View file

@ -1,10 +1,10 @@
<?php
namespace MVC\Command;
namespace MVC\Command\Sand;
/**
* Class Module
* Commande Système du Framework permettant de gérer les modules
* @package MVC\Command
* @package MVC\Command\Sand
*/
class Module
{

View file

@ -1,10 +1,10 @@
<?php
namespace MVC\Command;
namespace MVC\Command\Sand;
/**
* Class Page
* Commande Système du Framework permettant de gérer les pages
* @package MVC\Command
* @package MVC\Command\Sand
*/
class Page
{
@ -48,14 +48,14 @@ class Page
$shell_controlleur = shell_exec('cp ' . CONSOLE_PATH . '/skel/page.php ' . CONTROLLERS_PATH . '/' . $page . '.php');
$controlleur = file_get_contents(CONTROLLERS_PATH . '/' . $page . '.php');
$controlleur = preg_replace('%%PAGE%%', $page, $controlleur);
$controlleur = preg_replace('/%%PAGE%%/', $page, $controlleur);
file_put_contents(CONTROLLERS_PATH . '/' . $page . '.php', $controlleur);
print $shell_controlleur;
$shell_modele = shell_exec('cp ' . CONSOLE_PATH . '/skel/page.model ' . MODELS_PATH . '/' . $page . '.model');
$modele = file_get_contents(MODELS_PATH . '/' . $page . '.model');
$modele = preg_replace('%%PAGE%%', $page, $modele);
$modele = preg_replace('%%ENGINE%%', $template, $modele);
$modele = preg_replace('/%%PAGE%%/', $page, $modele);
$modele = preg_replace('/%%ENGINE%%/', $template, $modele);
file_put_contents(MODELS_PATH . '/' . $page . '.model', $modele);
print $shell_modele;
@ -66,12 +66,12 @@ class Page
$shell_view = shell_exec('cp ' . CONSOLE_PATH . '/skel/page-vuejs.blade.php ' . VIEW_PATH . '/view/' . $page . '.blade.php');
}
$view = file_get_contents(VIEW_PATH . '/view/' . $page . '.blade.php');
$view = preg_replace('%%PAGE%%', $page, $view);
$view = preg_replace('/%%PAGE%%/', $page, $view);
file_put_contents(VIEW_PATH.'/view/'.$page.'.blade.php', $view);
}else{
$shell_view = shell_exec('cp ' . CONSOLE_PATH . '/skel/page.html.twig ' . VIEW_PATH . '/view/' . $page . '.html.twig');
$view = file_get_contents(VIEW_PATH . '/view/' . $page . '.html.twig');
$view = preg_replace('%%PAGE%%', $page, $view);
$view = preg_replace('/%%PAGE%%/', $page, $view);
file_put_contents(VIEW_PATH.'/view/'.$page.'.html.twig', $view);
}

View file

@ -1,10 +1,10 @@
<?php
namespace MVC\Command;
namespace MVC\Command\Sand;
/**
* Class Symfony
* Commande Système du Framework permettant de gèrer les modules Symfony
* @package MVC\Command
* @package MVC\Command\Sand
*/
class Symfony
{

View file

@ -0,0 +1,15 @@
.tm_properties
.idea
.DS_Store
._*
.Spotlight-V100
.Trashes
/vendor
vendor
vendor/
vendor*
composer.phar
composer.lock
Output
*/Output
build.sh

View file

@ -0,0 +1,22 @@
Copyright (c) 2013 Jean-François Lépine <http://blog.lepine.pro>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,31 @@
# Livre sur le Développement piloté par le comportement
![](https://repository-images.githubusercontent.com/13304945/f5f26600-1e9b-11eb-84e7-fbbf90790e49)
## Télécharger les ebooks
+ 📗 **Tome 1 : à destination des personnes "métier"** ([pdf](https://github.com/Halleck45/livre-developpement-pilote-comportement/releases/download/1.0.0/developpement-pilote-par-le-comportement-tome1.pdf) | [epub](https://github.com/Halleck45/livre-developpement-pilote-comportement/releases/download/1.0.0/developpement-pilote-par-le-comportement-tome1.epub))
+ 📙 **Tome 2 : pour les développeurs** ([pdf](https://github.com/Halleck45/livre-developpement-pilote-comportement/releases/download/1.0.0/developpement-pilote-par-le-comportement-tome2.pdf) | [epub](https://github.com/Halleck45/livre-developpement-pilote-comportement/releases/download/1.0.0/developpement-pilote-par-le-comportement-tome2.epub))
## Générer les livres locallement
```./book --dir=doc publish <tome> <edition>```
Par exemple:
```./book --dir=doc publish tome1 print```
## Copyright
Ce livre est publié avec EasyBook.
Copyright (c) 2013 Jean-François Lépine. See LICENSE for details.
[![Licence Creative Commons](http://i.creativecommons.org/l/by-nc-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-nc-sa/3.0/deed.fr)
<span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">Le Développement piloté par le comportement</span> de [Jean-François Lépine](http://communiquez.lepine.pro) est mis à disposition selon les termes de la [licence Creative Commons Attribution - Pas dUtilisation Commerciale - Partage dans les Mêmes Conditions 3.0 non transposé](http://creativecommons.org/licenses/by-nc-sa/3.0/deed.fr).
Fondé(e) sur une œuvre à [https://github.com/Halleck45/livre-developpement-pilote-comportement](https://github.com/Halleck45/livre-developpement-pilote-comportement).
## Contributeur
+ Auteur: Jean-François Lépine (Halleck45, http://blog.lepine.pro)

View file

@ -0,0 +1,34 @@
#!/usr/bin/env php
<?php
/*
* This file is part of the easybook application.
*
* (c) Javier Eguiluz <javier.eguiluz@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (!file_exists(__DIR__.'/vendor/autoload.php')) {
throw new \RuntimeException(
"\n"
."[ERROR] easybook depends on some external libraries and components.\n"
."It seems that those dependencies aren't properly installed.\n\n"
."Perhaps you forgot to execute 'php composer.phar install' before\n"
."using easybook for the first time?\n\n"
."This command requires that you have previously installed Composer.\n"
."To do so, execute the following command:\n\n"
." $ curl -s http://getcomposer.org/installer | php"
."\n\n"
);
}
require __DIR__.'/vendor/autoload.php';
use Easybook\DependencyInjection\Application;
use Easybook\Console\ConsoleApplication;
$app = new Application();
$console = new ConsoleApplication($app);
$console->run();

View file

@ -0,0 +1,25 @@
{
"name": "halleck45/livre-bdd",
"version": "1.0.0",
"repositories": {
"geshi": {
"type": "package",
"package": {
"name": "geshi/geshi",
"version": "1.0.8.10",
"dist": {
"url": "http://sourceforge.net/projects/geshi/files/geshi/GeSHi%201.0.8.10/GeSHi-1.0.8.10.zip/download",
"type": "zip"
}
}
}
},
"require": {
"easybook/easybook": "dev-master"
},
"minimum-stability":"dev"
}

View file

@ -0,0 +1,16 @@
#Les étapes de configurations de SAND
il vous faut modifier quelques valeurs dans les fichiers de configuration suivant
- `application/config/app-parameters.php.skel`
- `application/config/bdd-parameters.php.skel`
et enlever l'extension `.skel` afin que l'autoload de composer puisse le prendre en compte
Vous pouvez tester une application de base simple en générant le dossier vendor en vous mettant à la racine de l'application et en lançant
`composer update`. Si votre serveur est correctement configurer pour pointer dans le dossier public sur l'index, vous devriez obtenir une application de test avec les fonctionnalités de base. En triturant un peu les fichier contenus dans le dossier `application/include` vous devriez comprendre comment se contruit une application faites avec SAND.
Les autres fichiers contenus dans config servent pour la branche dev, mais peuvent aussi servir pour votre application.
Dans le cas où vous choissisez d'utiliser les conduits lors du développement de votre application,
vous devrez modifier le fichier `application/config/files/routing.yml`.

View file

@ -0,0 +1,17 @@
#Comment bien utiliser les urls dans le framework SAND
Les urls d'accès basiques sont du type :
`www.domain.tld/{page}/{varname1}/{varvalue1}/{varname2}/{varvalue2}/` ...
Les variables sont automatiquement transmises au contrôleur et à la vue par le moteur MVC du framework
où {page} est le nom :
- Du contrôleur contenu dans `/application/include/controlleurs/{page}.php`
- Du modèle contenu dans `/application/include/modeles/{page}.model`
- De la vue contenue dans `/application/include/vues/view/{page}.blade.php` ou `/application/include/vues/view/{page}.html.twig` suivant le moteur de rendu
Vous pouvez ainsi récupérer les variables passées en GET dans le contrôlleur depuis `$url_params['varname1']`
Dautres types durls peuvent être mises en place par la configuration du routing symfony et des conduits, il faut alors renseigner les informations de routage dans le fichier `/application/config/files/routing.yml` et faire correspondre lurl daccès au Conduit.

View file

@ -0,0 +1,18 @@
#Comment bien utiliser les commandes dans le framework SAND
Les commandes console du framework sont toutes documentée par l'appel de la méthode help
Par exemple pour voir les méthodes associés à la commande page vous pourvez lancer la commande suivante depuis le dossier console:
`php bin.php page:help`
et vous verrez les différentes méthodes qui y sont associées.
Typiquement sur un projet on peut soit ajouter les fichiers manuellement quand on a l'habitude, soit aussi profiter des commandes:
`action`,`conduit`,`module` et `page`
Si vous avez a videz le cache des vues et des logs vous pouvez utiliser la commande
`php bin.php cache:clear`
quand a
`php bin.php cache:stabilize`
vous permet de vider le cache des vues blade et/ou twig

View file

@ -0,0 +1,41 @@
#Comment est architecturé le framework SAND
Ce framework est nommé SAND pour l'acronyme récursif (Simplement [AND et] un Autre Nouveau Dossier),
La racine contient les dossiers suivant :
- `application` : dossier contenant différents fichiers, propre à lapplication et au framework dont on détaillera le contenu plus bas.
- `console` : dossier contenant les commandes console propres au framework et à lapplication
- `data` : dossier contenant des données qui sont chargé par lapplications ou le framework
- `docs` : dossier contenant la documentation de lapplication
- `domain` : dossier contenant les classes propres à la manipulation du domaine visé par lapplication, ces classes peuvent être testées unitairement par PHPUnit
- `output` : dossier contenant les sorties des commandes console de lapplications, ce peut être des logs ou des fichiers de traitement
- `public` : dossier contenant la racine publique de lapplication, le serveur apache doit pointer sur ce dossier pour que le reste ne soit pas accessible, il contient tous les assets (css, js) de lapplication ainsi que le fichier index.php et .htaccess redirigant toutes les requêtes vers lindex.
- `tests` : dossier contenant les fichiers de tests unitaire ou fonctionnels
- `vendor` : dossier créé par composer lors de la récupération des paquets nécessaire à lapplication, contient aussi lautoloader de lapplication généré à la volée par composer
Le dossier `application` contient les dossiers suivants:
- `class` : dossier contenant les fichiers propres au framework. Ne doit pas être modifié.
- `config` : dossier contenant les fichiers de configuration, normalement lors de la récupération du dépôt, les fichiers sont a renommer et a ancrer avec les bonnes valeurs
- `include` : dossier de développement contient :
- `actions` : dossier contenant les actions réutilisables dans les vues de lapplication
- `conduits` : dossier contenant le contrôleur qui est conduit par le routage symfony, ici utilisé exclusivement pour générer des réponses AJAX
- `controlleurs` : dossier contenant les contrôleurs de lapplications, nous verrons plus tard le modèles MVC propre au framework, mais il faut savoir que les controlleurs contiennent les accès en bdd de la page correspondant à son nom
- `modeles` :dossier contenant les modèles de lapplication, il faut savoir que les modèles ont lextension .model et contiennent les variable propres à la page, comme le title, la description ou plus récemment le fil dariane
- `vues` : dossier contenant les fichiers blade ou twig utilisé dans les pages, les actions et les conduits dont voici le détail :
- `cache` : dossier contenant les fichiers de cache généré par le moteur de rendu
- `layout` : dossier contenant les layout des pages
- `system` : dossier contenant le layout systeme
- `view` : dossier contenant toutes les vues de lapplication, une convention de nommage peut être établie suivant le domaine de lapplication, par exemple, toutes les vues des actions doivent commencer par action et toutes les vues des conduits doivent commencer par le nom du conduit duquel ils sont appelés
- `logs` : dossier contenant les logs générer par lapplication, une classe dédiée aux logs est contenue dans le framework
- `modules` : dossier contenant les modules de lapplication, il faut savoir que le framework peut contenir des applications modulaires, genre des applications symfony, wordpress, etc… toutes applications externe php peut avec un peu de doigté peut être intégré à une application, typiquement on peut intégrer un module de dépôt git genre gitlist à lapplication que lon est en train de développer.
- `objets` : dossier contenant les objets de session du framework, ce dossier peut être modifié par lutilisateur, il contient des classes qui sont utilisé dans le cadre de la gestion de session, par exemple lauthentification CAS
- `traitements` : dossier contenant les traitements de formulaire selon le respect du pattern PRG (Post Redirect Get)
Le dossier `console` contient les dossiers suivants:
- `command` : dossier contenant les commandes console du framework et de lapplication
- `skel` : dossier contenant les squelettes utilisés lors des appels console, par exemple pour créer un nouvelle page vous pouvez utiliser la commande :
php bin.php page:add

View file

@ -0,0 +1,20 @@
#Comment modifier proprement une page contenu dans le framework SAND
Tout dabord il vous faut reconnaitre le nom de la page suivant le routage pour aller chercher les bons fichiers à modifier dans le dossier `include`.
Par exemple : pour la page `index`, les bon fichiers à modifier sont :
- `application/include/controlleurs/index.php`
- `application/include/modeles/index.model`
- `application/include/vues/view/index.blade.php` ou `application/include/vues/view/index.html.twig`
Si vous désirez modifier le comportement dune page il vous faudra très certainement modifier le contrôleur et la vue associée, voire peut-être laction et sa vue si la vue mère fait des appels de ce type.
Les actions se trouve dans le dossier `application/include/actions/` et leurs vues sont dans le même dossiers que les vues mères : `application/include/vues/view/`, il convient de la préfixer par `action-actionnamedescription`.
Le `.model` de la page contient une variable engine qui peut prendre les valeurs `blade` ou `twig`. Par défaut si ce paramètre de modèle nest pas renseigné cest le moteur de rendu `blade` qui sera appelé.
Si vous désirez juste modifier laffichage, il vous suffira simplement de modifier la vue `blade` ou `twig` suivant le moteur de rendu.
Cependant si vous désirez modifier le `head` ou le `layout` de la page vous devrez modifier les fichiers dans `application/include/vues/system/` ou `application/include/vues/layout/`

View file

@ -0,0 +1,14 @@
# Comment fonctionnent les objets de sessions
le dossier `application/objets` contient les classes qui sont utilisés par les sessions, vous trouverez dans ce dossier les classes suivantes:
- `Session.php` qui contient les méthodes permettant de créer les sessions, dans une application moderne il est courant de définir des droits sur les pages par un système d'authentification, ici SAND ne déroge pas à la règle et dans les fichiers .model possèdent une variable `authentification` qui peut prendre les valeurs `yes` ou `no`, ainsi le framework appelera automatiquement la méthode `createAndTestSession()` dans les controlleurs, si cette variable est défini à `no`, alors seule la méthode `sessionStart()` sera appelée, ceci afin que les alertes et l'historique puissent fonctionner.
Malheureusement les conduits et les traitements ne disposent pas d'un tel garde d'authentification, mais vous comprendrez qu'il est simple d'ajouter cette méthode au début d'un code de traitement ou de conduit.
- `Alert.php` contient quelques méthodes simples qui utilise la variable `$_SESSION`, elle est vidée a chaque génération de page sauf dans le cas des traitements, ainsi automatiquement une alerte peut être définie à afficher sur la page de redirection
- `History.php` permet d'obtenir à tout moment la page précédente de l'application, ainsi il est plus simple de rediriger les pages de traitement vers la page qui demande le traitement. Souvent dans les applications modernes vous avez un traitement qui doit être effectué depuis plusieurs pages cela permet de connaitre celle dont on provient sans passer par la variable serveur `$_SERVER["HTTP_REFERER"]` qui n'est pas toujours accessible.
- `XssToken.php` permet de définir un token dans la variable `$_SESSION` afin de protéger les formulaires de l'application contre la faille XSS.
Néanmoins il est possible que ce dossier contienne d'autres classes qui peuvent être utile, à vous de le fournir suivant les demandes de votre application.

View file

@ -0,0 +1,7 @@
#Comment faire évoluer une application écrite avec le framework SAND ?
Tout dabord, une fois lapplication créé, toutes les ressources sont téléchargée par composer et le fichier composer.lock est garant de la stabilité des dépôts auxquels lapplication fait appel. Donc normalement il ne sera pas nécessaire de faire évoluer ces ressources.
Néanmoins passer vers une nouvelle version de php par exemple de la 5.6 à la 8 nécessite des connaissances évolué des fonctions dépréciées entre les versions de PHP. SAND framework est php 8 ready, néanmoins certaines lib ne fonctionne que sur php7.3, mais celles-ci une fois installée ne changeront pas au cours du temps car elles sont directement accessibles depuis le dossier vendor.
Si vous utilisez les SPA vues.js, pensez à télécharger la version que vous utilisez afin de stabiliser votre application dans le temps, afin qu'elle ne consomme pas des ressources inutiles depuis le web.

View file

@ -0,0 +1,22 @@
#Le contrôleur de base le plus simple possible
il vous faut instancier deux fichiers sous cette forme:
* application/include/modeles/name.model
```
name : name
page_title : Page de l'application
description : Description de la page
params1 : {val1,val2}
params2 : val
```
il faut absolument renseigner le name avec le nom générique de la page, page_title permet de modifier le contenu de la balise html title et description permet de modifier le contenu de la balise meta description. Enfin les parametres suivant sont optionnels et permet de passer des valeur dans le controlleur ou dans la vue.
* application/include/controlleurs/name.php
```php
<?php
echo <<<EOD
Ce que vous voulez afficher en HTML
EOD;
```
par exemple les fichiers simple au niveau textuel du genre les CGU ou la Politique de confidentialité

View file

@ -0,0 +1,68 @@
#Le contrôleur de base
il vous faut instancier trois fichiers sous cette forme:
* application/include/modeles/name.model
```
name : name
page_title : Page de l'application
description : Description de la page
engine : blade
authentification : no
ariane : {acceuil, name}
arianelink : {index, name}
params1 : {val1,val2}
params2 : val
```
il faut absolument renseigner le `name` avec le nom générique de la page en minuscule, SAND n'est pas sensible à la casse sur le nom de la page. Désolé vous ne pourrez pas jouer avec la casse des caractères pendant le developpement des nouvelles pages.
- `page_title` permet de modifier le contenu de la balise html title,
- `description` permet de modifier le contenu de la balise meta description.
- `engine` est optionnel, sa valeur par défaut est 'blade', cette variable permet de charger un uatre moteur de rendu. Si vous êtes plus a l'aise avec Twig pas de problèmes, cependant vous ne pourrez pâs charger un module Symfony aussi facilement...
- Enfin les parametres suivants `params1`,`params2` sont optionnels et permettent de passer des valeurs dans le controlleur ou dans la vue.
* application/include/controlleurs/name.php
```php
<?php
use MVC\Classe\Logger;
$templateData = array(
"templating_a"=>'blade',
"templating_b"=>'twig',
"templating_c"=>'edge'
);
//recuperation des paramètres contenus dans le .model
$var[] = $params2;
foreach( $params1 as $key => $value ){
$var[] = $value;
}
Logger::addLog('ok', 'Hello world');
```
tout en sachant que la variable `$templateData` est envoyé à la vue Blade
* application/include/vues/view/name.blade.php
```php
@extends('body')
@section('sidebar')
@parent
<p>This is appended to the master sidebar.</p>
@endsection
@section('content')
<a href="{{ \MVC\Classe\Url::link_rewrite(false, 'accueil', []) }}">Revenir a l'acceuil ?</a>
<hr/>
{{$templating_a}}::{{$templating_b}}::{{$templating_c}}
{{-- récupération des paramètres contenus dans le model --}}
{{$params2}}
@foreach ($param1 as $key => $value)
{{$key}} -> {{$value}}
@endforeach
@endsection
```
par exemple...
---
Pour les instancier facilement vous pouvez utiliser la commande:
`php console/bin.php page:add`

View file

@ -0,0 +1,92 @@
#Le contrôleur de REST / HTML
>Ici le modèle (.model) n'est pas instancié, cela ressemble à symfony.
Étendre avec RESTResponse permet d'ajouter les methode get, put, post, delete
Étendre avec HttpResponse permet de n'avoir que les méthode Http qui sont utilisées
normalement avec tout php.
>Donc vous pouvez tout a fait écrire une application avec HttpResponse car l'on peut appeler des vues blade par la méthode render().
C'est un choix applicatif qu'il faut faire au moment de la contruction de l'application.
Vous devez instancier le fichier `application/include/controlleurs/{Name}HttpReponse.php`
qui est une classe peut implémenter `MVC\Classe\Implement\RestReponse` ou `MVC\Classe\Implement\HttpReponse` sachant que la différence se situe au niveau des méthodes qu'il doit instancier.
##Voici un exemple avec `RestResponse`
```php
<?php
use MVC\Classe\Dumper;
use MVC\Classe\Implement\RestReponse;
use MVC\Classe\Logger;
class NameHttpReponse extends RestReponse
{
public function put()
{
ob_start();
Dumper::dump($this->params);
Dumper::dump($this->data);
$text = ob_get_clean();
Logger::addLog('put', '____Hello Put____' . PHP_EOL . $text);
}
public function delete()
{
ob_start();
Dumper::dump($this->params);
Dumper::dump($this->data);
$text = ob_get_clean();
Logger::addLog('delete', '____Hello Delete:____' . PHP_EOL . $text);
}
public function get()
{
ob_start();
Dumper::dump($this->params);
Dumper::dump($this->data);
$text = ob_get_clean();
Logger::addLog('get', '____Hello GET____' . PHP_EOL . $text);
}
public function post()
{
ob_start();
Dumper::dump($this->params);
Dumper::dump($this->data);
$text = ob_get_clean();
Logger::addLog('post', '____Hello POST____' . PHP_EOL . $text);
}
}
```
##voici un exemple avec `HttpResponse`
```php
<?php
use MVC\Classe\Dumper;
use MVC\Classe\Implement\HttpReponse;
use MVC\Classe\Logger;
class NameHttpReponse extends HttpReponse
{
public function get()
{
ob_start();
Dumper::dump($this->params);
Dumper::dump($this->data);
$text = ob_get_clean();
Logger::addLog('get', '____Hello GET____' . PHP_EOL . $text);
return $this->render('name', array('var' => $text));
}
public function post()
{
ob_start();
Dumper::dump($this->params);
Dumper::dump($this->data);
$text = ob_get_clean();
Logger::addLog('post', '____Hello POST____' . PHP_EOL . $text);
return $this->render('name', array('var' => $text));
}
}
```
l'accès se fait par l'url `http://monapp.local/{name}`

View file

@ -0,0 +1,65 @@
#Les vues Twig
Elles sont chargées dans cette ordre:
* application/include/vues/system
* application/include/vues/layout
* application/include/vues/view
ainsi la vue standard peut étendre de `application/include/vues/layout/body.html.twig`
```php
{% block body %}
<!-- Body Inner -->
<section id="page-content">
<div class="container">
<!--Alerts-->
{% if $_SESSION['alerts'] is defined %}
{% foreach $_SESSION['alerts'] as alert %}
<div class="alert alert-{{alert.type}} alert-dismissible fade show" role="alert">
<strong>{{alert.title}}</strong> {{alert.message}}.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endforeach %}
{% endif %}
<!--end: Alerts-->
{% block content %}{% endblock %}
</div>
</section>
{% endblock %}}
```
qui étends de `application/include/vues/system/system.html.twig`
```php
<!DOCTYPE html>
<html>
<head>
{% block head %}
<title>{{page_title}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="author" content="" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" lang="fr" content="{{description}}"/>
{% block top-css %}
<link rel="stylesheet" href="{{ \MVC\Classe\Url::asset_rewrite('assets/bootstrap-5.0.0-beta1-dist/css/bootstrap.min.css')}}">
<link rel="stylesheet" href="{{ \MVC\Classe\Url::asset_rewrite('assets/css/custom.css')}}">
{% endblock %}
{% endblock %}
</head>
<body>
{% block top-javascript %}{% endblock %}
{% block body %}{% endblock %}
{% block bottom-javascript %}
<script src="{{ \MVC\Classe\Url::asset_rewrite('assets/bootstrap-5.0.0-beta1-dist/js/bootstrap.min.js')}}"></script>
<script src="{{ \MVC\Classe\Url::asset_rewrite('assets/js/custom.js')}}"></script>
{% endblock %}
</body>
</html>
```

View file

@ -0,0 +1,50 @@
#Les vues Blade
Elles sont chargées dans cette ordre:
* application/include/vues/system
* application/include/vues/layout
* application/include/vues/view
ainsi la vue standard peut étendre de `application/include/vues/layout/body.blade.php`
```php
@extends('system')
@section('body')
@section('sidebar')
This is the master sidebar.
@show
<div class="container">
@yield('content')
</div>
@endsection
```
qui étends de `application/include/vues/system/system.blade.php`
```php
<html>
<head>
<title>{{$page_title}}</title>
<meta name="description" lang="fr" content="{{$description}}"/>
@section('top-css')
@endsection
</head>
<body>
@section('top-javascript')
@endsection
@yield('body')
@section('bottom-javascript')
@endsection
</body>
</html>
```

View file

@ -0,0 +1,88 @@
#Les vues Blade avec une SPA Vue.js
Elles sont chargées dans le même ordre que les vues Blade normale:
* application/include/vues/system
* application/include/vues/layout
* application/include/vues/view
Cependant il faut inclure les biblitohèques Vue.js dans la page et coder à la mimine la SPA
par exemple:
```php
@section('top-javascript')
@parent
<script src="https://unpkg.com/vue@2.6.12/dist/vue.js"></script>
<script src="https://unpkg.com/axios@0.21.1/dist/axios.min.js"></script>
@endsection
@section('content')
<h1>%PAGE% - VUE.js Controlleur</h1>
<br/><br/><br/>
<div id="app">
<div>
<input v-model="searchText" placeholder="Search...">
</div>
<div v-if="items" >
<a href="#" v-for="item in itemsSearched" :key="item.id">
<div>
<div>
<h2>
@{{ item.title }}
</h2>
</div>
</div>
<div>
<p>
@{{ item.description.slice(0, 300) + "..." }}
</p>
</div>
<div>
<span>Year : @{{ item.release_date }}</span>
<span>Director : @{{ item.director }}</span>
<span>Producer : @{{ item.producer }}</span>
</div>
</a>
</div>
</div>
@endsection
@section('bottom-javascript')
@parent
<script>
const vue = new Vue({
el: '#app',
data: {
items: [],
searchText: ''
},
mounted() {
axios
.get('https://ghibliapi.herokuapp.com/films')
.then(response => {
this.items = response.data;
})
.catch(error => console.log(error))
},
computed : {
itemsSearched : function(){
var self = this;
if( this.searchText == ''){
return this.items;
}
return this.items.filter(function(item){
// https://www.reddit.com/r/vuejs/comments/62kfae/how_do_i_create_very_simple_instant_search_filter/
// Must be of string type
return item.title.toLowerCase().indexOf(self.searchText) >= 0 ||
item.producer.toLowerCase().indexOf(self.searchText) >= 0 ||
item.director.toLowerCase().indexOf(self.searchText) >= 0 ||
item.release_date.toString().indexOf(self.searchText) >= 0;
});
}
}
});
</script>
@endsection
```

View file

@ -0,0 +1,66 @@
#Les actions
Celles-ci peuvent être appellé dans une vue par la méthode static qu'il convient d'instancier dans un fichier se trouvant dans le dossier `application/include/action/`
par exemple:
```php
<?php
use MVC\Classe\HttpMethodRequete;
use MVC\Classe\Implement\Action;
use MVC\Classe\Url;
class DefaultAction extends Action
{
public function default($data1 = null,$data2 = null,$data3 = null)
{
/**your action algorythm**/
if ($data1 !== null) {
$var1 = $data1;
} else {
$var1 = 1;
}
if ($data2 !== null) {
$var2 = $data2;
} else {
$var2 = 2;
}
if ($data3 !== null) {
$var3 = $data3;
} else {
$var3 = 3;
}
return $this->render('action', array('var1' => $var1, 'var2' => $var2, 'var3' => $var3));
}
public function variableSlug($data1,$data2)
{
/**your action algorythm**/
ob_start();
print_r($data1);
echo "<br/>";
print_r($data2);
return ob_get_clean();
}
public function makeHttp11()
{
$data = array('myval' => 25);
$request = new HttpMethodRequete();
$request->setUrl(Url::absolute_link_rewrite(false,'accueil',['var10'=>'val10']))->get($data);
$request->setUrl(Url::absolute_link_rewrite(false,'accueil',['var10'=>'val10']))->post($data);
$request->setUrl(Url::absolute_link_rewrite(false, 'accueil', ['var10' => 'val10']))->put($data);
$request->setUrl(Url::absolute_link_rewrite(false,'accueil',['var10'=>'val10']))->delete($data);
}
}
```
avec cet accès dans la vue:
```php
{{\MVC\Classe\ControlleurAction::inserer('default',[])}}
{{\MVC\Classe\ControlleurAction::inserer('default.default',[4,5,6])}}
{{\MVC\Classe\ControlleurAction::inserer('default.variableSlug',['var1','var2'])}}
{{\MVC\Classe\ControlleurAction::inserer('default.makeHttp11',[])}}
```
il faut absolument que l'action retourne du texte soit par la la méthode `render` soit par un `système de tampon`

View file

@ -0,0 +1,51 @@
#Le conduit Symfony
>Le conduit est une nouveautée de l'application, celle permet de réaliser
un controlleur similaire a Symfony qui est dénomé ici Conduit car il prend
en paramètre une route défini dans le fichier routing.yml.
Cette fonctionnalité permet de choisir la route indépendamment du moteur.
il faut instancier le fichier `application/config/files/routing.yml`
avec la route de base et les routes que vous voulez conduire, par exemple:
```yml
home_route:
path: /
defaults: { controller: 'FooController::indexAction' }
foo_route:
path: /foo
defaults: { controller: 'FooConduit::index' }
foo_placeholder_route:
path: /foo/{id}
defaults: { controller: 'FooConduit::load' }
requirements:
id: '[0-9]+'
```
et définir le Conduit correspondant avec les méthodes correspondantes dans le dossier `application/include/conduits`, ici:
```php
<?php
use MVC\Classe\Implement\Conduit;
class FooConduit extends Conduit
{
// Route('/foo')
public function index()
{
echo "blob of foo";
return $this->render('foo', array('page_title' => 'Foo', 'description' => 'FooConduit'));
}
// Route('/foo/{id}')
public function load()
{
echo "load of foo";
return $this->render('foo', array('page_title' => 'Foo', 'description' => 'FooConduit', 'id' => $this->id));
}
}
```
Vous remarquerez que les variables passé en GET sont obtenu dans le conduit par `$this->varname`.

View file

@ -0,0 +1,29 @@
#Comment Configurer un module Symfony ou tout autre application php
il vous faut instancier trois fichiers:
le modèle (.model) contenant le nom de la page qui porte le model
ici : `application/include/modeles/syf51.model`
```yaml
name : syf51
page_title : Accueil de l'application modulaire
description : zatou stra bracadabla
params : params
```
le controlleur (.php) contenant ce code qui doit être automatisé
ici: `application/include/controlleurs/syf51.php`
```php
<?php
\MVC\Classe\Session::start();
$app = new MVC\Classe\Modular($name);
$templateData = array('app' => $app);
```
et déclarer le module dans `\application\modules\setup\registre.model`
par une ligne suplémentaire:
```yaml
syf51 : Application permettant de tester l'intégration d'un module avec symfony5.0.99
```
si besoin et que le module n'existe pas il vous faudras coder et modifier
le fichier `/application/class/Modular.php` voir peut-être `/application/class/ModularRegister.php`
Good Luck !

View file

@ -0,0 +1 @@
#Comment bien utiliser les modules

View file

@ -0,0 +1 @@
#Comment ajouter un module Wordpress

View file

@ -0,0 +1 @@
#Comment ajouter un module Prestashop

View file

@ -0,0 +1 @@
#Comment ajouter un module PHPList

View file

@ -0,0 +1 @@
#Comment ajouter un module GitList

View file

@ -0,0 +1 @@
#Comment ajouter un module Symfony

View file

@ -0,0 +1,48 @@
# Comment ecrire une fonctionnalité récursive d'appel avec SAND
Une fonctionnalité récursive d'appel permet d'appeler avec curl une api écrite avec le FrameWork SAND.*
Typiquement on peut:
- faire de multiples appel à l'api (REST ou Web) grace a curl dans un seul controlleur sans passez par javascript
- ainsi mieux découper les CRUD d'appel en bdd
- remplacer le pattern PRG, ou mieux le découper.
C'est un choix applicatif a faire lors du developpement de l'application
Il existe trois façon d'appeler un appel curl `HttpMethodRequest`, tous prennent en paramètre des valeurs passées dans un tableau:
```
$data = array('a','b','c');
```
Voici la première:
```
$request = new Response('http://myurl','myhttp1.1method');
$request->addContent($data);
$request->send();
```
Voici la seconde:
```
$request = new Response('http://myurl');
```
avec soit la création d'un context personnalisé
```
$request->createContext('myhttp1.1method')
$request->addContent($data);
$request->send();
```
Soit les methodes HTTP1.1
```
$request->get($data);
$request->post($data);
$request->put($data);
$request->delete($data);
```
Voici la dernière qui reste la plus facile à utiliser,
pour les développeurs qui comprennent les notations chainées:
```
$request = new Response();
$request->setUrl('http://myurl')->get($data)
$request->setUrl('http://myurl')->post($data)
$request->setUrl('http://myurl')->put($data)
$request->setUrl('http://myurl')->delete($data)
```

View file

@ -0,0 +1,15 @@
#BONUS - Comment troller efficacement
##prendre en compte l'aspect actuel de l'information
>en effet si absolument rendre compte que l'information n'est basé sur les faits divers et principalement sur l'actualité économique. En effet la plupart des médias ne parlent pas de l'information économique et informatique. En faisant cela vous devriez voir les niche qui doivent être visé par la trool attitude. Principalement parlez des faits divers ne nourris pas le trool. Et ne permet pas efficacement de nourrir une informations qui serait humoristique. Ainsi un troll d'humour serait basé sur des fait divers détourné et des sites comme le _Gorafi_ et l'_Echo de la boucle_ sont des niches a trool.
##se mettre en avant de l'information visée en se basant sur des faits vécu
>en effet vous ne pouvez troller efficacement que sur des faits qui se rapporte a ce que vous avez lu en amont et que vous vivez actuellement par exemple si vous connaissez le monde des hackers et leurs déviance vous pouvez éviter les personnes frauduleuse mettant en avant des news dont vous pouvez mettre en garde au devant de touts les autres
##se gardez de tout propos autre que ceux que vous mettez en avant
>avec des textes courts expliquant par des sources ce que vous visez vous pouvez mettre en avant votre informations vécue ainsi vous troller ceux qui n'ont pas vécu linformation dont vous parlez au moment de la lecture
##attendre..
>lorsque vous troller il se peut que l'information ne parvienne pas au oreille de ceux qui pourraient répondre. surtout si vous faites preuve de surréalisme. Ainsi vous expliquer ce que le pendant du monde réel as de pire et peut ainsi mettre en avant une expérience vécu.
##encore attendre...
>si vous êtes progressiste il se peut que certaines personnes vous suivent afin de mieux comprendre ce que vous voulez dire dans ce texte que vous partager, n'oubliez surtou pas de fournir le plus de sources documentées et scientifiquement valable afin que votre article, brève, ou chronique soit effectivement une source d'information fiable. Ainsi ce troll devient une source mal écrit contenant des documents connexes !

View file

@ -0,0 +1,200 @@
#BONUS - Quelques livres sur la programmation
* [Méta-listes](#méta-listes)
* [Non dépendant du langage](#non-dépendant-du-langage)
* [Algorithmique](#algorithmique)
* [Bases de données](#bases-de-données)
* [Logiciels libres](#logiciels-libres)
* [Makefile](#makefile)
* [Méthodes de développment](#méthodes-de-développement)
* [Systèmes informatiques](#systèmes-informatiques)
* [Théorie des langages](#théorie-des-langages)
* [Assembleur](#assembleur)
* [Bash / Shell](#bash--shell)
* [Caml](#caml)
* [C / C++](#c--c)
* [Coq](#coq)
* [CSS](#css)
* [Git](#git)
* [Haskell](#haskell)
* [Java](#java)
* [Javascript](#javascript)
* [LaTeX](#latex)
* [Asymptote](#asymptote)
* [Metapost](#metapost)
* [PGF/TikZ](#pgftikz)
* [Lisp](#lisp)
* [Perl](#perl)
* [PHP](#php)
* [Python](#python)
* [R](#r)
* [Ruby](#ruby)
* [Sage](#sage)
* [Scilab](#scilab)
* [SPIP](#spip)
* [TeX](#tex)
* [Vim](#vim)
###Méta-listes
* [Le SILO: Sciences du numérique &amp; Informatique au Lycée: Oui!](https://wiki.inria.fr/sciencinfolycee/Accueil)
###Non dépendant du langage
####Algorithmique
* [Algorithmique](http://pauillac.inria.fr/~quercia/cdrom/cours), par Michel Quercia
* [Éléments d'algorithmique](https://www.rocq.inria.fr/secret/Matthieu.Finiasz/teaching/ENSTA/IN101%20-%20poly%20algo.pdf) par Françoise Levy-dit-Vehel et Matthieu Finiasz
* [Éléments d'algorithmique](http://www-igm.univ-mlv.fr/~berstel/Elements/Elements.pdf) par D. Beauquier, J. Berstel, et Ph. Chrétienne
* [France-IOI](http://www.france-ioi.org/)
* [Prologin](http://www.prologin.org/)
####Bases de données
* [Bases de données I](http://decan.lexpage.net/files/bdd1/bdd1-syllabus.pdf), par Jef Wijsen
####Logiciels libres
* [Histoires et cultures du libres](http://framabook.org/histoires-et-cultures-du-libre/)
* [Option libre. Du bon usage des licences libres](http://framabook.org/option-libre-du-bon-usage-des-licences-libres/), par Jean Benjamin
* [Produire du logiciel libre](http://framabook.org/8-produire-du-logiciel-libre/), par Karl Fogel
* [Richard Stallman et la révolution du logiciel libre](http://framabook.org/richard-stallman-et-la-revolution-du-logiciel-libre/), par R.M. Stallman, S. Williams et C. Masutti
####Makefile
* [Concevoir un Makefile](http://icps.u-strasbg.fr/people/loechner/public_html/enseignement/GL/make.pdf), par Vincent Loechner d'après Nicolas Zin
* [Introduction aux Makefile](http://eric.bachard.free.fr/UTBM_LO22/P07/C/Documentation/C/make/intro_makefile.pdf)
####Méthodes de développement
* [Scrum et XP depuis les tranchées](http://www.infoq.com/resource/news/2007/06/scrum-xp-book/en/resources/ScrumAndXpFromTheTrenches_French.pdf), par Henrik Kniberg
####Systèmes Informatiques
* [Systèmes Informatiques (C, Unix/Linux,...)](http://sinf1252.info.ucl.ac.be/), par Olivier Bonaventure ([sources](https://github.com/obonaventure/SystemesInformatiques))
####Théorie des langages
* [Compilation. Théorie des langages](http://www.lisyc.univ-brest.fr/pages_perso/leparc/Etud/Master/Compil/Doc/CoursCompilation.pdf) par Université de Bretagne Occidentale
###Bash / Shell
* [Guide avancé d'écriture des scripts Bash](http://abs.traduc.org/abs-fr/)
###Caml
* [Introduction à Objective Caml](http://form-ocaml.forge.ocamlcore.org/html/index.html), par Maxence Guesdon
* [Le language Caml](http://caml.inria.fr/)
###C / C++
* [Cours de C/C++](http://casteyde.christian.free.fr/cpp/cours/online/book1.html) par Christian Casteyde
* [Le C en 20 heures](http://framabook.org/6-le-c-en-20-heures/), par Eric Berthomier et Daniel Schang
* [Initiation à la programmation (en C++)](https://www.coursera.org/course/intro-cpp-fr), MOOC de l'École Polytechnique Fédérale de Lausanne
* [Introduction à la rétro-ingénierie de binaires](http://progdupeu.pl/articles/45/introduction-a-la-retro-ingenierie-de-binaires), à partir de code C compilé pour x86.
* [Programmation en C](https://www.rocq.inria.fr/secret/Matthieu.Finiasz/teaching/ENSTA/IN101%20-%20poly%20C.pdf) par Pierre-Alain Fouque et David Pointcheval
###Coq
* [Le Coq'Art (V8)](http://www.labri.fr/perso/casteran/CoqArt) par Yves Bertot et Pierre Castéran
* [Preuves de programmes en coq](http://fuscia.inrialpes.fr/cours/coq/) par Yves Bertot
###CSS
* [Apprendre les mises en page CSS](http://fr.learnlayout.com/)
###Git
* [Git Magic](http://www-cs-students.stanford.edu/~blynn/gitmagic/intl/fr/) par par Alexandre Garel, Paul Gaborit et Nicolas Deram
* [Pro Git](http://www.git-scm.com/book/fr) par Scott Chacon
###Java
* [Initiation à la programmation (en Java)](https://www.coursera.org/course/intro-java-fr), MOOC de l'École Polytechnique Fédérale de Lausanne
###Javascript
* [Javascript Éloquent : Une introduction moderne à la programmation](http://fr.eloquentjavascript.net/), par Marijn Haverbeke
###Haskell
* [Apprendre Haskell vous fera le plus grand bien !](http://lyah.haskell.fr/)
* [A Gentle Introduction to Haskell](http://gorgonite.developpez.com/livres/traductions/haskell/gentle-haskell/) par Paul Hudak, John Peterson et Joseph Fasel
###LaTeX
* [Détecter et résoudre
les problèmes](http://www.pearson.fr/livre/?GCOI=27440100048330), Annexe B du LaTeX Companion 2006, par Frank Mittelbach et Michel Goossens, mis à disposition par l'éditeur dans l'onglet « Compléments »
* [LaTeX... pour le prof de maths !](http://math.univ-lyon1.fr/irem/IMG/pdf/LatexPourProfMaths.pdf) par Arnaud Gazagnes
* [Tout ce que vous avez toujours voulu savoir sur LaTeX sans jamais oser le demander](http://framabook.org/5-tout-ce-que-vous-avez-toujours-voulu-savoir-sur-latex-sans-jamais-oser-le-demander/) par Vincent Lozano
* [(Xe)LaTeX appliqué aux sciences humaines](http://geekographie.maieul.net/95) par Maïeul Rouquette
Voir aussi [TeX](#tex)
####Asymptote
* [Asymptote. Démarrage rapide](http://cgmaths.fr/cgFiles/Dem_Rapide.pdf), par Christophe Grospellier
####Metapost
* [Un manuel de Metapost](http://melusine.eu.org/syracuse/metapost/f-mpman-2.pdf), par John D. Hobby
* [Tracer des graphes avec Metapost](http://melusine.eu.org/syracuse/metapost/f-mpgraph.pdf), par John D. Hobby
####PGF/TikZ
* [TikZ pour l'impatient](http://math.et.info.free.fr/TikZ/), par Gérard Tisseau et Jacques Duma
###Lisp
* [Introduction à la programmation en Common Lisp](http://www.algo.be/logo1/lisp/intro-lisp.pdf) par Francis Leboutte
* [Traité de programmation en Common Lisp](http://dept-info.labri.fr/~strandh/Teaching/Programmation-Symbolique/Common/Book/HTML/programmation.html) par Robert Strandh et Irène Durand
###Perl
* [Guide Perl - débuter et progresser en Perl](http://formation-perl.fr/guide-perl.html), par Sylvain Lhullier
* [La documentation Perl en français](http://perl.mines-albi.fr/DocFr.html)
###Php
* [Cours de PHP 5](http://g-rossolini.developpez.com/tutoriels/php/cours/?page=introduction) par Guillaume Rossolini
* [Initiation au PHP](http://www.framasoft.net/IMG/pdf/initiation_php.pdf) par David Ducrocq
* [Programmer en PHP](http://www.lincoste.com/ebooks/pdf/informatique/programmer_php.pdf) par Julien Gaulmin
###Python
* [Appendre à programmer avec Python](http://inforef.be/swi/python.htm) par Gerard Swinnen
* [Dropbox a des fuites !Un aperçu de la rétro-ingénierie des programmes Python](http://progdupeu.pl/articles/34/dropbox-a-des-fuites)
* [Python](http://www.lincoste.com/ebooks/pdf/informatique/python.pdf) par Guido Van Rossum
###R
* [Introduction à la programmation en R](http://cran.r-project.org/doc/contrib/Goulet_introduction_programmation_R.pdf) par Vincent Goulet
###Ruby
* [Ruby en vingt minutes](https://www.ruby-lang.org/fr/documentation/quickstart/)
* [Venir à Ruby après un autre language](https://www.ruby-lang.org/fr/documentation/ruby-from-other-languages/)
####Ruby on Rails
* [Tutoriel Ruby on Rails : Apprendre Rails par l'exemple](http://french.railstutorial.org/chapters/beginning), par Michael Hartl
###Sage
* [Calcul mathématique avec Sage](http://sagebook.gforge.inria.fr/), par A. Casamayou, N. Cohen, G. Connan, T. Dumont, L. Fousse, F. Maltey, M. Meulien, M. Mezzarobba, C. Pernet, N. M. Thiéry, P. Zimmermann
###Scilab
* [Introduction à Scilab](http://forge.scilab.org/index.php/p/docintrotoscilab/downloads/) par Michaël Baudin, Artem Glebov, Jérome Briot
###SPIP
* [Programmer avec SPIP](http://programmer.spip.net/), par Matthieu Marcimat et collectif SPIP
###TeX
* [TeX pour l'Impatient](ftp://tug.org/tex/impatient/fr/fbook.pdf), par Paul Abrahams, Kathryn Hargreaves, and Karl Berry, trad. Marc Chaudemanche
Voir aussi [LaTeX](#latex)
###Vim
* [A Byte of Vim](http://swaroopch.com/notes/Vim_fr/)
* [Learn Vim Progressively](http://yannesposito.com/Scratch/fr/blog/Learn-Vim-Progressively/)

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

View file

@ -0,0 +1,83 @@
body {
color: #333333;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 14px;
line-height: 20px;
}
p strong, li strong {
color:#008287;
}
.code {
background:#000;
}
.code {
color:#999;
}
h1 {
}
h2 {
background-color: #F7F7F9;
border: 1px solid #E1E1E8;
padding:10px;
margin-top:30px;
}
h3 {
font-size:14px !important;
}
blockquote p {
font-size:18px;
background:#CCC;
color:#333;
width:80%;
font-style: italic;
margin-left:15%;
padding:10px;
}
.item.toc .part.level-1 {
color:#F7F7F9;
background-color: #000;
border: 1px solid #E1E1E8;
padding:10px;
margin-top:30px;
font-size:26px;
}
.item.part h1 {
text-align:center;
font-size:70px;
}
/* --- gherkin --- */
/*texte*/
div.code.gherkin {
color:#C5C8C6;
}
/*commentaire*/
div.code.gherkin .co1 {
color:#969896;
}
/*clef*/
div.code.gherkin .co3 {
color:#DE935F;
}
/*Exemples*/
div.code.gherkin .co4 {
color:#DE935F;
}
/*mot clef*/
div.code.gherkin .kw1 {
color:#81A2BE;
}
/*
vert #B5BD68
orange #DE935F
violet #B294BB
bleu #81A2BE
blanc #C5C8C6
gris #969896
jaune #B5BD68
*/

View file

@ -0,0 +1,63 @@
body {
color: #333333;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 14px;
line-height: 20px;
}
.code {
background:#000;
}
.code {
color:#999;
}
h2 {
background-color: #F7F7F9;
border: 1px solid #E1E1E8;
padding:10px;
margin-top:30px;
}
h3 {
font-size:14px !important;
}
em {
font-size:12px;
color:#c20cb9;
}
.item.part h1 {
text-align:center;
font-size:40px;
}
/* --- gherkin --- */
/*texte*/
div.code.gherkin {
color:#C5C8C6;
}
/*commentaire*/
div.code.gherkin .co1 {
color:#969896;
}
/*clef*/
div.code.gherkin .co3 {
color:#DE935F;
}
/*Exemples*/
div.code.gherkin .co4 {
color:#DE935F;
}
/*mot clef*/
div.code.gherkin .kw1 {
color:#81A2BE;
}
/*
vert #B5BD68
orange #DE935F
violet #B294BB
bleu #81A2BE
blanc #C5C8C6
gris #969896
jaune #B5BD68
*/

View file

@ -0,0 +1,75 @@
book:
title: "Le développement Avec Le Framework SAND"
subtitle: "Documentation d'utilisation de base"
author: "Emmanuel ROY"
edition: "First edition"
language: fr
publication_date: ~
generator: { name: easybook, version: 5.0-DEV }
contents:
# available content types: acknowledgement, afterword, appendix, author,
# chapter, conclusion, cover, dedication, edition, epilogue, foreword,
# glossary, introduction, license, lof (list of figures), lot (list of
# tables), part, preface, prologue, title, toc (table of contents)
#- { element: cover }
#- { element: toc }
#- { element: introduction, content: func-introduction.md }
- { element: chapter, number: 1, content: 00.a. Configuration de départ.md }
- { element: chapter, number: 2, content: 00.b. Comment bien utiliser les urls.md }
- { element: chapter, number: 3, content: 00.c. Comment bien utiliser les commandes console.md }
- { element: chapter, number: 4, content: 00.d. Comment est architecturé le framework.md }
- { element: chapter, number: 5, content: 00.e. Comment modifier proprement une page.md }
- { element: chapter, number: 6, content: 00.f. Comment fonctionnent les objets de sessions.md }
- { element: chapter, number: 7, content: 00.g. Comment faire évoluer une application SAND.md }
#- { element: author, content: author.md }
#- { element: license, content: license.md }
editions:
ebook:
format: epub
highlight_code: false
include_styles: true
labels: ['appendix', 'chapter'] # labels also available for: "figure", "table"
theme: clean
toc:
deep: 1
elements: ["appendix", "chapter", "part"]
print:
format: pdf
highlight_code: true
include_styles: true
isbn: ~
labels: ["appendix", "chapter"] # labels also available for: "figure", "table"
margin:
top: 25mm
bottom: 25mm
inner: 30mm
outter: 20mm
page_size: A4
theme: clean
toc:
deep: 2
elements: ["appendix", "chapter", "part"]
two_sided: true
web:
format: html
highlight_code: true
include_styles: true
labels: ["appendix", "chapter"] # labels also available for: "figure", "table"
theme: clean
toc:
deep: 2
elements: ["appendix", "chapter", "part"]
website:
extends: web
format: html_chunked

View file

@ -0,0 +1,7 @@
Je m'appelle Jean-François Lépine, et je suis consultant Web. Au quotidien, j'assiste les entreprises dans la conception et la réalisation de leurs applications web.
Très impliqué dans l'éco-système OpenSource Web, j'anime le blog technique blog.lepine.pro. Vous pouvez retrouver quelques-unes de mes contributions sur mon [compte Github](http://www.github.com/Halleck45).
Je suis également l'auteur du Mémento Industrialisation PHP : outils et qualité publié en 2012 aux éditions Eyrolles.
Ces livres sont gratuits et open source. S'ils vous ont plu, n'hésitez pas à me le signaler sur [twitter](https://www.twitter.com/Halleck45) :-)

View file

@ -0,0 +1,341 @@
# Communiquez
## Adoptez une Langue Commune
Ce que vous entendez en utilisant un mot peut parfois (souvent !) être
totalement différent de ce qu'une autre personne entend pour ce même
mot. Et c'est encore pire avec les développeurs !
Gardez cela à l'esprit : les développeurs ne parlent pas la même langue
que vous. Lorsque vous parlez "stock", "produit" ou "commande", un
développeur pensera "base de données", "enregistrement" et "sauvegarde
en base".
La première chose à faire est donc de constituer avec vos équipes une
Langue Commune. Peu importe le moyen : une feuille excel, un document
word ou un bout de papier feront l'affaire ! L'important  est de créer
un référentiel commun, souvent désigné par "Ubiquitus Language",
c'est-à-dire **un moyen d'utiliser une terminologie dont on sait qu'elle
est comprise par tous de la même manière**.
Attention, cet Ubiquitus Language, **cette Langue Commune ne doit PAS
être élaborée unilatéralement !** Instaurez un dialogue entre toutes les
parties prenantes du projet, jusqu'à déterminer des termes plus
importants que les autres. Identifiez les, puis, en commun,
définissez-les. Ne l'oubliez pas : une définition que vous aurez mis en
place tout seul ne voudra peut-être rien dire pour un développeur.
Dernière chose : ce référentiel commun ne doit porter que sur le domaine
fonctionnel. Il est inutile de créer un référentiel technique (du moins
pas en dehors des équipes techniques) : ce qui compte ce n'est pas de
faire du développement logiciel ; non, ce qui compte c'est votre
produit, vos bénéfices fonctionnels et votre vision !
Pour synthétiser cette Langue Commune en quelques mots, elle permet :
+ d'éviter un travail de traduction entre les tâches techniques et les
besoins fonctionnels (le jargon métier)
+ que tout le monde "parle" votre projet comme vous le "pensez"
+ d'éviter de vous retrouver avec des surprises idiotes, dues à des
incompréhensions sémantiques ou à des ambiguïtés.
> les développeurs ne parlent pas la même langue que vous
## Laissez la technique aux développeurs
Laissez-moi vous rassurez tout de suite : **non, vous n'avez pas besoin
de savoir comment fonctionne techniquement votre produit**. Non, vous
n'avez pas à comprendre la terminologie des développeurs.
Mieux ! Vous ne devez SURTOUT PAS comprendre ce que font les
développeurs.
Ça fait maintenant quelques années que je conduis une voiture. Je sais
passer mes vitesses, je comprend comment lire mon tableau de bord...
Mais je ne sais pas, mais alors pas du tout, comment fonctionne ma
voiture. Et croyez-moi, je n'en ai rien à faire ! 
Je dois vous avouer une chose : quand j'ai une panne, je vais voir mon
garagiste et je lui fais confiance. Quand il m'explique le problème, je
dis des "ah oui ?" avec un air curieux. Mais je ne comprend rien ! Et c'est
tant mieux !
Pourquoi serait-ce différent pour l'informatique ? Mettre les mains
"dans la cambouis" risque :
+ de brider vos demandes quand vous allez imaginer qu'un point va être
techniquement coûteux alors qu'il n'en n'est rien
+ de vous faire adopter une angle de vue différent (celui des développeurs) au détriment de votre vision initiale
+ de laisser le code dominer le domaine fonctionnel
+ de vous faire perdre votre force fonctionnel
Je peux vous le dire : les projets les plus coûteux et les plus en
retard sur lesquels j'ai travaillé ont été initié par d'anciens
développeurs devenus chefs d'entreprise ou fonctionnels. Naturellement,
et on ne peut pas les en blâmer, ils ont tendance à vouloir comprendre
l'implémentation technique de leur produit. 
Cependant, cela est très coûteux : tout d'abord l'équipe technique doit
passer beaucoup de temps à expliquer ce qu'elle fait au lieu d'avancer
réellement. Ensuite, elle doit passer du temps également à monter en
compétence le fonctionnel. Enfin, et ce n'est pas le moindre, cela
introduira un sentiment de défiance entre vous et l'équipe technique,
sentiment qui va ralentir et limiter vos possibilités de créer une
Langue Commune et freiner l'investissement de vos équipes.
> Vous ne devez surtout pas comprendre ce que font les développeurs
## Racontez votre produit
Combien de documents sont passés entre vos mains sans que vous ne les
lisiez totalement, partiellement ou pas du tout ? Avouez-le, cela nous
est tous arrivé au moins une fois. 
Pourquoi le document que vous fournissez à votre prestataire ne
serait-il pas justement celui-là même qu'il va survoler, ou mal
comprendre ?
Un document word, par exemple, est une excellente base de travail. Vous
pouvez y noter vos réflexions, vous en servir comme brouillon... Mais
pas comme spécification !
Comprenez : votre pensée est ce qu'elle est : mouvante, changeante, et
surtout personnelle. Avec tous les efforts du monde, vous n'arriverez
pas à transmettre l'ensemble de votre pensée par écrit. Il subsistera
toujours de l'interprétation, des non-dits, de l'implicite... Voire même
parfois des contradictions qu'il faudra lever. C'est normal, comme un
projet, une pensée vit et change.
Votre vision, vos besoins, vos spécifications... tout cela doit faire
l'objet d'un échange oral. Racontez votre produit plutôt que de le
décrire. Qu'en pensez-vous ?
**Votre projet doit être le résultat d'une conversation** : impliquez
vous, mais impliquez aussi le testeur, le fonctionnel, l'ergonome, le
graphiste et le développeur. Racontez leur votre produit, et dialoguez,
de telle manière que :
+ Ils **s'approprient votre besoin**
+ Ils **mettent en évidence certaines incohérences** le plus tôt possible
+ Ils vous proposent des changements (vous restez le seul maître de les
accepter ou non)
+ Ils soient impliqués et aient le sentiment d'être partie prenante de
votre projet
+ Ils ne perdent pas de temps à traduire votre message
C'est d'ailleurs comme ça que vous allez vous rendre compte que certains
points demeurent obscurs, malgré tous vos efforts. Cela signifiera peut-être que
ces points sont plus importants que vous ne l'estimiez, et il sera
peut-être utile d'y consacrer plus de temps.
Oubliez donc les spécifications fonctionnelles détaillées (SFD), et
autres joyeusetés qui font la joie du développeur quand il doit lire un
document de 200 pages pour comprendre un besoin qu'il mettra 20 minutes
à implémenter. La documentation est utile, les SFG, SFD, etc. aussi,
mais uniquement quand elle est réservée aux cas qui le nécessitent
vraiment ! 
Oubliez cette masse de documentation d'autant plus qu'elle va être un
frein à votre besoin de changements : très vite, avec de nombreux
documents, vous allez : 
+ ou bien avoir un décalage conséquent entre vos spécifications et votre produit (quid des nouveaux arrivants sur le projet ?),
+ ou bien devoir passer un temps précieux à mettre à jour vos spécifications à chaque changement. Et ça, croyez-moi, dans la vraie vie ça n'arrive jamais si vous n'avez pas une ressource dédiée à cette tâche, à temps plein !
Vous allez le voir, il existe d'autres moyens de préciser votre besoin.
En attendant, oubliez les documents word, pdf, rtf... Et Initiez la
conversation.
> Racontez votre produit plutôt que de le spécifier
## Identifiez le Domaine fonctionnel
Vous l'avez vu, vous avez besoin de constituer une Langue Commune avec
vos équipes. Vous le savez également, une image vaut souvent mieux qu'un
long discours... Pourquoi ne pas concilier les deux ?
Il existe une approche, mise en évidence par Eric Evans, pour faire en
sorte le code source (ce qui permet à votre produit de fonctionner)
corresponde de près aux fonctionnalités métiers. Cette approche, c'est
le Domain Driven Design, ou Conception Pilotée par le Métier.
En général, au fil du temps, les développeurs qui auront travaillé sur
votre projet vont mettre en place ce qu'on appelle familièrement des
"rustines", des morceaux de code source rapides à mettre en place mais
peu maintenables, destinés à gérer vos demandes de changements fonctionnels.
Pire, dès le départ, les développeurs vont se focaliser sur les aspects
techniques du projet. Normal me direz-vous ? Non, car s'ils font cela,
l'énergie à dépenser pour comprendre les liens entre le code source et
le besoin fonctionnel risque d'être très importante, voire tellement
importante que votre projet risque de vous mettre sur la paille à la
moindre demande de changement.
Le Domain Driven Design propose une approche différente : les
développeurs vont se focaliser avant tout sur le besoin métier, et
concevoir leur code source autour de ce besoin. Ça peut paraître une
évidence, mais c'est loin d'être le cas, croyez-moi ! Le code source
sera alors le reflet du besoin métier.
Si vous et vos équipes souhaitez mettre en place cette orientation (du
Domain Driven Design), **la première chose dont vous aurez besoin, après
une Langue Commune, sera une cartographie du domaine fonctionnel couvert
par votre application**. 
Rassurez-vous, rien de bien compliqué. Oubliez les logiciels de
modélisation, oubliez Visio, oubliez l'UML, Merise (si vous les avez
déjà utilisés), voici venue l'ère ... du papier et du crayon !
Listez, puis représentez sur un dessin simple, l'ensemble des grands
concepts fonctionnels liés à votre produit (ceux qui sont présents dans
votre glossaire, votre Langue Commune). Reliez-les entre eux par de
flèches annotées, qui représenteront les différentes interactions de ces
concepts entre eux. S'il y a trop de flèches à un endroit, c'est que
vous vous attardez trop sur des détails. Si vous pensez que ce ne sont
pas des détails, prenez une autre feuille et redémarrez, mais cette fois
en zoomant sur la partie concernée.
Cette cartographie, qui doit être simple (en caricaturant un peu, disons
que votre neveu de huit ans devrait pouvoir la comprendre s'il connaît
votre Langue Commune !), sera le **référentiel du Comportement de votre
Produit**.
Ce comportement étant désormais identifié, il sera plus facile pour les
équipes d'appréhender les changements et d'en identifier les
conséquences.
Cette cartographie vous servira également : elle va vous permettre
d'identifier l'indispensable, l'utile et le pratique dans votre produit.
Vos équipes doivent commencer à travailler sur l'indispensable.
L'utile et le pratique viendront après.
> Prenez un papier et un crayon, puis dessinez la cartographie
fonctionnelle de votre Produit
## Faites-vous interviewer
Mais attention, cette cartographie fonctionnelle, en réalité... ce n'est
pas à vous de la faire !
Pourquoi donc cet air surpris sur votre visage ? Je veux simplement dire que ce
n'est pas à vous *seul* de la réaliser. Mais rassurez-vous, vous en serez le
moteur.
Concrètement, vous devez dans un premier temps discuter avec vos
développeurs, mais surtout ceux-ci doivent réaliser un travail d'enquête :
vos développeurs doivent vous interviewer. 
Ou plutôt ils doivent interviewer le Produit. Après tout... vous êtes le
porte-parole de votre produit.
Cet interview, comme une interview classique va consister en différents
moments :
+ présentation générale d'un aspect fonctionnel
+ une question de l'équipe technique sur un point abordé
+ votre réponse fonctionnelle
+ une nouvelle question de l'équipe technique
+ etc.
Attention, l'interview ne doit jamais dériver sur des aspects
techniques. Il sera largement temps plus tard de voir comment résoudre
techniquement tel ou tel point. Pour l'instant, ne discutez QUE du
fonctionnel.
Cette démarche a au moins trois avantages :
+ impliquer les équipes techniques sur votre besoin métier
+ mettre en évidence des aspects implicites, qui sont évidents pour une
personne du métier, mais totalement inconnus des équipes techniques
+ vous permettre de prendre du recul sur votre métier et votre besoin en
l'expliquant à des néophytes.
> Les équipes techniques doient interviewer le porte-parole du produit
## Les tâches ne servent à rien
Vous voulez que vos développeurs développent une nouvelle fonctionnalité
? Ne leur donnez pas de tâche à faire ! N'exprimez que votre besoin...
Imaginez un instant cette scène : vous re-voila chez votre
concessionnaire automobile, prêt à signer le chèque de votre nouvelle
voiture. A votre avis, des deux situations suivantes, laquelle est la
plus adaptée :
+ Situation 1 :
> Client : "J'ai besoin de la voiture le mois prochain. Il vous faudra
> donc passer commande auprès du constructeur. Pour cela vous disposez du
> logiciel mis à disposition par ce dernier. Entrez vos codes d'accès,
> puis saisissez la référence de la voiture, puis cliquez sur "Commander".
> Dès que vous recevez la voiture, faites un bilan complet, puis
> appelez-moi."
+ Situation 2 :
> Client : "J'ai besoin de ma voiture le mois prochain, je sais que vous
> ferez le maximum. Tenez moi simplement régulièrement informé de
> l'avancée de la commande..."
Alors, à votre avis, quelle situation est la plus adaptée ? La deuxième
sans doute, non ? Examinons la Situation 1 : que se passe t-il si le
concessionnaire appelle directement le constructeur pour commander votre
voiture plutôt que de respecter les tâches qui lui sont assignées...
Quel en sera le résultat ?
+ Vous serez livré plus vite
+ **Les objectifs seront atteints**
+ **Pourtant le concessionnaire n'aura pas accompli les tâches demandées**
Je pense que vous avez compris : peu importe ce que va faire votre
concessionnaire, ce qui compte c'est d'être livré à temps. Pire, vous
risquez d'embrouiller le concessionnaire ou de le mettre sur des fausses
pistes. Avec une liste de tâches à suivre, le concessionnaire ne
pourrait pas prendre l'initiative d'appeler directement le constructeur
automobile. 
Et bien pour le développeur c'est pareil. **Exprimez votre besoin, les
délais souhaités, les modalités, mais ne lui dite pas comment réaliser
ce besoin**, vous risquez de le mettre sur de fausses pistes.
Attention, les listes de tâches sont utiles bien entendus, mais pas pour
communiquer. Vous pouvez avoir votre liste de tâches, les équipes de
développement vont peut-être (sans doute !) transformer votre besoin en
sous-tâches techniques... Mais en aucun cas vous n'avez besoin de
communiquer avec des tâches à faire. Le dialogue ne doit porter que sur
votre besoin métier.
> Communiquer en liste de tâches ne sert à rien, le dialogue ne doit
porter que sur le besoin métier.

View file

@ -0,0 +1,139 @@
# Le mot de la fin
## Parlons la même langue
Nous avons discuté des idées, des concepts... Il est temps d'établir
notre Langue Commune.
**Produit**
: Concept dont l'application sera à terme la réalisation. Ce concept vise
à rendre possible la Vision.
**Vision**
: Guide et oriente votre projet. Son but est de changer ce qui, dans la
vie de vos utilisateurs, peut les gêner, leur manquer ou les
insatisfaire.
**Bénéfice fonctionnel**
: Confort métier tiré par les utilisateurs de votre Produit. 
**Langue Commune**
: Langage clair pour l'ensemble des acteurs d'un projet. Ce langage est
défini en commun.
**Cartographie du Produit**
: Représentation visuelle simple du Comportement de votre Produit. Cette
représentation peut concerner l'ensemble ou une partie de votre Produit.
**Fonctionnalité**
: Besoin métier spécifique. Elle est représentée par un texte court qui
communique ce besoin métier au reste de l'équipe. Elle concerne le
service rendu à un utilisateur, et décrit le bénéfice fonctionnel qui
en est tiré.
**Scénario**
: Illustration des situations dans lesquelles se manifeste une
Fonctionnalité. Elle est représentée par une situation initiale, un
événement et un résultat attendu.
**Exemple**
: Illustre un Scénario de manière concrète. Il enlève toute ambiguïté
possible sur une étape d'un scénario ou sur le scénario lui-même.
**Livrable**
: Application concrète livrée au client. Il délivre le Comportement
raconté par les Fonctionnalités et les Scénarios. Il est possible de
fournir un livrable régulièrement au cours de la vie du Projet.
**Recette**
: Opération qui contrôle que le Livrable correspond au Produit, en se
basant sur les Fonctionnalités et les Scénarios. Peut être automatisée
avec des outils spécialisés.
## Cartographie du Développement piloté par le Comportement
![ Cartographie du Développement piloté par le Comportement ](cartographie.png)
## Les 10 commandements pour vous mettre au Développement piloté par le Comportement
1) **Votre Vision est le seul guide du projet**
: Chaque fonctionnalité, chaque ressource consacrée au projet, tout doit
servir cette Vision. Elle est le point de repère et la motivation de
chacun des acteurs de votre Produit. 
2) **Créez une Langue Commune**.
: Un développeur ne parle pas la même langue que vous. Créez un
référentiel et un vocabulaire commun ensemble, et utilisez la syntaxe
proposée par le Développement piloté par le Comportement, claire pour la
majorité des gens.
3) **Concevez vos scénarios ensemble**.
: C'est le seul moyen de retirer toutes les ambiguïtés qui peuvent exister
entre vous, votre produit et vos équipes. Ne laissez personne rédiger un
scénario tout seul.
4) **Vos scénarios ne concernent pas l'interface graphique**
: Faites abstraction du support matériel de votre Produit : site web,
application mobile... Ce qui compte vraiment c'est le comportement de
votre Produit.
5) **L'automatisation des recettes fonctionnelles n'est qu'un bonus**
: Automatiser des recettes fonctionnelles n'a de sens uniquement si au préalable
vous avez réussi à faire comprendre votre besoin. Sans dialogue ni
échanges, les tests automatisés testeront que l'application fait bien
quelque chose, mais pas forcément ce que vous attendez.
6) **L'automatisation des tests techniques est primordiale**
: Laissez le temps aux équipes techniques et poussez-les à écrire des
tests automatisés de code source (test unitaire). C'est le seul moyen
pour eux de réaliser vos demandes légitimes de changements sans faire
exploser vos coûts.
7) **KISS : Keep It Simple and Stupid**
: Gardez vos scénarios simples et explicites, et n'employez pas dix mots
quand cinq suffisent. Si votre scénario est long, c'est probablement
qu'il recouvre un domaine fonctionnel trop large : découpez-le.
8) **Soyez conscient que vos scénarios changeront**
: En confrontant régulièrement votre Produit aux avis des utilisateurs,
une grande partie de vos scénarios va changer, voire disparaître.
Acceptez-le, et faites en sorte que les équipes techniques l'acceptent
en les faisant participer à ce processus de changement.
9) **Utilisez des exemples**
: Vous ne rédigez pas des tests d'acceptation, mais établissez une
communication pour décrire votre besoin. Illustrez votre besoin par des
exemples, pourquoi pas avec humour, pour effacer toute ambiguïté.  
10) **Le Développement piloté par le Comportement n'est pas une recette miracle**
: La recette miracle n'existe pas. Mais c'est au moins un bonne démarche,
éprouvée, pour vous faire comprendre et faciliter la communication entre
fonctionnels et techniques. Elle aidera chacun des acteurs de votre
projet à comprendre son rôle et ce que vous attendez de lui ; il ne
reste plus à chacun qu'à être un bon acteur.

View file

@ -0,0 +1,351 @@
# Exprimez votre besoin
## Tous la même grammaire
Les spécifications classiques, on l'a vu, échouent souvent : elles
acceptent mal le changement, sont souvent lourdes et ne concernent pas
toujours que le besoin métier.
Pour remédier à cela, il est possible d'utiliser une autre approche,
celle préconisée par le Développement Piloté par le Comportement.
"Quel terme barbare !" me direz-vous. C'est vrai. Mais, en fait, rien de
technique ou de geek derrière ce terme. C'est simplement une démarche
qui consiste à communiquer avec vos développeurs d'une autre manière, de
sorte qu'il vous comprennent.
C'est cette démarche que je vous propose de découvrir à partir de
maintenant.
Cette approche a au moins trois avantages :
+ L'écrit sert à la fois à spécifier et à échanger avec les équipes
+ Le changement est mieux géré
+ Vous savez à tout instant ce qui est fait et ce qu'il reste à faire
Pour au moins un inconvénient :
+ L'investissement et la disponibilité du Propriétaire du Produit doivent
être importants
Cette approche se base sur la rédaction des spécifications sous un
formalisme différent, dénommé généralement Gherkin. Ce formalisme n'est
pas obligatoire, mais il a été prouvé à plusieurs reprises qu'il est
pratique et répond bien aux problématiques que vous rencontrerez
probablement.
Si vous souhaitez faire du Développement Piloté par le Comportement
(Behaviour Driven Development en anglais, ou BDD), chaque acteur de
votre projet doit apprendre à lire et à comprendre ce formalisme. Pas de
panique, le coût d'apprentissage est quasi nul ; c'est justement l'un
des nombreux atouts de Gherkin.
## Décrivez vos Fonctionnalités métiers
Vous avez votre Vision du Produit, il est temps d'expliquer ce que vous
attendez aux développeurs.
Rien de plus simple : commencez par identifier les aspects fonctionnels
que vous souhaitez qu'ils développent, et ce en les décrivant avec une
courte phrase. Juste une phrase, courte, pas plus. Cette phrase sera le
titre de votre fonctionnalité.
**Chaque fonctionnalité doit pouvoir se distinguer des autres par son
titre**. Prenez les fonctionnalités suivantes :
[gherkin]
# Distinguez vos fonctionnalités en leur donnant un titre :
Fonctionnalité : Retirer de largent au distributeur
Fonctionnalité : Consulter le solde de son compte au distributeur
Il est facile de les distinguer et de les comprendre non ?
Identifier clairement ces fonctionnalités est important : cela vous
permettra de les prioriser plus facilement.
Bon, vous allez me dire qu'une petite phrase de rien du tout ça laisse la
place à beaucoup d'ambiguïtés ; et vous aurez bien raison !
Vous le savez, un Produit n'est rien sans un utilisateur pour
l'utiliser. **Précisez donc qui est l'utilisateur de votre
fonctionnalité** :
[gherkin]
# Précisez qui est lacteur bénéficiaire de votre fonctionnalité :
En tant que rôle
En tant que administrateur du site
En tant que conseiller clientèle
En tant que ...
Voilà une bonne chose de faite ! **Identifiez maintenant le Service
rendu par votre fonctionnalité**. Je conseille toujours de voir le
service comme ni plus ni moins que ce que votre commercial entend lorsqu'il
dit "c'est génial, en tant que ... vous pouvez faire ça !". Par exemple
:
[gherkin]
# Identifiez le service délivré par votre fonctionnalité à lutilisateur :
Je peux un service rendu
Je peux retirer de largent au distributeur
Je peux connaître la quantité dargent quil me reste sur mon compte
Je peux ...
On commence déjà à y voir plus clair. **Il ne reste plus qu'à préciser
le bénéfice métier** de votre fonctionnalité. Car oui, une
fonctionnalité sans bénéfice pour l'utilisateur ne sert à rien. Si vous
ne voyez pas de bénéfice pour votre fonctionnalité, c'est sans doute qu'elle ne
mérite pas d'être développée. Décrivez ce bénéfice ainsi :
[gherkin]
# Décrivez le bénéfice fonctionnel obtenu par votre fonctionnalité :
De telle sorte que bénéfice attendu
De telle sorte que je puisse obtenir de largent même quand la banque est fermée
De telle sorte que ...
Ce qui fait que **toute fonctionnalité peut être décrite, de manière
explicite, en quatre courtes lignes** :
[gherkin]
Fonctionnalité : Retirer de largent au distributeur
En tant que client de la banque
Je peux retirer de largent au distributeur
De telle sorte que je puisse obtenir de largent même quand la banque est fermée
N'importe quel membre de votre équipe comprendra ce qu'est cette
fonctionnalité. Faites attention à n'employer que le vocabulaire de votre
Langue Commune pour éviter toute ambiguïté.
## Des scénarios pour vos fonctionnalités
Un titre, un rôle, le service rendu et le bénéfice métier c'est déjà pas
mal. Mais en général ça ne va pas suffire : vous pouvez avoir envie
d'illustrer vos fonctionnalités.
C'est le rôle des scénarios. **Chaque fonctionnalité peut contenir un
ensemble de scénarios. Ces scénarios doivent tous être clairs, uniques
et explicites**. Ils représentent le comportement concret que vous
attendez pour votre fonctionnalité. Par exemple :
[gherkin]
# Un Scénario est une situation concrète de votre Fonctionnalité :
Fonctionnalité : Retirer de largent au distributeur
Scénario : Retirer de largent avec une carte valide
Scénario : Retirer de largent avec une carte expirée
Scénario : Retirer de largent sur un distributeur qui ne contient
plus dargent
Scénario : ...
La réalisation (ou non) dans votre application de ces scénarios détermine l'avancée de votre
fonctionnalité.
Il est possible que ces scénarios évoluent : certains seront réalisés
tôt, d'autres seront réalisés plus tard ou seront modifiés... Dans tous
les cas, **jeter un oeil à l'avancée de ces scénarios vous permettra de
maîtriser l'avancée de votre fonctionnalité**.
Vous vous en doutez, il peut arriver qu'une simple phrase ne suffise pas
à décrire avec précision un scénario. Il sera alors temps d'y introduire
un contexte, un événement déclencheur ou un résultat attendu.
Le contexte du scénario est introduit par l'expression "étant donné". Il situe les
conditions d'existence de votre scénario :
[gherkin]
# Un Scénario sinscrit dans un contexte, une situation initiale :
Scénario : ...
Etant donné que tel contexte existe
Etant donné que que je nai plus dargent sur mon compte
Etant donné que ma carte est expirée
Etant donné que ...
Toute interaction de l'utilisateur avec votre produit peut se traduire
sous forme d'événement. Un événement est le déclencheur de votre
scénario, qui vient juste après que le contexte initial soit situé :
[gherkin]
# Un Scénario se démarque par un événement :
Scénario : ...
...
Quand tel événement déclencheur survient
Quand je demande à retirer de largent
Quand je demande le solde de mon compte
Quand ...
Si chaque action a une conséquence, il en va de même pour les événements :
chaque événement attend un résultat, exprimé par l'expression "alors" :
[gherkin]
# Chaque Scénario aboutit à un résultat :
Scénario : ...
...
Alors tel résultat est attendu
Alors je reçois 20 euros
Alors ma carte est aspirée
Alors ...
Toute cette syntaxe, qui permet de rendre vos fonctionnalités
explicites, sera comprise par vos développeurs. Et en plus elle n'est
pas très compliquée, si ?
Au final, voici une fonctionnalité plus complète :
[gherkin]
# Toute personne qui connaître votre Langue Commune comprend
# votre fonctionnalité :
Fonctionnalité : Retirer de largent au distributeur
En tant que client de la banque
Je peux retirer de largent au distributeur
De telle sorte que je puisse obtenir de largent
même quand la banque est fermée
Scénario : Retirer de largent avec une carte valide et un
compte approvisionné
Etant donné que je détiens un compte bancaire soldé de 100 euros
Et que ma carte expire lan prochain
Quand je demande à retirer 20 euros
Alors je reçois 20 euros
Et ma carte mest restituée
Scénario : Retirer de largent avec une carte expirée
Etant donné que ma carte est expirée
Quand je demande à retirer 20 euros
Alors ma carte est aspirée
## Illustrez le tout avec des exemples
Ce formalisme est utile. Il n'est en aucun cas obligatoire bien entendu,
mais il a démontré son efficacité, et a l'énorme avantage d'être **clair
tout autant pour les fonctionnels que pour les développeurs.**
Maintenant, ce formalisme peut manquer de concret. Qu'à cela ne tienne,
vous pouvez y ajouter vos exemples. Car on est bien d'accords, **rien de
mieux que des exemples**. Prenons celui-ci :
[gherkin]
# Votre fonctionnalité peut contenir un exemple :
Scénario : Retirer de largent avec un compte approvisionné
Etant donné que ma carte expire lan prochain
Quand je demande à retirer "20" euros
Alors je reçois "20" euros
Bon, c'est simple, mais limité, car cela nous oblige à recopier le
scénario autant de fois que nous avons d'exemples. Heureusement, notre
grammaire est riche, et vous pouvez utiliser la syntaxe suivante (votre
scénario devient alors un Plan du scénario) : 
[gherkin]
# Votre fonctionnalité peut contenir plusieurs exemples facilement :
Plan du Scénario : Retirer de largent avec un compte approvisionné
Etant donné que ma carte expire lan prochain
Quand je demande à retirer "<montant-demandé>" euros
Alors je reçois "<montant-reçu>" euros
Exemples :
| montant-demandé | montant-reçu |
| 20 | 20 |
| 1000 | 1000 |
| 50 | 50 |
Pratique non ? Les symboles < et \> indiquent une valeur d'exemple, à
rechercher dans le tableau juste en dessous.
Le tableau est dessiné grâce au caractère "pipe". Si vous ne savez pas le situer
sur votre clavier, il suffit de taper `Alt Gr" + 6`, ou `Alt + Maj + L` si vous
utilisez un Mac. Rassurez-vous, comme vous le verrez par la suite, il existe des
outils graphiques pour vous faciliter la vie.
## Travaillez en équipe
Vous êtes maître de votre Produit, et c'est vous qui décidez de vos
Fonctionnalités. Par contre, n'oubliez pas que **le dialogue et
l'échange sont primordiaux pour éviter les ambiguïtés dans votre
projet**.
Lorsque vous allez rédiger vos scénarios, voici ce qui risque de se
passer :
+ Vous allez devoir les expliquer à votre équipe technique lorsque vous les leur fournirez
+ Vous n'allez peut-être pas penser à tout, et vos équipes devront vous solliciter très (trop) régulièrement pour des aspects que vous aurez oubliés
+ Certains de vos scénarios ne seront pas clairs ou n'emploieront pas le vocabulaire de la Langue Commune (on a toujours tendance à se trouver soi-même très clair ; ce n'est pas toujours vrai...)
+ L'équipe risque de ne pas se sentir suffisamment impliquée
Ces écueils ne sont bien sûr pas systématiques, mais le risque est là.
Pourquoi prendre ce risque alors que la solution est simple ?
Il suffit en effet de faire participer toutes les équipes lors de la
rédaction des scénarios. Attention, il ne s'agit pas de laisser
n'importe qui faire n'importe quoi... Non, **c'est à vous d'expliquer
votre besoin**, dans la Langue Commune, et **ensuite vous allez ensemble
le traduire en scénarios**, de telle sorte que tous comprennent
clairement ce que vous attendez d'eux.
Pour résumer, écoutez les remarques de vos équipes lors de la rédaction
des scénarios. Idéalement, vous devriez entendre des "oui mais qu'est-ce
qui se passe si..." et "je ne comprend ce que devient...". Si c'est le
cas, le pari est réussi !
Dans tous les cas, gardez vos scénarios clairs et concis. Personne n'a
envie de lire des scénarios de 20 ou 30 lignes...
> "Ecrivez vos scénarios avec l'équipe technique ; le temps passé sera
compensé par le gain de compréhension et l'inutilité d'avoir à faire des
va-et-vient incessants au cours du développement"
## Des assistants visuels
Vous aviez déjà le vocabulaire (la Langue Commune), vous voici désormais
avec la grammaire nécessaire pour exprimer votre besoin. Mais on est
tous les mêmes : personne n'aime pas la grammaire !
Après tout, si votre véritable objectif est de vous focaliser sur
l'expression de votre besoin, sur la description du comportement de
votre Produit, à quoi bon se concentrer sur la manière de l'exprimer ?
Pour vous simplifier la vie il existe un certain nombre d'outils qui
vont vous assister dans la  rédaction de vos Fonctionnalités. Ils vont
vous permettre de rédiger vos features selon une approche plus agréable,
tandis même qu'ils vont présenter à vos développeurs votre besoin sous
forme de fichiers clairs qu'ils pourront directement exploiter.
![ Il existe des assistants visuels pour faciliter votre expression de besoin ](behat-wizard-edit.jpg)
Il existe plusieurs outils, qui ont tous leurs avantages. On peut penser
par exemple à BehatViewer, ou à BehatWizard... N'hésitez pas à demander
vos équipes techniques de vous installer ces outils.

View file

@ -0,0 +1,150 @@
# Impliquez les parties prenantes
## Un projet est comme un Film
Drôle de titre, n'est-ce pas ? Pourtant on peut le dire, un projet
informatique, c'est un peu comme un film : on peut prendre plaisir à le
tourner, y apprendre des choses, mais l'essentiel reste que ce film voit
le jour.
Faisons un jeu : quel est le point commun à tous les films, films
d'animation, court-métrages ? Tic-tac, tic-tac... Driiing ! Réponse :
ils ont tous un générique, c'est à dire une liste des différentes
personnes qui y ont travaillé, classées par rôle.
Et bien dans un projet informatique c'est pareil, il existe des rôles.
Il peut arriver que certaines personnes aient plusieurs rôles, selon la
taille du projet, mais il est indispensable de définir les domaines de
compétence nécessaires à la bonne tenue de votre projet.
En général, voici les rôles qui seront associés à votre projet :
1. Le **Propriétaire du produit** :
Personne qui fournit la Vision du produit. Est souvent celui qui finance
le projet.
2. Les **Alliés du produit** :
Personnes qui soutiennent et aident fonctionnellement le Propriétaire du
produit. Elles peuvent avoir un impact sur le Produit
3. Les **Analystes fonctionnels** :
Personnes qui déterminent les solutions fonctionnelles à apporter pour
répondre à la Vision du Propriétaire dur Produit
4. Les **Ergonomes** :
Personnes qui déterminent l'ergonomie la plus adaptée pour mettre en
place les solutions fonctionnelles auprès des utilisateurs ciblés par le
Produit
5. Les **Graphistes** :
Personnes en charge d'améliorer l'aspect visuel ou d'appliquer des
solutions proposées par les Ergonomes
6. Les **Testeurs** :
Personnes en charge de la recette applicative de premier niveau
7. Les **Développeurs** :
Personnes en charges de l'implémentation technique des solutions
proposées par les Analystes fonctionnels
Bien, ça, c'est dit. Bien entendu, il est fréquent que certains de ces
rôles se chevauchent, le plus souvent pour des raisons de coût ou de ressources :
l'ergonome est graphiste, l'analyste fonctionnel est propriétaire du
produit, etc.
Dans tous les cas, ces rôles doivent dialoguer entre eux, puisque chacun
a son rôle à jouer dans la réalisation du Produit. Gardez ce découpage
en tête, il est important pour la suite.
> Les Partie-prenantes sont au Produit ce que les acteurs sont au Film :
chacun joue un rôle différent, mais tous mettent en scène la Vision de
ce qu'ils produisent
## Devenez spectateur un instant
Votre produit est destiné à être vendu, que ce soit financièrement
auprès de vos clients, ou commercialement auprès de vos utilisateurs. En
général, c'est vous qui présenterez votre Produit, par le biais de
réunions commerciales, de plaquettes publicitaires, ou que sais-je
encore.
Mais avez-vous pensé à laisser vos développeurs faire cette présentation
? Pas de panique, **je ne vous parle pas d'envoyer un geek barbu auprès
de vos prospects et investisseurs**, non. Non, je vous propose de
laisser vos développeurs vous faire une présentation à vous, le
propriétaire du produit.
L'idée est la suivante : on l'a vu, il est plus pratique de travailler
par itérations successives pour votre projet. À la fin de chaque
itération, vos collaborateurs doivent être capables de vous fournir une
version exploitable de votre produit. **Pourquoi dans ce cas ne vous
feraient-ils pas la démonstration de ce qu'ils ont à vous livrer ?**
C'est assez classique dans les préceptes agiles : à la fin de chaque
cycle l'équipe technique va vous présenter ce qu'elle vous propose, et
ce pour différentes raisons :
+ cela vous permet de valider votre demande initiale
+ cela permet d'impliquer l'équipe technique dans la bonne marche fonctionnelle de votre produit
+ cela permet aux acteurs de votre projet d'éprouver régulièrement de la satisfaction personnelle en réussissant à vous livrer dans les temps quelque chose qui fonctionne
Une simple présentation d'une heure, pourquoi pas un vendredi sur deux,
par l'équipe technique, vous permet donc d'impliquer dans votre projet
les plus réfractaires : les développeurs. Pourquoi ne pas l'adopter ?
Bien entendu, encore une fois, ce n'est pas une recette miracle. Mais
l'accumulation des ces instants d'échange et de dialogue ne peut que
faciliter votre projet.
> Laissez l'équipe technique vous faire une démonstration à chaque
cycle.
## Tous les acteurs ont des bonnes idées
Un film, c'est avant tout un réalisateur, qui insuffle l'âme du film, sa
Vision. Pourtant il est très fréquent que de bonnes idées proviennent
d'acteurs : des improvisations, des échanges, des contestations, des
propositions... 
Les bonnes idées peuvent venir de partout. Qu'elles soient
fonctionnelles, ergonomiques, esthétiques... vous devez écouter ces
idées, les assimiler et, si certaines vous semblent pertinentes et en
accord avec votre vision, les implémenter.
Après tout, votre spécialité c'est la connaissance du domaine
fonctionnel. Votre produit peut répondre à un besoin de bien des
manières, et même d'une façon que vous n'avez pas encore imaginée.
Vos développeurs ne connaissent pas à la base votre besoin fonctionnel,
mais leur métier les amène à observer et comprendre une multitude de
manières de répondre à un problème. Chaque site internet qu'ils visitent
répond à une problématique, chaque site a une approche différente des
problèmes, et eux-mêmes sont utilisateurs de produits. 
Restez maître de votre Produit, mais, après tout, ce qui compte c'est de
rendre service, au mieux, à vos utilisateurs. Prenez les bonnes idées là
où elles sont...
> Imprégnez vos développeurs de votre besoin pour leur laisser l'occasion de trouver de bonnes idées

View file

@ -0,0 +1,56 @@
# Mettez toutes les chances de votre côté
Imaginez : voilà un bon père de famille qui se décide, enfin, a changer
sa vieille voiture. Bien décidé à investir dans du neuf, il se rend chez
le concessionnaire du coin, et explique ce qu'il veut... oh, rien de
bien compliqué : il doit pouvoir aller faire ses courses, partir en
vacances de temps en temps, et, ah si, aller au travail tous les jours.
"Pas de problème, je vous livre votre nouvelle voiture dans deux
semaines" répond le concessionnaire. 
Trois semaines plus tard ("ah oui, désolé il y a eu un peu de retard,
mais c'est normal" le rassure le concessionnaire), une petite surprise
attend notre père de famille : ce n'est pas la voiture familiale qu'il
espérait, mais une camionnette, 12m cube, 45 000 € ("on a rencontré des
difficultés imprévues"), 2m10 de haut (la porte de son garage mesure
1m90, mais le concessionnaire est convaincu que "c'est quand même plus
pratique d'avoir une bonne hauteur de coffre. Ah, et je vous ai même
ajouté un volant de course, le top du top !"). 
Pas très agréable, non ? Ce n'est pas du tout ce que notre père de
famille souhaitait ! Pourtant... Pourtant il peut faire ses courses,
partir en vacances... Tout ce qu'il a demandé au concessionnaire est là.
Le concessionnaire était plein de bonne volonté, il a fait son maximum
pour satisfaire son client, a fait de son mieux, l'a écouté, a tenté d'y
mettre du sien et d'ajouter des options qu'il pense indispensables ou
confortables. On ne va pas l'en blâmer !
Imaginez ça maintenant : **ce père (ou mère) de famille, c'est VOUS** !
Oui, c'est bel et bien vous, vous qui souhaitez concevoir un produit
informatique, un logiciel, un intranet, une application mobile... Vous
voilà parti avec une superbe idée, rentable, révolutionnaire !  Et vous
vous retrouvez finalement avec un produit coûteux, livré en retard,
voire parfois totalement inadapté au marché !
Allez-vous vous en prendre au développeur ? A la société qui a conçu
votre produit ? Au prestataire de service ? N'est-ce pas plutôt un
problème plus général de communication ? Après tout, chacun est
convaincu d'avoir fait de son mieux... N'y avait-il pas un moyen de
faire mieux ? De mieux faire comprendre votre besoin ? De mieux vous
préparer aux éventuels retard, de les limiter ? De réorienter votre
demande en cours de route ?
C'est justement l'objet de ce livre. Bien évidemment, ce livre ne va pas
vous offrir un moyen magique de réussir un projet informatique. Non, ça
n'existe pas, il n'y a jamais de *silver bullet*. Rien n'est magique :
**c'est à vous, et à vous seul, de faire réussir vos projets
informatiques**. Par contre, ce livre peut peut-être vous donner
quelques pistes de réflexion, afin de mettre plus de chances de votre
côté.

View file

@ -0,0 +1,309 @@
# Le besoin métier
## Ayez une vision de votre produit
Votre idée est peut-être géniale, révolutionnaire, utile ou juste
rentable (aucun mal à cela). Elle va peut-être changer le monde, ou plus
modestement faciliter le quotidien de pas mal de monde. 
Pensez au premier téléphone portable : en voilà un produit qui a changé
bien des choses; impossible aujourd'hui d'imaginer vivre sans : sans
accès à votre boîte mail, sans appareil photo, sans sms, sans carnet de
contacts... Mais, attendez, le premier téléphone, il ne faisait pas tout
ça ! Non, rappelez-vous, un téléphone portable, à la base, ça sert à
pouvoir téléphoner n'importe où. 
Tout le reste, c'est utile, pratique, génial, sans doute indispensable
au quotidien, bref, c'est tout autant révolutionnaire. Mais si on doit
définir le téléphone portable en quelques mots, c'est "juste" un moyen
d'échanger vocalement et instantanément de l'information entre deux
intervenants, où qu'ils soient dans le monde.
Votre produit est pareil : **il doit pouvoir se définir en une courte
phrase**, et en réalité ne sert qu'à une chose. Si si, tout le reste est
utile commercialement, esthétiquement, fonctionnellement... Mais votre
produit possède un coeur, et la première chose à faire est de
l'identifier.
Cela vous permettra de savoir vraiment ce dont vous avez besoin. Si vous
demandez au père de famille, dont nous parlions plus haut, de décrire sa
voiture, il va peut-être dire qu'il veut un break Citroen de 120 chevaux
gris métallisé, avec 5 portes. Il sait ce qu'il veut... Pourtant il
oublie l'essentiel : la voiture doit lui permettre de se rendre d'un
point A à un point B.
Oui, c'est évident : une voiture permet de se déplacer. Mais pourtant,
évident ou pas, une voiture, ce n'est rien d'autre ; c'est ce qui reste
une fois qu'on a enlevé tout le reste : retirez la climatisation, la
peinture métallisée, le cuir... Il nous reste le coeur de la voiture, ni
plus ni moyen qu'un moyen de locomotion.
Allez même plus loin, et imaginez une voiture sans moteur ; est-ce
toujours une voiture ? Oui, sans aucun doute, le moteur n'est qu'un
moyen pour cette fin, ultime, de permettre aux gens de se déplacer : une
voiture à cheval n'en reste pas moins une voiture. Certes, elle n'est
peut-être pas optimale, pas rapide, pas jolie, tout ce que vous
voudrez... Mais C'EST UNE VOITURE. Et peut-être moins cher en plus !
Pour votre logiciel, votre intranet, votre application mobile, c'est
pareil : **identifiez le coeur de votre produit, ce qui fait son essence
même, ce sans quoi votre produit n'est plus votre produit, et là vous
aurez de bonnes bases pour commencer**.
Comme le dit Liz Keogh, **chaque projet informatique doit poursuivre une
vision**. Cette vision répond souvent à un besoin économique (réduire
des coûts, améliorer la productivité), voire parfois à des souhaits
différents (améliorer le quotidien des gens, changer les mentalités...).
Dans tous les cas, tout ce que vous allez mettre dans votre produit doit
poursuivre cette vision.
> Tout ce que vous mettez dans votre produit doit poursuivre une
vision
## Le bon produit est celui qui répond à votre vision
Quand ils ont conçu Basecamp, un logiciel de gestion de projets
aujourd'hui reconnu et plébiscité, Jason Fried et David Heinemer avaient
une vision : faciliter la vie des différents intervenants lors de leurs
créations de projets. Cette vision est visible partout dans Basecamp :
simple, facile d'accès, rapide et ergonomique, il facilite réellement la
vie de celui qui l'utilise.
Ils auraient pu choisir de concevoir un logiciel riche, multi-fonction
et polyvalent ; ils ne l'ont pas fait. Pourquoi ? Tout simplement parce
que cela n'aurait pas servi leur vision. On pourrait vouloir un CRM dans
Basecamp, ou un intranet, ou tout ce que vous voudrez. Tous ces modules
pourraient être forts agréables, utiles et d'excellents arguments
commerciaux. Mais ils ne servent pas la vision du produit. Et c'est
justement pour ça que Basecamp plaît autant : il ne fait qu'une chose,
mais il le fait bien !
Pensez également à ceci : certes Basecamp n'est pas riche
fonctionnellement, mais
+ Il est largement suffisant dans 90% des cas
+ Il a été d'autant moins coûteux à concevoir
+ Il a été d'autant plus rapide à développer
+ Chaque fonctionnalité a pu être testée en profondeur et est fiable
+ Il ne souffre d'aucune complexité inutile et est rapide
+ Les équipes de développement se sont focalisés sur un domaine fonctionnel simple
+ Tout changement ou évolution est simple à mettre en place
Tout cela serait impossible si Jason Fried et David Heinemer ne
s'étaient pas focalisés sur leur vision du produit et n'avaient pas
refusé systématiquement d'ajouter des fonctionnalités qui ne répondent
pas à cette vision initiale.
Rappelez-vous : vous êtes le seul maître à bord. C'est à vous de vous
servir de votre vision du produit pour limiter le superflu et focaliser
toute l'énergie disponible (développeurs, serveurs, graphistes,
ergonomes...) sur ce qui répond à cette vision, autrement dit sur ce qui
est vraiment utile.
> Retirez de votre Produit tout ce qui ne sert pas votre Vision
## Vous attendez des résultats métiers
Vous avez probablement souvent entendu cette expression : ce qui compte,
ce sont les résultats ! 
Bon, je ne vais pas vous dire que la fin justifie les moyens, pas du
tout. Non, ce que je veux dire, c'est qu'en investissant du temps et de
l'argent dans votre projet, vous ne devez jamais oublier que ce qui
compte ce sont les résultats métiers (ou fonctionnels) de votre projet.
Ces résultats qui justement servent votre vision.
Pensez-y : chaque fonctionnalité, chaque élément d'interface, chaque
bouton, chaque champ de saisie... tout cela doit fournir un bénéfice à
l'utilisateur de votre produit ! 
Ça peut paraître évident... Mais alors pourquoi consacrer autant
d'énergie sur des choses inutiles fonctionnellement ? Si si, ça arrive
tout le temps ! En tant que développeur j'ai souvent eu l'occasion de le
voir : une grosse partie de mon temps était consacré à du superflu
(gestion des profils utilisateurs hyper poussée, interfaces graphique à
la iGoogle, optimisation prématurée des performances...), alors même que
les fonctionnalités métier n'étaient pas encore finies, voire même pas
spécifiées !
L'énergie dépensée sur un projet doit être corrélée aux bénéfices que
votre produit en tirera pour satisfaire votre vision. Si, alors que les
fonctionnalités métiers ne sont pas pleinement finies, testées, fiables,
éprouvées et ouvertes aux changements, l'énergie dépensée ne sert qu'à
"vendre du rêve", vous risquez la catastrophe. 
Concevez votre produit, non pas pour le vendre, mais pour qu'il réponde
à un but (votre vision). Si vous y arrivez, vous aurez à ce moment là en
main les meilleurs atouts pour le vendre.
Le bénéfice sera d'autant plus grand que, au lieu de perdre du temps sur
des choses moins utiles, vos développeurs, prestataires ou la société
qui a en charge votre projet, vont mieux comprendre votre besoin, sans se
perdre en détails inutiles pour le moment.
En vous focalisant sur les fonctionnalités métiers, vous allez aussi
pouvoir plus rapidement vous confronter au feedback de vos futurs
utilisateurs. Les changements fonctionnels de votre produit seront ainsi
réalisés plus tôt, et donc moins coûteux.
> Ne concevez pas votre produit pour le vendre, mais pour qu'il réponde
à un but. Vous aurez alors en main les meilleurs atouts pour le vendre
## Re-priorisez souvent, changez souvent
Vous l'avez vu : votre produit doit se focaliser sur ce qui apporte à un
métier, sur ce qui répond à votre vision. 
C'est bien beau, mais on en est tous conscients : un aspect métier peut
être essentiel aujourd'hui, mais totalement inutile ou différent demain
! Comment gérer ces changements dans votre projet ?
Vous vous en doutez, de nombreuses personnes ont tenté de répondre à
cette question. Parmi elles, les (nombreux) auteurs du Manifeste Agile.
Voici certains des principes de ce Manifeste tel qu'ils sont présentés
sur  [http://agilemanifesto.org](agilemanifesto.org), qui nous
intéressent particulièrement :
> "Notre plus haute priorité est de satisfaire le client
> en livrant rapidement et régulièrement des fonctionnalités
> à grande valeur ajoutée.
>
> Accueillez positivement les changements de besoins,
> même tard dans le projet. Les processus Agiles
> exploitent le changement pour donner un avantage
> compétitif au client.
>
> Livrez fréquemment un logiciel opérationnel avec des
> cycles de quelques semaines à quelques mois et une
> préférence pour les plus courts."
C'est assez clair : si l'on suit ces principes, largement reconnus
aujourd'hui dans le monde de l'édition logicielle, **le produit doit
être confronté le plus tôt possible au monde réel pour obtenir un
feedback régulier des potentiels utilisateurs**.
Ce feedback régulier va vous permettre de réorienter votre produit afin
de supprimer, modifier ou ajouter des comportements dans celui-ci. Vous
avez donc besoin de pouvoir re-prioriser certains éléments, de changer
en cours de route le parcours de développement de votre site, logiciel,
application ou intranet. 
En un mot : vous avez besoin de confronter votre produit aux
utilisateurs. Plus vous le confronterez souvent, plus votre produit sera
compétitif, et plus vous aurez besoin de faire évoluer votre produit.
Vous l'avez compris : vous avez besoin de changements tout au long de la
phase de conception de votre produit. Cependant, vous l'avez sans doute
déjà vécu, **tout changement dans un produit informatique est
généralement :**
+ long
+ coûteux
+ source d'erreurs et de bugs
+ difficile et démoralisant pour les équipes
L'idée pour résoudre ces difficultés est assez simple, mais parfois
difficile à mettre en place, comme nous allons le voir. 
> Vous devez trouver une solution pour faciliter le changement
## Gérez votre besoin de changements
L'idée du Manifeste Agile pour gérer le changement peut paraître simple
parce qu'il "suffit" (entre autres) de modifier les cycles de
développement de votre produit. Généralement, un produit est conçu d'un
seul bloc : on développe un produit non fini pendant une période assez
longue, et on livre un produit fini (enfin, ça c'est qu'on espère !) à
la fin. Cette méthode implique un effet tunnel assez long et souvent
dévastateur. 
Qui ne connaît pas le célèbre tableau de Léonard de Vinci : La Joconde ?
Que se serait-il passé si Léonard de Vinci avait dû peindre Mona Lisa
comme on travaille généralement sur un projet informatique ? Cela
donnerait à peu près ceci :
![ Méthodologie classique : le travail et découpé en lots, chaque lot est totalement réalisé avant de passer à la suite. Le changement fonctionnel en cours de route est difficile. ]
(mona-lisa-incremential.jpg)
Le travail est tout de suite très fin, et on ne peut le livrer qu'à la
fin... Difficile dans ces conditions d'accepter le changement !
Maintenant examinez la méthode proposée par les fondateurs du Manifeste
Agile. Les équipes techniques vont travailler en cycles, itérativement,
de manière à livrer régulièrement un produit, certes moins complet, mais
exploitable et sur lequel il est possible de fournir un feedback.
Le rythme de ces itérations, et leurs objectifs, sont fixés en accord
avec tous (équipes techniques, fonctionnels...), et chacun s'engage à
faire le maximum pour livrer un produit exploitable. Voici ce que cela
donnerait cette fois-ci pour notre cher Léonard :
![ Méthodologie agile : le tableau s'affine petit à petit. Le changement fonctionnel est facile, même en cours de route]
(mona-lisa-iterative.jpg)
Bien sûr, un logiciel qui prendra un an à être développé ne sera pas
exploitable commercialement au bout de trois itérations de deux semaines
! Par contre vous aurez moyen d'obtenir des premiers retours
utilisateurs, et surtout vous allez pouvoir reprioriser et changer
certains éléments en cours de route : la forme du visage ne vous
convient pas ? Faites la changer lors d'une prochaine itération ! Les
couleurs sont trop ternes ? Priorisez un changement des couleurs pour
voir ce qu'en pensent vos futurs utilisateurs. Bref, vous avez compris
l'idée !
Les principes agiles sont simples et évidents, mais ils peuvent être
étrangement contre-intuitifs à mettre en place : souvent, les équipes
(techniques et fonctionnels) ont du mal à se détacher de leurs anciennes
pratiques, quant bien même elles adhèrent aux concepts agiles.
J'ai à plusieurs reprises eu l'occasion de voir des entreprises adopter
des méthodologies agiles trop brusquement, ou d'une manière inadaptée.
Les méthodes agiles ne sont pas un remède miracle à tous les maux, il
serait faux de croire que du jour au lendemain des équipes peuvent
oublier toutes leurs anciennes pratiques et que par magie vous serez
livré à temps et avec un produit fini.
Mais le changement vers l'agilité peut être simple et rapide, sous deux
conditions : 
+ **vous DEVEZ vous impliquer dans votre projet !** C'est à vous de prioriser, de dire ce qui va, ne va pas, régulièrement.
+ Vous devez accepter de vous faire aider : **les changements à adopter ne sont pas que méthodologiques, ils sont aussi conceptuels**. De nombreuses sociétés agiles sauront vous guider et vous conseiller. Et croyez moi, l'investissement en vaut la peine, largement !
> Itération, feedback; itération, feedback; itération ...

View file

@ -0,0 +1,110 @@
# Recette et maintenabilité
## Chaque recette fonctionnelle peut être automatisée
La démarche et la syntaxe du Développement piloté a l'avantage d'être
claire et de faciliter la communication.
J'ai une excellente nouvelle pour vous : **cette syntaxe va vous
permettre d'automatiser la recette de votre application**. Vraiment !
Et je ne vous parle pas d'outils, si vous en avez déjà utilisé, qui
vont enregistrer puis reproduire les clics et saisies que vous faites
sur une page web (comme avec [Selenium](seleniumhq.org/...)). Non, surtout pas !
Je vous parle d'outils pour lesquels vous n'avez rien à faire...
Après tout, **si vous avez fait l'effort de respecter une syntaxe
spécifique pour décrire vos Scénario, un programme informatique doit
être capable de les interpréter**.
Il existe aujourd'hui deux principaux outils sur le marché : Cucumber et
Behat. Le choix de l'outil dépendra du socle technique choisi par vos
développeurs pour votre Projet.
Concrètement, ces outils vont transformer vos Scénarios en code
informatique. Ce code informatique sera adapté par vos développeurs qui
lui donneront un sens et s'assureront qu'il signifie bien ce que vous
avez demandé.
Par la suite vous disposerez d'une interface où chaque fonctionnalité,
chaque scénario et chaque étape seront, ou bien verte (terminée), ou bien
jaune (pas encore développé), ou bien rouge (ne répond pas au besoin
initial).
![ Retrouvez toutes vos fonctionnalités au sein d'une même interface. ](behat-wizard-home.jpg)
Utiliser de tels outils a un coût puisqu'il exige un travail de
traduction par l'équipe technique. Ce coût peut être important, cela
peut demander du temps non négligeable, en plus d'une montée en
compétence des équipes techniques (très rapide en général),
Cependant, en utilisant ces outils :
+ Les équipes techniques savent si oui ou non elles ont répondu au besoin
+ Les équipes techniques sont rassurées dans leur travail
+ Vous connaissez exactement l'avancée de votre projet
+ Vous pouvez sans risque gérer votre besoin de changement : si une autre fonctionnalité est "cassée" par ce changement, vous le savez tout de suite et pouvez agir en conséquent
+ Vous augmentez le niveau de qualité de votre projet. C'est autant de gains lors de la vie du Produit et de sa maintenance, qui sans cela peut être très coûteuse
+ Vous-même savez en un instant si le livrable est conforme à vos attentes
Rien ne vous oblige à utiliser ces composants d'automatisation de
recette. Ne pas les utiliser peut certes être dommage, mais n'enlève
rien à la démarche générale.
>Facilitez le changement en automatisant la recette fonctionnel
## Assurez-vous que les équipes techniques automatisent leurs recettes techniques
Tester automatiquement qu'un livrable correspond à vos **attentes**
fonctionnelles c'est bien ; mais être certain de la **fiabilité** de
votre produit c'est encore mieux !
La pratique du développement piloté par le comportement, c'est-à-dire de
tout ce que l'on a présenté ici (les fonctionnalités, les scénarios...)
nécessite quelque chose de fondamental : que **vos équipes mobilisent
leur énergie sur votre besoin, pas sur leurs bugs**.
Pour cela il n'y a pas énormément de solutions : **vos équipes
techniques doivent créer des tests automatisés de leur code source**. 
C'est un impératif fort : c'est le seul moyen pour qu'elles ne vous
disent pas "nous ne pouvons pas développer cette fonctionnalité, c'est
impossible car on risque de casser tout l'existant et d'introduire des
bugs". Non, avec des tests automatisés, une équipe compétente ne peut
pas vous répondre ça. Elle vous dira peut-être que la nouvelle
fonctionnalité a un coût, mais aucune fonctionnalité ne doit être
impossible à implémenter parce qu'elle risque de casser l'existant.
Si quelque chose casse lorsque vous introduisez du changement, vous
perdrez beaucoup d'argent : il va falloir identifier (et ça peut être
très long!) et corriger ce qui a cassé, corriger la nouvelle
fonctionnalité, la tester, ajouter des ressources pour le support
applicatif... 
Tous ces coûts, très importants sur le long terme, peuvent être réduits
en laissant à court terme une plus grande marge de manœuvre aux équipes
techniques pour fiabiliser leur code source et en écrivant des tests
automatisés. Ne soyez pas un mauvais économe : laissez leur le temps
qu'il faut pour vous fournir un produit plus stable et plus fiable. Vous
y gagnerez sur le long terme.
> Laissez le temps aux développeurs de fiabiliser leur code : aucune
fonctionnalité ne doit être impossible à implémenter sous prétexte
qu'elle risque de casser l'existant

View file

@ -0,0 +1,336 @@
# Un peu de recul sur le Développement piloté par le Comportement
## Votre fonctionnalité se spécifie elle-même
Vous savez désormais décrire votre besoin dans une Langue et une
grammaire compréhensible par tous les acteurs de votre projet.
Vous avez peut-être déjà rencontré cette difficulté : au fur-et-à-mesure
de la vie dun projet, la documentation, fruit dun travail difficile et
chronophage, se détache généralement de la réalité.
Cette difficulté a en réalité une origine simple : lorsque lon ajoute
une nouvelle fonctionnalité, mettre à jour la documentation prend
parfois plus de  temps que la réalisation même de la fonctionnalité.
Maintenant, examinez ceci : avec le Développement piloté par le
Comportement, cest-à-dire grâce à la Langue Commune, grâce une
grammaire spécifique, la documentation fonctionnelle est écrite en même
temps que les spécifications. Et oui! Vos Fonctionnalités sont aussi de
la documentation.
Il est assez facile dimaginer, par exemple, prendre lensemble de vos
fichiers de Fonctionnalités et les transformer en un fichier .pdf, ou
encore den faire un manuel en ligne. C'est ce que font, par exemple,
[Relish](https://www.relishapp.com) (hébergé, payant) ou
[Pickles](https://github.com/picklesdoc/pickles) (gratuit, à installer soi-même).
Bien plus, aucun changement fonctionnel de code source ne peut être
réalisé sans que lun de vos fichiers de Fonctionnalités  nait été
modifié. Cest le principe même du Développement piloté par le
Comportement : vous ne pouvez pas avoir de delta entre votre expression
de besoin et ce que vos développeurs vous livreront.
Par conséquent, vous laurez compris, vous avez ainsi un énorme avantage
:  **les Fonctionnalités que vous avez constituées  reflètent en
permanence létat réel de votre Produit**. 
Si ce n'est pas le cas, c'est :
+ que vous avez modifié votre Fonctionnalité sans en rédiger les Scénarios directement avec l'équipe technique. Votre erreur sera d'avoir rompu le dialogue avec vos équipes,
+ ou que les équipes n'auront pas encore réalisé votre demande de changement. Il faudra dans ce cas prioriser ce changement parmi l'ensemble de fonctionnalités qu'ils ont à développer.
> Spécification = Documentation = toujours à jour
## Servez-vous de vos fonctionnalités pour prioriser
Pensez à ceci : vous pouvez, si vous le souhaitez, associer un état à
chacun de vos fonctionnalités et scénarios. Par exemple :
+ En attente
+ En cours de développement
+ Réalisé
Vous verrez qu'il existe des outils pour vous aider dans cette tâche.
Grâce à ces indicateurs, vous disposez de la possibilité de visualiser à
chaque instant l'état de votre produit.
Si, donc, vous connaissez la phase de développement de chacun de ces
scénarios et fonctionnalités, pourquoi ne pas vous servir de cette
information pour changer leur priorité ? 
Vous le savez, votre Produit a besoin d'être confronté rapidement au
feedback de vos utilisateurs. Profitez en pour faire en sorte de vous
faire livrer régulièrement des versions simplifiées de votre projet ;
regardez ce qui plaît à vos utilisateurs... C'est justement ce qui plaît
qu'il va falloir développer en priorité dans votre projet, tout le reste
peut être remis à plus tard.
Vous l'aurez compris : ce découpage en fonctionnalités, puis en
scénarios, va vous permettre de prioriser intelligemment votre projet.
Bien plus, cela va vous pousser à abandonner certains points pour en
introduire de nouveaux, plus pertinents pour vos utilisateurs finaux ;
et puisque cela fait partie de votre Produit même, ce changement
fonctionnel sera à la fois rapide et peu coûteux !
> Vous avez un aperçu en temps réel de l'état de votre Produit
## Mesurez le chemin parcouru, pas l'énergie dépensée
C'est souvent la même chose : on surveille le temps passé, les tâches
réalisées... Mais on a tous le même problème : passer beaucoup de temps
ne veut pas dire obtenir un résultat. **Pourquoi mesurer ce temps passé
si vous n'avez pas le résultat attendu** **?** Ce qui compte, ce sont
uniquement les fonctionnalités.
Les outils classiques vous proposent de découper chaque besoin en tâche,
puis chaque tâche en temps. Or une tâche n'a aucun sens fonctionnel !
Vraiment ! C'est comme si vous demandiez à un chauffeur routier combien
de litres d'essence il a consommé ; certes, c'est important d'un point de
vue financier, mais ce qui compte c'est quand même de savoir s'il a pu
livrer tous ses clients, vous ne croyez pas ?
Dans un projet informatique c'est pareil : focalisez-vous sur les
fonctionnalités développées. Après tout, c'est ce qui compte vraiment...
Uniquement !
Bien entendu, peut-être que les équipes techniques, elles, travailleront
en tâches, mais :
+ rien ne les y oblige.
+ ça ne vous concerne pas, seules les fonctionnalités vous intéressent
**On n'a jamais vu un client obtenir un bénéfice métier parce qu'une
équipe a accompli une tâche**. Non, le bénéfice ne s'obtient qu'en
fournissant un service, autrement dit une fonctionnalité.
> Le client final n'est pas content parce qu'une tâche est accomplie ;
il est content parce qu'une fonctionnalité lui est offerte et qu'elle
répond a son besoin
## Une bonne fonctionnalité sert la Vision Produit
Prenez le réflexe : demandez-vous systématiquement si votre
fonctionnalité sert votre Vision. Si ce n'est pas le cas ... Et bien
oubliez la !
A contrario, ne vous limitez pas à un cadre. Après tout, ce qui compte vraiment ce
n'est pas la somme de fonctionnalités, c'est de réussir à satisfaire
votre Vision.
Prenez GMail, de Google, par exemple. Chaque fonctionnalité est
sélectionnée pour répondre à cette vision simple : "permettre à chacun
de communiquer facilement avec ses proches". Peu importe le cadre ; du
moment qu'une fonctionnalité sert cette vision, elle est bonne.
Sans Vision, GMail ne serait qu'une application, c'est à dire un simple
webmail. Mais c'est  justement pour cela que GMail c'est :
+ un webmail
+ un service de communication instantané (GTalk) 
+ une application mobile
+ un tchat vidéo (hangout)
+ un rappel des anniversaires de vos amis
+ un carnet de contacts
+ ...
Tous ces services desservent la même vision. C'est ce qui fait que GMail
plaît autant. Et c'est cette vision qui assure la cohérence de
l'ensemble : **il vous faudra parfois refuser certaines
fonctionnalités**, même si à court terme elles semblent rentables. 
Si elles ne répondent pas à la même vision, ces fonctionnalités vont
rendre votre produit incohérent et illogique. Pourquoi dépenser de
l'argent pour rendre votre Produit illogique ? **Tout le monde aime les
choses simples, claires et cohérentes** ; pire : si vous enlevez cette
clarté, vos développeurs eux-mêmes risquent de ne plus comprendre ce que
vous voulez !
Si vous tenez absolument à ajouter une fonctionnalité qui sert une autre
vision, créez un autre projet, avec d'autres équipes, mais ne la
greffez pas artificiellement à celui-ci.
> Respecter scrupuleusement une Vision assure la cohérence et la clarté
du Produit
## Oubliez l'interface graphique
Fatigué ? Pourquoi ne pas faire un petit jeu ? Vous connaissez Google
Calendar ? mais si, vous savez, le calendrier de Google, très pratique,
que vous retrouvez sur calendar.google.com...
A votre avis :
| Google Calendar serait-il toujours le même produit : | |
| --------------------------------------------------------- | ----------------- |
| Si le site web n'affichait plus la date du jour ? | ☐&nbsp;oui&nbsp;&nbsp;non |
| Sans page web pour y accéder ? | ☐&nbsp;oui&nbsp;&nbsp;non |
| S'il n'affichait pas de calendrier mensuel | ☐&nbsp;oui&nbsp;&nbsp;non |
| S'il ne vous permettait pas d'ajouter un rendez-vous en cliquant sur le bouton "nouveau rendez-vous" ?| ☐&nbsp;oui&nbsp;&nbsp;non |
| Si Internet nexistait pas ? | ☐&nbsp;oui&nbsp;&nbsp;non |
Au risque de surprendre, la réponse est partout la même : "oui" ! Oui,
même si Internet n'existait pas !
Après tout, qui nous dit que le web que nous connaissons ne va pas
disparaître ? Google Calendar pourrait très bien n'exister que sur
téléphone mobile. Mieux, sans électronique. Après tout, si Google avait
existé au début du XXème siècle, il lui aurait fallu trouver un autre
moyen pour délivrer ses services.
Considérez en effet cette Vision de Google Calendar : "permettre à
chacun de connaître facilement  les événements à venir qui le
concernent". Pas besoin de page web, d'application mobile... Un simple
courrier postal pour ajouter un événement, puis quelqu'un qui vient frapper à
notre porte à chaque fois qu'un événement va arriver... C'est suffisant, non ?
Certes, commercialement ce n'est pas l'idéal, mais même si Google
Calendar changeait pour désormais envoyer quelqu'un frapper chez nous à
chaque événement, le Produit serait inchangé ; seul le support matériel
serait modifié. Autrement dit : **le support n'a aucune importance
lorsque vous décrivez votre Produit !**
Quand vous décrivez votre produit, écrivez vos fonctionnalités de sorte
à ce qu'elles soient valables, même sur internet, même sur application
mobile, et même par courrier postal. C'est la seule façon de pérenniser
votre projet. Si vous avez un site web, vos Fonctionnalités et Scénarios
ne doivent pas changer d'un pouce lorsque vous décrivez votre
application mobile.
> Focalisez-vous sur le Comportement de votre Produit, et laissez
l'interface graphique aux ergonomes et aux graphistes.
## Le scénario n'est pas un critère d'acceptation
Considérez ce scénario, mis en évidence par Liz Keogh:
[gherkin]
Scénario : pouvoir acheter un animal domestique adulte
Etant donné qu'un chiot est trop petit pour être vendu
Quand j'essaye de l'acheter
Alors je suis informé qu'il ne peut être vendu car trop jeune
Bien. Bien ? Non, pas vraiment... Vous n'avez pas décrit votre besoin,
vous venez en réalité de fournir un Critère d'acceptation générique à
vos développeurs. Leur réaction face à ce scénario ne peut être que
"d'accord, mais à quel âge par exemple le chiot ne peut pas être vendu
?".
Tant qu'il reste des questions en suspend, quelque chose ne va pas.
N'oubliez pas que **vous décrivez vos Fonctionnalités et vos Scénarios, non
pas d'abord pour valider un travail fourni, mais avant tout pour être
sûr que tout le monde a bien compris votre besoin** et pour éviter les
allers et retours inutiles.
Chaque scénario doit contenir ses propres exemples. Notre scénario
pourrait être changé en :
[gherkin]
Scénario : pouvoir acheter un animal domestique adulte
Etant donné qu'un chiot ne peut être vendu avant qu'il n'ait "2 mois"
Et que "Médor le chien" a actuellement "1 mois"
Quand j'essaye d'acheter "Médor le chien"
Alors on doit me dire "Médor le chient est trop jeune. Veuillez revenir dans 1 mois"
Cest un peu plus explicite non ? Et il reste moins de questions. De
cette manière vous limitez les aller-et-venues inutiles et exprimez
votre besoin clairement.
> Si on vous demande: "Pouvez-vous me donner un exemple où cette
situation arrive?", vous n'avez pas rédigé un Scénario mais un Critère
d'acceptation. Effacez le.
## Les principales causes d'échec du BDD
Je vais être franc : cette voie de communication, le Développement
Piloté par le Comportement, n'est pas une recette miracle et peut
échouer.
Vous pouvez, comme pour tout, y perdre de l'argent si vous échouez à
appliquer ce principe fondamental : **ce qui compte c'est de réussir à
ce que chacun comprenne clairement votre besoin vis-à-vis de votre
Vision**.
Je pense que la première cause d'échec vient de la **difficulté à
identifier clairement les fonctionnalités d'un Produit**. On a tous en
tête des idées géniales, le site web qui va tuer Facebook et eBay ; le
vrai souci est de savoir comment, dans la pratique, ce site web va rendre
service aux utilisateurs, et quelles sont les fonctionnalités qu'on va lui
offrir.
La seconde difficulté réside dans notre propension à avoir besoin d'un
support visuel pour réfléchir à quelque chose. **Il n'est pas simple de
ne se focaliser uniquement sur le Comportement d'un Produit, sans se
soucier de son apparence**, de son interface graphique. Ce sera d'autant
plus vrai si vous avez un profil technique ou si vous êtes très
familiarisé avec les nouvelles technologies. 
Pour résoudre cette difficulté, tentez systématiquement de vous
représenter votre produit sur différents supports : un ordinateur, un
téléphone, mais aussi par courrier ou par pigeon voyageur ! Bref, faites
abstraction totale du support matériel.
Ne vous focalisez pas sur le cheminement qui permet à votre application
ou site web de délivrer un service. Partez en sens inverse depuis
l'utilisateur : quel comportement peut-il avoir avec mon Produit ?
Comment mon Produit peut-il l'aider ?
Enfin, et c'est le plus important : **vous aurez besoin de vous faire
conseiller, surtout si ce n'est pas votre premier projet informatique**.
Il est quasiment impossible de réussir du premier coup à se défaire des
habitudes antérieures.
Il existe aujourd'hui de nombreuses sociétés de conseil en Agilité qui
sauront vous conseiller, surtout dans la démarche de dialogue qu'il vous
faudra engager avec vos équipes. L'investissement risque fort d'en
valoir la peine... Si vous n'en avez pas les moyens vous pouvez (très
sérieusement) effectuer en parallèle ce dialogue auprès de personnes
totalement novices dans le domaine fonctionnel abordé et peu familières
des nouvelles technologies : vos parents, grand-parents, enfants ou vos
amis ermites.
> Il n'existe pas de recette miracle. Faites abstraction de tout
support, oubliez vos habitudes et demandez de l'aide

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 KiB

View file

@ -0,0 +1,8 @@
Ce livre est publié sous licence Creative Commons.
Vous pouvez contribuer à son amélioration sur [Github](http://wwww.github.com/Halleck45/book-bdd)
Copyright (c) Jean-François Lépine <http://www.twitter.com/Halleck45>
Ce livre de [Jean-François Lépine](http://communiquez.lepine.pro) est mis à disposition selon les termes de la [licence Creative Commons Attribution - Pas dUtilisation Commerciale - Partage dans les Mêmes Conditions 3.0 non transposé](http://creativecommons.org/licenses/by-nc-sa/3.0/deed.fr).
Fondé(e) sur une œuvre à [https://github.com/Halleck45/livre-developpement-pilote-comportement](https://github.com/Halleck45/livre-developpement-pilote-comportement).

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

View file

@ -0,0 +1,83 @@
body {
color: #333333;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 14px;
line-height: 20px;
}
p strong, li strong {
color:#008287;
}
.code {
background:#000;
}
.code {
color:#999;
}
h1 {
}
h2 {
background-color: #F7F7F9;
border: 1px solid #E1E1E8;
padding:10px;
margin-top:30px;
}
h3 {
font-size:14px !important;
}
blockquote p {
font-size:18px;
background:#CCC;
color:#333;
width:80%;
font-style: italic;
margin-left:15%;
padding:10px;
}
.item.toc .part.level-1 {
color:#F7F7F9;
background-color: #000;
border: 1px solid #E1E1E8;
padding:10px;
margin-top:30px;
font-size:26px;
}
.item.part h1 {
text-align:center;
font-size:70px;
}
/* --- gherkin --- */
/*texte*/
div.code.gherkin {
color:#C5C8C6;
}
/*commentaire*/
div.code.gherkin .co1 {
color:#969896;
}
/*clef*/
div.code.gherkin .co3 {
color:#DE935F;
}
/*Exemples*/
div.code.gherkin .co4 {
color:#DE935F;
}
/*mot clef*/
div.code.gherkin .kw1 {
color:#81A2BE;
}
/*
vert #B5BD68
orange #DE935F
violet #B294BB
bleu #81A2BE
blanc #C5C8C6
gris #969896
jaune #B5BD68
*/

View file

@ -0,0 +1,63 @@
body {
color: #333333;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 14px;
line-height: 20px;
}
.code {
background:#000;
}
.code {
color:#999;
}
h2 {
background-color: #F7F7F9;
border: 1px solid #E1E1E8;
padding:10px;
margin-top:30px;
}
h3 {
font-size:14px !important;
}
em {
font-size:12px;
color:#c20cb9;
}
.item.part h1 {
text-align:center;
font-size:40px;
}
/* --- gherkin --- */
/*texte*/
div.code.gherkin {
color:#C5C8C6;
}
/*commentaire*/
div.code.gherkin .co1 {
color:#969896;
}
/*clef*/
div.code.gherkin .co3 {
color:#DE935F;
}
/*Exemples*/
div.code.gherkin .co4 {
color:#DE935F;
}
/*mot clef*/
div.code.gherkin .kw1 {
color:#81A2BE;
}
/*
vert #B5BD68
orange #DE935F
violet #B294BB
bleu #81A2BE
blanc #C5C8C6
gris #969896
jaune #B5BD68
*/

View file

@ -0,0 +1,74 @@
book:
title: "Le développement piloté par le comportement"
subtitle: "Partie 1 : Communiquez avec les développeurs"
author: "Jean-François Lépine"
edition: "First edition"
language: fr
publication_date: ~
generator: { name: easybook, version: 5.0-DEV }
contents:
# available content types: acknowledgement, afterword, appendix, author,
# chapter, conclusion, cover, dedication, edition, epilogue, foreword,
# glossary, introduction, license, lof (list of figures), lot (list of
# tables), part, preface, prologue, title, toc (table of contents)
- { element: cover }
- { element: toc }
- { element: introduction, content: func-introduction.md }
- { element: chapter, number: 1, content: func-le-besoin-metier.md }
- { element: chapter, number: 2, content: func-communiquez.md }
- { element: chapter, number: 3, content: func-impliquez-les-parties-prenantes.md }
- { element: chapter, number: 4, content: func-exprimez-le-besoin.md }
- { element: chapter, number: 5, content: func-un-peu-de-recul.md }
- { element: chapter, number: 6, content: func-recette-maintenabilite.md }
- { element: chapter, number: 7, content: func-conclusion.md }
- { element: author, content: author.md }
- { element: license, content: license.md }
editions:
ebook:
format: epub
highlight_code: false
include_styles: true
labels: ['appendix', 'chapter'] # labels also available for: "figure", "table"
theme: clean
toc:
deep: 1
elements: ["appendix", "chapter", "part"]
print:
format: pdf
highlight_code: true
include_styles: true
isbn: ~
labels: ["appendix", "chapter"] # labels also available for: "figure", "table"
margin:
top: 25mm
bottom: 25mm
inner: 30mm
outter: 20mm
page_size: A4
theme: clean
toc:
deep: 2
elements: ["appendix", "chapter", "part"]
two_sided: true
web:
format: html
highlight_code: true
include_styles: true
labels: ["appendix", "chapter"] # labels also available for: "figure", "table"
theme: clean
toc:
deep: 2
elements: ["appendix", "chapter", "part"]
website:
extends: web
format: html_chunked

View file

@ -0,0 +1,7 @@
Je m'appelle Jean-François Lépine, et je suis consultant Web. Au quotidien, j'assiste les entreprises dans la conception et la réalisation de leurs applications web.
Très impliqué dans l'éco-système OpenSource Web, j'anime le blog technique blog.lepine.pro. Vous pouvez retrouver quelques-unes de mes contributions sur mon [compte Github](http://www.github.com/Halleck45).
Je suis également l'auteur du Mémento Industrialisation PHP : outils et qualité publié en 2012 aux éditions Eyrolles.
Ces livres sont gratuits et open source. S'ils vous ont plu, n'hésitez pas à me le signaler sur [twitter](https://www.twitter.com/Halleck45) :-)

View file

@ -0,0 +1,760 @@
# Automatisez votre recette
Vous l'avez vu, Gherkin est un moyen simple pour votre fonctionnel pour vous fournir
une expression de besoin claire et précise.
Que diriez-vous maintenant de traduire ce besoin en tests automatisés ? Car, oui, c'est possible !
Tout besoin, s'il est exprimé clairement, peut être testé. Si ce besoin est exprimé dans une
grammaire solide et complète, tout système d'information peut le tester automatiquement.
Je vous propose de voir comment traduire ce besoin en tests automatisés, de telle sorte
qu'une simple ligne de commande dans un terminal vous indique si ce que vous avez développé est
conforme ou non.
L'ensemble des exemples que nous allons voir est écrit en PHP. Pourquoi ? Tout simplement
parce que la communauté PHP a très fortement et très rapidement adhéré au Développement
piloté par le comportement. Les outils PHP pour le Développement piloté par
le comportement sont matures, nombreux, et surtout offrent une souplesse qui, à ce jour,
ne se retrouve pas dans d'autres langages.
Cependant, il existe des outils pour écrire et lancer des tests automatisés dans à
peu près n'importe quel langage :
+ Ruby : Cucumber (http://cukes.info)
+ Java : JBehave (http://jbehave.org)
+ C# : NBehave (https://github.com/nbehave/NBehave)
+ Python : Behave (http://packages.python.org/behave/)
+ PHP : Behat (http://behat.org) , PHPSpec (http://www.phpspec.net)
+ JavaScript : Jasmine (http://pivotal.github.com/jasmine/)
+ Net : NBehave (http://nbehave.org)
Il en existe bien d'autres, la liste est loin d'être exhaustive, mais ceux-ci sont particulièrement
utilisés dans le monde du développement aujourd'hui.
## Installez et utilisez Behat en PHP
Behat est un outil développé en PHP par Konstantin Kudryashov (@everzet) et soutenu
par la société KnpLabs. Cet outil efficace est aujourd'hui mature et largement utilisé.
Behat permet d'exécuter des tests automatisés sur tous types d'applications, PHP ou non.
Il peut tester :
+ des applications web, en pilotant un vrai navigateur ou non
+ des applications console (terminal)
+ des morceaux de code source
Du moment que ce qui est testé dispose d'un point d'entrée et d'une information de sortie,
Behat va vous permettre d'automatiser votre recette métier.
Dans tous les cas, il vous faudra PHP installé sur la machine qui exécutera les tests.
L'installation de PHP est résumée sur cette page : http://php.net/manual/fr/install.php.
Windows :
[bash]
Utilisez WampServer (http://www.wampserver.com)
Ubuntu, Debian :
[bash]
# en ligne de commande
apt-get install php5-common php5-cli php5-curl
Mac :
[bash]
Utilisez MampServer (http://www.mamp.info)
Installer Behat est simple, et peut être fait de plusieurs manières : sous forme d'archive PHP
(phar) ou en utilisant un gestionnaire de dépendance.
### Installation avec Composer
Créez un fichier composer.json à la racine de votre projet, avec le contenu suivant :
[json]
{
"require-dev": {
"behat/behat": "2.5.*@stable"
},
"config": {
"bin-dir": "bin/"
}
}
Exécutez ensuite la commande suivante dans votre terminal, en vous plaçant à la racine
de votre projet :
[bash]
curl http://getcomposer.org/installer | php
php composer.phar install --prefer-source
### Installation sous forme d'archive Phar
Il vous suffit de télécharger le fichier behat.phar à l'adresse suivante : http://behat.org/
downloads/behat.phar. Placez-le ensuite dans un dossier `bin` à la racine de votre projet. Vous
aurez donc l'arborescence suivante :
[bash]
/chemin/vers/mon/projet
(...)
- bin/
- behat.phar
Pour des raisons de maintenabilité, il est préférable d'utiliser la méthode d'installation
avec Composer, qui vous permettra de mettre à jour très facilement l'ensemble des librairies
PHP que vous utilisez, y compris Behat.
### Préparer le projet
Une fois que Behat est installé, il vous suffit d'exécuter la commande suivante :
[bash]
php ./bin/behat --init
Cela aura pour effet de créer dans votre projet tous les éléments dont Behat a besoin pour
fonctionner.
Vous voici désormais avec les dossiers suivants :
+ `features` : contient la listes des fonctionnalités, sous forme de fichier `.feature`
+ `features/bootstrap` : contient les fichiers PHP de traduction de Fonctionnalité en code source
Chaque nouvelle fonctionnalité devra donc être ajoutée dans le dossier `features`, sous forme d'un
fichier `.feature`. Créez par exemple le fichier `features/calculer-mon-age.feature`, avec le
contenu suivant :
![ Les sources de cet exercice sont disponibles sur http://goo.gl/lgWvy ]
(dev-qr-exo1-step1.png)
[gherkin]
# language: fr
Fonctionnalité: Calculer l'âge d'une personne
En tant qu'utilisateur de l'application
Je veux connaître le nombre d'années écoulées entre deux dates
De telle sorte que je puisse connaître mon age
Scénario: Calculer l'âge d'une personne depuis une date antérieure à aujourd'hui
Etant donné que je suis né le 06/07/1986
Et que nous sommes le 20/09/2013
Quand je calcule mon âge
Alors je suis informé que j'ai 27 ans
Scénario: Calculer l'âge d'une personne depuis une date postérieure à aujourd'hui
Etant donné que je suis né le 06/07/3013
Et que nous sommes le 20/09/2013
Quand je calcule mon âge
Alors je suis informé que je ne suis pas encore né
Scénario: Calculer l'âge d'une personne dont c'est l'anniversaire aujourd'hui
Etant donné que je suis né le 06/07/1986
Et que nous sommes le 06/07/2013
Quand je calcule mon âge
Alors je suis informé que j'ai 27 ans
Et on me souhaite un joyeux anniversaire
Puis exécutez la commande suivante pour lancer Behat :
[bash]
./bin/behat
![ Les étapes de la fonctionnalité ne sont pas encore traduites : elles sont jaunes ]
(dev-behat-exo-date-undefined.jpg)
Comme vous pouvez le voir, le résultat de cette commande est jaune. Cela veut tout simplement dire
que les phrases utilisées pour exprimer le besoin n'ont pas encore de signification pour Behat. Il va falloir
les traduire.
## Traduire une Fonctionnalité en code source
Par chance, Behat est suffisamment bien fait pour vous fournir une base de travail pour traduire vos fonctionnalités. Il suffit
de copier-coller dans le fichier `features/bootstrap/FeatureContext.php` le code PHP qui a été généré par la commande :
[bash]
./bin/behat
Pourquoi copier ce code dans ce fichier ? Tout simplement parce que les fichiers `features/bootstrap/*Context.php` vont servir
de passerelle entre le besoin exprimé (sous forme de phrases) et votre application.
Il vous appartient de modifier ces fichiers pour faire la traduction du besoin fonctionnel. C'est un travail
qui semble long, mais en réalité il n'est pas beaucoup plus long que de tester vous-même à main que la demande initiale
est respectée, mais possède surtout l'avantage de rendre ce travail de recette interne totalement automatique.
Traduisez maintenant la fonctionnalité en code source dans le fichier `features/bootstrap/FeatureContext.php`, en adaptant
le code PHP fourni par Behat selon votre besoin. Par exemple :
[php]
<?php
// (...)
class FeatureContext extends BehatContext
{
private $birthDate;
private $today;
private $output;
/**
* Initializes context.
* Every scenario gets it's own context object.
*
* @param array $parameters context parameters (set them up through behat.yml)
*/
public function __construct(array $parameters)
{
}
/**
* @Given /^que je suis né le (\d+)\/(\d+)\/(\d+)$/
*/
public function queJeSuisNeLe($day, $month, $year)
{
$this->birthDate = new \DateTime(sprintf('%d-%d-%d', $year, $month, $day));
}
/**
* @Given /^que nous sommes le (\d+)\/(\d+)\/(\d+)$/
*/
public function queNousSommesLe($day, $month, $year)
{
$this->today = new \DateTime(sprintf('%d-%d-%d', $year, $month, $day));
}
/**
* @When /^je calcule mon âge$/
*/
public function jeCalculeMonAge()
{
$this->output = shell_exec(sprintf('php src/age.php --birthdate=%s --today=%s', $this->birthDate->format('Y-m-d'), $this->today->format('Y-m-d')));
}
/**
* @Then /^je suis informé que j\'ai (\d+) ans$/
*/
public function jeSuisInformeQueJAiAns($age)
{
if(!preg_match('!'.$age.' ans!', $this->output)) {
throw new Exception();
}
}
/**
* @Then /^je suis informé que je ne suis pas encore né$/
*/
public function jeSuisInformeQueJeNeSuisPasEncoreNe()
{
if(!preg_match('!Vous n\'êtes pas encore né!', $this->output)) {
throw new Exception();
}
}
/**
* @Then /^on me souhaite un joyeux anniversaire$/
*/
public function onMeSouhaiteUnJoyeuxAnniversaire()
{
if(!preg_match('!Joyeux anniversaire!', $this->output)) {
throw new Exception();
}
}
}
Notez ces différents aspects :
+ chaque phrase est convertie en une méthode PHP
+ le lien entre les phrases et les méthodes PHP est effectué par un expression régulière (par exemple : `/^on me souhaite un joyeux anniversaire$/`)
+ vous devez traduire chaque étape. Behat comprendra qu'une étape n'est pas valide si vous levez une exception, comme c'est le cas dans la méthode `onMeSouhaiteUnJoyeuxAnniversaire()`
+ il est possible de recevoir certaines informations (nombres, exemples...) sous forme de paramètres de méthodes.
+ l'application qui va être testée fonctionne en ligne de commande (`php src/age.php`)
Maintenant, il vous suffit de relancer Behat pour vérifier automatiquement que votre application a bien
le comportement attendu :
[bash]
./bin/behat
![ Les tests échouent ; c'est normal, les fonctionnalités n'ont pas encore été développées ]
(dev-behat-exo-date-fail.jpg)
Il vous suffit finalement de développer votre application PHP, conforme aux attentes fonctionnelles, puis de relancer
Behat pour vous assurer que vous avez bien traité la demande initiale.
## Exploitez les jeux d'exemples
![ Les sources de cet exercice sont disponibles sur http://goo.gl/jaLxP ]
(dev-qr-exo1-step2.png)
Vous l'avez vu, votre fonctionnel peut vous fournir des exemples, grâce à la syntaxe Gherkin.
On pourrait par exemple modifier notre fonctionnalité de la façon suivante :
[gherkin]
# language: fr
Fonctionnalité: Calculer l'âge d'une personne
En tant qu'utilisateur de l'application
Je veux connaître le nombre d'années écoulées entre deux dates
De telle sorte que je puisse connaître mon age
Plan du Scénario: Calculer l'âge d'une personne
Etant donné que je suis né le "<dateNaissance>"
Et que nous sommes le "<dateDuJour>"
Quand je calcule mon âge
Alors on me répond "<reponseAttendue>"
Exemples:
| dateNaissance | dateDuJour | reponseAttendue |
| 06/07/1986 | 20/09/2013 | Vous avez 27 ans |
| 06/07/1985 | 20/09/2013 | Vous avez 28 ans |
| 26/11/2020 | 20/09/2013 | Vous n'êtes pas encore né |
| 06/07/1986 | 06/07/2013 | Vous avez 27 ans. Joyeux anniversaire |
Vous voici avec une fonctionnalité simple, claire et complète.
Travailler avec des exemples ne change strictement rien pour vous. En réalité, Behat
va travailler avec chaque jeu d'exemple, un à un, et va vous envoyer chaque information
sous forme de paramètre de méthode, sans que cela n'ait le moindre impact sur votre code.
Voici une traduction possible de cette fonctionnalité :
[php]
<?php
// file features/bootstrap/FeatureContext.php
// (...)
class FeatureContext extends BehatContext
{
private $birthDate;
private $today;
private $output;
/**
* @Given /^que je suis né le "([^"]*)"$/
*/
public function queJeSuisNeLe($date)
{
$this->birthDate = DateTime::createFromFormat('d/m/Y', $date);
}
/**
* @Given /^que nous sommes le "([^"]*)"$/
*/
public function queNousSommesLe($date)
{
$this->today = DateTime::createFromFormat('d/m/Y', $date);
}
/**
* @When /^je calcule mon âge$/
*/
public function jeCalculeMonAge()
{
$this->output = shell_exec(sprintf('php src/age.php --birthdate=%s --today=%s', $this->birthDate->format('Y-m-d'), $this->today->format('Y-m-d')));
}
/**
* @Then /^on me répond "([^"]*)"$/
*/
public function onMeRepond($response)
{
if (false === strpos($this->output, $response)) {
throw new Exception;
}
}
}
Votre fonctionnel peut désormais ajouter autant d'exemples qu'il le souhaite, votre travail de traduction ne changera plus.
> Utiliser des exemples est très simple avec Behat.
## Réutilisez vos précédents tests
![ Les sources de cet exercice sont disponibles sur http://goo.gl/onk8x ]
(dev-qr-exo2.png)
Vous l'avez vu, la phase de traduction d'une phrase (étape) en code source peut parfois être longue.
C'est pour cela que vous devez faire en sorte de faciliter votre travail : réutilisez au maximum vos définitions. Attention, je ne
vous parle en aucun cas ici de découper votre code comme vous le feriez dans une application (refactoring, respect des
principes SOLID, découpage des méthodes...).
Non, la réutilisabilité dans les Contextes de traduction (fichiers `*Context.php`) ne passe pas par une réutilisation du code source,
mais bel et bien par une réutilisation de phrases. **En réalité, vous devez apprendre à faire du refactoring de phrases**.
Cette tâche n'est pas simple au départ, mais est en réalité assez naturelle. Chaque phrase, qui correspond à un contexte, un
élément déclencheur ou un résultat attendu, peut être découpée en différentes étapes, qui **elles-mêmes pourront être décomposées
jusqu'à arriver à des expressions atomiques simples**.
Prenez par exemple la phrase suivante :
[gherkin]
Quand j'ajoute dans mon panier "télévision Sony" depuis le catalogue produit
Cette phrase peut être découpée, par exemple :
[gherkin]
Etant donné que je consulte le catalogue produit
Quand j'ajoute dans mon panier "télévision Sony"
Qui elles-mêmes peuvent être découpées pour créer des expressions atomiques réutilisables :
[gherkin]
Etant donné que je suis sur la page "/catalogue/produits"
Quand je coche "télévision Sony"
Et je clique sur "Ajouter au panier"
Vous pouvez constater que les trois dernières expressions sont en réalité des étapes (web) atomiques réutilisables à l'infini.
Cela signifie qu'une fois que vous les aurez traduites, vous n'aurez plus jamais à revenir dessus, et vous pourrez vous en servir à votre gré.
Vous pourriez désormais écrire, par exemple :
[gherkin]
Etant donné que je suis sur la page "/home"
Etant donné que je suis sur la page "/mon-compte"
...
Cette démarche permet donc de faire du refactoring de phrases pour arriver à des expressions atomiques. Par chance, c'est
extrêmement simple à faire avec Behat. Regardez plutôt :
[php]
<?php
// (...)
use Behat\Behat\Context\Step;
class FeatureContext extends BehatContext
{
/**
* @When /^j\'ajoute dans mon panier "([^"]*)" depuis le catalogue produit$/
*/
public function jAjouteDansMonPanierDepuisLeCatalogueProduit($produit)
{
return array(
new Step\Given('que je consulte le catalogue produit')
, new Step\When(sprintf('j\'ajoute dans mon panier "%s"', $produit))
);
}
Comme vous le voyez, il suffit simplement, dans la méthode de définition, de retourner un tableau d'étapes. Chaque
étape est en réalité un objet PHP (`Given`, `When` ou `Then`) qui accepte en paramètre de constructeur la phrase que l'on souhaite
utiliser. Pratique non ?
Ce qui donnerait par exemple dans notre cas :
[php]
<?php
// (...)
use Behat\Behat\Context\Step;
class FeatureContext extends BehatContext
{
/**
* @When /^j\'ajoute dans mon panier "([^"]*)" depuis le catalogue produit$/
*/
public function jAjouteDansMonPanierDepuisLeCatalogueProduit($produit)
{
return array(
new Step\Given('que je consulte le catalogue produit')
, new Step\When(sprintf('j\'ajoute dans mon panier "%s"', $produit))
);
}
/**
* @Given /^que je consulte le catalogue produit$/
*/
public function queJeConsulteLeCatalogueProduit()
{
return array(
new Step\Given('que je suis sur la page "/catalogue/produits"')
);
}
/**
* @When /^j\'ajoute dans mon panier "([^"]*)"$/
*/
public function jAjouteDansMonPanier($produit)
{
return array(
new Step\When(sprintf('je coche "%s"', $produit))
, new Step\When('je clique sur "Ajouter au panier"')
);
}
/**
* @Given /^que je suis sur la page "([^"]*)"$/
*/
public function queJeSuisSurLaPage($url)
{
// ?
}
/**
* @When /^je coche "([^"]*)"$/
*/
public function jeCoche($produit)
{
// ?
}
/**
* @When /^je clique sur "([^"]*)"$/
*/
public function jeCliqueSur($bouton)
{
// ?
}
}
Notez les trois dernières traduction (les méthodes ̀ queJeSuisSurLaPage()`, `jeCoche()` et `jeCliqueSur()` ). Ces méthodes
de traduction concernent le comportement d'un navigateur web, comme Firefox ou Chrome... Il arrive en effet très souvent
qu'il faille effectuer des actions qui n'existent que dans un navigateur. Vous allez voir qu'avec Behat c'est très facile !
> Oubliez le refactoring de code. Vous devez apprendre à faire du refactoring de phrases.
## Testez une application Web
Vous savez désormais automatiser une recette fonctionnelle d'un applicatif. Cependant, dans le cadre d'une application internet,
la recette fonctionnelle consiste le plus souvent à parcourir des pages web, vérifier leur conformité (délivrent-elles le service
attendu ?), en soumettant un formulaire, en cliquant sur un lien... Bref, en surfant sur un site web.
Heureusement, il est aujourd'hui très simple d'automatiser une recette fonctionnelle, quand bien même elle concerne une
application web. Allons-y !
Une fois de plus nous allons utiliser Behat. Plus précisément, nous allons utiliser une extension de Behat, appelée Mink, qui permet de
naviguer dans une application web et de lancer des tests automatisés lors de cette navigation.
Concrètement, Mink permet une double approche :
+ Exécuter des tests fonctionnels dans un navigateur virtuel (émulateur)
+ Exécuter des tests fonctionnels au sein d'un vrai navigateur, comme Chrome ou Firefox par exemple
Il peut sembler étrange d'exécuter des tests dans un navigateur virtuel. Cependant, bien souvent le comportement fonctionnel
que l'on souhaite tester est en réalité disponible directement au sein des pages web, dans le HTML. *On préférera alors privilégier
les tests lancés dans un vrai navigateur uniquement lorsque le test porte sur des fonctionnalités complexes (en Javascript ou en Ajax
par exemple), ces tests étant en général beaucoup plus lourd et long à s'exécuter que les autres*.
Pour commencer, installez `Mink` :
### Installer Mink avec Composer
Modifiez le fichier composer.json que vous avez préalablement créé, et ajoutez-y le code suivant :
[json]
"require-dev": {
"behat/behat": "2.5.*@stable",
"behat/mink": "1.4.*@stable",
"behat/mink-extension": "~1.3",
"behat/mink-goutte-driver": "~1.1"
}
Puis relancez Composer :
[bash]
php composer.phar update
### Installer Mink sous forme d'archive Phar
Exécutez la commande suivante :
[bash]
wget https://github.com/downloads/Behat/Mink/mink.phar
Il vous suffit ensuite d'ajouter l'instruction suivantes dans vos fichiers PHP de Contexte :
[php]
require_once 'mink.phar';
### Configurer Mink
Maintenant, il suffit de configurer Behat pour lui indiquer que l'on utilise Mink. Mink étant une extension de Behat, C'est très simple.
Il suffit de créer le fichier `behat.yml` à la racine de votre projet :
[yaml]
default:
extensions:
Behat\MinkExtension\Extension:
base_url: http://url-de-votre-site.fr
goutte: ~
Voilà, Mink est installé !
Rappelez-vous, le travail de Spécification fonctionnelle passe par l'utilisation d'expressions, elles-mêmes organisés autour
d'une grammaire : Gherkin. Mink a ceci d'intéressant qu'il propose nativement un panel assez large d'expressions qui concernent
un navigateur, que vous pouvez donc réutiliser (`comme "Quand je vais sur "http://..."`, ou encore `Quand je remplis "Votre prénom" avec
"Jean-François"`...).
Un besoin exprimé de la façon suivante sera donc automatiquement compris par Behat lorsque Mink est installé:
[gherkin]
Scenario: s'identifier au sein de l'application
Etant donné que je suis sur "/accueil"
Quand je suis le lien "Me connecter"
Et que je remplis "Identifiant" avec "Jean-François"
Et que je remplis "Mot de passe" avec "azerty"
Et que je clique sur "Valider"
Alors je dois voir "Bienvenue Jean-François"
Pratique non ? Constatez que vous n'avez même pas besoin de parler de nom (attribut `name`) des champs HTML ; non, Behat
fera le lien pour vous entre les `label`, `title`, `class`... de vos champs de formulaire et l'expression que vous avez utilisée.
Au fait, avez-vous lancé Behat pour vérifier que cela fonctionne ? Allez-y ; Utiliser Mink ne change rien à l'utilisation de Behat,
il suffit comme avant d'exécuter la commande suivante :
[bash]
php ./bin/behat
Bien entendu, il va souvent arriver que vous ayez besoin de gérer des cas plus complexes que ce qu'il est possible de faire avec
les expressions disponibles nativement dans Mink.
Dans ce cas, il va s'agir, ni plus ni moins, de piloter votre navigateur (quel qu'il soit). Un très large éventail
de méthodes sont disponibles :
[php]
<?php
class FeatureContext extends MinkContext {
// (...)
$session = $this->getMink()->getSession();
$page = $session->getPage();
$button = $page->find('css', '.class-css-du-bouton');
$button->click();
}
Notez que désormais notre classe n'hérite plus de `BehatContext` mais de `MinkContext`.
Examinons ce code ensemble. Tout d'abord, nous récupérons la page courante affichée par le navigateur :
[php]
$session = $this->getMink()->getSession();
$page = $session->getPage();
Ensuite, il suffit de récupérer un élément HTML dans la page, puis d'exécuter l'action souhaitée sur cet élément (ici un clic,
mais on pourrait imaginer saisir une valeur, le cocher...) :
[php]
$button = $page->find('css', '.class-css-du-bouton');
$button->click();
Vous avez bien vu : la méthode `find()` permet de récupérer des éléments en utilisant des sélecteurs CSS. Ce sont les mêmes
que ce que vous utilisez dans vos feuilles de style CSS. Attention, les pseudo-styles (':hover', etc) ne sont pas supportés.
Bien entendu, il est également possible de récupérer des éléments HTML en utilisant des expressions xPath. La
[documentation de Mink est assez complète](http://mink.behat.org/#xpath-selectors) sur ce sujet.
Il ne vous reste plus qu'à traduire les expressions fonctionnelles de vos clients en différentes actions au sein
d'un navigateur, et vous saurez traiter alors la majorité des cas.
Sachez également que Mink permet très facilement de piloter un vrai navigateur. C'est utile lorsque l'on souhaite, par exemple, tester
des fonctionnalités qui nécessite un environnement Ajax ou JavaScript. Dans ce cas, juste au dessus des
Scénarios ou des Fonctionnalités concernées, il suffit d'ajouter le tag `@javascript`. Ce tag indiquera à Behat que vous souhaitez, dans ces
cas spécifiques, lancer un vrai navigateur pour les tests. Bien entendu, dans ce cas, la machine qui exécute les tests doit posséder un
environnement graphique (comme c'est le cas pour les ordinateurs de Bureau).
Lorsque l'on souhaite piloter un vrai navigateur, Behat délègue en réalité le travail à des outils spécialisés, comme `Sahi`, ou encore
comme `Selenium`. Dans ce cas, ces outils doivent être installés sur votre machine. La procédure pour les installer est en
général très simple, et est bien expliquée dans la [documentation officielle](http://mink.behat.org/#different-browsers-drivers).
Voici la configuration à ajouter dans le fichier `behat.yml` pour indiquer que vous souhaitez utiliser Chrome par exemple, grâce au driver Sahi :
[yaml]
default:
extensions:
Behat\MinkExtension\Extension:
base_url: http://url-de-votre-site.fr/
goutte: ~
default_session: sahi
javascript_session: sahi
browser_name: chrome
sahi:
host: localhost
port: 9999
Voici celle que vous pourriez utiliser pour piloter Firefox :
[yaml]
default:
extensions:
Behat\MinkExtension\Extension:
base_url: http://url-de-votre-site.fr/
goutte: ~
default_session: sahi
javascript_session: sahi
browser_name: firefox
sahi:
host: localhost
port: 9999
Vous avez désormais toutes les connaissances requises pour commencer à tester automatiquement un projet web. Pourquoi ne pas vous
entraîner par exemple sur une petite application web de guichet bancaire ?
![ La correction et les sources de cet exercice sont disponibles sur http://goo.gl/LISNg ]
(dev-qr-exo3.png)
Je vous propose de vous entraîner en traduisant le besoin fonctionnel suivant :
[gherkin]
#language: fr
Fonctionnalité: Gérer un compte bancaire
Afin de gérer mon compte bancaire
En tant qu'utilisateur connecté
Je peux ajouter ou retirer de l'argent sur mon compte
Contexte:
Etant donné que je suis connecté en tant que "jean-françois"
Et que j'ai "50" euro
Et je suis sur "/"
Scénario: Consulter mes comptes
Alors je devrais voir "Vous avez 50 euro sur votre compte"
Plan du Scénario: Ajouter de l'argent
Etant donné que j'ai "<montantInitial>" euro
Quand je sélectionne "<operation>" depuis "Operation"
Et je remplis "Montant" avec "<montant>"
Et je presse "Go"
Alors je devrais voir "Vous avez <montantFinal> euro sur votre compte"
Exemples:
| operation | montantInitial| montant | montantFinal |
| Ajouter | 50 | 10 | 60 |
| Ajouter | 50 | 20 | 70 |
| Ajouter | 50 | 5 | 55 |
| Ajouter | 50 | 0 | 50 |
| Retirer | 50 | 10 | 40 |
| Retirer | 50 | 20 | 30 |
| Retirer | 50 | 30 | 20 |
Scénario: Les découverts sont interdits
Etant donné que j'ai "50" euro
Quand je sélectionne "Retirer" depuis "Operation"
Et je remplis "Montant" avec "60"
Et je presse "Go"
Alors je devrais voir "Vous avez 50 euro sur votre compte"
Et je devrais voir "Les découverts ne sont pas autorises"
A vous de jouer !
> Mink permet facilement de piloter un navigateur pour tester vos applications web.

View file

@ -0,0 +1,271 @@
# Comprenez (enfin!) ce que votre client vous demande
Votre client ne parle pas la même langue que vous. Comment comprendre ce qu'il vous demande dans ce cas ?
Certains vous répondront : "utilisez UML". D'autres vous diront qu'il faut demander à
votre client de s'exprimer sous forme de "si...alors". J'imagine que cela doit être possible
dans certain cas. Mais dans la majorité des situations, exiger de vos clients qu'ils apprennent l'UML,
ou leur demander de formaliser leur pensée sous forme de logique booléenne, est un contre-sens !
Ils n'y arriveront pas efficacement : ce n'est pas leur métier, et probablement pas leur mode de pensée.
C'est pour cela qu'il existe ce que l'on appelle le "Développement piloté par le Comportement"
("Behavior Driven Development", ou "BDD" en anglais). Ce qui se cache derrière ce terme barbare est
en réalité très simple : il s'agit d'une démarche pour faciliter la communication entre fonctionnels
et techniques, démarche soutenue par l'utilisation d'une langue et d'une grammaire commune.
Cette grammaire commune (appelée "Gherkin") est simple, facile à apprendre, et compréhensible tout
autant par un informaticien que par votre voisin, votre conjoint(e)..., et par là-même par votre client.
Utiliser cette grammaire vous offrira un certain nombre d'avantages :
+ vous éviterez les quiproquos
+ les spécifications vous serviront de documentation
+ il sera plus facile d'identifier et de gérer les changements fonctionnels de dernière minute
+ vous saurez à tout moment ce qu'il vous reste à faire
Attention, le Développement piloté par le comportement a un pré-requis majeur et non
négociable : *le client doit s'investir*. Il faudra que le client (ou son représentant fonctionnel)
soit disponible pour répondre à chacune de vos questions, en permanence. Si personne autour de vous
n'est prêt à s'investir pour exprimer le besoin clairement, oubliez l'idée de pratiquer le Développement
piloté par le comportement : vous n'aurez pas les moyens d'y parvenir.
> Gherkin est une grammaire accessible à tous pour structurer l'expression de besoin
## Le besoin doit être exprimé par des Fonctionnalités
Concrètement, comment démarrer ? La première tâche revient à votre client. C'est lui qui
va devoir recenser la liste des Fonctionnalités qu'il souhaite voir dans son application.
Pour cela, il va devoir identifier chaque fonctionnalité par un titre simple, court, explicite et unique :
[gherkin]
# Le client va distinguer les fonctionnalités en leur donnant un titre
Fonctionnalité: Avoir accès à la liste des animaux de compagnie
Fonctionnalité: Choisir un animal de compagnie
Fonctionnalité: Acheter un animal de compagnie
Fonctionnalité: ...
Il est impératif qu'à cette étape les titres des fonctionnalités soient clairs et explicites.
Ensuite, il va lui suffire de contextualiser un peu cette fonctionnalité. Par exemple, il devra
indiquer qui est le bénéficiaire de cette fonctionnalité :
[gherkin]
En tant que vendeur
En tant que acheteur
En tant que propriétaire de la boutique
En tant que ...
Vous aurez donc désormais connaissance de l'acteur bénéficiaire de la fonctionnalité. Il
reste encore à identifier le service offert par la fonctionnalité. C'est cela que vous aurez, finalement, à programmer :
[gherkin]
Je veux acheter un animal de compagnie
Je veux connaître la liste des animaux de compagnie de mon magasin
Je veux connaître la liste des vendeurs
Je veux ...
Pour lever toute ambiguïté, il est important pour vous de comprendre quel est le bénéfice
de la fonctionnalité que vous aller développer : à quoi sert-elle vraiment ?
Après tout, c'est indispensable de comprendre et de connaître le pourquoi de votre métier.
Lorsque vous travaillez, le fruit de votre travail est vraiment utile ; et il est toujours gratifiant
de voir que l'on a rendu service à quelqu'un. C'est pour cela qu'il est important que le
client exprime le bénéfice obtenu par la fonctionnalité :
[gherkin]
De telle sorte que je puisse repartir avec un nouveau compagnon
De telle sorte que je sache s'il me faut renouveler le stock
De telle sorte que je puisse organiser les congés de chacun
De telle sorte que ...
Chaque fonctionnalité peut donc être exprimée en quatre lignes, très simples et compréhensibles par tous :
[gherkin]
Fonctionnalité : Connaître la liste des animaux de compagnie disponibles
En tant que vendeur
Je veux connaître la liste des animaux de compagnie disponibles à la vente
De telle sorte que je sache s'il me faut renouveler le stock
Pratique non ? Cette manière d'exprimer les fonctionnalités (dénommée "Gherkin"), est
simple, mais surtout est compréhensible par tous. C'est le rôle de votre client (ou fonctionnel)
de recenser l'ensemble des fonctionnalités du projet de cette manière.
Mais, vous vous en doutez, cela ne suffit pas. Il va falloir maintenant comprendre en détail
chaque fonctionnalité ; c'est un travail que vous ferez en commun
> Gherkin permet de décrire des fonctionnalités
## Vous êtes un journaliste : interviewez !
Chaque Fonctionnalité peut donc être traduite en quatre petites phrases. Mais dans la majorité
des cas cela ne suffira pas : il reste des ambiguïtés, ce n'est pas très précis...
C'est là que vous entrez en scène. A partir du moment où les fonctionnalités sont décrites
dans leurs grandes lignes, vous allez devoir les détailler. Oui, vous-même !
Comment ? Tout simplement en prenant quelques instants la casquette d'un journaliste :
interviewez votre fonctionnel !
Attention, je vous parle d'une vraie interview. Prenez le temps, pour chaque Fonctionnalité,
de poser un maximum de questions pertinentes : "et qu'est-ce qui se passe quand ... ?" ;
ou encore "je ne comprend pas le bénéfice tiré de cette fonctionnalité pour l'utilisateur."
Posez, donc, toutes ces questions. Et surtout planifiez systématiquement un moment,
avant chaque itération, où votre fonctionnel et l'ensemble des équipes techniques (oui,
toutes les personnes qui sont concernées), vont se réunir pour cette interview.
J'insiste : il ne s'agit pas d'une réunion facultative : comment ferait-on sans cela pour être
sûr d'avoir bien compris la demande du client ? Le temps passé n'est pas perdu, loin de là :
c'est du temps de gagné sur la future maintenance, les futures recettes et les futurs va-et-vient
entre le client et les équipes techniques.
L'objectif de ces interviews est de comprendre exactement, sans aucune ambiguïté possible,
ce qui vous est demandé fonctionnellement. Pour cela, il faudra découper les prochaines
Fonctionnalités que vous aurez à développer en "Scénarios".
## Chaque Fonctionnalité peut être découpée en Scénarios
Chaque Fonctionnalité peut être décrite en quatre points :
+ un titre
+ un rôle
+ un service rendu
+ un bénéfice métier
Mais cela ne suffira probablement pas. Il reste des questions en suspens. C'est le rôle des
Scénarios de lever ces incertitudes. Ce sera d'autant plus vrai qu'ils seront rédigés en commun
avec le fonctionnel et les équipes techniques.
Chaque Fonctionnalité peut contenir un ou plusieurs Scénarios, et chaque Scénario doit
pouvoir se distinguer facilement des autres par un titre :
[gherkin]
Fonctionnalité : acheter un animal de compagnie
(...)
Scénario: acheter un animal de compagnie disponible à la vente
Scénario: tenter d'acheter un animal de compagnie qui est trop jeune
Scénario: tenter d'acheter un animal de compagnie qui est réservé
...
Votre travail de développeur va consister à rendre ces Scénarios effectifs dans
l'application. En identifiant les Scénarios réalisés et ceux qui ne le sont pas vous saurez
donc exactement ce qu'il vous reste à faire.
Vous vous en doutez : un simple titre ne suffit pas ; il va falloir compléter chaque Scénario.
Posez par exemple cette question : "dans quel cadre ce scénario se situe t-il ?". Cela vous
permettra de connaître le *Contexte de votre Scénario*:
[gherkin]
Scénario : ...
Etant donné que tel contexte existe
Etant donné que je souhaite acheter un chien
Etant donné qu'il n'y a plus un seul animal disponible
Etant donné ...
Une application consiste généralement à réagir à des *événements*. Précisez-donc quels
sont ces événements :
[gherkin]
Scénario : ...
(...)
Quand j'essaye d'acheter un chien
Quand je regarde quels sont les animaux disponibles
Quand ...
Dès lors, il ne vous reste plus qu'à préciser le *Résultat attendu* lorsque cet événement
survient :
[gherkin]
Scénario : ...
(...)
Alors je peux repartir avec un petit chien
Alors je dois être informé que le chien est trop jeune pour être
vendu
Alors ...
Cette syntaxe, simple, que l'on nomme Gherkin, va suffire dans la majorité des cas pour
que le fonctionnel puisse exprimer son besoin et surtout pour que vous puissiez comprendre
sans ambiguïté ce qui vous est demandé.
Voici un exemple de Fonctionnalité :
[gherkin]
Fonctionnalité : acheter un chiot
En tant que client du magasin
Je veux pouvoir acheter un chiot
De telle sorte que je puisse avoir un animal de compagnie
Scénario : acheter un chiot disponible à la vente
Etant donné qu'un chiot est disponible en stock
Quand j'achète un chiot
Alors on me donne un chiot
Scénario: acheter un chiot sevré
Etant donné qu'un chiot est trop jeune pour être vendu
Quand j'essaye d'acheter ce chiot
Alors je suis informé qu'il est trop jeune pour être vendu
Pratique non ?
## Demandez (exigez) des exemples précis
Rappelez-vous que l'objectif du Développement piloté par le comportement est de lever
toutes les ambiguïtés. Pourtant, dans le scénario suivant, il reste des questions :
[gherkin]
Scénario: acheter un chiot sevré
Etant donné qu'un chiot est trop jeune pour être vendu
Quand j'essaye d'acheter ce chiot
Alors je suis informé qu'il est trop jeune pour être vendu
Ces questions sont nombreuses :
+ à partir de quel âge un chiot peut-il être vendu ?
+ quel est l'âge du chiot que l'on essaye d'acheter ?
+ comment suis-je informé ? par quelle phrase ?
Autant de questions auxquelles, si vous ne les posez pas maintenant, vous serez obligé de
répondre vous-même, avec tous les risques que cela comporte, notamment celui de devoir
recommencer votre développement !
Heureusement, il est tout à fait possible, avec Gherkin, de préciser des valeurs à utiliser. Il
suffit de les encadrer dans des guillemets :
[gherkin]
Scénario : acheter un chiot sevré
Etant donné qu'un chiot ne peut être vendu avant qu'il n'ait "2 mois"
Et que "Médor le chien" a actuellement "1 mois"
Quand j'essaye d'acheter "Médor le chien"
Alors on doit me dire "Médor le chien est trop jeune !"
Pas mal d'ambiguïtés sont levées non ? Et ça ne prend pas beaucoup plus de temps à écrire.
Maintenant, il peut arriver qu'un seul exemple ne suffise pas ; il en faudrait plusieurs. Pas
de problèmes, Gherkin vous permet d'utiliser des exemples facilement ; il suffit de les passer
sous forme de tableaux. Les variables sont alors à encadrer par les symboles "<" (plus petit que)
et ">" (plus grand que).
[gherkin]
Plan du Scénario : acheter un chiot sevré
Etant donné qu'un chiot ne peut être vendu avant qu'il n'ait "2 mois"
Et que "<nom-du-chien>" a actuellement "<age-du-chien>"
Quand j'essaye d'acheter "<nom-du-chien>"
Alors on doit me dire "<nom-du-chien> est trop jeune !"
Exemples :
| nom-du-chien | age-du-chien |
| médor | 1 mois |
| rex | 1 mois et 3 jours |
| rantanplan | 15 jours |
Remarquez qu'il ne s'agit plus dans ce cas d'un "Scénario" mais d'un "Plan du Scénario".
Vous voici donc avec un besoin simple, découpé et exprimé clairement. A vous de jouer !

View file

@ -0,0 +1,23 @@
# Le mot de la fin : le pouvoir du canard !
Connaissez-vous le "Duck Typing" (traduit par "typage canard") ? La légende veut que le poète James Whitcomb Riley soit à l'origine de cette expression :
> Si je vois un animal qui vole comme un canard, cancane comme un canard, et nage comme un canard, alors j'appelle cet oiseau un canard
Ce principe peut s'appliquer au test logiciel : si un module fonctionnel semble avoir le comportement attendu, possède l'apparence souhaitée,
ne génère pas d'erreur, est utilisable facilement, a été utilisé par plusieurs personnes... Alors on peut sans risque penser que
ce module fonctionnel est correct et cohérent.
Cette analogie est importante car elle permet de comprendre que **tout ne peut (et ne doit) pas être testé par un logiciel**.
Traduire un besoin fonctionnel en tests automatisés prend du temps ; et ce temps, en général, vous ne l'aurez pas. Il faut donc
faire des choix : ne testez pas tout, ayez parfois confiance au travail de l'humain, et concentrez-vous sur ce qui est essentiel
ou sensible dans l'application que vous avez à développer.
N'oubliez pas non plus que l'ensemble des pratiques que nous avons évoqué concernent avant tout une démarche. **Le développement
piloté par le Comportement est une démarche de travail avant de reposer sur des outils**. Non, les outils ne comptent pas, seule la communication
entre les différents acteurs d'un projet est essentielle.
Enfin, et c'est le plus important, rappelez-vous qu'**un projet informatique consiste à produire un service qui sera utilisé
par des humains** (utilisateurs finaux). C'est à ces personnes qu'il faut penser en priorité. Toutes les pratiques, toutes les recettes
fonctionnelles et techniques qui peuvent être mises en place dans un projet ne consistent qu'à optimiser et à améliorer le
service rendu par un Produit. A vous de faire en sorte que ce Produit soit le plus efficace possible.

View file

@ -0,0 +1,194 @@
# Le client ne sait pas ce qu'il veut. Sauf si... vous communiquez.
## Le client doit vous fournir sa Vision
J'ai souvent été confronté, en tant que développeur, et sur des projets de toutes tailles
(très grosses applications financières, petits intranet, sites web...) à cette situation : des
clients étaient incapables de me décrire ce qu'ils voulaient que je réalise pour eux.
A chaque fois, dans ce cas, il m'a fallu moi-même interpréter leurs souhaits, à partir de captures d'écrans de
sites concurrents, de discussions interminables... Et pour un résultat pas toujours très heureux.
A quoi la faute ? Au client ? Pas forcément : après tout, ce n'est pas parce qu'on est patron d'entreprise
ou que l'on a un besoin bien précis que l'on sait comment résoudre ce besoin, ou l'exprimer clairement.
Est-ce la faute du développeur, qui semble incapable de comprendre ce qu'on lui demande ? Personnellement
j'ai toujours essayé de faire de mon mieux, même si je suis conscient de ne pas avoir toujours été à la hauteur.
Et je crois que la plupart des développeurs font de même.
Alors ? Et si personne n'était en tort ? En réalité, la plupart des projets informatiques échouent car
ils ne sont pas motivés par une Vision. Certes on veut délivrer un super site web, avec plein de fonctionnalités
qui vont tuer la concurrence, on veut faire mieux que son voisin... Mais on oublie l'essentiel : un projet doit
voir un but.
Quel est ce but ? Peu importe : changer le monde, rendre service à une catégorie de personne, se faire de
l'argent... Tout est bon à prendre, du moment que cet objectif, cette Vision, reste le seul et unique maître
du projet.
On le comprend bien alors : ce n'est pas parce qu'un concurrent propose un service qu'il faut le recopier.
Non, on propose un nouveau service parce qu'il sert la Vision du projet.
Vous l'aurez compris : la Vision est essentielle, et c'est justement le rôle de votre client de la fournir.
Sans Vision, le projet est condamné à être un échec, ou au mieux une semi-réussite.
Votre client doit impérativement vous fournir cette Vision. S'il en est incapable, insistez pour qu'il soit
aidé : faites lui lire le premier tome de ce livre, faites le coacher par une société spécialisée...
Sans cela, vous ne pourrez pas travailler efficacement avec lui et ne prendrez pas autant de plaisir
que vous le méritez dans votre travail.
> La plupart des projets informatiques échouent car ils ne sont pas motivés par une Vision.
## Votre Client ne parle pas la même langue que vous
Vous l'avez vécu : votre client et vous ne vous comprenez pas toujours. Pour vous, un "réseau social"
c'est une plate-forme communautaire, avec des amis, relations, des groupes, des flux de messages...
Bref c'est Facebook.
Pour votre client, un "réseau social" c'est (par exemple) un espace où des employés font des demandes
de documents, découvrent les actualités de l'entreprise, échangent des informations sur les commandes...
Bref, c'est un intranet.
Attendez... Mais comment donc voulez-vous réussir à satisfaire votre client si vous n'employez
pas le même vocabulaire sur des choses si fondamentales ?
Ajoutez à cela que votre client va toujours avoir tendance à faire deux choses :
+ employer des acronymes, sigles et autre vocabulaire fonctionnel
+ employer des termes techniques ("base de données", "formulaire", "sauvegarder") sans savoir précisément ce qu'ils signifient
La première chose à faire lorsque vous démarrez un projet avec un client, c'est donc de vous
créer un vocabulaire commun. Il va falloir inventer une nouvelle langue, qui ne laisse plus la
place aux ambiguïtés, où chaque mot n'a qu'une seule signification.
J'ai une mauvaise nouvelle pour vous : ce nouveau vocabulaire, c'est à vous de l'apprendre, pas
à votre client. Cela vous évitera des débats interminables et vous permettra de mieux comprendre
le besoin du Client.
Si votre client, lorsqu'il dit "bus", parle en réalité d'un véhicule avec des ailes et que vous
retrouvez dans un aéroport, ne lui dites pas qu'il a tort. Non, désormais, lorsque vous parlerez
avec lui, vous emploierez le mot "bus" pour désigner ce que LUI entend par "bus".
Bien entendu, ce vocabulaire commun, vous devez le constituer ensemble. Si votre client parle de
"bus", et que c'est important dans le projet, discutez-en ensemble, et mettez noir sur blanc une
définition simple de ce qu'il entend par là.
Faites de même pour chaque expression que votre client emploie régulièrement. De cette manière vous
n'aurez plus aucune ambiguïté dans votre quotidien.
C'est le postulat de base du Développement piloté par le Comportement : vous devez élaborer avec votre
client une Langue Commune.
## Engagez-vous à livrer régulièrement
Quoi de plus frustrant, après de longues semaines de travail acharné, d'entendre un si triste
"Mais ce n'est pas du tout ce que j'avais demandé" ?
Et même un simple "ne pourrait-on pas juste changer..." peut s'avérer totalement démoralisant,
compte-tenu de tout ce qu'il faudra refaire techniquement pour gérer cette demande, et sachant
surtout combien cela aurait été simple si seulement on vous avait prévenu quelques semaines à l'avance.
Comment éviter d'être touché par ce malheureux constat d'échec, ou de semi-réussite ?
La réponse est en théorie simple : il suffit de livrer son travail très régulièrement au client, de sorte qu'il
puisse rapidement s'apercevoir le plus tôt possible que le projet n'est pas parti dans la direction
à laquelle il s'attendait.
Cette démarche est celle des méthodes agiles, particulièrement de Scrum. Le principe est le suivant :
plutôt que de livrer votre projet une bonne fois pour toute (lorsque le travail est terminé), vous vous engagez à livrer des
bouts de fonctionnalités très régulièrement (une fois toutes les deux semaines par exemple).
C'est ce qu'on appelle le développement par itérations, par opposition au cycle en V. Vous développez
grossièrement une fonctionnalité, puis vous l'affinez, l'affinez encore si besoin, jusqu'à arriver au
résultat final. De cette manière le client peut réorienter le projet à chaque itération sans que n'en
soyez affecté négativement.
Imaginez, par exemple, que votre travail consiste à peindre le célèbre tableau La Joconde. Avec la
méthodologie classique, votre devriez travailler de manière à finir chaque fonctionnalité de bout
en bout, puis, une fois qu'elle est entièrement terminée, passer à la suivante.
![ Méthodologie classique : le travail et découpé en lots, chaque lot est totalement réalisé avant de passer à la suite. Le changement fonctionnel en cours de route est difficile. ]
(mona-lisa-incremential.jpg)
Avec les méthodes agiles la démarche est inverse : vous esquissez d'abord les traits de ce que vous avez
à développer, afin de permettre au client d'avoir un aperçu du produit final et de bénéficier rapidement
du feedback des utilisateurs, puis vous affinez, selon la priorité de chaque fonctionnalité : une
fonctionnalité plus complète par là, un autre lors de l'itération suivante...
![Méthodologie agile : le tableau s'affine petit à petit. Le changement fonctionnel est facile, même en cours de route ]
(mona-lisa-iterative.jpg)
Bien entendu, cela ne va pas sans un changement des méthodologies de travail : il va falloir découper
les fonctionnalités pour faire en sorte qu'elles puissent être développées rapidement, il faut optimiser
les recettes (pourquoi ne pas en profiter pour utiliser des tests automatisés, comme des tests
unitaires ?)...
Mais, croyez-moi, ces efforts valent la peine : non seulement les relations avec votre client / patron
seront de plus en plus saines (le projet devient totalement transparent pour tous), mais en plus vous
arriverez vite à livrer du code fonctionnel régulièrement.
Et ô combien cela fait plaisir de voir que l'on avance ! Cela vous permettra même de gérer plus
facilement les demandes de changements fonctionnels : il est toujours plus facile de revenir sur
deux semaines de travail que sur trois mois, et c'est bien moins démoralisant.
Je vous conseille même de faire quelque chose qui peut sembler assez étrange : à chaque fois que vous
livrerez un lot fonctionnel, n'hésitez pas à présenter, pendant une heure ou deux, le fruit de votre
travail à votre client. Oui, comme un commercial ! Prenez même un vidéo-projecteur.
Calez systématiquement une réunion à chaque fin d'itération, et prenez la parole : montrez ce que
vous avez fait, et soyez-en fier ! Après tout, si vous avez donné le meilleur de vous même, il est
légitime que tout le monde sache de quoi il était question.
> Prenez la parole ! N'entendez plus jamais le fameux "Ce n'est pas ce que j'avais demandé".
## Adoptez le point de vue de l'utilisateur final
Chaque projet informatique, qu'il s'agisse d'un site web, d'un intranet, d'une application... tout
projet dessert un objectif : rendre service à quelqu'un. Il faut vous mettre dans la peau de cette personne.
Lorsque vous développez une boutique eCommerce, le service est rendu à un potentiel acheteur; lorsque
vous développez un intranet, ce sont les employés qui utiliseront l'intranet qui sont les bénéficiaires
du service.
Dans les deux cas, vous aurez besoin de comprendre comment le Produit va être utilisé. Finalement, à quoi
sert cette fonctionnalité ? Pourquoi est-elle utile ? Comment va t-elle rendre service ? Va t-elle faciliter
la vie de l'utilisateur ? Va t-elle lui permettre de réaliser quelque chose de nouveau ? Lui faire gagner
du temps ? Bref, quel est le bénéfice métier de la fonctionnalité que je vais développer ?
Pourquoi se poser ces questions ? Tout simplement pour prendre plus de plaisir dans votre travail, et pour
être plus efficace. Tant que ça ? Oui oui...
Après tout, si vous connaissez les personnes qui vont utiliser ce que vous êtes en train de développer, vous
pouvez discuter avec elles, adopter leur vocabulaire, et donc profiter directement de leur feedback. Petit à
petit, ce feedback sera de plus en plus positif ; ce sera alors de plus en plus agréable de voir que les gens
sont contents de ce que vous leurs offrez.
Cela vous permettra aussi de quitter à l'occasion la casquette de développeur pour, pourquoi pas, proposer
des améliorations, discuter de l'orientation du projet... Si vous savez comment va être utilisé le Produit,
qu'est-ce qui vous empêche d'essayer de l'améliorer ?
Changer de casquette peut parfois être difficile. Vous pouvez très bien travailler sur des projets dont
vous n'avez rien à faire ; c'est triste, mais ça arrive fréquemment. Il arrive de devoir travailler sur
un projet pour des besoins alimentaires. C'est légitime. Mais autant faire en sorte que même ces projets,
alimentaires, vous apportent de la satisfaction humaine. Adopter la vision de l'utilisateur final vous
permettra toujours d'échanger : échanger avec votre client, les utilisateurs finaux, vos collègues...
Il y a quelques temps, j'ai lancé un sondage auprès des développeurs de la société que j'ai accompagnée.
Une des questions était à peu près la suivante : "Prenez-vous plaisir dans votre travail?".
Près d'un quart des réponses étaient négatives. Quel dommage !
N'oubliez pas que vous travaillez dans un monde d'humains : plus vous interagirez avec eux, plus vous
fournirez un travail qui leur procurera satisfaction, plus vous même éprouverez du plaisir à travailler.
Le métier de développeur offre une chance unique : il permet de prendre plaisir en travaillant ; autant
en prendre le maximum !
> Changez de casquette pour prendre le maximum de plaisir dans votre métier de développeur.

View file

@ -0,0 +1,21 @@
# Le développement est un plaisir
"Le client ne sait jamais ce qu'il veut". Comment pouvez-vous, dans ce cas, faire en sorte qu'il soit satisfait ?
Êtes-vous condamné à délivrer des logiciels, sites web ou applications dont le client ne sera pas réellement
satisfait ?
Et vous-même, êtes-vous vraiment obligé de subir les contraintes fonctionnelles, de brider vos compétences
techniques ? Après tout, le métier de développeur est passionnant, et mérite qu'on y prenne le maximum de
plaisir ! Et c'est tellement décevant d'entendre cette fameuse phrase : "ce n'est pas ce que je voulais"...
Il m'arrive de poser cette question aux personnes que je rencontre : "avez-vous, au moins une fois,
participé à un projet informatique où le projet a été livré à l'heure, et où, non seulement le client,
mais aussi le développeur, le testeur, l'intégrateur... ont été pleinement satisfaits et y ont pris plaisir ?".
A l'heure où j'écris ces lignes, seule une personne m'a répondu "oui".
Quoi ?! Une seule personne ? Mais pourtant tous les projets devraient se passer comme ça.
Tous les projets devraient être livrés à l'heure, devraient être intéressants, enrichissants...
Toutes les personnes qui travaillent sur un projet devraient y prendre plaisir. Sinon, à quoi bon travailler ?
L'émergence des méthodes agiles, ces dernières années, a permis de remettre l'humain, et ses valeurs,
au centre des projets. Je vous propose de découvrir ici l'autre versant, la face technique, des méthodes
agiles : le Développement piloté par le Comportement.

View file

@ -0,0 +1,194 @@
# Optimisez vos tests fonctionnels
## Organisez vos Contextes de tests
Vous l'avez vu, l'ensemble des définitions (traduction d'une fonctionnalité) est stocké au sein
d'une classe PHP, ici `FeatureContext`.
Vous aurez très rapidement besoin d'organiser vos définitions de manière à vous y retrouver facilement. En effet, vous aurez
de plus en plus de définitions au fur-et-à-mesure que votre application grossira.
Il est très simple avec Behat de créer plusieurs Contextes de définitions. Par exemple, pour une application bancaire, on pourrait créer
les contextes de définition suivants :
+ Contexte de définitions pour les clients
+ Contexte de définitions pour les banquiers
+ Contexte de définitions pour les comptes bancaires
+ etc.
Pour cela, il suffit simplement de créer un fichier PHP (et une classe) par Contexte de définition, par exemple :
+ `ClientContext.php`
+ `BanquierContext.php`
+ `CompteContext.php`
Puis de les initialiser dans le fichier principal `FeatureContext` :
[php]
class FeatureContext extends BehatContext
{
public function __construct(array $parameters) {
$this->useContext('client', new ClientContext($parameters));
$this->useContext('banquier', new BanquierContext($parameters));
$this->useContext('compte', new CompteContext($parameters));
}
}
Désormais Behat utilisera l'ensemble des contextes disponibles pour traduire les expressions qu'il reçoit.
Remarquez les alias de Contexte que nous avons utilisés, par exemple "mink" dans le code suivant :
[php]
$this->useContext('mink', new MinkContext($parameters));
Ces alias vont vous permettre de récupérer facilement vos Contextes d'un Contexte à l'autre. Par exemple
pour récupérer votre contexte `mink` depuis le contexte `client`, il vous suffit d'utiliser le code suivant :
[php]
$mink = $this->getMainContext()->getSubContext('mink');
$session = $mink->getSession();
N'hésitez pas à découper vos Contextes de manière à les rendre facilement réutilisables par la suite. Cela vous évitera de mauvaises surprises
lorsque votre application grossira et que vous aurez à naviguer parmi plusieurs centaines de définitions.
> Découpez et organisez vos Contextes de définition
## Créez une couche d'isolation de l'IHM
Une grande (très grande!) difficulté du développement piloté par le Comportement consiste à réussir
à s'abstraire de l'interface graphique.
Imaginez par exemple la situation suivante : vous avez développé un site web pour votre client. Tout marche à merveille,
vous avez de très nombreuses définitions pour vérifier avec Behat que le besoin est bien implémenté...
Votre client est tellement content que désormais il souhaite disposer d'une application mobile, identique au site web.
Vous voyez le problème ? Vous allez devoir récrire toutes les définitions où vous avez écrit des choses comme
[php]
return array(
'Etant donné que je suis sur "/login"'
,'Quand je presse "Me connecter"
);
Car oui, sur mobile, il est fort probable que la manière de vérifier si le besoin est bien implémenté change radicalement par rapport
à un site web.
Et même sans un changement aussi radical que le passage d'un site web à une application mobile, comment gérer facilement les changements
d'interface graphique : une `table` devient une `div`, le texte du bouton `Se connecter` devient `Connexion`...
Le seul moyen d'éviter de devoir réécrire toutes ses définitions lorsqu'un changement d'interface survient (ce qui est le cas dans les
deux précédents exemples) est de **créer des couches d'isolation de l'interface**.
Concrètement, c'est très simple : il suffit de créer des Contextes de définition spécialisé dans l'affichage des pages. On peut
imaginer par exemple un Contexte de définition consacré à l'affichage des pages Web, qui contiendra donc nos définitions liées à l'affichage :
[php]
namespace View;
class WebContext extends BehatContext {
// (...)
}
Et une autre, le jour où l'on en a besoin, consacré à l'affichage sur mobile :
[php]
namespace View;
class MobileContext extends BehatContext {
// (...)
}
Désormais, il suffit d'ajouter un paramètre de configuration spécifique dans le fichier `behat.yml`, que l'on utilisera
pour définir quel Contexte de définition l'on souhaite utiliser :
[yaml]
default:
context:
parameters:
view: web # mobile | web ...
Une simple condition dans le constructeur du Contexte principal suffit à nous permettre d'utiliser le bon Contexte :
[php]
public function __construct(array $parameters)
{
if ($parameters['view'] == 'mobile') {
$this->useContext('view', new View\MobileContext($parameters));
} else {
$this->useContext('view', new View\WebContext($parameters));
}
}
Pour les applications assez conséquentes, il devient rapidement intéressant de créer même un Contexte
de définition par page (ou par lot fonctionnel) :
[php]
$this->useContext('view.catalogue', new View\Web\CatalogueContext($parameters));
$this->useContext('view.panier', new View\Web\PanierContext($parameters));
Cette pratique, que l'on pourrait désigner par Isolation de l'IHM, peut sembler complexe, mais est
en réalité le seul moyen efficace de péreniser les définitions au cours de la vie d'un projet.
N'hésitez pas à consulter la documentation de [BehatPageObjectExtension](https://github.com/sensiolabs/BehatPageObjectExtension),
qui est une extension de Behat dédiée à cet usage.
> Isolez ce qui concerne l'interface graphique dans des Contextes spécifiques
## Exploitez les compte-rendus de tests
Vous avez désormais un outil pour valider et vérifier qu'un besoin métier a bel et bien été implémenté. Pour l'instant,
vous avez exécuté vous-même Behat pour afficher ces informations dans un terminal. Vous vous en doutez, Behat va pouvoir
en faire bien plus.
Pour commencer, il est tout à fait possible de générer une page web synthétique des résultats des tests. Pour cela,
il suffit d'exécuter Behat en spécifiant le `html` comme format de sortie :
[bash]
php ./bin/behat --format html --out resultat.html
Vous disposerez donc d'une page web, graphique, que vous pouvez fournir à votre fonctionnel pour lui
indiquer de manière claire ce qui est fait ou reste à faire parmi les spécifications.
![ Le résultat de chaque Fonctionnalité et Scénario est visible dans une page web ](screen-export-html.jpg)
Bien entendu, ce n'est pas tout. La majorité des outils de tests automatisés sont capables de générer des
fichiers de sortie dans un format standard (xml). Ces fichiers peuvent donc être fournis à des logiciels tiers,
capables de les traiter ou de les transformer selon leurs spécificité.
Il est par exemple tout à fait possible d'intégrer Behat à une plate-forme d'intégration continue, comme Jenkins.
Une plate-forme d'intégration continue permet de délivrer en permanence du code source (déploiement continu),
c'est-à-dire de permettre à un site web d'être mis à jour très régulièrement.
Indirectement, les plate-formes d'intégration continue (PIC) fournissent une vision d'ensemble sur un projet : les
bonnes pratiques sont-elles respectées ? Le code est-il fiable ? Le besoin est-il respecté ? Behat va pouvoir se greffer
au coeur de cette plate-forme et va ainsi fournir des indices précieux pour la pilotage du projet.
Pour générer un résultat réutilisable par une plate-forme d'intégration continue, il suffit d'exécuter la commande suivante :
[bash]
php ./bin/behat --format junit --out resultat.xml
Pour aller plus loin avec les plate-formes d'intégration continue, je vous invite par exemple à consulter le site http://jenkins-php.org/.
Il existe également des outils visuels, basés sur ce format de sortie, pour fournir aux fonctionnels une vraie interface graphique
pour rédiger les spécifications, mais aussi pour avoir une vue d'ensemble des résultats des implémentations de ces spécifications.
![ Des outils graphiques pour visualiser et éditer les spécifications ](behat-wizard-home.jpg)
Parmi ces outils, on peut mentionner par exemple [BehatWizard](http://halleck45.github.com/BehatWizardBundle/demo/behat/wizard/list.html)
ou [BehatViewer](https://github.com/behat-viewer/BehatViewer).
Pour éviter de préciser manuellement quel format de sortie vous souhaitez utiliser lorsque vous lancez Behat, vous pouvez tout à
fait les préciser une bonne fois pour toute dans votre configuration, c'est-à-dire dans le fichier `behat.yml` :
[yaml]
default:
formatter:
name: pretty,junit,html
parameters:
output_path: null,junit,report.html
Cette configation vous permet par exemple d'afficher le résultat dans votre terminal, mais aussi générer des fichiers
de compte-rendu en HTML et en XML.
> Multiplier les formats de sortie de compte-rendus permet de multiplier les usages

View file

@ -0,0 +1,152 @@
# Votre code doit refléter le Besoin fonctionnel
Vous le savez, il arrive très souvent qu'un besoin fonctionnel évolue au cours de
la vie d'un projet. Et, parfois, une évolution fonctionnelle, même mineure, peut
entraîner une refonte majeure d'un code source.
C'est l'effet boule de neige : modifier un bloc de code va avoir un impact sur une
grande partie de code source, qui elle-même va concerner des domaines fonctionnels très variés,
entraînant des régressions fonctionnelles nombreuses et imprévisibles.
Si vous l'avez vécu, vous savez que c'est quelque chose qui est totalement
incompréhensible pour une personne qui n'est pas développeur. Ce n'est pas de la mauvaise
volonté, non ; c'est simplement que, s'il est déjà difficile de saisir pleinement qu'écrire
du code source permet au final d'avoir une application qui marche, comprendre qu'il existe
dans le code source des interactions fines, complexes et non liées aux domaines fonctionnels est
une chose quasiment impossible pour un fonctionnel.
Il faut donc trouver une solution pour répondre à ces deux questions fondamentales :
+ comment assurer la cohérence des changements techniques face aux changements fonctionnels ?
+ comment permettre aux fonctionnels d'anticiper le coût technique d'un changement fonctionnel ?
## Le Domain Driven Design
C'est justement l'enjeu du Domain Driven Design de répondre à ces questions. L'objet de
cet ouvrage n'est pas de faire de vous des spécialistes du Domain Driven Design (ou DDD) en
quelques pages. Non, il existe des livres très bien conçus, que je ne peux que vous inviter à
lire *(cf. Domain Driven Design Vite Fait + DDD de Eric Envans) - Liens à mettre*
Non, l'objectif ici est de comprendre qu'il existe des démarches de travail et de conception
logicielle qui permettent de faciliter la gestion du besoin fonctionnel. Et c'est là, justement, l'objet du DDD.
Le DDD est une démarche d'échange, de conception et de développement, dont l'objectif est de calquer
le code source (code, base de données, ressources...) sur le besoin métier.
Impossible ? Si, et même très profitable. Sitôt que vous aurez commencé à travailler de cette manière,
vous ne pourrez plus vous en passer.
L'idée générale est d'élaborer une Langue commune (cette Langue dont nous avons déjà parlé) avec
le fonctionnel, puis de concevoir une cartographie fonctionnelle de l'application, afin
d'utiliser, dans le code source, uniquement des concepts présents dans le domaine fonctionnel.
Dès lors, si cette démarche a été accomplie, il devient facile pour le développeur
d'identifier quelle proportion de code et quels modules techniques seront impactés par une
demande de changement fonctionnel : il lui "suffit" de superposer le nouveau besoin fonctionnel
sur l'ancien code source.
De cette manière, toute modification technique devient représentative des modifications fonctionnelles :
une modification fonctionnelle mineure risque moins d'entraîner une refonte technique longue et coûteuse.
Et a contrario, il est totalement légitime qu'une évolution fonctionnelle lourde nécessite une refonte
tout autant importante du code source.
De manière générale, il est important de prendre conscience que le travail du développeur est de répondre à
un besoin fonctionnel. Il est donc important de structurer son code, de quelque manière que ce soit, de
façon à répondre au mieux et le plus facilement à ce besoin.
> Les impacts techniques doivent être à la mesure des changements fonctionnels
## Les tests unitaires sont indispensables
En informatique on adore les sigles ; connaissez-vous le VDD ? C'est un sigle à la mode qui désigne
le "var_dump driven development", ou autrement dit, le développement piloté par la fonction `var_dump()` de PHP.
Notez que ça marche aussi si vous faites un `console.log()` en JavaScript, ou dans n'importe quel langage...
Pourquoi est-ce une expression à la mode ? Tout simplement parce qu'elle désigne une pratique de développement
vouée à l'extinction, qui consiste pour le développeur à afficher à l'écran les valeurs de certaines variables pour
en vérifier le contenu manuellement.
La raison pour laquelle cette pratique est vouée à disparaître est simple : lorsque l'on vérifie à la main
une valeur d'une variable, c'est long, ennuyant, et on risque de faire des erreurs.
En réalité, faire un var_dump() pour afficher une information à l'écran n'est ni plus ni moins qu'un contrôle sur
l'état d'une variable. Or il est très facile d'imaginer des robots dont la seule fonction est de s'assurer en permanence
de l'état d'une variable. Et ces robots, infatigables et extrêmement rapides, ne se tromperont jamais.
Ces robots, ce sont les tests unitaires automatisés. Écrire des tests unitaires est, à ce jour, l'un des seuls moyens vraiment efficaces
pour faciliter la vie d'un développeur, fiabiliser son code et réduire les coûts de maintenance d'une application.
Il existe dans tous les langages de programmation des outils qui facilitent la rédaction de tests unitaires : JUnit en Java, QUnit en JavaScript...
En PHP, deux outils se démarquent par leur fiabilité et leur grande communauté: [PHPUnit](http://phpunit.de), développé par Sebastian Bergmann,
et [atoum](http://docs.atoum.org), développé par Frédéric Hardy. Ces deux outils proposent une approche légèrement différente des tests unitaires,
mais sont tous les deux simples, efficaces et complets.
De manière générale, rédiger un test unitaire consiste à dérouler un processus simple :
+ mettre en condition un code que l'on souhaite tester : ce sont les conditions du test
+ exécuter une commande : il s'agit de ce que l'on souhaite tester
+ décrire quel doit être l'effet de la commande : il s'agit alors du résultat attendu
Lorsque l'on affiche une variable à l'écran pour vérifier sa valeur, en réalité, tout ce que l'on fait c'est exiger que
cette variable ait telle ou telle valeur. En d'autres termes, *on fait une assertion sur la valeur de la variable*.
Et toute assertion peut être traduite en code source.
On peut imaginer, par exemple, créer un test unitaire automatisé pour une fonction d'addition, qui utiliserait la
fonction PHP native `assert()` :
[php]
$resultat = addition(5,5);
assert($resultat === 10);
Ce code PHP générera une erreur si la fonction addition() ne renvoie pas "10".
L'avantage d'utiliser un outil de tests automatisés sera de pouvoir organiser ses tests facilement et efficacement. Chaque
assertion valide sera affichée en vert, les erreurs seront remontées aux développeur en un instant.
![ Les tests unitaires permettent de s'assurent que le code fonctionne comme prévu](phpunit.png)
Grâce aux tests automatisés, vous saurez à tout instant si vous venez de tout casser ou pas ;
ce sera d'autant plus facile de tout réparer...
> Les tests unitaires sont le seul moyen efficace de fiabiliser un code source
## Tester le besoin métier est indispensable
Tester son code source est bien. C'est même déjà pas mal du tout ! Mais une application web est plus qu'un code source : c'est
un assemblage de *comportements* (code source) *vis-à-vis d'informations* (données, souvent issues d'une base de données), *pour
délivrer un message* (par exemple une page web), le tout exécuté dans un environnement spécifique (serveur), le tout
*vis-à-vis d'un utilisateur* (navigateur).
On comprend vite du coup que ce n'est pas parce qu'un code source fonctionne de la manière attendue que l'application, elle aussi,
aura le comportement désiré.
Bien plus, il est en réalité difficile de tester unitairement l'ensemble d'un code source : c'est long et coûteux, et cela
exige des changements importants dans les pratiques de développement (Développement piloté par les tests, génération de
tests aléatoires, etc.).
C'est pour ces raisons qu'il existe différents niveaux de tests automatisés :
+ les *tests d'intégration*, qui s'assurent de l'environnement donné (version de PHP, présence d'un module apache...)
+ les *tests de charge*, qui s'assurent de la performance d'une application
+ les *tests unitaires*, qui vérifient le comportement du code source
+ les *tests d'interface*, qui vérifient qu'une application a bien l'aspect attendu
+ les *tests fonctionnels*, qui s'assurent que l'application délivre bien un service métier à l'utilisateur
Il existe bien entendu d'autres niveaux de tests (sécurité, cohérence...), mais ceux-ci sont les plus
répandus.
Le dernier niveau de test (le test fonctionnel) est sans doute parmi les plus importants. Finalement, tout votre travail
consiste justement à faire en sorte que l'utilisateur tire un bénéfice fonctionnel d'une application. S'assurer que
ce bénéfice fonctionnel est bien présent est indispensable pour votre client.
Mais justement, ce contrôle, autrement dit ce travail de Recette client, est long et laborieux. Il est source
d'erreurs, et surtout il est impossible de contrôler à la main, lors de chaque évolution fonctionnelle, que
l'ensemble de l'application fonctionne toujours de la manière attendue.
C'est pour cela qu'il existe désormais des outils de tests fonctionnels automatisés. Ces outils sont
infatigables: ils traquent en permanence votre application à la recherche d'anomalies fonctionnelles.
Nous verrons par la suite comment mettre en place ces outils. Mais avant de faire une recette fonctionnelle,
il faut déjà commencer par comprendre la demande initiale. Il est temps de découvrir comment faciliter la compréhension
d'une demande fonctionnelle.

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 KiB

Some files were not shown because too many files have changed in this diff Show more