Vous aimez ce que vous lisez sur ce blog ?
Envie d'aller plus loin avec véritable formation d'expertise en Java ?
Venez suivre ma formation Masterclasse Expertise Java !

"Même un développeur experimenté a besoin de continuer à apprendre. Et dans cette formation... j'ai appris beaucoup !" - A.G., Java Champion

Prochaine sessions inter-entreprises : 13-16 février 2018
Sessions intra-entreprises sur demande : contact[at]mokatech.net.
Inscrivez-vous vite !

Devs vs Threads : une comparaison pifométrique

Dans la religion méthodologie Scrum, les spécifications du produit à développer ne sont pas rédigées dans leur intégralité au début du projet, mais au contraire fournies par le client au fur et à mesure de l'avancement du développement, afin de lui offrir une plus grande réactivité.
Le périmètre courant du projet est matérialisé par le "product backlog", c'est-à-dire un flux priorisé de fonctionnalités à développer, alimenté en permanence par le client, et consommé en flux tendu par l'équipe de développement.

Mine de rien, on est là en plein pattern producteur-consommateur. On pourrait même y voir une certaine similarité avec le fonctionnement d'un ThreadPool, les thread (les développeurs) traitant des jobs (les fonctionnalités) dans leur ordre de soumission.

Question : les bonnes pratiques associées à la gestion des thread pools (en particulier leur dimensionnement) pourraient-elles être appliquées aux équipes de développement Scrum ?

Un ThreadPool sur mesure

Un point particulièrement important est le dimensionnement du pool de threads. Dans "Java Concurrency In Practice"[1], Brian Goetz nous propose la formule suivante[2] :

Nombre de threads optimal = Ncpu × Ucpu × (1 + W/C)

Petite explication des symboles :

  • Ncpu = nombre de processeurs
  • Ucpu = Utilisation souhaitée des processeurs (0 <= Ucpu <= 1).
    En effet, si notre programme n'est pas le seul à fonctionner sur la machine, il faut faire attention à ne pas monopoliser le temps de calcul.
  • W/C = rapport du temps d’attente par rapport au temps de calcul.
    Certains traitements sont orientés calcul, et ne dépendent donc que de la puissance CPU disponible. D'autres en revanche effectuent beaucoup d'I/O et peuvent donc passer la majorité de leur temps à attendre que les données deviennent disponibles; il est donc possible de traiter un autre traitement pendant ce temps.Le ratio W/C permet de représenter la probabilité relative de ces deux cas.

Par exemple, avec 10 processeurs, un taux d'occupation de CPU maximal de 60%, et une répartition 50/50 (ratio:1) entre les tâches orientées calcul et les tâches de type IO, le nombre optimal de threads dans le pool est de 10 * 0.6 * (1 + 1), soit 12 threads. Autrement dit, à un instant T, chaque processeur est responsable de 1.2 tâches, ce qui n'est pas gênant au vu de leur type (CPU vs IO).

Plus on est de fous...

Maintenant, voyons comment cette formule pourrait être appliquée à une équipe de développement.

On peut imaginer remplacer les threads par des développeurs[3], et le taux d'occupation CPU par le pourcentage du temps d'un développeur réellement consacré au développement, c'est-à-dire hors réunion, emails, téléphone, pause café, drague de la fille du marketing relations humaines, etc. (valeur réaliste : autour de 60%[4]).
Pour ce qui est du ratio CPU/IO, mesurez le temps que chaque tâche reste bloquée en attente d'un événement quelconque hors de votre portée (spécifications fonctionnelles, installation d'une base de données, autorisation d'accès à un système, etc.).

(Pour simplifier le calcul, je pars du principe que toutes les tâches ont une complexité équivalente. Peut-être serait-il plus judicieux de parler de "story points", pour reprendre la terminologie Scrum. Mais passons.)

Application pratique : avec une équipe de 10 développeurs disponibles à 60% de leur temps, sachant qu'en moyenne les tâches sont bloquées 50% de leur temps d'existence, on obtient une capacité de développement de 10 * 0.6 * (1 + 1) = 12 tâches par unité de temps. Autrement dit, chaque développeur peut se voir affecter environ 1.2 tâches, la moitié étant en attente d'événements extérieurs.

Le raisonnement peut s'appliquer dans l'autre sens : comment dimensionner mon équipe pour traiter X tâches dans un temps donné ? Je vous laisse faire le calcul.


dev.jpg

Conclusion

Je sais bien que l'exercice de la comparaison a ses limites, et qu'on ne gère pas tout à fait de la même façon un pool de threads et une équipe de développeurs[5]. Mais l'organisation en flux tendu proposée par Scrum m'a tellement rappelé le pattern producteur/consommateur que j'ai souhaité suivre cette idée pour voir où elle pouvait mener.

Même si les chiffres finaux sont hautement discutables, une idée est néanmoins intéressante à rappeler : un développeur ne consacre jamais 100% de son temps à coder. Ca peut paraître scandaleux (surtout à celui qui tient le planning), mais la réalité du terrain est implacable : les réunions et interruptions diverses absorbent un temps considérable. Pensez à prendre ce facteur en compte lors de vos prochaines estimations !

Notes

[1] "Java Concurrency in practice", Brian Goetz, Tim Peierls, Johua Bloch, Joseph Bowbeer, David Holmes, Doug Lea. A lire absolument ! (mais un petit bout à la fois)

[2] Page 175 sur l'édition française

[3] Réjouissez-vous qu'on ne sache pas encore faire l'inverse !

[4] Faites donc le calcul dans votre équipe : vous serez surpris du résultat ! Et vous saurez enfin pourquoi le projet a constamment l'air en retard par rapport aux prévisions du chef de projet...

[5] En particulier, les threads n'ont pas besoin d'être nourris.


Commentaires

1. Le mercredi 31 octobre 2012, 07:26 par Benoît

<quote>En particulier, les threads n'ont pas besoin d'être nourris.</quote>

Pourtant, les consommateurs consomment ... ;-)

2. Le mercredi 31 octobre 2012, 08:49 par boblemar

Amusant !
Dev un jour, dev pour toujours.
Ce qui me plait dans cette approche, c'est que la boucle est bouclée : on a créé différents paradigmes informatiques en s'inspirant du monde réel (objets...). Pourquoi ne pas s'inspirer des théories qui ont fait leur preuve en informatique dans le monde réel ?
Mais attention, et tu y fais allusion (remplacement des devs par des threads), le soulèvement des machines approche ;)

bblmr

3. Le mercredi 31 octobre 2012, 12:16 par Guillaume

Salut Olivier,

La comparaison me semble extrèment intéressante ! Je penses qu'il faudrait plus faire le lien avec Kanban, où la limite du travail en cours, des files d'attentes, le calcul du temps de cycle et les classes de services peuvent trouver leur pendant du côté du Threads.
Peut être une idée de présentation pour Devoxx France derrière ça, contactes moi si ça t'intéresse, il y a moyen de s'amuser ;-)

4. Le mercredi 31 octobre 2012, 21:56 par Olivier Croisier

Un quickie pour le Devoxx-FR 2013 ?

5. Le jeudi 1 novembre 2012, 12:01 par Antoine

On est plutôt dans le kanban que dans scrum, comme ça a été dit.
La modélisation de scrum pourrait être intéressante mais plus compliquée. En première analyse, scrum serait plus une file d'attente (le backlog produit) dont les éléments et leur priorité changent en fonction d'un contexte global (l’abstraction de la collaboration product owner/équipe de dév), qui est traitée par lot (le backog de sprint) par un pool de threads/développeurs. Un timer de durée fixe pendant toute l'exécution du programme commence avec le traitement du lot, quand il arrive à échéance, l'activité des threads s'interrompt, les éléments de la liste non commencés ou non terminés sont réinjectés dans le backlog produit, on remet le timer à zéro, on collecte des statistiques sur la quantité de travail effectuée par les threads, ces statistiques sont passée à l'objet contexte qui ajuste sur cette base la talle du lot à traiter pour la prochaine itération (le sprint backlog), et on réitère. L'idée est d'obtenir une stabilisation spontanée de la taille du lot traité à chaque itération.
L'enjeu de l'agilité, dans cet exercice de style comme dans la vraie vie, est d'instaurer une boucle de feedback pour qu'il y ait un ajustement mutuel entre capacité de travail des développeurs et la charge de travail qu'ils s'affectent. Par ailleurs, un aspect important de l'agilité (XP notamment, mais scrum aussi) veut que l'équipe de développement soit considéré comme une boite noire à laquelle du travail est confié, et qui se débrouille pour le réaliser, il n'appartient qu'à l'équipe de s'organiser. Modéliser l'activité en considérant les développeurs comme des machines prédictibles micromanagées et parallélisables peut provoquer quelques lèvements de sourcils chez les agilistes.
Et, juste pour finir de pinailler, la religion Scrum ne parle pas de story points :)

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.