Partager du code
maintenable et évolutif
Édition Débutant
{ PHP Style }
@wixiweb / @maximemdotnet
Les années 80 c'est terminé
Source : https://secure.flickr.com/photos/flysi/2586786319/in/photostream/
2014

Fini les nerd qui développent des application à eux tous seul

Entreprise IT / Système d'information / R&D

Freelance / Prestation

Projet open source / communautaire
Les technologies évoluent

L'électronique et l'informatique

Les techniques et langages de programmation

Les services

Les utilisateurs
Internet est omniprésent

Smartphone, tablette, PC, objets connectés

Tout le monde veut être présent

Se démarquer demande de + en + de ressources

Les utilisateurs sont de + en + exigeants
Problématiques
Source : https://secure.flickr.com/photos/watz/329055725/in/photostream/
Collaboration vs. Autonomie

Travailler en équipe sans interférer sur les tâches de chacun

Contrôler le code sans être derrière chaque développeur

Intégration de ressource / équipe distante ou télétravail

Être capable de reprendre le code d'un autre développeur
Rapidité vs. Réflexion

Les demandes clients et l'environnement changent

Il faut être réactif et compétitif face à la concurrence

Le manque de visibilité favorise les mauvais choix

Dette technique
Complexité vs. Compréhension

Les architectures sont de + en + complexes

Au fur et à mesure du temps le code devient + complexe

Un code complexe est difficile à maintenir et à changer

La complexité nécessite d'avoir plus de compétences
Pérennité vs. Péremption

Le code a une date de péremption, 3 à 5 ans

Les langages évoluent : amélioration, dépréciation, cassure

Les systèmes d'exploitation évoluent

En tant que développeur, vous évoluez
Solutions
Source : https://secure.flickr.com/photos/puuikibeach/3192430591/in/photostream/
10 trucs & astuces simples et rapides

10 conseils facilement applicables, dès demain !

Centrés sur le travail en équipe et la maintenabilité

Pas besoin d'être un Dieu du PHP pour les utiliser

À peaufiner au quotidien dans votre travail
Disclaimer

Conseils != Règles absolues

Je n'ai pas la prétention de vous apprendre à coder

Mettez en place une organisation à votre échelle

Appliquez le principe du « Close Enough »
Travailler en équipe
1. Outil de gestion de versions

git, subversion, mercurial

Travailler à plusieurs sur le même code source

Garder un historique et faire des versions de son application

Faire des évolutions et des bugfixes en parallèle
1. Outil de gestion de versions
Source : http://nvie.com/posts/a-successful-git-branching-model/
2. Utiliser un IDE

Netbeans, PhpStorm, vim

Environnement de Développement Intégré

Regroupe des outils pour coder plus rapidement / facilement

Utiliser le même IDE au sein d'une équipe
3. Utiliser une convention de codage

PEAR, Zend, PSR-1, PSR-2

Permet d'avoir un code source cohérent et une meilleure prise en main par une
personne qui ne l'aurait pas écrit

Les conventions de codage sont faites pour améliorer la lisibilité et éviter les
erreurs bêtes

Évite les débats stériles
PSR-*

PHP Framework Interoperability Group (PHP-FIG)

PSR = PHP Specification Request

Une recommandation pour utiliser PHP de manière interopérable

http://www.php-fig.org/
PSR-*

PSR-0 : Standard pour l'Autoloading

PSR-1 : Convention de codage de base

PSR-2 : Convention de style

PSR-4 : Amélioration du standard pour l'Autoloading
PHP_CodeSniffer

https://github.com/squizlabs/PHP_CodeSniffer

Parse le code PHP pour détecter les violations d'une convention
de codage définie

Supporte les conventions de codage les + populaires

Tester la compatibilité avec une version de PHP donnée
PHP_CodeSniffer
$ phpcs /path/to/code/myfile.php
FILE: /path/to/code/myfile.php
--------------------------------------------------------------------------------
FOUND 5 ERROR(S) AND 1 WARNING(S) AFFECTING 5 LINE(S)
--------------------------------------------------------------------------------
2 | ERROR | Missing file doc comment
20 | ERROR | PHP keywords must be lowercase; expected "false" but found
| | "FALSE"
47 | ERROR | Line not indented correctly; expected 4 spaces but found 1
47 | WARNING | Equals sign not aligned with surrounding assignments
51 | ERROR | Missing function doc comment
88 | ERROR | Line not indented correctly; expected 9 spaces but found 6
--------------------------------------------------------------------------------
PHP_CodeSniffer
4. Partager un environnement de
développement commun

Développer sur un environnement similaire à la production

Système d'exploitation, serveur web, version de PHP, SGBD

Une machine (ou un vhost) par développeur et par projet

Utiliser une solution de virtualisation : docker, proxmox, vagrant
Pourquoi produire du code maintenable ?
Source : https://xkcd.com/844/
Deux exemples concrets récents

Le firmware ECM de Toyota

=> Un mort

Le bug SSL d'Apple

=> Du troll à foison
if ((err = SSLFreeBuffer(&hashCtx)) != 0)
goto fail;
if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
err = sslRawVerify(ctx,
ctx->peerPubKey,
dataToSign, /* plaintext */
dataToSignLen, /* plaintext length */
signature,
signatureLen);
if(err) {
sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify "
"returned %dn", (int)err);
goto fail;
}
fail:
SSLFreeBuffer(&signedHashes);
SSLFreeBuffer(&hashCtx);
return err;
}
Source : https://opensource.apple.com/source/Security/Security-55471/libsecurity_ssl/lib/sslKeyExchange.c?txt
if ((err = SSLFreeBuffer(&hashCtx)) != 0)
goto fail;
if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
err = sslRawVerify(ctx,
ctx->peerPubKey,
dataToSign, /* plaintext */
dataToSignLen, /* plaintext length */
signature,
signatureLen);
if(err) {
sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify "
"returned %dn", (int)err);
goto fail;
}
fail:
SSLFreeBuffer(&signedHashes);
SSLFreeBuffer(&hashCtx);
return err;
}
Le code historique

Legacy code

Code présent avant vous, développé par quelqu'un d'autre

Principe du « touche pas le truc », inchangé depuis des années

Souvent fouillis, complexe, difficilement lisible
Pourquoi détestons-nous le code d'autrui ?

Le code nous paraît complexe

Manque de visibilité sur les choix faits

Syndrôme NIH : Not Invented Here

Avec le temps on déteste notre propre code
Mesurer la complexité
WTF / minute
Mesurer la complexité
Complexité Cyclomatique

Métrique pour mesurer la complexité logique

~ Représente le nombre de conditions + boucles dans le code

Plus de conditions équivaut à moins de compréhension

Le cerveau doit être attentif à tous les points de décisions
class Foo {
1 public function example() {
2 if ($a == $b) {
3 if ($a1 == $b1) {
fiddle();
4 } else if ($a2 == $b2) {
fiddle();
} else {
fiddle();
}
5 } else if ($c == $d) {
6 while ($c == $d) {
fiddle();
}
7 } else if ($e == $f) {
8 for ($n = 0; $n > $h; $n++) {
fiddle();
}
} else{
switch ($z) {
9 case 1:
fiddle();
break;
10 case 2:
fiddle();
break;
11 case 3:
fiddle();
break;
12 default:
fiddle();
break;
}}}}Source : http://phpmd.org/rules/codesize.html
Mesurer la complexité
Complexité N-Path

Représente le nombre de chemins uniques possibles

= nombre de tests nécessaires pour couvrir 100 % des cas

Plus de chemins égale moins de compréhension

Le cerveau doit garder en tête toutes les solutions possibles
Mesurer la complexité
Complexité N-Path
function example($a, $b) {
$c = 0;
if ($a < $b) {
$c = $a;
} elseif ($a > $b) {
$c = $b;
}
if ($c < 2) {
$c = $a + $b;
}
return $c;
}
Mesurer la complexité
Complexité N-Path
Les seuils idéaux

CC pour une méthode : de 1 à 4

CC moyenne par méthodes : de 1 à 2

CC sur le nombre total de lignes de code : de 0.01 à 0.05

N-Path pour une méthode : de 1 à 16
PHP Mess Detector

http://phpmd.org/

Calcul la complexité d'un code source selon plusieurs indicateurs

Indique l'utilisation de fonctions controversées

Détecte le code mort
PHP Mess Detector
Produire du code maintenable
Qu'est ce qu'un code maintenable ?

Lisible

Compréhensible

Réutilisable

Testable
La meilleure façon d'avoir un code maintenable
Source : https://secure.flickr.com/photos/f-oxymoron/9647972522/in/photostream/
La meilleure façon d'avoir un code maintenable
Ne pas l'écrire
Source : http://whynne.deviantart.com/art/Comic-Trolls-98357844
La meilleure façon d'avoir un code maintenable

Laisser quelqu'un d'autre coder et corriger à sa place

Ne pas réinventer la roue

L'utilisation de code produit par d'autres est instructif

Attention : ne pas confondre avec le copier / coller !
5. Utiliser un (bon) framework

Symfony 2, Zend Framework 2, Silex, Aura, Phalcon

Communauté active et ouverte

Des fondateurs / mainteneurs reconnus

Tirant partie des dernières fonctionnalités de PHP
5. Utiliser un (bon) framework

Symfony 2, Zend Framework 2, Silex, Aura, Phalcon

Communauté active et ouverte

Des fondateurs / mainteneurs reconnus

Tirant partie des dernières fonctionnalités de PHP
Composer

Gestionnaire de dépendances pour PHP

Installe et met à jour les librairies tierces utilisées dans vos projets

Possibilité de télécharger les librairies depuis plusieurs sources :
packagist.org par défaut

Génère un fichier pour gérer l'autoload dans vos projet
Composer

composer.json
{
"require": {
"phpmd/phpmd": "~1.5"
}
}
Composer
$ composer.phar install
Loading composer repositories with package information
Updating dependencies (including require-dev)
- Installing symfony/filesystem (v2.5.0)
Downloading: 100%
- Installing symfony/config (v2.5.0)
Downloading: 100%
- Installing symfony/dependency-injection (v2.5.0)
Downloading: 100%
- Installing pdepend/pdepend (2.0.0)
Downloading: 100%
- Installing phpmd/phpmd (1.5.0)
Downloading: 100%
symfony/dependency-injection suggests installing symfony/yaml ()
symfony/dependency-injection suggests installing symfony/proxy-manager-bridge (Generate service proxies to lazy load them)
Writing lock file
Generating autoload files
Produire du code maintenable (en vrai)
Source : https://twitter.com/dr4goonis/status/476617165463105536
Objectifs

Écrire le moins de code possible

Réduire la complexité

Augmenter la ré-utilisabilité

Pouvoir écrire des tests rapidement
Les 5 principes SOLID
S Single responsibility Responsabilité unique
O Open/closed Ouvert/fermé
L Liskov Substitution Substitution de Liskov
I Interface Segregation Ségrégation des interfaces
D Dependency Inversion Principle Inversion des dépendances
6. Factoriser son code

20 lignes maximum par méthode

200 lignes maximum par classe

10 méthodes maximum par classe

15 classes maximum par package
7. Un seul niveau d'indentation par méthode

Pas de condition / boucle imbriquée

Tirer partie des fonctions natives de PHP, + rapides, + lisibles

Responsabilité unique, - complexité, + ré-utilisabilité

Mode ninja : pas de « else »
7. Un seul niveau d'indentation par méthode

Early return / Guard clauses

Extraire les conditions dans des méthodes : isValid()

PHP propose ~80 fonctions natives pour manipuler les tableaux

D'autres pratiques :
http://sourcemaking.com/refactoring/simplifying-conditional-expressions
7. Un seul niveau d'indentation par méthode
8. Pas d’abréviation !

Utiliser des noms de variable et méthode qui ont du sens (in english !)

Penser le nommage comme des Lego

Éviter les noms génériques : $index,  $key, $value, $object, etc.

Nom de variable / méthode trop long et dupliqué partout ?
→ Trop de responsabilités, pas assez de factorisation
$temp = array();
for ($i = 0; $i < strlen($title); $i++)
{
$ordinal = ord($title[$i]);
if ($ordinal < 128)
{
$x[] = "|".$ordinal;
}
else
{
if (count($temp) == 0)
{
$count = ($ordinal < 224) ? 2 : 3;
}
$temp[] = $ordinal;
if (count($temp) == $count)
{
$number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] %
$x[] = "|".$number;
$count = 1;
$temp = array();
}
}
}
Source : CodeIgniter 2.2.0
8. Pas d’abréviation !
Source : http://trollcats.com
8. Pas d’abréviation !
function findUserByEmail($emailAddress) {}
function write(PostTitle $postTitle, PostContent $postContent);
$pageCount = ceil(count($userCollection) / $entityPerPage);
$addressLines = explode(PHP_EOL, $address);
8. Pas d’abréviation !
9. Lisibilité
Morbi molestie, elit vitae consectetur adipiscing, orci nulla hendrerit
risus, ac vehicula orci eros sed leo. Fusce auctor ut ipsum non
pharetra. Nunc at lorem gravida, scelerisque neque sed, lacinia
ipsum! Aenean malesuada felis quam, fermentum fermentum elit
viverra ut! Ut a orci sapien. Nulla dictum leo et tortor sollicitudin
tempus. Aliquam lacinia, quam in condimentum aliquet, nisi augue
feugiat ligula; eget cursus felis est sit amet augue. Morbi pulvinar
pharetra cursus? Mauris feugiat lectus vel felis bibendum dignissim.
In hac habitasse platea dictumst. Phasellus id consectetur magna!
9. Lisibilité
Morbi molestie, elit vitae consectetur
adipiscing, orci nulla hendrerit risus, ac
vehicula orci eros sed leo.
Fusce auctor ut ipsum non pharetra.
Nunc at lorem gravida, scelerisque neque
sed, lacinia ipsum!
Aenean malesuada felis quam, fermentum
fermentum elit viverra ut!
Ut a orci sapien. Nulla dictum leo et tortor
sollicitudin tempus.
Aliquam lacinia, quam in condimentum
aliquet, nisi augue feugiat ligula; eget
cursus felis est sit amet augue.
9. Lisibilité

Penser le code comme du texte

Faire des paragraphes, aérer le code

Faire le moins de colonnes possibles

Une seule par ligne→
9. Lisibilité
$serviceManager = $this->serviceManager;
$events = $this->events;
$listeners = array_unique(array_merge($this->defaultListeners, $listeners));
foreach ($listeners as $listener) {
$events->attach($serviceManager->get($listener));
}
// Setup MVC Event
$this->event = $event = new MvcEvent();
$event->setTarget($this);
$event->setApplication($this)
->setRequest($this->request)
->setResponse($this->response)
->setRouter($serviceManager->get('Router'));
// Trigger bootstrap events
$events->trigger(MvcEvent::EVENT_BOOTSTRAP, $event);
return $this;
Source : Zend Framework 2.3.1
9. Lisibilité
public function someVeryLongMethodName(ObjectType $firstArgument,
ObjectType $secondArgument,
ObjectType $thirdArgument)
{
// ...
}
public function someVeryLongMethodName(
ObjectType $firstArgument,
ObjectType $secondArgument,
ObjectType $thirdArgument)
{
// ...
}
$longVariableName = array($someKey => $someValue,
$anotherKey => $anotherValue);
$longVariableName = array(
$someKey => $someValue,
$anotherKey => $anotherValue);
9. Lisibilité
$this->context->customer->firstname.' '.$this->context->customer->lastname
$this->getCustomer()
->getFullname();
Source : Prestashop 1.6.0.8
10. Documenter son code

Utiliser le (presque) standard PHPDoc

Ajouter un DocBlock au début de chaque méthode

1 à 2 lignes de commentaires au début de chaque paragraphe

Auto-complétion / Documentation dans l'IDE
10. Documenter son code
// Si le formulaire est valide
if ($form->isValid() === true) {
}
// Retourne l'utilisateur
return $user;
//When I wrote this, only God and I understood what I was doing
//Now, God only knows
10. Documenter son code
/**
* Bootstrap the application
*
* Defines and binds the MvcEvent, and passes it the request, response, and
* router. Attaches the ViewManager as a listener. Triggers the bootstrap
* event.
*
* @param array $listeners List of listeners to attach.
* @return Application
*/
public function bootstrap(array $listeners = array())
Source : Zend Framework 2.3.1
10. Documenter son code
// Send a challenge in each acceptable authentication scheme
$headers = $this->response->getHeaders();
if (in_array('basic', $this->acceptSchemes)) {
$headers->addHeaderLine($headerName, $this->_basicHeader());
}
if (in_array('digest', $this->acceptSchemes)) {
$headers->addHeaderLine($headerName, $this->_digestHeader());
}
return new AuthenticationResult(
AuthenticationResult::FAILURE_CREDENTIAL_INVALID,
array(),
array('Invalid or absent credentials; challenging client')
);
Source : Zend Framework 2.3.1
Récapitulatif
1. Utiliser un outil de gestion de versions
2. Utiliser un IDE
3. Utiliser une convention de codage
4. Partager un environnement de développement commun
5. Utiliser un framework / du code produit par d'autres équipes
6. Factoriser son code : 20 lignes de code maximum par méthode
7. 1 niveau d'indentation maximum par méthode
8. Pas d'abréviation dans les noms de variables et méthodes
9. Améliorer la lisibilité de son code en formant des paragraphes
10.Documenter son code
Prochaines étapes

Écrire du code propice à l'évolution

Tester son code

Intégration continue

Passer Paladin niveau 7
Entraînez-vous :)
Questions ?
Merci de votre attention :)
@wixiweb / @maximemdotnet

Conférence #nwx2014 - Maxime Mauchaussée - Partager du code maintenable et évolutif

  • 1.
    Partager du code maintenableet évolutif Édition Débutant { PHP Style } @wixiweb / @maximemdotnet
  • 2.
    Les années 80c'est terminé Source : https://secure.flickr.com/photos/flysi/2586786319/in/photostream/
  • 3.
    2014  Fini les nerdqui développent des application à eux tous seul  Entreprise IT / Système d'information / R&D  Freelance / Prestation  Projet open source / communautaire
  • 4.
    Les technologies évoluent  L'électroniqueet l'informatique  Les techniques et langages de programmation  Les services  Les utilisateurs
  • 5.
    Internet est omniprésent  Smartphone,tablette, PC, objets connectés  Tout le monde veut être présent  Se démarquer demande de + en + de ressources  Les utilisateurs sont de + en + exigeants
  • 6.
  • 7.
    Collaboration vs. Autonomie  Travailleren équipe sans interférer sur les tâches de chacun  Contrôler le code sans être derrière chaque développeur  Intégration de ressource / équipe distante ou télétravail  Être capable de reprendre le code d'un autre développeur
  • 8.
    Rapidité vs. Réflexion  Lesdemandes clients et l'environnement changent  Il faut être réactif et compétitif face à la concurrence  Le manque de visibilité favorise les mauvais choix  Dette technique
  • 9.
    Complexité vs. Compréhension  Lesarchitectures sont de + en + complexes  Au fur et à mesure du temps le code devient + complexe  Un code complexe est difficile à maintenir et à changer  La complexité nécessite d'avoir plus de compétences
  • 10.
    Pérennité vs. Péremption  Lecode a une date de péremption, 3 à 5 ans  Les langages évoluent : amélioration, dépréciation, cassure  Les systèmes d'exploitation évoluent  En tant que développeur, vous évoluez
  • 11.
  • 12.
    10 trucs &astuces simples et rapides  10 conseils facilement applicables, dès demain !  Centrés sur le travail en équipe et la maintenabilité  Pas besoin d'être un Dieu du PHP pour les utiliser  À peaufiner au quotidien dans votre travail
  • 13.
    Disclaimer  Conseils != Règlesabsolues  Je n'ai pas la prétention de vous apprendre à coder  Mettez en place une organisation à votre échelle  Appliquez le principe du « Close Enough »
  • 14.
  • 15.
    1. Outil degestion de versions  git, subversion, mercurial  Travailler à plusieurs sur le même code source  Garder un historique et faire des versions de son application  Faire des évolutions et des bugfixes en parallèle
  • 16.
    1. Outil degestion de versions Source : http://nvie.com/posts/a-successful-git-branching-model/
  • 17.
    2. Utiliser unIDE  Netbeans, PhpStorm, vim  Environnement de Développement Intégré  Regroupe des outils pour coder plus rapidement / facilement  Utiliser le même IDE au sein d'une équipe
  • 18.
    3. Utiliser uneconvention de codage  PEAR, Zend, PSR-1, PSR-2  Permet d'avoir un code source cohérent et une meilleure prise en main par une personne qui ne l'aurait pas écrit  Les conventions de codage sont faites pour améliorer la lisibilité et éviter les erreurs bêtes  Évite les débats stériles
  • 19.
    PSR-*  PHP Framework InteroperabilityGroup (PHP-FIG)  PSR = PHP Specification Request  Une recommandation pour utiliser PHP de manière interopérable  http://www.php-fig.org/
  • 20.
    PSR-*  PSR-0 : Standard pourl'Autoloading  PSR-1 : Convention de codage de base  PSR-2 : Convention de style  PSR-4 : Amélioration du standard pour l'Autoloading
  • 21.
    PHP_CodeSniffer  https://github.com/squizlabs/PHP_CodeSniffer  Parse le codePHP pour détecter les violations d'une convention de codage définie  Supporte les conventions de codage les + populaires  Tester la compatibilité avec une version de PHP donnée
  • 22.
    PHP_CodeSniffer $ phpcs /path/to/code/myfile.php FILE:/path/to/code/myfile.php -------------------------------------------------------------------------------- FOUND 5 ERROR(S) AND 1 WARNING(S) AFFECTING 5 LINE(S) -------------------------------------------------------------------------------- 2 | ERROR | Missing file doc comment 20 | ERROR | PHP keywords must be lowercase; expected "false" but found | | "FALSE" 47 | ERROR | Line not indented correctly; expected 4 spaces but found 1 47 | WARNING | Equals sign not aligned with surrounding assignments 51 | ERROR | Missing function doc comment 88 | ERROR | Line not indented correctly; expected 9 spaces but found 6 --------------------------------------------------------------------------------
  • 23.
  • 24.
    4. Partager unenvironnement de développement commun  Développer sur un environnement similaire à la production  Système d'exploitation, serveur web, version de PHP, SGBD  Une machine (ou un vhost) par développeur et par projet  Utiliser une solution de virtualisation : docker, proxmox, vagrant
  • 25.
    Pourquoi produire ducode maintenable ? Source : https://xkcd.com/844/
  • 26.
    Deux exemples concretsrécents  Le firmware ECM de Toyota  => Un mort  Le bug SSL d'Apple  => Du troll à foison
  • 27.
    if ((err =SSLFreeBuffer(&hashCtx)) != 0) goto fail; if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail; err = sslRawVerify(ctx, ctx->peerPubKey, dataToSign, /* plaintext */ dataToSignLen, /* plaintext length */ signature, signatureLen); if(err) { sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify " "returned %dn", (int)err); goto fail; } fail: SSLFreeBuffer(&signedHashes); SSLFreeBuffer(&hashCtx); return err; } Source : https://opensource.apple.com/source/Security/Security-55471/libsecurity_ssl/lib/sslKeyExchange.c?txt
  • 28.
    if ((err =SSLFreeBuffer(&hashCtx)) != 0) goto fail; if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail; err = sslRawVerify(ctx, ctx->peerPubKey, dataToSign, /* plaintext */ dataToSignLen, /* plaintext length */ signature, signatureLen); if(err) { sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify " "returned %dn", (int)err); goto fail; } fail: SSLFreeBuffer(&signedHashes); SSLFreeBuffer(&hashCtx); return err; }
  • 29.
    Le code historique  Legacycode  Code présent avant vous, développé par quelqu'un d'autre  Principe du « touche pas le truc », inchangé depuis des années  Souvent fouillis, complexe, difficilement lisible
  • 30.
    Pourquoi détestons-nous lecode d'autrui ?  Le code nous paraît complexe  Manque de visibilité sur les choix faits  Syndrôme NIH : Not Invented Here  Avec le temps on déteste notre propre code
  • 31.
  • 32.
    Mesurer la complexité ComplexitéCyclomatique  Métrique pour mesurer la complexité logique  ~ Représente le nombre de conditions + boucles dans le code  Plus de conditions équivaut à moins de compréhension  Le cerveau doit être attentif à tous les points de décisions
  • 33.
    class Foo { 1public function example() { 2 if ($a == $b) { 3 if ($a1 == $b1) { fiddle(); 4 } else if ($a2 == $b2) { fiddle(); } else { fiddle(); } 5 } else if ($c == $d) { 6 while ($c == $d) { fiddle(); } 7 } else if ($e == $f) { 8 for ($n = 0; $n > $h; $n++) { fiddle(); } } else{ switch ($z) { 9 case 1: fiddle(); break; 10 case 2: fiddle(); break; 11 case 3: fiddle(); break; 12 default: fiddle(); break; }}}}Source : http://phpmd.org/rules/codesize.html
  • 34.
    Mesurer la complexité ComplexitéN-Path  Représente le nombre de chemins uniques possibles  = nombre de tests nécessaires pour couvrir 100 % des cas  Plus de chemins égale moins de compréhension  Le cerveau doit garder en tête toutes les solutions possibles
  • 35.
    Mesurer la complexité ComplexitéN-Path function example($a, $b) { $c = 0; if ($a < $b) { $c = $a; } elseif ($a > $b) { $c = $b; } if ($c < 2) { $c = $a + $b; } return $c; }
  • 36.
  • 37.
    Les seuils idéaux  CCpour une méthode : de 1 à 4  CC moyenne par méthodes : de 1 à 2  CC sur le nombre total de lignes de code : de 0.01 à 0.05  N-Path pour une méthode : de 1 à 16
  • 38.
    PHP Mess Detector  http://phpmd.org/  Calculla complexité d'un code source selon plusieurs indicateurs  Indique l'utilisation de fonctions controversées  Détecte le code mort
  • 39.
  • 40.
    Produire du codemaintenable
  • 41.
    Qu'est ce qu'uncode maintenable ?  Lisible  Compréhensible  Réutilisable  Testable
  • 42.
    La meilleure façond'avoir un code maintenable Source : https://secure.flickr.com/photos/f-oxymoron/9647972522/in/photostream/
  • 43.
    La meilleure façond'avoir un code maintenable Ne pas l'écrire
  • 44.
  • 45.
    La meilleure façond'avoir un code maintenable  Laisser quelqu'un d'autre coder et corriger à sa place  Ne pas réinventer la roue  L'utilisation de code produit par d'autres est instructif  Attention : ne pas confondre avec le copier / coller !
  • 46.
    5. Utiliser un(bon) framework  Symfony 2, Zend Framework 2, Silex, Aura, Phalcon  Communauté active et ouverte  Des fondateurs / mainteneurs reconnus  Tirant partie des dernières fonctionnalités de PHP
  • 47.
    5. Utiliser un(bon) framework  Symfony 2, Zend Framework 2, Silex, Aura, Phalcon  Communauté active et ouverte  Des fondateurs / mainteneurs reconnus  Tirant partie des dernières fonctionnalités de PHP
  • 48.
    Composer  Gestionnaire de dépendancespour PHP  Installe et met à jour les librairies tierces utilisées dans vos projets  Possibilité de télécharger les librairies depuis plusieurs sources : packagist.org par défaut  Génère un fichier pour gérer l'autoload dans vos projet
  • 49.
  • 50.
    Composer $ composer.phar install Loadingcomposer repositories with package information Updating dependencies (including require-dev) - Installing symfony/filesystem (v2.5.0) Downloading: 100% - Installing symfony/config (v2.5.0) Downloading: 100% - Installing symfony/dependency-injection (v2.5.0) Downloading: 100% - Installing pdepend/pdepend (2.0.0) Downloading: 100% - Installing phpmd/phpmd (1.5.0) Downloading: 100% symfony/dependency-injection suggests installing symfony/yaml () symfony/dependency-injection suggests installing symfony/proxy-manager-bridge (Generate service proxies to lazy load them) Writing lock file Generating autoload files
  • 51.
    Produire du codemaintenable (en vrai) Source : https://twitter.com/dr4goonis/status/476617165463105536
  • 52.
    Objectifs  Écrire le moinsde code possible  Réduire la complexité  Augmenter la ré-utilisabilité  Pouvoir écrire des tests rapidement
  • 53.
    Les 5 principesSOLID S Single responsibility Responsabilité unique O Open/closed Ouvert/fermé L Liskov Substitution Substitution de Liskov I Interface Segregation Ségrégation des interfaces D Dependency Inversion Principle Inversion des dépendances
  • 54.
    6. Factoriser soncode  20 lignes maximum par méthode  200 lignes maximum par classe  10 méthodes maximum par classe  15 classes maximum par package
  • 55.
    7. Un seulniveau d'indentation par méthode  Pas de condition / boucle imbriquée  Tirer partie des fonctions natives de PHP, + rapides, + lisibles  Responsabilité unique, - complexité, + ré-utilisabilité  Mode ninja : pas de « else »
  • 56.
    7. Un seulniveau d'indentation par méthode  Early return / Guard clauses  Extraire les conditions dans des méthodes : isValid()  PHP propose ~80 fonctions natives pour manipuler les tableaux  D'autres pratiques : http://sourcemaking.com/refactoring/simplifying-conditional-expressions
  • 57.
    7. Un seulniveau d'indentation par méthode
  • 58.
    8. Pas d’abréviation !  Utiliserdes noms de variable et méthode qui ont du sens (in english !)  Penser le nommage comme des Lego  Éviter les noms génériques : $index,  $key, $value, $object, etc.  Nom de variable / méthode trop long et dupliqué partout ? → Trop de responsabilités, pas assez de factorisation
  • 59.
    $temp = array(); for($i = 0; $i < strlen($title); $i++) { $ordinal = ord($title[$i]); if ($ordinal < 128) { $x[] = "|".$ordinal; } else { if (count($temp) == 0) { $count = ($ordinal < 224) ? 2 : 3; } $temp[] = $ordinal; if (count($temp) == $count) { $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % $x[] = "|".$number; $count = 1; $temp = array(); } } } Source : CodeIgniter 2.2.0
  • 60.
  • 61.
    8. Pas d’abréviation ! functionfindUserByEmail($emailAddress) {} function write(PostTitle $postTitle, PostContent $postContent); $pageCount = ceil(count($userCollection) / $entityPerPage); $addressLines = explode(PHP_EOL, $address);
  • 62.
  • 63.
    9. Lisibilité Morbi molestie,elit vitae consectetur adipiscing, orci nulla hendrerit risus, ac vehicula orci eros sed leo. Fusce auctor ut ipsum non pharetra. Nunc at lorem gravida, scelerisque neque sed, lacinia ipsum! Aenean malesuada felis quam, fermentum fermentum elit viverra ut! Ut a orci sapien. Nulla dictum leo et tortor sollicitudin tempus. Aliquam lacinia, quam in condimentum aliquet, nisi augue feugiat ligula; eget cursus felis est sit amet augue. Morbi pulvinar pharetra cursus? Mauris feugiat lectus vel felis bibendum dignissim. In hac habitasse platea dictumst. Phasellus id consectetur magna!
  • 64.
    9. Lisibilité Morbi molestie,elit vitae consectetur adipiscing, orci nulla hendrerit risus, ac vehicula orci eros sed leo. Fusce auctor ut ipsum non pharetra. Nunc at lorem gravida, scelerisque neque sed, lacinia ipsum! Aenean malesuada felis quam, fermentum fermentum elit viverra ut! Ut a orci sapien. Nulla dictum leo et tortor sollicitudin tempus. Aliquam lacinia, quam in condimentum aliquet, nisi augue feugiat ligula; eget cursus felis est sit amet augue.
  • 65.
    9. Lisibilité  Penser lecode comme du texte  Faire des paragraphes, aérer le code  Faire le moins de colonnes possibles  Une seule par ligne→
  • 66.
    9. Lisibilité $serviceManager =$this->serviceManager; $events = $this->events; $listeners = array_unique(array_merge($this->defaultListeners, $listeners)); foreach ($listeners as $listener) { $events->attach($serviceManager->get($listener)); } // Setup MVC Event $this->event = $event = new MvcEvent(); $event->setTarget($this); $event->setApplication($this) ->setRequest($this->request) ->setResponse($this->response) ->setRouter($serviceManager->get('Router')); // Trigger bootstrap events $events->trigger(MvcEvent::EVENT_BOOTSTRAP, $event); return $this; Source : Zend Framework 2.3.1
  • 67.
    9. Lisibilité public functionsomeVeryLongMethodName(ObjectType $firstArgument, ObjectType $secondArgument, ObjectType $thirdArgument) { // ... } public function someVeryLongMethodName( ObjectType $firstArgument, ObjectType $secondArgument, ObjectType $thirdArgument) { // ... } $longVariableName = array($someKey => $someValue, $anotherKey => $anotherValue); $longVariableName = array( $someKey => $someValue, $anotherKey => $anotherValue);
  • 68.
  • 69.
    10. Documenter soncode  Utiliser le (presque) standard PHPDoc  Ajouter un DocBlock au début de chaque méthode  1 à 2 lignes de commentaires au début de chaque paragraphe  Auto-complétion / Documentation dans l'IDE
  • 70.
    10. Documenter soncode // Si le formulaire est valide if ($form->isValid() === true) { } // Retourne l'utilisateur return $user; //When I wrote this, only God and I understood what I was doing //Now, God only knows
  • 71.
    10. Documenter soncode /** * Bootstrap the application * * Defines and binds the MvcEvent, and passes it the request, response, and * router. Attaches the ViewManager as a listener. Triggers the bootstrap * event. * * @param array $listeners List of listeners to attach. * @return Application */ public function bootstrap(array $listeners = array()) Source : Zend Framework 2.3.1
  • 72.
    10. Documenter soncode // Send a challenge in each acceptable authentication scheme $headers = $this->response->getHeaders(); if (in_array('basic', $this->acceptSchemes)) { $headers->addHeaderLine($headerName, $this->_basicHeader()); } if (in_array('digest', $this->acceptSchemes)) { $headers->addHeaderLine($headerName, $this->_digestHeader()); } return new AuthenticationResult( AuthenticationResult::FAILURE_CREDENTIAL_INVALID, array(), array('Invalid or absent credentials; challenging client') ); Source : Zend Framework 2.3.1
  • 73.
    Récapitulatif 1. Utiliser unoutil de gestion de versions 2. Utiliser un IDE 3. Utiliser une convention de codage 4. Partager un environnement de développement commun 5. Utiliser un framework / du code produit par d'autres équipes 6. Factoriser son code : 20 lignes de code maximum par méthode 7. 1 niveau d'indentation maximum par méthode 8. Pas d'abréviation dans les noms de variables et méthodes 9. Améliorer la lisibilité de son code en formant des paragraphes 10.Documenter son code
  • 74.
    Prochaines étapes  Écrire ducode propice à l'évolution  Tester son code  Intégration continue  Passer Paladin niveau 7
  • 75.
  • 76.
  • 77.
    Merci de votreattention :) @wixiweb / @maximemdotnet