Débuguer son code sans utiliser d'IDE ...
Écrire un code sans erreur est une gageure que bla bla bla. J'ai écrit du code, je constate qu'il ne fonctionne pas, comment faire pour le débuguer ?
La méthode, peut-être la plus simple, est de lancer un IDE (Netbeans ou autre) et de jouer avec son outil de débugage. Je place des points d'arrêt dans mon code et je trace le programme ... cette méthode nécessite le recours à un IDE et demandera un peu de temps de prise en main. On peut lire le how to Netbeans à ce sujet.
Il existe cependant d'autres manières de faire qui peuvent être plus appropriées dans le cas de projets simples ...
Avertissement Je ne parle pas de JUnit dans la suite car je parle bien de debuguer son code et non de le tester. Ce sont, pour moi, deux tâches différentes (et toutes les deux indispensables ... quoique les bisounours peuvent sans doute se passer de débugage)
- Comment débuguer son code ?
- La méthode de l'homme pauvre
- Utilisations des assertions
- Utilisation d'un débugueur, jdb
Comment débuguer son code ?
Débuguer un code, c'est trouver où et quand le code devient mauvais et pourquoi ? Il existe plusieurs types d'erreurs; les erreurs de compilation et de syntaxe, les erreurs logiques et les erreurs à l'exécution (runtime). En Java, les erreurs de compilation et de syntaxe sont rapidement détectées grâce au compilateur.
Pour détecter les autres erreurs;
- placer des points d'arrêt (breakpoints) afin de savoir «jusqu'où ça fonctionne»
- inspecter (inspect) le contenu des variables afin de voir si elles contiennent bien les valeurs que l'on attend
- entrer à l'intérieur d'une méthode afin de parcourir ce qu'elle fait (step in) ou bien simplement l'exécuter car l'on sait qu'elle fait bien son travail et passer à la suite (step over)
Si l'on ne sait pas par où commencer, il suffit de commencer par la première instruction de la méthode main
.
Pour débuguer son code, il existe différentes techniques
- la méthode de l'homme pauvre (ou des
System.out.println
) décrite ci-dessous - la méthode des commentaires qui consiste à mettre tout le code en commentaires et à décommenter ligne par ligne jusqu'à trouver l'endroit «qui coince»
- l'utilisation d'un débugueur
La méthode de l'homme pauvre (poor man)
La première méthode, celle que l'on préconise pour les débutants, consiste à placer des instructions sout
[1] dans son code afin de voir le contenu de certaines variables ou simplement de savoir si le programme «passe bien» par certaines instructions.
System.out.println("DEBUG (...)");
On évitera des commentaires de style «coucou», «passe par ici» et l'on préfèrera toujours commencer par le mot «DEBUG». Ceci afin de pouvoir facilement retrouver ce type de commentaire dans son code.
Cette méthode, bien que qualifiée d'archaïque, fait le boulot et peut convenir lorsqu'un débutant veut débuguer un programme (moyennement) simple. L'inconvénient de la méthode est qu'il faudra retirer ces commentaires à un moment donné.
Si l'on veut améliorer un peu la méthode, on peut placer à l'endroit qui va bien une variable booléenne précisant si l'on veut les commentaires de débugage ou pas (on peut même envisager que cette valeur soit un argument du programme). Le code aura alors l'allure suivante
private static boolean debugEnabled = true; // (...) if (debugEnabled) System.out.println("DEBUG - <mon commentaire>");
Utilisation des assertions
Cette technique peut venir en complément de la précédente. Le mécanisme consiste à placer à certains endroits du code un check du style; «je suppose que mon programme est dans cet état, sinon arrête toi». Ce test consiste le plus souvent à tester l'état d'une ou plusieurs variables.
You can use assertions to detect errors that may otherwise go unnoticed. Assertions contain Boolean expressions that define the correct state of your program at specific points in the program source code.
Extrait de http://java.sun.com/developer/technicalArticles/JavaLP/assertions/
Cette méthode est liée au design by contract (design-by-contract model of programming voir Qusay) qui, pour moi, peut être résumé par
- certaines conditions sont invariantes tout au long du programme, je peux vérifier ces invariants
- certaines conditions doivent être vérifiées avant l'appel d'une procédure ou d'un traitement, je peux vérifier ces préconditions
- certaines conditions doivent être vérifiées après l'appel d'une procédure ou d'un traitement, je peux vérifier ces postconditions
Par exemple: Un traitement consiste en le calcul d'une racine carrée: précondition, le nombre doit être positif.
Une assertion s'exprime à l'aide d'une expression booléenne. Lorsque celle-ci est fausse, le programme s'arrête et génère une exception. Une assertion peut être affublée d'un message spécifique.
Board b = null; // on essaie de créer ce plateau de jeu b = new Board(); assert b != null; // ou assert b != null : "Can't create game board";
En Java, ce mécanisme est disponible depuis Java 1.4[2]. Par défaut les assertions ne sont pas utilisées au runtime. Ajouter ces instructions dans le code ne fait donc que «grossir» le code mais ne le font pas «ralentir». Pour que ces assertions soient testées, il faut le dire à la machine virtuelle par le biais de l'option enableassertion.
java -ea my.package.MyClass java -enableassertions my.package.MyClass
Utilisation d'un débugueur, jdb
Java est fourni avec un débugueur (malheureusement) en ligne de commande. Pour pouvoir l'utiliser, il faut demander au compilateur de générer un bytecode qui pourra être utilisé par jdb. Cela se fait grâce à l'option -g
(l'option -O
est alors à proscrire car un code optimisé ne pourra pas être débugué). Ensuite, lancer le débugueur
java -g MyClass.java jdb MyClass
Les commandes comprise par jdb sont (entre autres)
- stop in MyClass.foo
- run (démarre l'exécution)
- cont (continue l'exécution après un break, ... )
- step (ligne par ligne)
- print (affiche la valeur d'une expression)
- locals (affiche les variables locales)
- threads (liste tous les threads)
- help (affiche l'aide)
Une séance de débugage avec le code (erroné) suivant peut avoir l'allure décrite brièvement ci-dessous
public class TestJdb { public static void main ( String[] args ) { int i; i = 5; i = foo(i); } public static int foo(int i){ // Attention, c'est sans doute mieux --i; return i--; } }
En quelques images;
- lancer jdb et placer un breakpoint au début de la méthode main
- à grands coups de step / print j'exécute le code instruction par instruction en regardant le contenu de la variable
i
L'utilisation d'un débugueur demandera un certain temps d'adaptation avant de pouvoir correctement tracer son programme.
Enjoy !
Note d'orthographe
Certains utilisent le mot débogage puisqu'ils recherchent des bogues dans le programme ... ce sont les plus proches de l'académie française.
D'autres utilise le mot débugage car ils sont à la recherche de bugs dans leur programme ... ce sont les plus enclins à moins françiser les mots.
... l'important c'est de pouvoir se comprendre ;-)
Sources / Liens
- Using Assertions in Java Technology (Oracle-exSun)
- Tuto minimaliste au hasard du web
- Tuto 'Java debugging' from Laura Bennett (pdf) (la partie traitant de Jikes est obsolète)
- Howto Netbeans (debugger)
- Java debugger chez Oracle
- Crédit photo chez 500px par Sandeep Somasekharan
Commentaires
Ah tiens, y'a une ou deux choses que j'ignorais, merci !
Je note au passage l'ironie de la faute d'accord dans la phrase mentionnant l'académie française. ;)
Merci John, je corrigerai ;-)