Merci pour ces tutoriels, très intéressants. Si je peux me permettre, l'implementation de la profondeur (deep ou depth) n'est pas forcement la plus simple, en utilisant le pure TDD, code le plus simple, je suis arrivé a ceci ... public string DrawLine(string line, int depth) { if (depth == 0) { return line; }
return DrawSourceLine(line) + DrawLine(DrawNextLine(line), depth - 1); } ... qui au final ne t'oblige pas a stocker le string concaténée car au final ton objet de retour est un string simple et pas d'autres méthodes privées. Le seul inconvenient est que si tu veux changer le retour disons en dictionary de string ou array de string, je dois tout refactorer en suivant ta solution. Merci encore pour tout le boulot sur TDD !
merci ! Tu touches ici à l'avantage principal de TDD, le refacto ;) Du coup toute amélioration est bonne à prendre tant qu'elle...passe les tests ;) Tu as ta sentinelle pour arranger le code.
Bonjour, je ne connais pas bien le TDD mais je suis un grand fan de l'idée de toujours partir d'un code simple et refactorer au fur et à mesure. Du coup j'ai essayé de faire l'exercice à ma façon et voilà comment ça s'est passé : je me suis dit, étant donné une ligne, il faut la parcourir et compter au passage le nombre de caractères identiques. Du coup je me retrouve à faire un simple parcours de la chaine et je trouve que mon code est simple, malgré que j'ai pas utilisé de TDD, j'ai juste suivi la technique de penser simple. Voilà mon code (en C++ mais c'est pareil) (à noter que je met pas d'espaces entre les chiffres de la ligne) string getNextLine(string line) { string nextLine; for (int i = 0; i < line.length();) { char curChar = line[i]; int curCharCount = 0; while (i < line.length() && curChar == line[i]) { curCharCount++; i++; } nextLine += std::to_string(curCharCount) + curChar; } return nextLine; } Par contre je n'ai pas écrit de tests du coup, il faudrait le faire en plus alors que avec TDD on les a direct
Top comme vidéo, c'est super intéressant de regarder quelqu'un coder comme ça. Par contre je sais pas s'il y a tant de monde que ça qui se plaint d'être ralenti par le TDD pour coder une fonction pure. En général, ce qui ralentit, il me semble, c'est plutôt toute l'architecture à mettre en place pour pouvoir tester justement. Tout le code qu'on rajoute et qu'on doit maintenir en plus du code de base, et qui plante dès qu'on modifie un truc. C'est sûrement souvent un signe de mauvais design mais je pense que l'argument "TDD ne ralentit pas, regarde ça" serait plus percutant s'il adressait aussi (plutôt ?) cette problématique.
Le fait qu'il plante des que tu modifie un truc est en général un signe qu'il y a un truc à corriger avant de livrer en prod sinon c'est la cata. Donc c'est plutôt cool non ?
M’intéressant depuis longtemps au TDD, j'ai voulu tester ce kata en (TS / mocha / chai), une fois l'environnement en place, j'ai mis moins de 20 min à faire la suite ( github.com/np42/conway-suite ), la ou j'ai rencontré une réelle difficulté c'est pour faire les baby steps, 1, 2, 2 2 pas de soucis, par contre à partir du suivant (ou celui d’après peut-être), l'algo était valide pour tout les autres cas, en effet j'ai eu plus de mal à trouver quel était la plus petite modification à faire sans péter les autres tests plutôt qu'a faire une version générique directement. Est-ce une erreur sur la manière de faire correctement du TDD ? Probablement que oui car je n'ai peut-être pas le code minimal, des astuces pour éviter de brûler les étapes ?
Bonjour Michael, Dans ta démo tu mets les tests dans un package unit donc différent du package de la classe que tu testes. Souvent on se place dans le même package pour éviter d'augmenter trop la visibilité de certaines méthodes pour effectuer des tests. Est-ce que tu peux développer les raisons qui font que tu places tes tests comme ça ?
Bonne remarque, c'est effectivement fait exprès :) Cela force à ne passer que par les méthodes publiques d'une classe. Dès que tu as besoin d'augmenter la visibilité d'une méthode, c'est un signe de mauvais design ;) Cette pratique est mentionnée dans le livre "Growing object-oriented software guided by Tests" de Steve Freeman et Nat Price. L'effet miroir est à proscrire car il permet des mauvaises pratiques comme tester explicitement des détails d'implémentations (méthodes non publiques).
Ok je vois. Je me doutais que c'était quelque chose dans ce genre là. Ça fait quelques temps que je me posais des questions sur cette manière de faire et ton point de vue m'intéressait :) Je vais regarder du côté de ce livre. Merci !
Pas de debug, je reste mitigé, quand ton test ne passe pas tu dois forcément comprendre pourquoi et ce que fais ton code ce qui n'est pas toujours visible à l'œil. Dans ton cas tu vas vite : "vous pouvez vous poser pour regarder mais c'est compliqué à expliquer" tu as surtout travaillé ta vidéo et tu sais exactement ce que tu dois dire ou faire donc oui tu vas vite
Merci je suis également fan de tdd et clean coding. Par contre je commence à m'intéresser au functionnal programming et je me demande si cela n'est pas risqué en Java à cause du stackoverflow possible. (contrairement à Clojure que j'aimerais maîtriser)?
Aucun problème pour le faire en php ou tout autre language, par contre l'auteur de la vidéo s'est clairement pris la tête (je pense volontairement pour illustrer le TDD), en réalité y a moyen de faire beaucoup plus simple via l'utilisation de boucle...
@@wealcome_company Merci! Les tests unitaires servent à quoi? je les verrai au second semestre pour l'instant on est sur algo et programmation Orientée Objet.
Merci pour le challenge ! Sur python j'ai mis 35min sans TDD, en débuggant beaucoup et avec 20 lignes de code. Donc pas totalement convaincu même si je comprend l'intérêt d'avoir une ligne directrice safe, je me dis que ça enlève le côté créatif. A voir...
Le code pour ceux qui veulent : suite = [1] def conway(s='1'): new_s = '' last_n = s[0] first = True count = 1 for n in s: if n == last_n: if first: first = False else: count += 1 else: new_s += str(count) + last_n last_n = n count = 1 new_s += str(count) + last_n suite.append(int(new_s)) if len(suite) == 15: return suite return conway(new_s) print(conway())
Yung Ab Le nombre de lignes de code ne signifient rien, si le code fait 20 lignes et jamais splitté, il sera incompréhensible à la lecture. Pour être 100% convaincu, commence par réaliser de vrais projets avec, et non des Kata. Maintenant que tu as écrit ce code, tu recrutes Benoit, qui propose d’y toucher et de changer des choses pour l’améliorer, ne serais-tu pas en stress à l’idée de penser qu’il puisse le casser par inadvertance ? La peur de changer ne serait-elle pas une limite de la créativité ? Oh que si. Tu constateras si tu le fais bien que ce qui enlève le côté créatif, c’est justement de ne PAS suivre la discipline TDD. TDD autorise le refactoring sans crainte.
Je pense que cette méthode peut être utile quand on ne sait pas trop où l'on va et comment on va réussir à s'en sortir. Alors on peut choisir de ne pas résoudre le problème d'un coup mais d'y aller par étapes, en augmentant la difficulté au fur et à mesure, en utilisant la méthode que vous décrivez. Jusque là ça me va. Mais de là à dire qu'il faut toujours travailler comme ça, que c'est le saint Graal et qu'il faut évangéliser les mécréants, là je trouve que ça devient une posture extrémiste. Car dans le cas où l'on sait d'emblée écrire l'algorithme, je ne vois pas pourquoi s’empêcher de le faire. Car cela ralenti l'écriture et ne garantit pas un code optimal (je dirais même plutôt le contraire). TDD ça peut servir mais ça ne doit pas être une religion non plus.
petitpoidferoce J'ai formé en présentiel plus de 1500 développeurs jusque-là dont la plupart avait ce genre de discours (faussement sensé). Je peux vous garantir que la quasi totalité en sont sortis bouleversés avec un : « wow on est convaincu du bienfait ! ». Ne jugez pas sur cet exemple juste expliquer la pratique. Je garantis que si l’on maîtrise la pratique, on va 100 fois plus vite avec TDD que sans dans les algo non triviaux.
J'ai joué le jeu et il y a un truc qui me titille... J'ai choisi exprès HTML comme format de sortie car ça rend les tests très peu lisibles et donc bien moins utiles. Je ne trouve pas une bonne manière de gérer ,ca Je vois trois mauvaises solutions (l'onglet HTML c'est du boilerplate): - tester des internals (et se faire taper sur les doigts) jsfiddle.net/1bLj8m2d/ - ne rien faire (à part plisser les yeux) jsfiddle.net/1bLj8m2d/1 - tenter de cleaner le HTML (et Dieu reconnaîtra les siens) jsfiddle.net/1bLj8m2d/2 De ton côté, tu as géré la difficulté avec ta fonction `expectConwaySuite`, mais tu as de la chance : ton format est simple. Se débarrasser du HTML c'est plus hasardeux et on peut se demander si le helper ne fait pas partie intégrante du test (il peut provoquer faux positifs ou faux négatifs). Aussi, on peut toujours imaginer des formats plus lourds à gérer que le HTML. Que fais-tu dans ces cas là ?
L'HTML est le format ADAPTÉ de sortie, il n'a rien à faire dans ta réflexion TDD sur le comportement du use case. Cet HTML généré par tes soins (j'imagine) doit être réalisé par l'intermédiaire d'un Presenter (pattern Presenter) qui fera émerger le View Model. Dans tes tests de la "logique métier", tu auras au choix : soit une dépendance vers un presenter Fake (car aucun intérêt de gérer la réelle présentation lorsque l'on teste l'orchestration du système), soit carrément ne pas en dépendre. Et tu auras une autre suite de tests pour ton réel presenter (l'HTMLConwayPresenter) Donc dans la suite de Conways, tu as deux zones : celle qui assurent le comportement du système et une autre distincte qui procède à l'affichage choisi des données. Explications ici sur le Presenter : softwareengineering.stackexchange.com/a/357066/43961
@@wealcome_company selon les domaines oui. Le DDD préconise de parler la langue du métier même dans le code, donc si l'environnement de travail du métier est en anglais ou dans un environnement international pourquoi pas. Dans mon cas en 12 ans de carrière moitié en France moitié à l'étranger, j'ai toujours codé dans le langage du métier et ce n'était jamais l'anglais (français en France et Japonais au Japon) c'est pour cela que ça m'interpelle.
Comme d'habitude, super tutoriel qui montre la puissance de la méthodologie.
Encore merci Michaël.
Tu m'as convaincu 😅 Où plutôt j'ai enfin compris à quoi le TDD sert !
Merci pour ces tutoriels, très intéressants. Si je peux me permettre, l'implementation de la profondeur (deep ou depth) n'est pas forcement la plus simple, en utilisant le pure TDD, code le plus simple, je suis arrivé a ceci ...
public string DrawLine(string line, int depth)
{
if (depth == 0)
{
return line;
}
return DrawSourceLine(line) + DrawLine(DrawNextLine(line), depth - 1);
}
... qui au final ne t'oblige pas a stocker le string concaténée car au final ton objet de retour est un string simple et pas d'autres méthodes privées. Le seul inconvenient est que si tu veux changer le retour disons en dictionary de string ou array de string, je dois tout refactorer en suivant ta solution.
Merci encore pour tout le boulot sur TDD !
merci !
Tu touches ici à l'avantage principal de TDD, le refacto ;) Du coup toute amélioration est bonne à prendre tant qu'elle...passe les tests ;)
Tu as ta sentinelle pour arranger le code.
Excellent !! On voit la puissance d’intellij mais aussi la puissance du tdd, continuer!
Bonjour, je ne connais pas bien le TDD mais je suis un grand fan de l'idée de toujours partir d'un code simple et refactorer au fur et à mesure. Du coup j'ai essayé de faire l'exercice à ma façon et voilà comment ça s'est passé : je me suis dit, étant donné une ligne, il faut la parcourir et compter au passage le nombre de caractères identiques. Du coup je me retrouve à faire un simple parcours de la chaine et je trouve que mon code est simple, malgré que j'ai pas utilisé de TDD, j'ai juste suivi la technique de penser simple. Voilà mon code (en C++ mais c'est pareil) (à noter que je met pas d'espaces entre les chiffres de la ligne)
string getNextLine(string line) {
string nextLine;
for (int i = 0; i < line.length();) {
char curChar = line[i];
int curCharCount = 0;
while (i < line.length() && curChar == line[i]) {
curCharCount++;
i++;
}
nextLine += std::to_string(curCharCount) + curChar;
}
return nextLine;
}
Par contre je n'ai pas écrit de tests du coup, il faudrait le faire en plus alors que avec TDD on les a direct
Top comme vidéo, c'est super intéressant de regarder quelqu'un coder comme ça.
Par contre je sais pas s'il y a tant de monde que ça qui se plaint d'être ralenti par le TDD pour coder une fonction pure.
En général, ce qui ralentit, il me semble, c'est plutôt toute l'architecture à mettre en place pour pouvoir tester justement. Tout le code qu'on rajoute et qu'on doit maintenir en plus du code de base, et qui plante dès qu'on modifie un truc. C'est sûrement souvent un signe de mauvais design mais je pense que l'argument "TDD ne ralentit pas, regarde ça" serait plus percutant s'il adressait aussi (plutôt ?) cette problématique.
Le fait qu'il plante des que tu modifie un truc est en général un signe qu'il y a un truc à corriger avant de livrer en prod sinon c'est la cata. Donc c'est plutôt cool non ?
@@kanaillaurent526 le code de test plante
TDD c est le top !!! Sors plus de videos si tu peux tu nous regales
Salut. Bonne vidéo. Pour les asserts j'ai une préférence pour assertj plutôt que harmcrest.
M’intéressant depuis longtemps au TDD, j'ai voulu tester ce kata en (TS / mocha / chai), une fois l'environnement en place, j'ai mis moins de 20 min à faire la suite ( github.com/np42/conway-suite ), la ou j'ai rencontré une réelle difficulté c'est pour faire les baby steps, 1, 2, 2 2 pas de soucis, par contre à partir du suivant (ou celui d’après peut-être), l'algo était valide pour tout les autres cas, en effet j'ai eu plus de mal à trouver quel était la plus petite modification à faire sans péter les autres tests plutôt qu'a faire une version générique directement. Est-ce une erreur sur la manière de faire correctement du TDD ? Probablement que oui car je n'ai peut-être pas le code minimal, des astuces pour éviter de brûler les étapes ?
Bonjour Michael,
Dans ta démo tu mets les tests dans un package unit donc différent du package de la classe que tu testes. Souvent on se place dans le même package pour éviter d'augmenter trop la visibilité de certaines méthodes pour effectuer des tests. Est-ce que tu peux développer les raisons qui font que tu places tes tests comme ça ?
Bonne remarque, c'est effectivement fait exprès :)
Cela force à ne passer que par les méthodes publiques d'une classe.
Dès que tu as besoin d'augmenter la visibilité d'une méthode, c'est un signe de mauvais design ;)
Cette pratique est mentionnée dans le livre "Growing object-oriented software guided by Tests" de Steve Freeman et Nat Price.
L'effet miroir est à proscrire car il permet des mauvaises pratiques comme tester explicitement des détails d'implémentations (méthodes non publiques).
Ok je vois. Je me doutais que c'était quelque chose dans ce genre là. Ça fait quelques temps que je me posais des questions sur cette manière de faire et ton point de vue m'intéressait :)
Je vais regarder du côté de ce livre. Merci !
@@Kuroidoruido Pas de soucis ! Bonne question en tout cas, peu de monde l'avait soulignée :)
Pas de debug, je reste mitigé, quand ton test ne passe pas tu dois forcément comprendre pourquoi et ce que fais ton code ce qui n'est pas toujours visible à l'œil.
Dans ton cas tu vas vite : "vous pouvez vous poser pour regarder mais c'est compliqué à expliquer" tu as surtout travaillé ta vidéo et tu sais exactement ce que tu dois dire ou faire donc oui tu vas vite
Merci je suis également fan de tdd et clean coding. Par contre je commence à m'intéresser au functionnal programming et je me demande si cela n'est pas risqué en Java à cause du stackoverflow possible. (contrairement à Clojure que j'aimerais maîtriser)?
Salut, un livre / vidéo en particulier à conseiller pour développer sa logique algorithmique ?
Si apres la ligne 19 on rajoute au niveau du parameter line "2 1 3 1 3 2" , ça donne quoi ??
Un autre bel exemple, merci!
Bonjour, je vois qu'on ne parle que de l'algorithme, dans une application web en php par exemple, ca ne serait pas un peu plus compliqué ?
Aucun problème pour le faire en php ou tout autre language, par contre l'auteur de la vidéo s'est clairement pris la tête (je pense volontairement pour illustrer le TDD), en réalité y a moyen de faire beaucoup plus simple via l'utilisation de boucle...
@@keysersoze8847 sauf qu'il a voulu le faire en programmation fonctionnelle exprès je n'ai ps trop compris pourquoi
Bonjour, voyez-vous un problème avec ce résultat obtenu sans TDD en 26 min, sans toucher au debugger ?
pastebin.com/kfBvsisw
Vous êtes sur quel IDE?
IntelliJ Ultimate
@@wealcome_company Merci!
Les tests unitaires servent à quoi? je les verrai au second semestre pour l'instant on est sur algo et programmation Orientée Objet.
@@dataengineerazure2983 servent à mener à bien l'écriture et la découverte de l'algorithme. Sans tests unitaires, pas de bon programme.
@@wealcome_company pourrais-tu donner plus de détails sur ce "Sans tests unitaires, pas de bon programme." stp
@@saidoubarry4455 ua-cam.com/video/is41fgDrqn0/v-deo.html
Merci pour le challenge !
Sur python j'ai mis 35min sans TDD, en débuggant beaucoup et avec 20 lignes de code.
Donc pas totalement convaincu même si je comprend l'intérêt d'avoir une ligne directrice safe, je me dis que ça enlève le côté créatif.
A voir...
Le code pour ceux qui veulent :
suite = [1]
def conway(s='1'):
new_s = ''
last_n = s[0]
first = True
count = 1
for n in s:
if n == last_n:
if first:
first = False
else:
count += 1
else:
new_s += str(count) + last_n
last_n = n
count = 1
new_s += str(count) + last_n
suite.append(int(new_s))
if len(suite) == 15:
return suite
return conway(new_s)
print(conway())
Yung Ab Le nombre de lignes de code ne signifient rien, si le code fait 20 lignes et jamais splitté, il sera incompréhensible à la lecture.
Pour être 100% convaincu, commence par réaliser de vrais projets avec, et non des Kata.
Maintenant que tu as écrit ce code, tu recrutes Benoit, qui propose d’y toucher et de changer des choses pour l’améliorer, ne serais-tu pas en stress à l’idée de penser qu’il puisse le casser par inadvertance ?
La peur de changer ne serait-elle pas une limite de la créativité ? Oh que si.
Tu constateras si tu le fais bien que ce qui enlève le côté créatif, c’est justement de ne PAS suivre la discipline TDD.
TDD autorise le refactoring sans crainte.
Je pense que cette méthode peut être utile quand on ne sait pas trop où l'on va et comment on va réussir à s'en sortir. Alors on peut choisir de ne pas résoudre le problème d'un coup mais d'y aller par étapes, en augmentant la difficulté au fur et à mesure, en utilisant la méthode que vous décrivez. Jusque là ça me va. Mais de là à dire qu'il faut toujours travailler comme ça, que c'est le saint Graal et qu'il faut évangéliser les mécréants, là je trouve que ça devient une posture extrémiste. Car dans le cas où l'on sait d'emblée écrire l'algorithme, je ne vois pas pourquoi s’empêcher de le faire. Car cela ralenti l'écriture et ne garantit pas un code optimal (je dirais même plutôt le contraire). TDD ça peut servir mais ça ne doit pas être une religion non plus.
petitpoidferoce J'ai formé en présentiel plus de 1500 développeurs jusque-là dont la plupart avait ce genre de discours (faussement sensé). Je peux vous garantir que la quasi totalité en sont sortis bouleversés avec un : « wow on est convaincu du bienfait ! ». Ne jugez pas sur cet exemple juste expliquer la pratique. Je garantis que si l’on maîtrise la pratique, on va 100 fois plus vite avec TDD que sans dans les algo non triviaux.
J'ai joué le jeu et il y a un truc qui me titille...
J'ai choisi exprès HTML comme format de sortie car ça rend les tests très peu lisibles et donc bien moins utiles. Je ne trouve pas une bonne manière de gérer ,ca
Je vois trois mauvaises solutions (l'onglet HTML c'est du boilerplate):
- tester des internals (et se faire taper sur les doigts) jsfiddle.net/1bLj8m2d/
- ne rien faire (à part plisser les yeux) jsfiddle.net/1bLj8m2d/1
- tenter de cleaner le HTML (et Dieu reconnaîtra les siens) jsfiddle.net/1bLj8m2d/2
De ton côté, tu as géré la difficulté avec ta fonction `expectConwaySuite`, mais tu as de la chance : ton format est simple. Se débarrasser du HTML c'est plus hasardeux et on peut se demander si le helper ne fait pas partie intégrante du test (il peut provoquer faux positifs ou faux négatifs). Aussi, on peut toujours imaginer des formats plus lourds à gérer que le HTML.
Que fais-tu dans ces cas là ?
L'HTML est le format ADAPTÉ de sortie, il n'a rien à faire dans ta réflexion TDD sur le comportement du use case.
Cet HTML généré par tes soins (j'imagine) doit être réalisé par l'intermédiaire d'un Presenter (pattern Presenter) qui fera émerger le View Model.
Dans tes tests de la "logique métier", tu auras au choix : soit une dépendance vers un presenter Fake (car aucun intérêt de gérer la réelle présentation lorsque l'on teste l'orchestration du système), soit carrément ne pas en dépendre.
Et tu auras une autre suite de tests pour ton réel presenter (l'HTMLConwayPresenter)
Donc dans la suite de Conways, tu as deux zones : celle qui assurent le comportement du système et une autre distincte qui procède à l'affichage choisi des données.
Explications ici sur le Presenter : softwareengineering.stackexchange.com/a/357066/43961
Hum, c'est vrai qu'à vouloir mettre TDD en défaut j'ai créé une chimère
Super vidéo. Par contre pourquoi faire la vidéo en français mais coder en anglais? On y perd en compréhension je trouve
Un code est en anglais c'est le standard ;)
@@wealcome_company selon les domaines oui. Le DDD préconise de parler la langue du métier même dans le code, donc si l'environnement de travail du métier est en anglais ou dans un environnement international pourquoi pas. Dans mon cas en 12 ans de carrière moitié en France moitié à l'étranger, j'ai toujours codé dans le langage du métier et ce n'était jamais l'anglais (français en France et Japonais au Japon) c'est pour cela que ça m'interpelle.
-J’ai comme le sentiment que tout pète si on se retrouve avec un nombre >= 10- 😛
Pourquoi ça ?
@@wealcome_companyDe toute façon c’est impossible, on ne peut se retrouver qu’avec des 1, 2 ou 3
@@wealcome_companyMais si la ligne initiale était 45 par exemple, on pourrait se demander si on doit le considérer comme « 1 45 » ou comme « 1 4 1 5 »
c'est sur que tdd ça va vite quand on a préparé 10 fois l'exercice avant de se filmer entrain de le faire
pock picket c’était bien en live et non surpréparé ;)