Et si la clé des réussites business se trouvait dans l’UX du code ?

Les meilleures réussites business se construisent sur des expériences utilisateurs (UX) bien pensées, qui apportent de la valeur à l’usager∙e et répond à ses besoins. On parle souvent d’UX pour évoquer le produit fini, mais ne serait-il pas intéressant de s’intéresser à l’UX vécue par les développeurs∙ses lors de l’écriture du code ? En effet, les développeurs∙ses sont utilisateurs∙trices du code écrit par quelqu’un d’autre. Et de manière intéressante, ils ou elles sont également UX designers du code utilisé par d’autres.

L’expérience avant tout

L’UX design est en effet crucial pour tout type d’activité. “Nous passons d’une société matérialiste à une société expérientialiste” expliquait Carine Lallemand, chercheuse en UX, à BlendWebMix l’année dernière (Van Boven, L., & Gilovich, T., 2003). Avec la multiplication des Smartbox, de plus en plus de cadeaux gravitent autour des expériences. Et si l’on cherche un peu, on réalise vite que nous sommes tous des concepteurs et conceptrices d’expérience utilisateur : l’enseignante qui prépare son cours, le restaurateur qui choisit l’ambiance et le menu de son restaurant, l’avocate qui prépare sa plaidoirie, le réalisateur qui prépare sa mise en scène… et la développeuse qui écrit du code qu’un autre développeur enrichira par la suite.

The user of software design is the developer

Alexandru Bolboaca

Dans le cadre du travail comme ailleurs, nous souhaitons tous vivre de bonnes expériences utilisateurs, et à tous les niveaux :

  • un lieu de travail proche de chez soi, avec une bonne ambiance ;
  • un bureau ergonomique avec un fauteuil confortable et un éclairage agréable ;
  • un ordinateur puissant et non vérolé ;
  • des logiciels de travail stables et performants ;

Si elles sont bonnes, ces expériences utilisateurs nous permettent d’être efficaces et épanouis au travail. Au niveau le plus fin, si nous avions un code plus facile à utiliser pour les évolutions que nous devons apporter alors nous (dev, business, entreprise) serions plus performants et plus épanouis.

Comment faire ?

Illustration objet inutilisable
Objet inutilisable de Katerina Kamprani – Source : http://www.lsd-mag.com/blog/design-inconfortable/

Pour concevoir de bonnes UX il faut être bien conscient d’une chose : s’il y a un problème d’utilisabilité, ce n’est pas la faute de l’utilisateur∙trice, c’est la faute du design ! En effet, les UX designer ne peuvent pas modifier les personnes qui vont utiliser leur design. La seule chose sur laquelle nous avons le contrôle est notre propre design. L’amélioration ne peut donc que venir de celui-ci.

La clé pour concevoir de bonnes UX est théoriquement simple : connaître sa cible et ses besoins. Pour cela, nous disposons d’une batterie de méthodes :

  • interviews pour comprendre qui sont les gens et quels sont leurs besoins
  • observation d’activité pour observer in situ les problèmes rencontrés et leur cause
  • tests utilisateurs pour évaluer les limites d’un design
  • questionnaires UX pour évaluer quantitativement la qualité de l’expérience ou l’utilisabilité d’un produit
  • etc

Un modèle intéressant pour identifier les besoins est celui d’Hassenzahl (2003). Selon lui, les gens perçoivent les produits interactifs selon deux dimensions :

  • Les qualités pragmatiques : les capacités à soutenir l’accomplissement de “do-goals”. Par exemple dans le cas d’un vélo : se déplacer.
  • Les qualités hédoniques : les capacité à soutenir l’accomplissement de “be-goals”. Par exemple dans le cas d’un vélo : être autonome.

Bien que souvent sous-estimés, la satisfaction des besoins hédoniques est au coeur de l’UX. Dans le contexte du développement, le “do” consiste à développer sur du code existant sans introduire de régressions. Le “be”, quant-à-lui serait un besoin de se sentir efficace, autonome, et en situation de contrôle vis à vis du code produit. Si ces 3 besoins hédoniques sont assouvis, à la fois les employé∙e∙s et leurs supérieurs hiérarchiques seront satisfaits.

Des grilles d’évaluation

Ces trois besoins étant les plus pragmatiques des besoins hédoniques, nous pouvons utiliser des grilles d’évaluation utilisées dans le domaine de l’ergonomie logicielle pour s’assurer que ces besoins sont satisfaits. En reliant chacun des besoins à des critères plus concrets, il sera plus simple d’améliorer l’UX du code.

Il existe plusieurs grilles d’évaluation qui guident l’étude de systèmes interactifs. Les critères d’utilisabilité de Nielson sont au nombre de 5 :

  • Apprentissage : combien de temps faut-il pour maîtriser le système ?
  • Efficience : une fois le système maîtrisé, à quelle vitesse les tâches sont-elles effectuées ?
  • Mémorabilité : après une période sans utiliser le système, combien de temps faut-il pour le maîtriser à nouveau ?
  • Erreurs : combien d’erreurs sont faites ? Quelles est leur gravité ? Est-il simple de les corriger ?
  • Satisfaction : à quel point l’utilisation du système est agréable ?

Pour les relier à nos Be-goals, les critères d’apprentissage et de mémorabilité favoriseront l’autonomie, le critère efficience est directement lié au sentiment d’être efficace, et le critère erreurs se rapporte au sentiment d’être en situation de contrôle.

Une autre grille d’évaluation que l’on peut utiliser, plus détaillée, est celle de Bastien & Scapin (1993). Elle comporte 8 critères et 16 sous-critères pour évaluer une interface homme-machine. Nous avons identifié sept de ces sous-critères comme facilement applicables dans le domaine du développement logiciel.

Améliorons l’autonomie

Pour favoriser l’apprentissage et la mémorabilité, trois sous-critères de Bastien & Scapin peuvent facilement s’appliquer au domaine du développement.

Incitation

Le terme Incitation a ici une définition plus large que celle qu’on lui confère généralement. Ce critère recouvre les moyens mis en œuvre pour amener les utilisateurs à effectuer des actions spécifiques. Ce critère englobe aussi tous les mécanismes ou moyens faisant connaître aux utilisateurs·trices les alternatives, lorsque plusieurs actions sont possibles, selon les états ou contextes dans lesquels ils se trouvent. L’incitation concerne également les informations permettant de savoir où on en est, d’identifier l’état ou le contexte dans lequel on se trouve, de même que les outils d’aide et leur accessibilité.

Dans la vie quotidienne, on peut parler de manque d’incitation face à une porte dont on ignore s’il faut la tirer ou la pousser pour l’ouvrir.

Dans les interfaces web, un bon exemple d’incitation est celui du site de Voyage-SNCF qui incite très bien les usager·e·s à remplir le formulaire pour faire une recherche de voyage, tout en affichant les alternatives (avion, bus, etc).

Bonne incitation sur le site de Voyage SNCF
Bonne incitation sur le site de Voyage SNCF

À l’échelle du code il n’est pas toujours facile de savoir qu’est-ce qui constitue un objet valide. Prenons un petit exemple d’une application dans la restauration où l’on doit instancier un objet Menu. Un mauvais exemple serait d’avoir un constructeur sans paramètres. On ne sait pas ce qu’il faut pour construire un menu correct. Un plat principal, bien entendu, mais faut-il un dessert et ou une entrée ? Du café ? S’il y a une entrée et/ou un dessert. Une possibilité serait de fournir un Builder, pour guider la construction :

return menuWith()
    .starter("Foie Gras")
    .mainCourse("RoastedBeef")
    .dessert("CremeBrulee")
    .build();

Ou encore mieux avec des types, l’incitation devient très forte.

Exemple de code incitant

Une autre solution, plus simple, serait d’avoir des constructeurs nommés pour énumérer les variantes autorisées : menuWithStarterAndMainCourse(starter, mainCourse).

Homogénéité / cohérence

Ce critère signifie que les choix de conception d’interface doivent être conservés pour des contextes identiques, et doivent être différents pour des contextes différents. Cet aspect touche à la fois le visuel des éléments, leur appellation, les réactions du système, les procédures… Le revers de ce critère est que les éléments qui ne se ressemblent pas doivent être différenciés visuellement et dans leur terminologie. L’utilisateur·trice ne doit pas confondre deux éléments parce qu’ils se ressemblent.

Dans la vie quotidienne, les panneaux routiers répondent parfaitement à ce critère : les panneaux exprimant un danger sont tous rouges et triangulaires, les panneaux exprimant une obligation, une interdiction, ou une indication sont chacun identiques entre eux et différents des autres. Cette notion de cohérence est apprise en maternelle (cf exemple).

Exercice de maternelle sur le classement de panneaux routiers
Exercice de maternel sur la sécurité routière – Source : http://lesmoyensgrands.over-blog.com

Dans les interfaces web, un mauvais exemple que l’on peut donner est celui de facebook qui propose 4 pictogrammes différents pour le concept de Photographie (un dans le chat, un pour une nouvelle publication, un dans les commentaires, et un dans le menu gauche).

Manque de cohérence sur facebookManque de cohérence sur facebook

Sur facebook 3 pictos différents pour poster une photo : dans mon fil, dans un commentaire, dans un chat. Un 4ème picto Photo pour voir mes photos (menu sur le côté).

Dans le code on retrouve souvent une cohérence de rangement de classes : tous les *Repository dans un dossier, tous les *Controller dans un autre, ainsi de suite. Cela aide la navigation. Cela dit, il y a dans l’exemple suivant une double cohérence, donc superflue : le nom et le dossier. Une autre approche intéressante existe : ranger les classes par fonctionnalité, c’est à dire mélanger une classe Repository et la classe Controller etc dans un même dossier, lié à la fonctionnalité. Regardez comment cet exemple offre une navigabilité par fonctionnalité sans pour autant faire de compromis sur la cohérence par couche technique : si on cherche un contrôleur il suffit de faire une recherche de classes qui s’appellent *controller.

Exemple de code homogène

Compatibilité

La compatibilité signifie que les interactions doivent être conçues pour que le système s’adapte au mieux aux caractéristiques de l’utilisateur∙trice. Ces caractéristiques peuvent être intrinsèques (âge, handicap, niveau d’expertise vis à vis de l’outil…) ou liées à la tâche (besoin de rapidité, de limiter les erreurs ou d’être facile à prendre en main…).

On trouve énormément d’exemples dans le marché des produits pour enfant. Ce lit a été designé pour des enfants, avec des rangements à leur hauteur.

Lit compatible pour les enfants
Lit compatible pour enfants – Source : https://www.designferia.com/meubles-design-chambre-enfant-lola

Côté IHM, on voit souvent des designs d’interface très différents selon le niveau d’expertise attendu des utilisateurs∙trices. Par exemple, l’outil de traitement d’image Photoshop va être adapté à un public d’experts dont l’objectif sera de faire des choses très complexes de la manière la plus efficace possible, tandis que l’outil Paint a été pensé pour un public beaucoup plus large, dont les besoins techniques sont plus simples et pour lesquels la découvrabilité des fonctionnalités est plus cruciale. Identifier ces objectifs différents permet d’adapter le design en fonction de ces derniers : plus de boutons accessibles vite et plus de raccourcis sur Photoshop, au détriment de l’intuitivité de l’interface. Dans un cas comme celui-ci où l’efficacité est privilégiée sur l’apprentissage et la mémorabilité, il est pertinent de prévoir des mécanismes d’assistance pour faciliter la prise en main de l’outil : tutoriels vidéo, aide technique, etc.

IHM de Paint
Interface pour novices sur Paint
IHM de Photoshop
Interface pour experts sur Photoshop

Il en va de même dans le développement, où l’efficacité devrait primer sur l’apprentissage et sur la mémorabilité, jusqu’à un certain point. Prenons par exemple ces deux variantes de la même fonctionnalité : trouver les adultes parmi un ensemble de personnes.

// imperative style
let adults = []
for (var person of people) {
    if (person.age >= 18) {
        adults.push(person)
    }
}

// functional style
function isAtleast18(person) {
    return person.age >= 18
}
let adults = people.filter(isAtleast18)

Beaucoup de développeurs vont préférer le for-loop, alors que le style fonctionnel peut sembler plus utilisable, grâce au fait qu’il se lit comme une phrase et que le prédicat “isAtleast18()” utilisé peut être réutilisé. Que doit-on faire dans un cas comme celui-là ? Faut il suivre la préférence des usager·e·s dans tous les cas ? Non, parfois il vaut mieux former les individus car c’est l’efficacité sur le long terme qui prime ici.
L’objectif ici lorsqu’on écoute les utilisateurs∙trices n’est pas d’aveuglement suivre leurs préférences, mais de comprendre leurs difficultés afin de leur faciliter l’accès à une nouvelle compétence. Bref on fait primer l’efficacité sur la facilité d’apprentissage (learnability).

En faisant attention à ces trois critères, l’apprentissage et la mémorabilité de votre code seront meilleurs, générant au passage un agréable sentiment d’autonomie chez vos collègues.

Toujours plus efficace

Pour améliorer l’efficacité du développement sur le code écrit par un tiers, nous avons identifié deux sous-critères de Bastien & Scapin auxquels porter attention.

Lisibilité

Le critère de lisibilité concerne les caractéristiques lexicales de présentation des informations pouvant entraver ou faciliter la lecture de ces informations. Les contrats, par exemple, sont réglementés en termes de lisibilité : les caractères essentiels des produits ou prestations, leurs prix, et les délais de livraison ou d’exécution doivent être communiqués de manière lisible et compréhensibles.

Dans le cadre des IHM, il existe de nombreuses recommandations pour favoriser la lisibilité d’un texte :

  • Taille de police : min = 12pt, normal = 16pt
  • Taille des lignes : 45-75 caractères (best = 66) espaces compris
  • Interlignes : 1,5x la taille de la police ; entre 2 paragraphes : 1,5x l’interligne
  • Contraste : différence de contraste entre couleur du texte et couleur du fond : 70%

Si l’on compare les interfaces de Wikipédia et de Wikiwand (petit plugin permettant de rediriger les liens Wikipédia vers le même contenu affiché différemment), on voit immédiatement que la seconde est plus lisible que la première. Les lignes sont plus courtes et le sommaire est visible en permanence.

Mauvaise lisibilité sur Wikipédia
Mauvaise lisibilité sur Wikipédia
Bonne lisibilité sur Wikiwand
Bonne lisibilité sur Wikiwand

Dans le code, il est courant de voir des lignes très longues, mal formatées et qui dépassent même l’écran. Par exemple :

var urlParameters = 'restaurantId=' + firstMenu.restaurantId + '&menuId=' + firstMenu.id + '&customerId=' + customerId

Lorsque les développeurs·ses rencontrent une ligne qui dépasse l’écran, ils ou elles vont souvent scroller pour voir au lieu de formater la ligne ! Les quelques secondes gagnées par le premier développeur se paient cher par la suite. Il serait tellement plus pertinent de formater pour améliorer la lisibilité.

var urlParameters =
    'restaurantId=' + firstMenu.restaurantId + '&' +
    'menuId=' + firstMenu.id + '&' +
    'customerId=' + customerId

Pour à peine plus d’effort, on peut aller plus loin en séparant la logique métier du formatage :

var urlParameters = joinUrlParameters({
    restaurantId: firstMenu.restaurantId,
    menuId: firstMenu.id,
    customerId: customerId
})

Densité informationnelle

Le critère de Densité informationnelle propose de réduire la charge de travail du point de vue perceptif et mnésique. Pour cela, il faut limiter le nombre d’informations présentées en même temps. Si certaines sont inutiles dans un contexte donné, il est nécessaire de les supprimer ou de les transférer à un autre endroit.

Dans la vie courante, si une personne reçoit de nombreuses informations ou conseils simultanément (le premier jour dans un nouveau boulot par exemple), elle ne sera pas en mesure de tout mémoriser.

Côté IHM, on peut prendre l’exemple de la page d’accueil de Cdiscount, tellement chargée qu’on a des difficultés à s’orienter sur cette page : on ne sait pas où cliquer. A contrario, la page d’accueil de Google est un très bon exemple de l’application de cette recommandation ergonomique. Ici, l’interface épurée de laisse aucun doute sur l’action à réaliser, c’est limpide.

Densité importante sur CDiscount
Densité informationnelle très importante sur CDiscount
Densité faible sur Google
Densité informationnelle très faible sur Google

Côté code, on peut prendre l’exemple d’un test sélenium faisant une requête rest pour créer les données nécessaires, ensuite pointant le navigateur sur la page du menu nouvellement créé, puis attendant que certains éléments deviennent visibles avant de lancer le premier test. Ce code aurait tendance à être un amas de détails de bas niveau mélangés avec des informations au niveau métier. Cela deviendra problématique dès lors qu’on aura beaucoup de suites de tests qui dupliquent plus ou moins ce schéma de setup. La solution serait ici de réduire la densité informationnelle en faisant émerger les trois grosses étapes citées ci-dessus (création de menu, navigation, attendre la fin du chargement), et en extrayant les parties communes dans un objet. De cette manière il ne reste dans chaque test que ce qui le différencie d’un autre.

Le code avant (ne lisez pas le code, un coup d’oeil est suffisant) :

postMenus(menus, backendUrl + "/restaurant/" + restaurantId).then(function (res) {
    var firstMenu = {
        restaurantId: res.restaurant[0].id,
        id: res.restaurant[0].menus[0].id
    }

    var urlParameters = 'restaurantId=' + firstMenu.restaurantId + '&menuId=' + firstMenu.id + '&customerId=' + customerId

    return browser.get(serversConfig.compileUrl('/restuarant/', urlParameters))
}).then(function () {
    browser.wait(ExpectedConditions.presenceOf(elementSelector.restaurants.restaurantTitle))
}).then(done)

Le code après :

testButler()
    .addMenusToRestaurant(menus)
    .navigateToPage('restaurant', restaurantId)
    .wait(until.presenceOf(restaurantTitle))
    .then(done)

En contrôle avant tout

Pour réduire les erreurs et leur impact, deux sous-critères de Bastien & Scapin peuvent être exploités.

Protection contre les erreurs

Ce premier critère est assez explicite, il consiste à mettre en place des moyens pour détecter et prévenir les erreurs.

Un exemple de la vie quotidienne est le jeu pour enfant ci-dessous, dans lequel les erreurs sont “interdites” par le design : l’enfant ne peut pas mettre une forme triangulaire dans un trou rond.

Jeu pour enfant d'insertion de formes en bois dans une boite trouée
Jeu pour enfant où l’erreur est impossible – Source non retrouvée (désolés)

Dans les IHM, il existe de nombreuses manières de protéger contre les erreurs : sélecteur de date, complétion d’adresse, message de confirmation avant de faire une action sensible…

Protection contre les erreurs sur google Agenda
Exemples de protection contre les erreurs dans google Calendar
Protection contre les erreurs sur Gmail
Exemples de protection contre les erreurs dans gmail

Rendre l’erreur impossible

Dans le code, on peut obtenir la même chose dans un langage typé statiquement. Prenons le constructeur pour la classe Menu. Dans la forme ci-dessous il est bien trop facile de se tromper d’ordre entre entrée et plat principal.

Menu(String mainCourse, String starter, String dessert) {

}

Si par contre on utilise des types, alors cette erreur n’est plus possible :

Menu(MainCourse mainCourse, Starter starter, Dessert dessert) {

}

C’est en général une très bonne idée de se débarrasser des types primitives au plus vite et de les encapsuler dans des objets propres au métier de l’application.

Que doit-on faire dans un langage dynamique tel que javascript alors ? Encore une fois le pattern Builder peut nous servir à rendre l’erreur moins probable par l’incitation (voir le premier exemple dans la section “Incitation”).

Corriger les erreurs

Avez-vous connu des bugs de config ? C’est à dire une fonctionnalité qui était hors-service à cause d’une erreur dans la configuration de l’application. C’est assez fréquent et cela peut paraître une fatalité. Qui plus est, c’est difficile de tester ces configs. La bonne nouvelle est que l’on peut en éliminer un grand nombre par le design.

Exemple de code fragile :

let checkoutUrl = config.paymentProvider + "somepath/" + "paymentOptions"

En effet si paymentProvider ne contient pas de slash à la fin nous avons un (gros) bug.
Pourtant il est facile de corriger les erreurs de config. Au lieu d’exposer des primitives comme l’url, on encapsule la donnée avec le calcul qui y est lié (de la programmation orientée objet quoi).

let checkoutUrl = config.paymentProviderUrlFor("somepath", "paymentOptions")

// then in the Config class we have ...
function paymentProviderUrlFor(path, destination) {
    return joinWithSlashes(path, destination)
}

Feedback immédiat

Ici, il s’agit d’informer l’utilisateur·trice sur l’efficacité de ses actions. Le système doit réagir à chacune des actions. Dans les critères de Bastien & Scapin, ce sous-critère est associé au guidage plus qu’à la gestion des erreurs. Cependant, un feedback immédiat permet aussi de corriger une erreur très vite, avant qu’elle n’ait d’impact. Dans la vie courante, les feedbacks immédiats sont partout. Quand on ouvre une porte, on a un feedback visuel immédiat qui confirme que la porte s’ouvre. Quand on fait un mouvement brusque qui fait tomber un objet, ce même feedback visuel immédiat peut permettre de ratrapper l’objet avant qu’il ne touche le sol et ne se casse, donc avant que l’erreur de mouvement n’ait un réel impact.

Du côté des IHM, un bon exemple est celui des validations de formulaires. Dans le formulaire de création de compte d’Amazon, il faut attendre la validation du formulaire pour que les erreurs réalisées soient indiquées, alors même que la présence d’un @ dans l’adresse mail ou le nombre de caractères dans le mot de passe pourraient être vérifiés en temps-réel. Un meilleur exemple est celui de Cdiscount qui valide ou invalide email et mot de passe au fur et à mesure de la saisie.

Feedback pas immédiat sur Amazon
Pas de feedback pendant la saisie sur Amazon
Feedback pas immédiat sur Amazon
Erreurs signalées uniquement après clic sur le bouton “Créer votre compte Amazon”
Feedback immédiat sur CDiscount
Feedback en temps-réel sur CDiscount

De manière générale et en particulier dans le code, le coût de correction d’une erreur est fortement lié au temps passé entre l’introduction de l’erreur et sa détection. Imaginons que quelqu’un fasse une erreur détectée quelque dizaines de secondes plus tard par un test unitaire. Dans ce laps de temps la personne a fait très peu de choses, elle va donc trouver l’erreur en quelques secondes. Si le feedback est très rapide, tout va bien.Feedback immédiat dans le code

Imaginons maintenant que l’erreur ne soit vue que par les tests système éxécutés la nuit, après que fusion avec la branche principale. Le lendemain, c’est un collègue qui se lance sur l’investigation. Il doit chercher parmi toutes les fusions de la veille, parmi le travail de l’ensemble des personnes développant sur le projet en une journée complète. Le coût de debug n’est pas le même, il est supérieur de plusieurs ordres de grandeur. Et encore l’erreur a été vu en moins de 24h.
On peut bien imaginer qu’une application où la majeure partie des erreurs se voit très vite avec des tests unitaires, ou tout du moins sur le poste de développement, avancera beaucoup plus vite qu’une application qui n’a que des tests système, passés une fois par jour, la nuit. C’est pour cette raison que l’on parle d’une pyramide de tests.

Si une attention particulière est portée sur ces deux points, les erreurs seront moins nombreuses et moins graves, créant ainsi un sentiment d’être en situation de contrôle.

You are not your user!

You are not your userEn UX design, nous sommes bien conscients que même le meilleur designer commet des erreurs de design, simplement parce que le regard de néophyte dont il aurait besoin est trop contaminé par sa profonde connaissance du problème auquel il apporte une solution. Du côté du code, cela nous est plutôt étrange. L’idée qu’un ou une développeur∙se sénior demande l’avis d’un∙e junior sur son design semble absurde. Pourtant c’est justement ce qu’il faut ; en observant nos utilisateurs∙trices on découvre des soucis d’utilisabilité à adresser. Ce n’est jamais la faute de l’utilisateur·trice.

En UX on utilise des tests utilisateur et des interviews. Côté code nous avons plusieurs façons de traduire ces pratiques. Voici trois exemples, le Code Review, la prise de température en rétrospective d’équipe et les tests utilisateur.

Code Review

C’est une classique, indispensable, mais avec de nombreux pièges relationnels qui nous guettent. Ici nous conseillons d’utiliser des critères d’UX (Nielson ou Bastien & Scapin) pour entrer dans une discussion constructive. Par exemple :

  • Je pense que l’utilisation d’un integer pour modéliser un prix est une potentielle source d’erreur. Un autre développeur pourrait facilement passer le prix en euros au lieu de centimes. Y aurait-il une autre option où le risque d’erreur serait moindre ?
  • Je peux nommer le paramètre “priceInCents”
  • Bonne idée ! D’autres possibilités ?
  • Euh, … non
  • Cela me fait penser qu’une possibilité serait d’utiliser un objet Price, au lieu d’un constructeur nous pouvons créer un méthode statique “inCents(cents)”. Tous les prix de l’application devraient être construits en appelant Price.inCents().
  • Effectivement cela adresse bien ce risque d’erreur.

Au passage vous l’aurez compris, après une première lecture du reviewer, nous donnons le feedback à l’oral, ce qui est vécu comme moins violent.

Prise de température en rétrospective

Qu’est ce qui était difficile dans le dernier sprint ?

Quelle partie du code était difficile à comprendre ?

Où as-tu eu peur d’introduire une régression ?

Alexandru Bolboaca

Avec cette approche, on cherche à identifier des endroits dans le code où l’on passe régulièrement et qui sont identifiés comme des sources de ralentissement. Si on améliore un peu l’UX à ces endroits, le ROI est maximal.
À plusieurs reprises, ces questions nous ont emmenés vers des améliorations significatives pour un investissement très très faible : essentiellement du renommage. Certes, ce n’est pas toujours le cas, mais cela nous a montré souvent qu’une bonne manière de détecter des inepties de design a déjà énormément de valeur.

Tests utilisateur

Alexandru Bolboaca a effectué de vrais tests utilisateur simulant une utilisation pendant 2 heures avec un protocole de questions à la sortie. Plus facile à mettre en place, nous pouvons simplement nous asseoir à côté d’un coéquipier pendant 20 minutes lorsqu’il utilise pour la première fois une partie du code écrit récemment. Cela donne en un temps record un feedback souvent surprenant et facile à prendre en compte.

Synthèse

En se focalisant sur les besoins d’utilisabilité, les concepts techniques comme le refactoring, le clean code et le TDD trouvent un ancrage de métier : le besoin de ne pas être freiné par un mauvais outil de travail. Un besoin davantage priorisable que les pratiques techniques. Un besoin que tout le monde peut comprendre et auquel tout le monde peut contribuer. Cela rejoint un concept clé en UX design : s’intéresser au besoin plutôt qu’à la solution. Les pistes que nous proposons dans cette article ne sont que des suggestions, c’est à chaque équipe de développement d’identifier un ensemble de solutions qui lui conviennent afin de répondre au besoin d’un code utilisable, qui rend les développeurs et les développeuses autonomes, efficaces et en situation de contrôle.

On se plaint souvent qu’on ne fait pas de code assez propre, qu’on ne refactore pas assez, etc. En déplaçant le dialogue sur le terrain de l’utilisabilité nous faisons le pari que la situation va s’améliorer, car personne ne peut croire qu’il est possible de faire des merveilles en négligeant l’utilisabilité de notre outil de travail premier : le code !

Pour rappel, les axes de vigilance sont les suivants :

Améliorer l’apprentissage et la mémorabilité du code pour rendre plus autonome

  • Inciter en proposant les alternatives
  • Homogénéité et cohérence dans l’écriture
  • Rendre le code compatible avec les développeurs·ses, ou l’inverse !

Augmenter l’efficience du code pour rendre plus efficace

  • Lisibilité des nommages
  • Brièveté & densité informationnelle : factoriser le code

Réduire les risques d’erreurs pour améliorer le contrôle

  • Corriger les erreurs automatiquement
  • Feedback immédiat : tests, etc

Fortune, bonheur, retour de l’être aimé

En faisant quelques efforts sur cet aspect du développement, les bénéfices sont partagés à travers tous les métiers : les développeur·ses ressentiront moins de lassitude et de frustration, seront moins en conflit les un·e·s avec les autres et auront moins envie de quitter un projet ou une entreprise, les dirigeant·e·s verront augmenter la rentabilité de l’entreprise et les bénéfices, et les utilisateurs·trices obtiendront un produit de meilleure qualité qui évolue plus vite. Qu’est ce qu’on attend ?

Notes

Cet article a été écrit à 4 mains par Johan Martinsson et moi-même.

Johan et mon entreprise Sogilis s’associent pour proposer une formation sur l’amélioration de la qualité du code, n’hésitez pas à nous contacter pour avoir plus d’informations. En savoir plus (sur le site Johan Martinsson).

Ressources

Références scientifiques

  • Bolboaca A. (2016). Usable software design 
  • Norman D. (1988). The Design of Everyday Things
  • Van Boven, L., & Gilovich, T. (2003). To do or to have? That is the question. Journal of Personality and Social Psychology, 85, 1193–1202.
  • Hassenzahl, M. (2003). The thing and I: understanding the relationship between user and product. In M.Blythe, C. Overbeeke, A. F. Monk, & P. C. Wright (Eds.), Funology: From Usability to Enjoyment (pp. 31-42). Dordrecht: Kluwer Academic Publishers.
  • Lallemand, C. (2015). Towards Consolidated Methods for the Design and Evaluation of User Experience. (Doctoral dissertation). University of Luxembourg. http://orbilu.uni.lu/handle/10993/21463
  • Lallemand C. (2015) UX design, et si la clé du succès se trouvait dans les théories sur l’UX  ? Conférence à BlendWebMix
  • Nielsen, J. (1994). Usability Engineering. Morgan Kaufmann Publishers.
  • Bastien C. & Scapin D. (1993). Critères Ergonomiques pour l’Évaluation d’Interfaces Utilisateurs (version 2.1), INRIA, Technical report N° 156

Exemples dans la vie courante

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.