Emerger des parenthèses

Cybo Test n°18

by Jeko — dim. 28 juillet 2019

Le projet Cybo

Cybo est le nom d'un de mes toy-projects (un projet personnel) en Guile. La vision est de développer un cyber-assistant personnel qui gère ma liste de tâches et peut à tout moment me dire quelle est la tâche la plus opportune à faire en fonction de la date et de l'heure, de l'endroit où je me trouve, des personnes avec qui je suis censé être, et que sais-je encore ! Mon apprentissage de Guile avance au fur et à mesure que j'ajoute des fonctionnalités à Cybo.

L'idée : automatiser une partie de la méthode GTD

David Allen, l'auteur de la méthode Getting Things Done alias GTD, est persuadé que notre esprit est fait pour générer des idées, pas pour les retenir. Il a donc mis au point une méthode qui vise à nous libérer l'esprit de toutes les choses à faire de manière à focaliser notre énergie dans leur réalisation et non dans leur rétention.

Ce que j'ai lu sur la méthode m'a beaucoud plu et j'ai essayé de l'utiliser personnellement. La mise en place est longue et il y a clairement un effort à fournir pour que les rituels de la méthode deviennent des habitudes. Mais le bénéfice se fait vite sentir.

Grossièremet, il faut imaginer quatre étapes :

Lorsque j'ai découvert la méthode GTD, j'apprenais justement Guile et naturellement j'ai cherché à automatiser une partie du processus de la méthode GTD. L'étape automatisable m'a semblé être la sélection. Ainsi est né Cybo.

L'implémentation : développer suivant la méthode TDD

La méthode que j'applique pour mes développements s'appelle le Test Driven Development, alias TDD. C'est une méthode mise au point par Kent Beck qui permet de développer des logiciels dont la conception émerge de manière organique, avec des tests automatisés et un réusinage du code (code refactoring).

A l'heure où j'écris cet article, la prochaine fonctionnalité que je vais implémenter dans Cybo est celle qui va permettre à Cybo de proposer des tâches en lien avec un contexte en particulier. Par exemple : "smartphone" car il faut que la tâche soit réalisable depuis mon téléphone ; ou bien "home" car j'ai besoin d'être chez moi pour effectuer la tâche.

Voici un cycle de TDD :

  1. Rapidement ajouter un test.
  2. Lancer tous les tests et voir le nouveau échouer.
  3. Apporter une petie modification au code.
  4. Lancer tous les tests et les voir tous réussir.
  5. Réusiner pour retirer les dupplications.

Après avoir pris le temps de chercher quel test je pourrais écrire qui entrainerai la plus petite modification dans le code (toujours dans l'optique d'apporter la fonctionnalité des contextes à Cybo), j'en suis arrivé à la chose suivante :

(file-empty TODO.TXT)
(test-assert "Next-action-with-context-parameter-with-empty-todo.txt-file-Should-return-null"
  (null? (next-action TODO.TXT #:context "@the-context")))
(clear-test-files)

La particularité de ce test est qu'il indique que la fonction next-action attend deux paramètres : un chemin vers un fichier et un contexte pour retourner la tâche contextualisée correctement. Or, actuellement cette fonction n'accepte qu'un chemin vers un fichier comme paramètre. Avec ce second paramètre le retour sera nul.

Alors forcemment, lorsque je lance les tests, l'interpréteur me signale gentilement un problème dans le nombre de paramètres dans la fonction next-action :

;;; note: source file /home/jeko/Workspace/guile-cybo/cybo-test.scm
;;;       newer than compiled /home/jeko/.cache/guile/ccache/2.2-LE-8-3.A/home/jeko/Workspace/guile-cybo/cybo-test.scm.go
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling /home/jeko/Workspace/guile-cybo/cybo-test.scm
;;; cybo-test.scm:149:9: warning: possibly wrong number of arguments to `next-action'
;;; compiled /home/jeko/.cache/guile/ccache/2.2-LE-8-3.A/home/jeko/Workspace/guile-cybo/cybo-test.scm.go
%%%% Starting test cybo-harness  (Writing full log to "cybo-harness.log")
cybo-test.scm:148: FAIL Next-action-with-context-parameter-with-empty-todo.txt-file-Should-return-null
# of expected passes      17
# of unexpected failures  1

Le test ne passe pas, dans le jargon du TDD on dit que le test est au rouge. La prochaine étape est de le faire passer au vert le plus rapidement possible. C'est parti !

Voici la fonction avant :

(define-public next-action
  (lambda (filename)
    (let ((nexts (filter-for-highest-priority
    	  (filter-for-remaining-tasks
    	   (read-tasks-from filename)))))
      (if (null? nexts) EMPTY_LIST (oldest nexts)))))

Voici la fonction après :

(define-public next-action
  (lambda* (filename #:key context)
    (let ((nexts (filter-for-highest-priority
    	  (filter-for-remaining-tasks
    	   (read-tasks-from filename)))))
      (if (null? nexts) EMPTY_LIST (oldest nexts)))))

Et voila le travail. Difficile de faire plus rapide (merci Guile).

;;; note: source file ./cybo.scm
;;;       newer than compiled /home/jeko/.cache/guile/ccache/2.2-LE-8-3.A/home/jeko/Workspace/guile-cybo/cybo.scm.go
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling ./cybo.scm
;;; compiled /home/jeko/.cache/guile/ccache/2.2-LE-8-3.A/home/jeko/Workspace/guile-cybo/cybo.scm.go
%%%% Starting test cybo-harness  (Writing full log to "cybo-harness.log")
# of expected passes      18

Maintenant que le test passe, on dit qu'il est vert. Vient alors l'étape du réusinage (ou refactoring pour les intimes)... Mais j'ai la flem, il est tard et j'ai fait tellement peu de modifications que je vais me cacher derrière le faux argument du "Mais y a rien qui a changé".

Aller, bon hack !

Bibliographie :