IX. Style et efficacité▲
La qualité est importante. Les programmes ont des bogues. Les programmes ont besoin de maintenance et d'expansion. Les programmes ont plusieurs programmeurs.
Pour bien programmer, nous devons trouver l'équilibre entre finir le travail maintenant et rendre nos vies plus faciles à l'avenir, lors de la maintenance. Nous devons équilibrer temps, ressources et qualité. L'art de la programmation exige que nous le fassions au mieux de notre capacité.
Pour bien écrire en Perl, nous devons comprendre le langage. Nous devons aussi cultiver un sens du bon goût pour le langage et la conception des programmes. La seule façon de le faire est de pratiquer en maintenant du code et en lisant et écrivant du très bon code. Ce chemin n'a aucun raccourci, mais il a des repères.
IX-A. Écrire du Perl maintenable▲
La maintenabilité évalue de façon nébuleuse dans quelle mesure un programme est facile à comprendre et à modifier. Écrivez du code. Revenez-y dans six mois. Combien de temps vous faut-il pour corriger un bogue ou ajouter une fonctionnalité ? C'est cela la maintenabilité.
La maintenabilité ne prend pas en compte si vous devez rechercher la syntaxe d'une commande interne ou une fonction d'une bibliothèque. Elle ne mesure pas la façon dont quelqu'un qui n'a jamais programmé avant lira ou pas votre code. Il est plus intéressant de se demander si un programmeur compétent qui comprend le problème que vous essayez de résoudre trouvera facile ou difficile de modifier le programme. Quels sont les problèmes qui gênent la correction d'un bogue ou l'ajout correct d'une amélioration ?
Pour écrire un logiciel facile à maintenir, vous avez besoin d'expérience dans la résolution des problèmes réels, une compréhension des idiomes, des techniques et du style de votre langage de programmation et du bon goût. Vous pouvez développer tout cela en vous concentrant sur quelques principes :
- supprimez le code dupliqué. Les bogues se cachent dans les sections de code répété et similaire lorsque vous corrigez un bogue dans un morceau de code, est-ce que vous devez le corriger aussi ailleurs ? Lorsque vous mettez à jour une section, devez-vous en mettre à jour d'autres ?
Les systèmes bien conçus ont peu de duplication. Ils utilisent des fonctions, des modules, des objets et des rôles pour extraire le code dupliqué dans des composants distincts qui modélisent avec précision le domaine du problème. Les meilleures conceptions vous permettent d'ajouter des fonctionnalités en supprimant du code ; - nommez bien les entités. Votre code raconte une histoire. Chaque nom que vous choisissez pour une variable, une fonction, un module et une classe vous permet de clarifier ou d'obscurcir votre intention. Choisissez soigneusement vos noms. Si vous rencontrez des difficultés à choisir de bons noms, vous devrez peut-être repenser votre conception ou étudier votre problème plus en détail ;
- évitez l'ingéniosité inutile. Le code concis est bon lorsqu'il révèle ses intentions. Le code ingénieux cache votre intention derrière des astuces voyantes. Perl vous permet d'écrire le bon code au bon moment. Choisissez la solution la plus évidente lorsque cela est possible. L'expérience et le bon goût vous guideront.
Certains problèmes exigent des solutions astucieuses. Lorsque cela se produit, encapsulez ce code derrière une interface simple et documentez votre ingéniosité ; - embrassez la simplicité. Si tout le reste est égal, un programme simple est plus facile à maintenir que sa version plus complexe. La simplicité signifie savoir ce qui est le plus important et faire exactement cela.
Parfois, vous avez besoin d'un code puissant, robuste. Parfois, vous avez besoin d'une seule ligne de script. La simplicité signifie faire la différence entre les deux cas de figure et utiliser seulement ce dont vous avez besoin. Il n'existe aucune excuse pour éviter la vérification des erreurs ou la modularité ou la validation ou la sécurité. Le code simple peut utiliser des fonctionnalités avancées. Le code simple peut utiliser des modules du CPAN et beaucoup d'entre eux. Le code simple peut nécessiter du travail pour être compris. Pourtant le code simple résout les problèmes de manière efficace, sans travail inutile.
IX-B. Écrire du Perl idiomatique▲
Perl s'inspire largement d'autres langages. Perl vous permet d'écrire le code que vous voulez écrire. Les programmeurs C écrivent souvent en Perl dans un style ressemblant au C, tout comme les programmeurs Java écrivent du Perl du style du Java. Les programmeurs Perl efficaces écrivent du Perl « perlien », embrassant les idiomes du langage.
- Comprenez la sagesse de la communauté. Les programmeurs Perl débattent souvent farouchement des techniques et des idiomes. Les programmeurs Perl partagent également souvent leur travail et pas seulement sur le CPAN. Faites attention et obtenez l'illumination sur les compromis entre les différents idéaux et styles.
Les développeurs du CPAN, les Mongueurs de Perl et les participants aux listes de diffusion ont de l'expérience durement acquise lors de la résolution des problèmes de multiples façons. Parlez-leur. Lisez leur code. Posez des questions. Apprenez d'eux et ils apprendront de vous. - Suivez les normes de la communauté. Perl est une communauté de créateurs d'outils. Nous résolvons des problèmes divers, y compris l'analyse du code statique (Perl::Critic), le reformatage (Perl::Tidy) et les systèmes privés de distribution (CPAN::Mini, Carton, Pinto). Profitez de l'infrastructure du CPAN ; suivez le modèle du CPAN dans l'écriture, la documentation, le paquetage, les tests et la distribution de votre code.
- Lisez du code. Rejoignez des listes de diffusion telles que Perl Beginners (http://learn.perl.org/faq/beginners.html) ou, en français, perl@mongueurs.net, participez à des forums Perl (https://www.developpez.net/forums/f82/autres-langages/perl/), parcourez PerlMonks (http://perlmonks.org/), et immergez-vous dans la communauté en général. Voir http://www.perl.org/community.html. Lisez du code et essayez de répondre à des questions même si vous ne postez jamais les réponses, c'est une excellente occasion d'apprendre.
IX-C. Écrire du Perl efficace▲
Écrire du code maintenable signifie concevoir du code maintenable. Une bonne conception vient des bonnes habitudes :
- écrivez du code testable. L'écriture d'une suite de tests efficaces demande les mêmes compétences en conception que l'écriture du code efficace. Un code est un code. De bons tests vous donnent aussi la confiance nécessaire pour modifier un programme tout en conservant son fonctionnement correct ;
- modularisez. Tracez des frontières en appliquant l'encapsulation et l'abstraction. Trouvez les bonnes interfaces entre composants. Nommez bien les choses et mettez-les au bon endroit. La modularité vous oblige à penser aux modèles et abstractions dans votre code pour comprendre comment ils semboîtent. Trouvez les parties qui ne correspondent pas bien. Améliorez-les jusqu'à ce qu'elles le fassent ;
- suivez des normes de codage sensées. Des directives efficaces discutent la gestion des erreurs, la sécurité, l'encapsulation, la conception des API, la mise en page du projet et d'autres facettes du code maintenable. D'excellentes directives aident les développeurs à communiquer entre eux et avec le code. Votre travail consiste à résoudre des problèmes avec du code. Laissez votre code parler clairement ;
- exploitez le CPAN. Les programmeurs Perl résolvent des problèmes. Ensuite, nous partageons ces solutions. Le CPAN est un démultiplicateur de force ; recherchez une solution ou une solution partielle à votre problème. Investissez du temps dans la recherche afin de trouver des solutions complètes ou partielles que vous pouvez réutiliser. Cela se révélera payant.
Si vous trouvez un bogue, signalez-le. Corrigez-le, si possible. Corrigez une faute de frappe. Demandez une nouvelle fonctionnalité. Dites « Merci ! » Nous sommes meilleurs ensemble que nous le sommes séparément. Nous sommes puissants et efficaces lorsque nous réutilisons du code.
Lorsque vous êtes prêt lorsque vous créez quelque chose de nouveau ou corrigez quelque chose de vieux d'une manière réutilisable, partagez votre code. Rejoignez-nous. Nous résolvons des problèmes.
IX-D. Exceptions▲
Les bons programmeurs anticipent l'imprévu. Les fichiers qui devaient exister n'existeront pas. Un disque énorme qui ne serait jamais plein se remplira. Le réseau qui marche toujours tombe en panne. La base de données la plus fiable sera endommagée. Les exceptions se produisent. Un logiciel robuste doit les gérer. Si vous pouvez résoudre le problème, tant mieux ! Si vous ne le pouvez pas, collectez les informations pertinentes et réessayez.
Perl gère des circonstances exceptionnelles par des exceptions : un mécanisme dynamique de flot d'exécution, conçu pour détecter et traiter les erreurs.
IX-D-1. Signalez les exceptions▲
Supposons que vous voulez écrire un fichier journal. Si vous ne pouvez pas ouvrir le fichier, quelque chose s'est mal passé. Utilisez die pour signaler l'exception... ou laissez autodie (Le pragma « autodie »Le pragma « autodie ») l'ajouter pour vous, dans ce cas :
sub open_log_file
{
my $nom
=
shift
;
open
my $fh
, '>>'
, $nom
or
die "Impossible d'ouvrir le fichier journal '
$nom
': $!"
;
return $fh
;
}
die() définit la variable globale $@ à son opérande et quitte immédiatement la fonction actuelle sans rien retourner. Cette exception lancée remontera la pile des appels (Exécution contrôléeExécution contrôlée) jusqu'à ce que quelque chose l'intercepte. Si rien n'intercepte l'exception, le programme se terminera avec une erreur.
La gestion des exceptions utilise la même portée dynamique (Portée dynamiquePortée dynamique) que les symboles déclarés avec local.
IX-D-2. Intercepter les exceptions▲
Parfois, il est utile d'autoriser une exception à mettre fin à l'exécution du programme. Un programme exécuté comme un processus chronométré pourrait lancer une exception lorsque les journaux d'erreurs sont remplis, provoquant un SMS en sortie pour les administrateurs. Pourtant, toutes les exceptions ne devraient pas être fatales. Votre programme pourrait avoir besoin de continuer à s'exécuter après certaines exceptions. D'autres exceptions pourraient seulement vous donner une chance de sauver le travail de votre utilisateur et s'arrêter proprement.
Utilisez la forme de bloc de l'opérateur eval pour intercepter une exception :
# le fichier journal ne peut pas s'ouvrir
my $fh
=
eval {
open_log_file( 'monkeytown.log'
) }
;
Si l'ouverture du fichier réussit, $fh contiendra le descripteur de fichier. Si elle échoue, $fh restera indéfini, et le déroulement du programme se poursuivra.
Le bloc de eval introduit une nouvelle portée, à la fois lexicale et dynamique. Si open_log_file() a appelé d'autres fonctions et quelque chose signale finalement une exception, cet eval pourrait l'intercepter.
Un gestionnaire d'exceptions est un outil grossier. Il interceptera toutes les exceptions signalées dans sa portée dynamique. Pour vérifier quelle exception vous avez interceptée (ou si vous n'en avez intercepté aucune), vérifiez la valeur de $@. Soyez sûr de localiser $@ avant de tenter d'intercepter une exception, car $@ est une variable globale :
local $@
;
# le fichier journal ne peut pas s'ouvrir
my $fh
=
eval {
open_log_file( 'monkeytown.log'
) }
;
# exception interceptée
if (my $exception
=
$@
) {
... }
Copiez immédiatement $@ dans une variable lexicale pour éviter la possibilité que du code subséquent écrase la variable globale $@. Vous ne savez jamais quoi d'autre a utilisé ailleurs un bloc eval et a réinitialisé $@.
$@ contient généralement une chaîne décrivant l'exception. Inspectez son contenu pour voir si vous pouvez gérer l'exception :
if (my $exception
=
$@
)
{
die $exception
unless $exception
=~
/^Can't open logging/
;
$fh
=
log_to_syslog();
}
Relancez une exception en appelant à nouveau die(). Passez-lui l'exception existante ou une autre, si nécessaire.
Appliquer des expressions régulières aux exceptions de chaîne peut être fragile, parce que les messages d'erreur pourraient changer au fil du temps. Cela inclut les exceptions lancées par Perl même. Au lieu de lancer une exception sous forme de chaîne, vous pouvez utiliser une référence même une référence liée avec die. Cela vous permet de fournir beaucoup plus d'information dans votre exception : des numéros de lignes, des fichiers et d'autres informations de débogage. La récupération des informations à partir d'une structure de données est beaucoup plus facile que l'analyse des données d'une chaîne. Interceptez ces exceptions comme vous le feriez pour toute autre exception.
Le module Exception::Class du CPAN facilite la création et l'utilisation des objets exception :
package Zoo::Exceptions
{
use Exception::Class
'Zoo::AnimalEchappe'
,
'Zoo::HandlerEchappe'
;
}
sub cage_ouverte
{
my $self
=
shift
;
Zoo::AnimalEchappe->
throw
unless $self-
>
contient_animal;
...
}
sub breche_ouverte
{
my $self
=
shift
;
Zoo::HandlerEchappe->
throw
unless $self-
>
contient_handler;
...
}
IX-D-3. Dangers des exceptions▲
Bien que lancer des exceptions soit relativement simple, les intercepter l'est moins. L'utilisation correcte de $@ vous oblige à naviguer parmi plusieurs risques subtils :
- son utilisation non localisée plus loin dans la portée dynamique peut modifier $@ ;
- $@ peut contenir un objet qui renvoie une valeur fausse dans le contexte booléen ;
- un gestionnaire de signal (en particulier le gestionnaire de signal DIE) peut modifier $@ ;
- la destruction d'un objet lors de la sortie de la portée peut appeler eval et modifier $@.
Perl 5.14 a remédié à certains de ces problèmes. Ils se produisent rarement, mais ils sont souvent difficiles à diagnostiquer et corriger. Le module Try::Tiny du CPAN améliore la sécurité de la gestion des exceptions et la syntaxe Try::Tiny a inspiré des améliorations à la manipulation des exceptions de Perl 5.14.
Try::Tiny est facile à utiliser :
use Try::Tiny;
my $fh
=
try {
open_log_file( 'monkeytown.log'
) }
catch {
log_exception( $_
) }
;
try remplace eval. Le bloc optionnel catch s'exécute uniquement lorsque try intercepte une exception. catch reçoit l'exception interceptée dans la variable sujet $_.
IX-D-4. Exceptions internes▲
Perl signale lui-même plusieurs conditions exceptionnelles. perldoc perldiag énumère plusieurs « erreurs fatales récupérables ». Certaines sont des erreurs de syntaxe que Perl produit lors de l'échec de la compilation, mais vous pouvez intercepter les autres pendant l'exécution. Les plus intéressantes sont :
- utiliser une clé rejetée dans un hachage verrouillé (Verrouiller des tables de hachageVerrouiller des tables de hachage) ;
- lier une non-référence avec bless (Références liéesRéférences liées) ;
- appeler une méthode sur un invoquant invalide (MooseMoose) ;
- impossibilité de trouver sur l'invoquant une méthode ayant le nom donné ;
- utilisation d'une valeur en entrée de façon non sécurisée (Données d'origine non fiable et le mode taintDonnées d'origine non fiable et le mode taint) ;
- modification d'une valeur en lecture seule ;
- exécution d'une opération non valide sur une référence (RéférencesRéférences).
Bien sûr, vous pouvez aussi intercepter des exceptions produites par autodie (Le pragma « autodie »Le pragma « autodie ») et tout avertissement lexical promu au rang d'exception (Enregistrer vos propres avertissementsEnregistrer vos propres avertissements).
IX-E. Pragmas▲
La majorité des modules Perl fournissent de nouvelles fonctions ou définissent des classes (MooseMoose). D'autres, tels que strict ou warnings, influencent le comportement du langage même. Cette seconde classe de module s'appelle pragma ou module pragmatique. Par convention, les pragmas ont des noms en minuscules pour les différencier des autres modules.
IX-E-1. Pragmas et portée▲
Les pragmas fonctionnent en exportant des comportements ou des informations spécifiques dans les portées lexicales de leurs appelants. Vous avez vu comment la déclaration d'une variable lexicale rend disponible un nom de symbole dans une portée. L'utilisation d'un pragma active également son comportement à l'intérieur d'une portée :
{
# $lexical pas visible; strict pas en vigueur
{
use strict;
my $lexical
=
'disponible ici'
;
# $lexical est visible; strict est en vigueur
}
# $lexical à nouveau invisible; strict pas en vigueur
}
Tout comme les déclarations lexicales concernent les portées intérieures, les pragmas maintiennent leurs effets dans des portées intérieures :
IX-E-2. Utiliser des pragmas▲
Utilisez un pragma comme vous le feriez pour tout autre module, à l'aide de l'instruction use. Les pragmas prennent des arguments, tels qu'un numéro minimal de version à utiliser ou une liste d'arguments pour modifier le comportement du pragma :
# nécessite des déclarations de variables, interdit les mots nus
use strict qw( subs vars )
;
# basé sur la sémantique du livre de 2012
use Modern::Perl '2012'
;
Parfois, vous devez désactiver la totalité ou une partie de ces effets dans une portée lexicale imbriquée. La commande interne no effectue un unimport (ImportationImportation), qui annule les effets d'un pragma. Par exemple, pour désactiver la protection de strict lorsque vous devez manipuler la table des symboles :
IX-E-3. Pragmas utiles▲
Perl comprend plusieurs pragmas standard utiles.
- strict active la vérification des références symboliques par le compilateur, l'utilisation des mots nus et la déclaration des variables.
- warnings active les avertissements optionnels pour comportements obsolètes, involontaires et maladroits.
- utf8 indique au compilateur d'utiliser l'encodage UTF-8 pour comprendre le code source du fichier actuel.
- autodie active la vérification automatique des erreurs des appels système et des commandes internes.
- constant vous permet de créer des valeurs constantes à la compilation (mais regardez Const::Fast du CPAN pour une autre solution).
- vars vous permet de déclarer des variables globales de paquetage, comme $VERSION ou @ISA (Références liéesRéférences liées).
- feature vous permet d'activer et désactiver individuellement les nouvelles fonctionnalités de Perl. L'instruction use 5.14; active toutes les fonctionnalités Perl 5.14 et le pragma strict, et use feature ':5.14'; fait la même chose. Ce pragma est plus utile pour désactiver les fonctionnalités individuelles dans une portée lexicale.
- less montre comment écrire un pragma.
Comme vous pouvez l'imaginer avec ce qui vient d'être dit sur le pragma less, vous pouvez écrire vos propres pragmas lexicaux en Perl pur. perldoc perlpragma explique comment le faire, alors que la documentation de $^H dans perldoc perlvar explique comment marche cette fonctionnalité.
Le CPAN a commencé à recueillir des pragmas non standard :
- autovivification désactive l'autovivification (AutovivificationAutovivification) ;
- indirect prévient l'utilisation de l'invocation indirecte (Objets indirectsObjets indirects) ;
- autobox active le comportement de type objet pour les types de base de Perl (scalaires, références, tableaux et hachages) ;
- perl5i combine et active de nombreuses extensions expérimentales du langage dans un ensemble cohérent.
Ces outils ne sont pas encore largement utilisés, mais ils ont leurs champions. autovivification et indirect peuvent vous aider à écrire du code plus correct. autobox et perl5i sont des expérimentations sur ce que Perl pourrait devenir un jour ; cela vaut la peine de jouer avec eux dans de petits projets.