Si vous me connaissez depuis un moment, vous savez que j’adore automatiser tout ce qui peut l’être. C’est un travers de développeur, mais c’est aussi une qualité : grâce à mes petits scripts, j’arrive à m’éviter un monceau de tâches répétitives et chronophages, ce qui me permet de me concentrer sur les tâches à haute valeur ajoutée. À l’époque, je répétais « si un stagiaire PEUT le faire, un script DOIT le faire ». C’est encore plus vrai à l’heure de l’IA : si vous pouvez déléguer la tâche, il y a de grandes chances qu’une machine puisse s’en occuper.
-
-
Teste ton code
Tu veux siroter des cocktails sur une plage, pendant que ton code travaille sans toi ? Si tu veux éviter les coups de fil toutes les 5 minutes, chaque fois que quelque chose déraille, il n’y a qu’une solution : teste ton putain de code.
Qu’on soit bien d’accord, je ne vais volontairement pas te noyer sous un flot de détails techniques à propos des tests. L’idée de ce post est de t’expliquer pourquoi c’est important, et en quoi c’est sympa.
Mettons-nous en situation
Scénario catastrophe : On te remonte un petit bug dans du code que tu as écrit. Pas dramatique, juste un edge case mal géré. Une fois les mains dans le code (qui date de 6 mois), tu te rappelles du jour où tu l’as écrit. C’était un peu crade, mais tu n’avais pas le temps de faire mieux, et ça marchait, donc c’est passé en prod tel quel. Aucun jugement ici, ça arrive à tout le monde. Tu corriges ton petit bug, et tu pousses ton fix en prod. Cinq minutes plus tard, un des mecs du marketing (en général, celui qui te gonfle le plus) arrive tout affolé pour savoir ce qu’il se passe, en beuglant « ÇA MARCHE PAS ». T’as pété un truc. Grosse régression. Changement d’ambiance : d’un coup, c’est le feu, tout le monde gueule, t’as la pression et tu dois réparer ta connerie ET le bug qu’on t’avait remonté ce matin, le plus vite possible, sous pression.
Ça aussi, ça arrive à tout le monde. Enfin, plus à moi, ça m’a gonflé et j’ai fini par le comprendre : le code, ça se teste.
Même scénario, une fois tes tests en place : On te remonte un souci : un edge case qui n’est pas géré. Tu ajoutes le test qui le couvre, puis tu répares le bug. Tu fais tourner tes tests. Oups, ton fix casse autre chose. Tu reprends. Au deuxième essai, ça marche. Tu rajoutes deux-trois assertions pour le sport, tu pousses en prod. Café ?
Comme le dit Mehdi Zed, « Et si j’entends encore quelqu’un dire que tester, ça fait perdre du temps, je lui fais avaler son clavier ». D’ailleurs, tiens, va lire sa prose sur les compétences clefs pour les développeurs.
Le nez dans la QA
La QA, pour Quality Assurance, ça devrait faire partie de ta culture. Ton boulot n’est pas d’écrire du code, mais de résoudre des problèmes, et le code est un outil. Tu te dois d’affuter ton outil, et chaque action que tu mènes et qui va dans ce sens est une action positive.
J’entends souvent dire qu’il est très difficile de faire accepter au client qu’il va devoir payer pour le temps de rédaction des tests. C’est un faux problème : tu n’as pas à lui demander son avis, c’est une histoire entre toi et ton code. Évidemment qu’il va devoir payer, comme il doit payer pour les licences de tes logiciels, ton électricité et ton café.
Je n’ai que deux bras et j’ai envie que mes projets avancent vite, donc j’ai pris la bonne habitude d’acheter du code. Ça m’aide à mettre ce genre de coûts en perspective : est-ce que je préfère payer mon code 30 % moins cher, ou avoir la certitude qu’il fonctionne comme prévu ?
Par quoi je commence ?
Imaginons que tu doives ajouter une feature à un site. Commence par rédiger (à l’arrache) un scénario d’utilisation : « Je suis utilisateur. Quand je valide un paiement, mon compte prépayé est débité du montant, et j’ai une nouvelle facture disponible ».
La première étape va être d’écrire un test, qu’on nommera par exemple « un_utilisateur_peut_valider_un_paiement ». Dans ce test, on appelera la fonction $user->validatePayment($payment), et on vérifiera si la date de validation du paiement est bien passée de null à une date courante. Ça s’appelle faire une assertion : on s’attend à ce comportement. Un test « qui passe », c’est un test pour lequel toutes les assertions ont été vérifiées.
À partir de notre exemple fictif, voici quels tests j’écrirais pour commencer :
- un utilisateur peut valider un paiement
- la validation d’un paiement pioche dans le crédit d’un utilisateur
- la validation d’un paiement entraîne la création d’une facture
Évidemment, puisqu’on n’a pas encore écrit de code, ces tests ne passeront pas. Je vais maintenant écrire le minimum de code possible. Bravo, on vient de faire du TDD (Test Driven Development) : ce sont les tests qui ont motivé la rédaction du code.
Et c’est là que ça devient marrant. Une fois le premier code jeté en place, il est maintenant temps de le passer au grill. Réfléchissons aux problèmes futurs (aux erreurs courantes qui vont se présenter en utilisation normale de l’appli) : un utilisateur peut ne pas avoir assez de crédit, le paiement peut avoir déjà été validé, etc. Chacun de ces petits scénarii d’erreur fera l’objet d’un nouveau test, ou d’une assertion dans un test existant.
Ensuite, deuxième passe : comment quelqu’un de mal intentionné pourrait-il me la faire à l’envers. Si le montant du paiement est négatif, est-ce que le crédit est quand même retiré à l’utilisateur (ou ajouté ?) Est-ce que la méthode/route peut etre appelée par quelqu’un qui n’est pas connecté ? Est-ce qu’on peut valider un paiement pour un autre utilisateur ? etc.
On revient à notre scénario catastrophe : maintenant que tu as la méthode, tu vas pouvoir appeler Antoine (prénom choisi presque au hasard) et le faire participer à la rédaction des scénarii. Au début, il sera frileux, mais une fois qu’il aura pris le coup, il sera utile pour t’aider à repérer les edge cases avant qu’ils n’arrivent en prod, et à écrire les tests qui vont avec.
Quand un souci arrivera, il saura d’avance que c’est parce qu’un des scénarii n’était pas assez complet.
Tu verras qu’au bout de quelques temps, ça va devenir un jeu : chacun voudra écrire le scénario le plus complet, et même si tu bosses seul, tu vas te faire un noeud au cerveau pour être certain de n’avoir laissé aucune faille. Là où tu pouvais parfois te dire « bof, ça suffira », tu passeras deux heures de plus pour essayer d’être vraiment exhaustif. Et la qualité de ton code s’en ressentira. Tu passeras moins de temps en debug (c’est une promesse) et plus de temps sur de nouvelles features. Ça débloquera aussi du temps pour nettoyer et maintenir ton code, via le refactoring.
Autre avantage : le refactoring
Le fait d’avoir une suite de tests solide répond aussi à une question qu’on me pose souvent : « je ne sais pas si je dois mettre le code dans un controlleur, dans un modèle, ou créer un service à part ». Ma réponse sera simple : on s’en fout. Fais passer tes tests, et on refactorisera ton code plus tard si ça s’avère nécessaire. Avec des tests au carré, on n’a pas peur de mettre les mains dans son code pour le faire muter en fonction de la demande, puisque son bon fonctionnement est verrouillé. Chaque erreur de refactoring fera péter un test.
Le refactoring est un excellement moyen de se coller à écrire des tests quand on n’en a pas l’habitude. La prochaine fois que tu dois t’en taper une session, réfléchis à tes scénarios existants, écris tes tests (qui, cette fois, devront passer tout de suite), puis modifie ton code, en faisant tourner tes tests le plus souvent possible.
Si tu t’y mets aujourd’hui, je te promets que dans six mois, tu ne te poseras plus de questions, et que tu testeras systématiquement tout le code que tu écris.
-
Est-ce qu’on met en prod le vendredi ?
Difficile de trancher cette éternelle question qui taraude les services techniques : est-ce qu’on met en prod un vendredi ? L’équipe « contre » trouve ça impensable. L’équipe « pour » considère que c’est un manque de confiance dans son code. Si tu ne mets pas en prod le vendredi, est-ce que c’est parce que tu bosses à l’arrache ?
Vingt années de carrière, et j’ai toujours du mal à trancher. D’un côté, je veux avoir des week-ends tranquilles, loin des bugs en production, et de l’autre, je devrais faire suffisamment confiance en mon travail pour que ça ne pose pas de souci.
Les précautions
Je bosse beaucoup avec Laravel. Soumettre.fr est sponsor officiel du framework : on se tient au courant des évolutions, on étudie de près les nouveautés et les services de l’écosystème.
On teste notre code (peut-être pas assez, mais on est loin d’être à la ramasse) avec des tests unitaires et fonctionnels (avec phpunit évidemment, mais aussi notamment Laravel Dusk). Quand on me remonte un bug, ma première action est d’écrire un test qui le reproduit, avant de le régler. Comme ça, je m’assure que chaque bug n’arrive qu’une fois, et que je ne casse rien en le réparant.
On bosse avec un administrateur système au top : il dissèque de près nos besoins, préconise des solutions, les met en place, puis nous aide à monter en compétences pour qu’on soit autonomes, sous sa sainte surveillance. On déploie avec Capistrano, qui permet des déploiements sans interruption de service, en intégrant nos tests au process (GitLab-CI). En cas de pépin, la mise en prod échoue, et le site reste en ligne sur la dernière version fonctionnelle. La configuration des serveurs est répliquée via Ansible, donc on sait aussi où on déploie.
Les développements sont validés en preprod par l’équipe Produit avant d’arriver en ligne.
Bref, sur le papier, on est tranquilles – et dans 99.99% des cas, tout roule.
Mais dans 0.01 % des cas…
Je ne peux pas m’empêcher de frémir en repensant aux fantômes du passé. Je ne remonterai pas jusqu’à l’époque où on criait des noms de fichiers dans l’openspace, pour savoir qui bossait sur quoi, avant de les mettre en ligne par FTP (sincèrement, je me demande comment on arrivait à faire du business comme ça). Mais des petits accrocs de mise en prod, j’ai eu le temps d’en voir passer.
Je me rappelle du vendredi où la commerciale est entrée dans l’openspace en m’annonçant que son projet venait d’être signé : un mini-site événementiel, pour la sortie d’un film, avec un jeu en flash type « carte à gratter » pour gagner des places pour l’avant-première. Les maquettes étaient prêtes à être intégrées (réalisées en avant-vente), et l’opération commençait le lundi. Je vous laisse imaginer le niveau de dégueulasserie du code pour que ça rentre dans le timing annoncé. Je vous laisse imaginer aussi qui a oublié de faire tourner le script de génération des instants gagnants en prod. L’opération au tourné plusieurs jours avant qu’on se rende compte que personne ne gagnait. Propre. Le comble ? La commerciale en question, après m’avoir expliqué qu’elle avait vraiment besoin de sa commission parce que son fils avait toujours rêvé de nager avec des dauphins dans la Mer Noire (si si, je te jure), s’est barrée en week-end, à 16 heures.
Je me rappelle du jour où on a poussé en prod la refonte du site d’une radio nationale. Grosse audience. Le service informatique du groupe nous avait filé les identifiants du serveur du prod un peu à la bourre (c’était un gros rebranding, tout le monde était dans le jus). On développait sous Debian, le serveur était sous Solaris. Pour des raisons que je ne m’explique toujours pas, les pontes avaient décidé que la refonte se ferait sous eZ Publish, un CMS connu (et redouté) pour ses nombreuses couches de cache. Problème, en PHP, la fonction glob() (qui lit le contenu d’un dossier) comporte un bug sous Solaris, qui renvoie des dates de fichiers erronées. Boum. Aucun cache, et des animateurs qui balancent l’url du nouveau site toutes les 5 minutes à la radio (pour info, on faisait des pics de 100.000 connexions simultanées). On a souffert.
Je me rappelle du jour où Laravel a changé la façon dont on définit combien de temps une donnée reste en cache avant d’être invalidée (on appelle ça le « TTL » pour « Time To Live », durée de vie). C’était annoncé et documenté. En gros, sans rien changer au code, on est passé de « 10 minutes » à « 10 secondes », forçant le cache à se rafraîchir 60 fois plus souvent que prévu. C’est clairement passé inaperçu quand on a mis à jour le framework, et le serveur de prod s’est pris une grosse claque.
Je pourrais continuer comme ça longtemps.
Je ne mets pas de code en production le vendredi
Ces anecdotes relèvent d’erreurs humaines, on est d’accord. J’adore mon métier, je pense n’être pas mauvais, et j’ai de la bouteille. Ça ne suffit malheureusement pas à empêcher les boulettes d’arriver. Bref, si ce n’est pas indispensable, je ne pousse pas en production le vendredi, ni les veilles de jours fériés.
Évidemment, on fait des exceptions. Si le code répare un petit bug, ça passe. Si on est sur une feature sur laquelle le temps a un gros impact, ça peut le faire. Pour le reste, on attend le lundi, et on fait ça au calme. Très généralement, ça ne change rien, pour personne.
Dans tout projet informatique, il reste une zone d’ombre quelque part. J’estime que ton métier de développeur n’est pas de chercher à tout prix à l’éliminer : le temps t’est compté. Tu ne peux pas toujours prendre le temps que tu aimerais sur chaque feature, la réalité du business finit toujours par te rattraper. Tu dois parfois prendre un risque calculé. Ne pas le reconnaître, c’est te voiler la face.
Par contre, ton taff consiste aussi à être là quand le problème surviendra pour le réparer. Alors on fait comment : tu te caches, en attendant de te faire démonter le lundi matin, ou tu te pourris le week-end ? Et dans ce cas, tu rumines parce que ton boulot t’a encore gavé, ou tu me factures les heures supplémentaires ? Ça pourrait m’inciter à ne pas « laisser passer » l’erreur (souvent humaine, on l’a vu), et ça nous mettrait dans un rapport de force qui est malvenu quand on est tous dans le même bateau.
Comment justifier ça en entreprise ?
Il y a un « détail » que j’ai mis très longtemps à comprendre (comme quoi, je dois quand même être un peu con) : en tant que développeur, lead dev, CTO d’une société, tu n’es pas un simple exécutant. Arrête de te comporter comme tel. Tu n’es pas une victime : pour tes collègues et ta hiérarchie, qu’ils te le montrent ou pas, tu es le sachant sur les questions techniques. Un rôle-clé dans l’équipe, puisque tu as un jeu de compétences indispensables à l’entreprise, et que les autres n’ont pas.
J’ai bossé avec (et pour) de sacrées têtes de mule. Chaque fois que j’ai pris le temps de leur expliquer les tenants et aboutissants d’une décision, celle-ci a été respectée. Mieux : c’est quand j’ai commencé à oser imposer mes décisions que ma carrière a vraiment démarré. Une des clés est d’éviter le jargon : tu ne veux pas étaler ta science, mais faire comprendre les éléments de réflexion qui t’ont poussé à une décision logique. Et la logique, c’est ton boulot.
Évidemment, pour que ça marche, n’attends pas un vendredi 15h pour annoncer qu’il n’y aura pas de mise en production. Il faut savoir anticiper ces choses, prévenir le plus tôt possible, en expliquant pourquoi c’est risqué. Ce n’est pas un aveu de faiblesse !
Si ça n’a jamais été fait dans ta boîte, je te propose de rédiger une politique d’entreprise concernant les dates de mise en production. Détailles-y les contraintes, les interdictions, et les exceptions qui seront admises. Pour aider la pilule à passer, préviens du monde, et envoie-leur en leur précisant que c’est un brouillon et que tu aimerais qu’ils le complètent de leurs avis. Tu verras : ça va négocier vite fait, mais personne ne rechignera. Je ne peux pas te promettre que tu ne mettras plus jamais en prod le vendredi, mais ça sera un excellent début.
-
RTFM… et la bienveillance ?
Quand est-ce qu’on a décidé qu’il serait normal de se parler mal ?
À la fin des années 90, quand IRC était à la mode, on pouvait voir, souvent plusieurs fois par jour, un développeur poser une question, et quelqu’un lui répondre « RTFM » (pour « Read The Fucking Manual », soit en français « Lis le putain de manuel », sous-entendu parce que la réponse y est, et que donc la question ne méritait pas d’être posée. On est ensuite passé à la mode du « Google est ton ami », pour dire à la personne ayant posté qu’elle pourra trouver sa réponse en cherchant sur Google.
Je peux comprendre, vraiment, qu’on n’aie pas envie d’aider certaines personnes. D’autant plus quand on fait ça bénévolement, souvent sur son temps libre.
Sur StackOverflow, par exemple, on voit souvent des étudiants venir copier/coller l’intitulé d’un exercice, en demandant directement des solutions. Ils n’ont pas l’air coincés par un point spécifique, ils veulent juste qu’on leur mâche le travail. Sur des forums, on voit aussi passer des gens qui veulent « créer un site ecommerce », mais n’ont aucune idée de comment ça se passe.
Par contre, j’ai de plus en plus de mal (et ça fait 20 ans que ça monte) avec les gens qui envoient simplement chier les personnes qui viennent pour de l’aide. Pourquoi ne pas leur parler gentiment ? Si c’est uniquement l’attrait de la phrase toute prête, c’est de la fainéantise. Si c’est pour le plaisir d’être désagréable, c’est déplacé.
Je soupçonne une raison encore plus profonde, et plus malsaine. On a tous notre petit syndrome de l’imposteur. C’est compréhensible : même ceux qui ont été le mieux formés peuvent se retrouver sur le carreau lorsque la technologie aura changé, et elle change tous les jours.
Là où le bât blesse, c’est qu’une fois que la personne qui voulait se faire aider sera montée en compétences, elle trouvera naturel et normal de reproduire ce comportement en ligne.
(et quand je cherche la solution à un problème, je tombe assez régulièrement sur un forum où quelqu’un avait la même question que moi, et cette personne s’est faite renvoyer vers Google. Super, en général, c’est de là que j’arrive…)
Pour le domaine de la musique, Romain Morlot parle de « Sainte Inquisition Musicale » pour les ultra-orthodoxes qui ont décidé, on ne sait pas trop pourquoi, que prêcher la bonne parole en ligne deviendrait leur mission de vie. En général, ils ne pardonnent aucun écart vis-à-vis de leur sainte doctrine.
C’est pareil chez les devs. Je ne compte plus les fois où j’ai vu un mec arriver, tout content, et expliquer qu’il avait utilisé curl (ou autre, hein, c’est un exemple fictif) pour faire X, et quelqu’un lui répondre, menton levé et ton hautain implicite, « pour ça tu dois utiliser Y ».
L’exemple typique, c’est avec les frameworks. Et encore plus avec les frameworks JS (comme par hasard).
Allez lire l’annonce d’une nouvelle feature React, vous trouverez forcément un commentaire « Angular le fait depuis 3 ans ». Mouais, et alors ?
Tu vois aussi des mecs arriver en disant « je galère sur un petit script de statistiques en PHP » et le couperet tombe immédiatement : « pour les stats il faut faire du Python ». Réponse suivante : « le Python c’est moisi, maintenant il faut faire du R »… Bon les jeunes, je voudrais pas casser l’ambiance, mais entre taper 2 requêtes SQL un peu complexes, et apprendre un nouveau langage, y’a tout un monde. Dans l’absolu, vous n’avez pas tort, mais vous êtes carrément à côté de la plaque.
Les personnes qui m’ont le plus aidé à progresser dans ma carrière sont celles qui ont été bienveillantes. Par exemple, mon ami Gabriel m’aurait expliqué, d’un ton doctoral mais avec le sourire, qu’il existe de très bons outils pour régler mon problème, en Python et en R, et qu’il en existe peut-être des implémentations en PHP. Ça me motive à aller voir les technologies citées, à suivre des tutos, potentiellement à adapter des choses vers le PHP, ou à switcher de langage « dans le pire des cas ».
Je conçois tout à fait qu’on aie ses préférences (je n’ai jamais caché mon amour pour Laravel – avec ses forces et ses défauts). Pour autant, il ne me viendrait pas à l’idée d’aller harceler les forums Symfony en leur expliquant comment l’herbe est plus verte chez nous, et encore moins en essayant de montrer du doigt les failles de leur outil pour espérant promouvoir ma façon de faire, qui serait la seule et unique bonne façon. Le pire, c’est que la bienveillance, ça marche bien : quand j’ai présenté Laravel devant les membres de l’AFUP Aix-Marseille, j’ai bien senti que je n’arrivais pas en terrain conquis (la plupart des participants étant plutôt symfony-addicts), et ça s’est pourtant très bien passé. J’ai même noué des relations amicales avec des pro-symfony, avec qui j’échange encore régulièrement, très cordialement.
Bref, pour conclure, ma proposition est la suivante : et si on essayait de se parler un peu plus amicalement ? Après tout, on est tous dans le même bateau…
-
Pourquoi j’ai un canard en plastique sur mon bureau
J’ai un canard en plastique sur mon bureau, devant mon écran de droite. Il ne bouge jamais de là. Mon défi du jour, c’est de faire un post sur les canards en plastique, et de vous glisser un lien d’affil pour que vous en achetiez un. On parie ?
Plus qu’un objet de déco, mon canard, que j’ai nommé Captain Debug, est un vrai outil de travail. Ça s’appelle du « Rubber Duck Debugging » : quand je me sens coincé devant un bout de code qui refuse obstinément de fonctionner (reconnaissez que ça vous arrive aussi), je fais appel à mon canard magique.
Il est magique, parce qu’il connaît toutes les réponses. Il est beaucoup plus malin que moi, et il n’est jamais coincé (coincoincé, même… bravo pour ceux qui suivent). Du coup, quand je suis vraiment en galère, je fais appel à lui. Pour que son pouvoir fonctionne, il faut qu’il soit en possession de toutes les informations nécessaires.
Je me retrouve alors à lui expliquer, point par point, ce que j’attends de mon code, et ligne par ligne, ce qu’il fait. Et la magie opère : je finis quasi-systématiquement par buter sur un piège logique.
Pourquoi ça marche ?
Parfois, j’ai du mal à expliquer la situation au canard. Il devient alors évident qu’une partie de ce que je fais n’est pas claire dans mon esprit, et que c’est un des points sur lesquels je dois me pencher pour résoudre mon casse-tête.
Il y a très longtemps, j’ai fait de l’eXtreme Programming : on était deux développeurs devant un poste (« Pair programming »), et on se surveillait à tour de rôle. Ça permettait, en plus d’éviter les fautes de frappes et d’inattention, d’avoir un petit lutin qui gardait la tête froide sur les objectifs que le code devait atteindre. Pendant que l’un se concentre sur la logique en mode « big picture », le deuxième s’occupe de l’implémentation fine. Ça marche super bien, mais ça a un inconvénient majeur, puisque dans l’esprit des acheteurs, ça double le prix d’une session de travail. Difficile d’expliquer au client qu’il va payer plus, parce qu’un mec a les bras croisés derrière moi, et qu’il sera payé aussi. Croyez-moi, j’ai essayé. Rares étaient ceux, à l’époque, qui étaient prêts à comprendre le principe.
Pourtant, c’est comme ça qu’à démarré la mode des méthodes agiles, dont les revues de code sont partie intégrante. En poussant à l’eXtreme (d’où le nom), on se retrouve avec un mec perché sur l’épaule, dans une revue de code en temps réel et en continu.
Sur Internet, on a aussi la mode émergente des « ELI5 » pour « Explain Like I’m Five« , ou « Explique-moi comme si j’avais 5 ans ». On dévie un peu du debugging, puisque le eli5 est utilisé pour un peu tout et n’importe quoi, et c’est très bien comme ça. On en voit souvent passer sur Reddit, par exemple : « eli5 blockchain ». Un mec débarque, il s’est renseigné sur le sujet, et pourtant ça ne rentre pas. Il demande alors qu’on lui explique, de bout en bout et avec des mots simples, le concept, ses bénéfices, etc. Répondre à ces questions demande un énorme travail de vulgarisation, mais ça permet d’avoir une vue d’ensemble claire et compréhensible d’un problème complexe.
C’est la même chose avec le canard : on doit reprendre du début à la fin, sans sauter d’étapes, et en restant le plus explicites possible.
Origine
Pour la petite histoire, la méthode du Canard en Plastique semble être apparue en premier dans « The Pragmatic Programmer« , par Andrew Hunt et David Thomas. Ce livre, qui date de 1999, présente un tour d’horizon de méthodes de travail (orientés code), avec leurs points forts et leurs limites. Je vous conseille d’y jeter un oeil, c’est avec le Hacker Manifesto un des écrits qui m’a beaucoup fait évoluer. Je me suis jeté sur l’édition « 20e anniversaire » sortie en septembre 2019.
Alors, j’ai réussi mon pari ? Achetez votre canard : https://amzn.to/2Jy1Be8 (lien affilié)