Je m'appelle Victor, je suis analyste système chez Sportmaster. Et aujourd'hui, je voudrais parler de la décomposition des tâches et de leur transfert vers le développement. Tout objet se compose de pièces, qu'il s'agisse d'une voiture ou d'un logiciel. Et il faudra du temps pour assembler l'un de ces objets en un seul tout à partir de ses composants. Parfois, cela prend même beaucoup de temps. Surtout si avant cela vous ne démontiez pas seulement la partie principale, mais décidiez d'aller au fond de celle-ci au niveau atomique.
Où se situe la frontière entre une définition adéquate des tâches et un chaos total? Je vais partager un exemple de la façon dont chez Sportmaster nous recevons périodiquement des tâches de développement de l'entreprise.
Comme vous pouvez le voir dans les exemples ci-dessus, la description de chaque tâche dépend en grande partie de l'imagination et du bon sens du client. Quelque part c'est plus, quelque part c'est moins, mais les analystes doivent travailler avec ça d'une manière ou d'une autre. Parfois, ils indiquent également les limites de la fonctionnalité, et parfois ils envoient simplement un sujet. Si nous transférons une telle tâche directement au développement, nous obtiendrons quelque chose d'incompréhensible en sortie. Que dois-tu faire?
Marchez vers le client avec vos pieds et demandez toutes les exigences, clarifiez ce qui devrait être exactement à la sortie. Certes, il y a aussi des clients Gold, qui, en fait, sont majoritaires - ils écrivent toutes les exigences dans leur Confluence, vous pouvez donc aller le lire à tout moment et poser des questions. Et lorsque tout est déjà clair avec le cadre de la fonctionnalité, vous pouvez commencer à couper la tâche.
Pourquoi se décomposer
L'objectif principal de la décomposition est de permettre à l'entreprise de mettre en œuvre rapidement tous ses souhaits et de faire passer le moins de temps possible à l'utilisateur de l'idée elle-même à l'apparition de la fonctionnalité. Pour ce faire, vous pouvez effectuer des tâches plus petites, à partir desquelles, bien que petites, mais néanmoins, la fonctionnalité de travail atteindra l'utilisateur.
En plus d'atteindre l'objectif global de répondre aux besoins des utilisateurs et de l'entreprise, la décomposition des tâches vous permet d'obtenir plus rapidement des commentaires du client, que le développement creuse dans la bonne direction ou que cela ne s'est pas du tout imaginé par le client.
Si la tâche est initialement importante et que nous l'avons assumée entièrement en même temps, nous y passerons beaucoup de temps et après les commentaires du client, nous devrons tout jeter. Eh bien, si la tâche est petite, un jour ou deux de travail au maximum, - ça va. La retouche prendra environ le même montant. La deuxième approche est également moins chère. Sans parler des nerfs sauvés des deux côtés.
Si une fonctionnalité est divisée en plusieurs éléments, les développeurs peuvent travailler dessus en parallèle. Ainsi, nous allons paralléliser le flux et accélérer la sortie de la fonctionnalité dans prod. L'important est que les tâches dépendent le moins possible les unes des autres.
Plus des tests rapides et des corrections de bogues. Encore une fois, une petite fonctionnalité est beaucoup plus facile et plus rapide à tester qu'un colosse monstrueux. Et si quelque chose ne va pas, le développeur dépensera très peu pour «réparer», et tout fonctionnera plus rapidement.
Au stade de la décomposition des tâches, avec le client, vous pouvez immédiatement comprendre quelle fonctionnalité est importante ici et maintenant, afin de commencer à faire des bénéfices, ce qui peut être laissé pour plus tard et ce qui, peut-être, deviendra inutile.
Il est important pour les entreprises de savoir à quelle vitesse la fonctionnalité opérationnelle apparaîtra. Et une fois décomposés en tâches, nous pouvons prédire et estimer plus précisément le temps qu'il faudra pour les terminer que lorsque vous avez un seul grand front de travail. Mais outre le fait que les petites tâches sont plus faciles à évaluer en termes de temps pour les résoudre, il est également plus facile pour un développeur d'évaluer les risques qui peuvent survenir dans le processus.
Par exemple, les frameworks ont été mis à jour, certaines méthodes ont été mises hors service, des problèmes avec le code, etc. En prenant de petites tâches dans le travail, nous minimisons tous ces risques, et même si une telle tâche bloque quelque chose dans le flux, ce ne sera pas aussi critique que s'il s'agissait d'une pièce lourde (qui bloquerait tout du tout). Si nécessaire, il sera possible de faire une solution de travail et de mettre une dette technique dans l'arriéré, qui pourra être traitée un peu plus tard, lorsque les problèmes seront résolus.
Approches de base et règles de décomposition
Il existe deux approches principales de la décomposition des tâches: horizontale et verticale. Avec l'horizontale, les tâches sont divisées par type de travail, par niveau ou par composant. Par exemple, chaque tâche passe par plusieurs étapes: front-end, back-end, bases de données. Et avec une approche horizontale, une tâche va vers l'arrière, la seconde vers l'avant et la troisième conduit à des changements dans la base de données.
Pourquoi cette approche est-elle mauvaise? Nous n'obtenons pas de fonctionnalité fonctionnelle après avoir terminé chaque tâche individuelle. Ce n'est qu'en collectant les résultats de trois sources que nous pouvons obtenir une sorte de résultat et des commentaires à ce sujet. Pour cette raison, la décomposition horizontale n'est le plus souvent pas utilisée.
L'approche verticale est beaucoup plus pratique, dans laquelle une fonctionnalité visuelle peut être créée dans chaque tâche - la tâche passe par toutes les étapes et le résultat est un résultat qui peut être analysé, testé, montré au client et corrigé, si nécessaire. Et démarrer et utiliser rapidement.
Si nous parlons des règles, ici je n'en ai identifié que trois. Premièrement, la tâche doit être logiquement complète, c'est-à-dire indépendante en soi. Il ne doit pas briser la logique qui l'entoure et doit nécessairement porter au moins un certain sens commercial que l'utilisateur recevra en conséquence. Dans le même temps, vous ne devez pas décomposer en parties les tâches qui n'ont pas de sens commercial (idéalement, elles ne devraient pas du tout exister).
Deuxièmement, le résultat de l'accomplissement d'une petite tâche devrait apporter de petits changements. Plus les changements sont petits, plus ils entrent rapidement dans le code général, et donc le code ne devient pas obsolète. De plus, de petites tâches permettent d'éviter les conflits entre les développeurs lors de la fusion.
Troisièmement, vous ne devriez pas diviser la tâche en parties très microscopiques. Si la ventilation est trop petite, il faudra beaucoup de temps pour gérer ces tâches. À chaque étape, il peut être nécessaire de redéfinir les priorités, de réapposer des dépendances, et c'est tout. Ainsi, la vitesse de développement n'augmentera pas, mais au contraire chutera fortement. Par conséquent, vous devez rechercher un terrain d'entente.
Méthodes de décomposition
Selon la source, le nombre de méthodes de décomposition varie considérablement: quelque part elles ne sont indiquées que huit, quelque part dix, quelque part vingt. Je voudrais souligner les façons dont je dois utiliser chaque jour au travail.
Besoins multiples
Cette méthode est la plus pratique à utiliser lorsqu'il y a des conjonctions "et", "ou" dans l'histoire. Par exemple, un consommateur souhaite passer une commande et payer avec une carte ou des bonus. Cette tâche peut être divisée en trois: la première, dans laquelle l'utilisateur passe une commande, la seconde, où il la paie avec une carte, et la troisième, où les bonus sont utilisés.
Scénarios d'utilisation
Une autre méthode courante consiste à diviser les tâches en fonction du cas d'utilisation. Dans ce cas, une histoire est une voie principale et plusieurs alternatives. Disons qu'un utilisateur souhaite acheter un article, et ce serait le scénario principal. Mais il existe encore des moyens alternatifs - il peut immédiatement mettre le produit dans le panier et payer, ou il peut vouloir comparer ce produit avec d'autres avant d'acheter. Et puis nous faisons de la comparaison de produits une tâche distincte.
Peut-être qu'il ne veut pas acheter tout de suite, mais le remettre quelque part, l'ajouter aux favoris, pour qu'il puisse y revenir plus tard. Ou l'utilisateur a aimé le produit et est prêt à l'acheter, mais il est en rupture de stock. Vous devez donc lui faire savoir quand les marchandises apparaîtront. Et voici comment se déroulent quatre scénarios.
Du simple au complexe
La page principale du site "Sportmaster" est constituée de bannières. Et la chose la plus simple que nous puissions faire est de prendre une photo et de la montrer à l'utilisateur. C'est le moyen le plus simple et le plus rapide de transmettre les bonnes informations. Ensuite, nous pouvons augmenter la fonctionnalité et ajouter non pas une image, mais trois ou quatre, qui sont combinées dans une grille. C'est une tâche distincte.
Avec cette approche, à chaque tâche ultérieure, la fonctionnalité devrait se développer. Par exemple, nous pouvons créer un carrousel à partir de la grille, puis ajouter des liens, des textes, des boutons et le reste. En général, nous implémentons d'abord la version la plus simple et la plus performante, puis passons à une version plus complexe.
Tout récemment, j'ai été engagé dans une tâche similaire de mise en œuvre d'une bannière. La bannière était censée accrocher la bannière principale et être contrôlée depuis le CMS. Si vous demandez au client ce qu'il aimerait gérer exactement, il répondra volontiers sans ciller - tout le monde. Par conséquent, il était important ici de plonger un peu dans le sujet et de mettre en évidence ce qui doit être géré maintenant, ce qui est juste souvent et ce qui n'est presque jamais utilisé du tout. Et ainsi, priorisez la mise en œuvre et divisez-la en tâches.
Opérations (CRUD)
C'est probablement la méthode de décomposition la plus courante. Ici, les tâches sont divisées en opérations de création, de lecture, de mise à jour et de suppression. Il convient aux tâches où vous devez gérer quelque chose ou configurer quelque chose. Par exemple, la tâche de passer une commande est divisée en quatre plus petites: créer une commande, la visualiser, la modifier et la supprimer.
Options d'interface
Utilisé lorsque plusieurs options d'interface doivent être prises en charge. Par exemple, un site doit prendre en charge plusieurs langues. Tout d'abord, nous créons la version russe. Ensuite, lors du lancement dans d'autres pays, nous ajoutons l'anglais. Si le pays utilise une langue autre que l'anglais, nous pouvons également l'ajouter. Dans ce cas, il est plus facile de tout faire d'abord dans une seule langue, puis d'ajouter progressivement des traductions.
Plus récemment, nous avons réalisé un projet de compte personnel pour les personnes morales, qui nécessitait un support multilingue. Les délais étant serrés, ils ont tout d'abord fait tout dans une seule langue, mais ont jeté les bases d'une traduction ultérieure. Désormais, ajouter la prise en charge d'une nouvelle langue ne prend qu'une petite tâche. Si vous devez ajouter plusieurs langues à la fois, une tâche distincte est créée pour chacune d'elles.
Séparation par rôle
Convient aux situations dans lesquelles la fonctionnalité implique le fonctionnement de plusieurs rôles et groupes d'utilisateurs. Sur le site Sportmaster, un utilisateur peut avoir différents rôles. Par exemple, les utilisateurs sont divisés par rôles en un utilisateur autorisé, un utilisateur anonyme et, par exemple, un utilisateur de centre d'appels. Ce dernier rôle peut également être divisé en deux: il peut s'agir d'un utilisateur ordinaire ou d'un administrateur.
Pour chaque rôle, nous pouvons faire une tâche distincte. Commencez par afficher pour un utilisateur anonyme, puis ajoutez des fonctionnalités avancées dans le cadre d'une tâche pour un utilisateur autorisé. Et n'oubliez pas les rôles techniques des opérateurs de centres d'appels et leurs fonctionnalités.
Traitement des erreurs
Si les délais sont serrés et que la fonctionnalité minimale est nécessaire le plus rapidement possible, vous pouvez intégrer la gestion des erreurs dans une tâche distincte. Nous ne parlons pas ici d'écrire des tests, mais de gérer les erreurs des utilisateurs et des systèmes avec lesquels le site est intégré. Imaginons que nous traitions une page de catalogue contenant une vignette de produit. Chaque carte a une description, une photo et des informations supplémentaires.
Il se trouve que certaines informations ne proviennent pas des bases de données.
Peut-être que si nous parlons d'une marque ou d'un matériau, cela peut être négligé et simplement ne pas afficher d'informations. Mais si le prix ou le nom n'apparaît pas, vaut-il la peine de montrer cette carte?
Que faire dans une telle situation? Cette question peut être traitée dans une tâche distincte, puis traiter chaque champ distinct. Autrement dit, si le prix n'est pas venu, nous effectuons une action, la description du produit est perdue - une autre. C'est la même chose avec les erreurs des utilisateurs. S'il a mal saisi quelque chose et qu'une erreur s'est affichée, par exemple "Page non trouvée" ou erreur 500, nous devons lui montrer des informations spécifiques sur ce qui s'est passé et lui proposer un script sur ce qu'il peut faire ensuite.
Cette méthode convient également aux situations où vous avez besoin d'obtenir rapidement des commentaires sur les fonctionnalités afin de décider de la conserver ou non.
Statique puis dynamique
C'est l'un de mes moyens préférés. Convient dans les situations où il est possible d'implémenter la fonctionnalité «sur les stubs», c'est-à-dire que les systèmes externes ne sont pas prêts à prendre en charge la fonctionnalité. Par exemple, certains blocs de la page principale ne peuvent pas être contrôlés depuis le CMS. Ou un menu, lorsque nous le faisons dans notre code et l'affiche à l'utilisateur, mais en même temps, il ne peut pas être contrôlé par l'entreprise. Et pour apporter des changements, l'entreprise doit constamment se développer et demander à le faire.
Ici, nous priorisons les besoins des utilisateurs et le profit. L'utilisateur obtient immédiatement la fonctionnalité prête à l'emploi, même si nous pouvons rencontrer des inconvénients à l'intérieur. Par conséquent, nous divisons la tâche en plusieurs et mettons d'abord le nouveau bloc à la disposition de l'utilisateur, mais l'entreprise ne peut pas encore le gérer directement. Mais ensuite, nous pouvons intégrer un système ou une base de données, où l'entreprise elle-même pourra échanger des éléments et en ajouter de nouvelles par elle-même, et nous les dessinerons sans participation au développement.
Nous utilisons souvent cette méthode: d'abord, nous créons des fonctionnalités sur nos propres données, qui ne peuvent pas être contrôlées de l'extérieur, puis nous ajoutons de la dynamique et commençons à recevoir des données de systèmes tiers.
Performance
Si la tâche dans son ensemble est complexe et volumineuse, on ne sait pas à partir de quelle extrémité la traiter, alors la performance peut être négligée. La première tâche est de faire ressortir une fonctionnalité prête à l'emploi qui a fonctionné d'une manière ou d'une autre, bien que lentement. Et la tâche suivante consiste à accélérer le travail. Par exemple, il peut s'agir d'un lent travail de recherche de marchandises, d'application de filtres, d'obtention d'informations
. Mais vous pouvez apprendre beaucoup de la lenteur de la mise en œuvre, et cela a une certaine valeur pour l'utilisateur qui, autrement, ne pourrait pas effectuer une action importante. Dans tous ces cas, les tâches sont décomposées en «faire fonctionner» et «accélérer».
Difficultés possibles
Si vous décidez d'utiliser la décomposition des tâches dans vos projets, la première difficulté à laquelle vous serez confronté sera probablement la dépendance des tâches les unes par rapport aux autres. D'après mon expérience, c'est le problème de blocage de thread le plus courant. Pour éviter cela, la décomposition doit être abordée de manière responsable et disposer de suffisamment de temps.
Une autre difficulté consiste à déterminer la finesse dont vous avez besoin pour décomposer la tâche. Et ici, seul le bon sens fait office de frontières. Par exemple, nous prenons le composant de sélection de ville. Il a des boutons, du texte, un champ de saisie. À quel point devriez-vous battre cette tâche?
Nous avons déduit une règle pour nous-mêmes que la tâche doit se dérouler tout au long du flux en une semaine au maximum (environ 40 heures). Nous parlons de toutes les étapes: l'étape de l'analyse, du développement, des tests. De plus, deux étapes de développement backend et frontend sont prises en compte, y compris l'examen et les tests à chacune.
Nous avons également eu un problème avec le fait que les limites de l'épopée ne sont pas toujours claires. Récemment, on nous a confié la tâche de passer une commande. Où sont ses frontières? Quel devrait être le résultat? Il n'était pas clair pour nous si nous devions faire toutes les fonctionnalités jusqu'au bout ou choisir une partie. Cette épopée inclut-elle le paiement ou s'agit-elle déjà d'une épopée distincte.
Certaines tâches sont difficiles à comprendre comment décomposer et quand. Nous décomposons la plupart des tâches au stade de la réception de l'épopée, mais il y a des situations où cela doit être fait, par exemple au stade de l'analyse. Nous prenons la tâche de travailler et pensons que toutes les données nécessaires sont déjà dans nos systèmes d'intégration, mais au cours de l'analyse, il s'avère que soit nous ne sommes pas satisfaits du format des données, soit le problème réside dans la qualité des données elles-mêmes, soit une amélioration est requise de la part d'autres systèmes avec lesquels nous sommes connectés. Ensuite, nous devons faire la tâche "sur les stubs" et ajouter un autre élément au backlog, que nous commencerons après avoir résolu les principaux problèmes.
Voilà, semble-t-il, tout. Ce sera formidable si vous partagez des histoires sur l'approche de la décomposition des tâches que vous utilisez et pourquoi dans les commentaires.
Merci d'avoir lu!