JavaScript de zéro

When it comes to problem-solving in general (and JavaScript in particular), I have a similar bias towards single-purpose solutions. Rather than creating a monolithic framework that attempts to solve all possible problems, I prefer a collection of smaller scripts that only do one thing, but do it really well; the UNIX philosophy.

Small lessons, loosely learned (cache)

En un temps relativement restreint (8 heures de cours), j’ai essayé d’enseigner JavaScript à des étudiants n’ayant aucune notion de programmation en ne partant finalement d’aucun niveau d’abstraction. Pour seuls outils : le navigateur et son inspecteur/console et un fichier HTML de test, l’objectif étant d’alterner entre du théorique avec ce fichier et du pratique en manipulant des pages existantes. J’appréhendais un peu suite aux désillusions de l’année dernière mais j’avais gagné en expérience à la fois en JS et en réduisant mes prétentions sur ce que je voulais leur transmettre.

La première heure, compréhension des notions de variable et d’opérateur puis introduction de console.log pour faire la différence entre un script et son exécution dans la console. La deuxième heure a été consacrée à document.querySelector et document.querySelectorAll où l’on parle forcément de tableaux/listes et c’est peut-être à ce moment là que j’aurais dû introduire la conversion d’un NodeList en Array mais on n’en avait pas encore le besoin… En troisième heure, on commence à jouer avec les styles avec Element.style et surtout Element.classList et ça commence à être ludique d’aller modifier des pages existantes. Enfin pour clôturer la session, on expérimente avec innerHTML et outerHTML pour introduire du dynamisme. Et de manière transverse on parle de NaN, d’undefined et des commentaires.

À la fin de cette première demi-journée j’étais très optimiste car tous les étudiants avaient compris et savaient appliquer ce genre de code (valide) :

<!doctype html>
<meta charset="utf-8">
<title>Test JavaScript</title>
<style>
    .turn-red { color: red; }
    .turn-green { color: green; }
    .turn-blue { color: blue; }
</style>
<h1>red</h1>
<h1>green</h1>
<h1>blue</h1>
<script>
    var titles = document.querySelectorAll('h1')
    titles[0].classList.add('turn-' + titles[0].innerHTML)
    titles[1].classList.add('turn-' + titles[1].innerHTML)
    titles[2].classList.add('turn-' + titles[2].innerHTML)
</script>

Mine de rien ça fait énormément de concepts à assimiler pour les 24 personnes n’ayant jamais fait de programmation ! Et la transition est toute trouvée pour parler de la répétition avec les boucles et les fonctions. Hop, une semaine de repos pendant laquelle ils n’ont… rien fait :’(.

Voir ces 3 lignes répétées doit faire bondir un développeur, j’ai commencé par introduire la notion de fonction avec un nom suffisamment explicite pour limiter les commentaires puis l’usage d’une boucle for pour itérer sur les éléments. Au passage on a besoin d’Array.length et de comprendre les conditions. Jusque là tout allait bien, j’en profite pour montrer qu’il est possible de le faire avec un while et déjà ça amène de la confusion mais alors là où ça a vraiment bloqué c’est au passage à forEach. Je ne sais pas si c’est la syntaxe ou la conversion en Array ou le fait d’avoir des fonctions anonymes ou la fatigue cognitive mais toujours est-il que ça a commencé à décrocher à ce moment là. Il faut dire qu’un Array.prototype.slice.call en plein milieu n’arrange pas les choses. Peut-être qu’un Array.from ou un for(… of …) eut été plus explicite mais limité en terme de support. Dur.

Pour finir, j’ai montré qu’une fonction pouvait retourner une valeur avant d’enchaîner sur les évènements à base d’addEventListener ce qui ouvre la porte des interactions avec l’utilisateur. On arrive à cet enchaînement :

function addClassFromHTML(element) {
    element.classList.add('turn-' + element.innerHTML)
}
function dealWithTitleOnClick(title) {
    title.addEventListener('click', function() {
        addClassFromHTML(title)
    })
}
var titles = document.querySelectorAll('h1')
titles = Array.prototype.slice.call(titles)
titles.forEach(dealWithTitleOnClick)

Je retiendrai qu’il faut un peu plus de temps pour découvrir certains concepts. Travail demandé pour la semaine suivante : faire une fonction qui permette à partir d’un article de presse d’avoir une version lisible avec uniquement le titre et le contenu sans images. Une sorte de bookmarklet à la readability. Et jouer aussi.

Enseigner JavaScript ET la programmation à partir de zéro est un moyen d’identifier les forces et faiblesses du langage. D’un côté on a le TDD du pauvre avec un feedback visuel immédiat et la possibilité d’utiliser la console du navigateur. De l’autre les plusieurs façons de faire la même chose et les restrictions liées au non-support d’ES6 par les navigateurs. J’ai presque envie de troller sur la programmation fonctionnelle mais je vais plutôt ajouter une couche d’abstraction pour la prochaine fois, ce sera plus simple en demi-groupes. En espérant que ça devienne davantage compréhensible et utilisable par des néophytes, le code précédent devenant :

$('h1').on('click', function(event) {
    addClassFromHTML(event.target)
})