Quand être développeur backend ne suffit plus : ce que j'ai appris en portant plusieurs casquettes
Sur un projet avec une petite équipe, mon rôle a progressivement dépassé le backend. Architecture, données, mobile, déploiement, métier et priorisation m'ont surtout appris qu'être autonome ne signifie pas tout savoir faire.
Quand j'ai commencé ce projet, mon rôle était avant tout celui d'un développeur.
Je devais reprendre une application existante, travailler sur le backend et participer à sa refonte.
Progressivement, pourtant, mon travail a largement dépassé l'écriture de code. J'ai dû concevoir une nouvelle base de données, développer un portail web, participer aux choix d'architecture, travailler avec une application Flutter, préparer le déploiement, rédiger de la documentation, échanger avec l'administration système, organiser mon travail, estimer des délais et présenter régulièrement l'avancement au métier.
Je ne suis pas devenu soudainement expert dans tous ces domaines.
C'est même probablement l'apprentissage principal que je retiens de cette expérience :
Être autonome sur un projet ne signifie pas tout savoir faire. Cela signifie savoir avancer, prendre certaines décisions, chercher l'information et reconnaître quand il faut s'appuyer sur les compétences des autres.
Dans une petite équipe, les frontières entre les rôles deviennent rapidement moins nettes que les intitulés de poste.
Et j'ai découvert qu'à partir d'un certain niveau de responsabilité, savoir coder ne suffit plus.
Au départ, je pensais surtout comme un développeur
Quand on parle de développement backend, on pense naturellement à des tâches comme :
- concevoir des modèles ;
- écrire des requêtes ;
- développer des API ;
- implémenter des règles métier ;
- corriger des bugs ;
- tester ;
- optimiser.
C'était aussi ma manière de voir mon rôle.
Mais lorsque l'on reprend un projet qui possède déjà beaucoup de retard et que l'équipe est réduite, d'autres questions apparaissent très vite.
Quelle fonctionnalité doit être développée en premier ?
Quel délai peut-on raisonnablement annoncer ?
Quelle architecture est suffisamment bonne pour avancer ?
Que faut-il montrer au métier maintenant ?
Qu'est-ce qui doit être documenté ?
Qu'est-ce qui peut attendre ?
Aucune de ces questions ne se résout uniquement avec du code.
C'est à partir de là que mon rôle a commencé à changer.
Première responsabilité : remettre les données au centre
La conception de la base de données a toujours occupé une place importante dans ma manière de développer.
Sur ce projet, il fallait notamment reprendre une structure existante dont certaines relations rendaient les données difficiles à comprendre. Avant même de réfléchir aux écrans, il fallait donc revenir à une question plus fondamentale :
À quoi doivent réellement ressembler les données ?
Cela implique de comprendre :
- les entités ;
- leurs relations ;
- les contraintes ;
- les règles d'unicité ;
- ce qui appartient réellement au métier ;
- ce qui provient uniquement de choix historiques de l'ancienne application.
Une décision prise à ce niveau se propage ensuite dans tout le système :
Base de données
↓
Backend
↓
API
↓
Application mobile
↓
Affichage
↓
Calculs métier
J'ai donc consacré beaucoup de temps à la modélisation.
Ce travail ressemble peu à l'image que l'on se fait parfois du développeur qui "produit des fonctionnalités". Pourtant, une mauvaise compréhension des données peut rendre toutes les fonctionnalités construites au-dessus plus complexes.
À l'inverse, un modèle compris par le métier et cohérent avec ses règles crée une base beaucoup plus saine pour la suite.
Deuxième responsabilité : traduire le métier en problème technique
Une autre évolution importante a été de travailler directement avec des utilisateurs qui ne sont pas développeurs.
Un utilisateur ne formule pas son besoin comme ceci :
Il nous faut une relation many-to-many
avec une contrainte d'unicité conditionnelle.
Il dira plutôt :
Je veux retrouver cette information ici.
Ou :
Aujourd'hui, je ne sais pas si ma donnée a correctement été enregistrée.
Ou encore :
Cette étape prend trop de temps.
Le travail du développeur consiste alors à comprendre ce qui se cache derrière la demande.
Parfois, la première formulation correspond réellement au problème.
Parfois non.
J'ai progressivement pris l'habitude de poser davantage de questions, mais aussi de montrer quelque chose de concret lorsque les discussions devenaient trop abstraites.
Une démonstration, un export ou un premier écran peut parfois faire avancer la compréhension plus vite qu'une longue réunion.
Cela m'a appris une chose importante :
Le développeur ne doit pas seulement comprendre ce que demande le métier. Il peut aussi l'aider à visualiser ce qui est possible afin de préciser le besoin.
Cette relation fonctionne dans les deux sens.
Le métier explique son problème.
Le développeur traduit les conséquences techniques.
Puis les deux peuvent prendre une meilleure décision.
Proposer une solution ne signifie pas décider à la place du métier
Certaines demandes peuvent être satisfaites de plusieurs manières.
Le métier ne mesure pas forcément les conséquences techniques de chaque option, et ce n'est pas son rôle.
Le mien a progressivement consisté à transformer le besoin en choix compréhensibles :
Besoin métier
↓
Compréhension du problème
↓
Solutions possibles
↓
Conséquences de chaque solution
↓
Décision
↓
Implémentation
Dans certaines situations, les utilisateurs me laissaient choisir l'approche technique après avoir exprimé leur besoin.
C'est une responsabilité que j'ai appréciée, notamment parce qu'elle oblige à arrêter de réfléchir uniquement en termes de technologies.
La question n'est plus :
Comment faire cela avec Django ?
Elle devient :
Quelle solution répond correctement au problème avec les contraintes que nous avons ?
La différence semble petite.
Elle change pourtant profondément la manière de concevoir.
Troisième responsabilité : choisir une architecture que nous pouvions réellement assumer
Le projet partait d'une architecture différente de celle qui a finalement été retenue.
La refonte s'est progressivement organisée autour d'un portail web Django, d'un backend Django et d'une application mobile Flutter.
Django représentait aussi une évolution pour moi. Je connaissais déjà Python, j'avais utilisé Pandas et Jupyter pendant mes études et travaillé professionnellement avec Python, mais je n'avais pas encore la même expérience avec Django.
Cela aurait pu être une raison pour choisir uniquement une technologie que je connaissais déjà davantage.
Mais la maîtrise immédiate d'une technologie n'est qu'un critère parmi d'autres.
L'écosystème Python correspondait bien à plusieurs besoins du projet et à des compétences que je possédais déjà. J'ai donc appris Django tout en développant réellement avec Django.
Cette expérience m'a appris à regarder une décision technique autrement :
Choisir une technologie ne consiste pas nécessairement à prendre celle que l'on maîtrise le mieux aujourd'hui. Il faut surtout choisir une solution adaptée au projet et être capable d'assumer ensuite le coût de son apprentissage et de sa maintenance.
Cela suppose de lire la documentation, d'expérimenter, de faire des erreurs et parfois de demander de l'aide.
Autrement dit, le niveau de connaissance actuel compte.
Mais la capacité à monter en compétence compte aussi.
Quatrième responsabilité : sortir de mon périmètre backend
À l'origine, je n'avais pas vocation à prendre en charge toute la partie Flutter.
Une autre personne travaillait principalement dessus et m'a beaucoup apporté sur le maquettage et l'aspect visuel, qui ne sont pas mes points forts.
Cette précision est importante.
Porter davantage de responsabilités sur un projet ne signifie pas :
J'ai tout fait tout seul.
Certains résultats existent précisément parce que plusieurs compétences se complètent.
Les circonstances du projet m'ont néanmoins amené progressivement à intervenir davantage sur l'application mobile.
Il a alors fallu comprendre :
- son organisation ;
- les appels API ;
- la persistance locale ;
- la synchronisation ;
- les interactions avec le backend.
Je quittais régulièrement mon domaine de confort.
Dans ces situations, la compétence la plus utile n'était pas de connaître immédiatement toutes les réponses.
Elle était plutôt de savoir répondre à cette question :
Comment puis-je obtenir une réponse suffisamment fiable pour continuer sans prendre une décision au hasard ?
C'est une forme de compétence technique différente de la simple connaissance d'un framework.
Documentation, expérimentation et IA : apprendre suffisamment pour décider
Lorsqu'on intervient dans un domaine que l'on maîtrise moins, plusieurs ressources deviennent importantes.
On peut :
- lire la documentation officielle ;
- étudier le code existant ;
- faire une petite expérimentation ;
- chercher un exemple ;
- demander à un collègue ;
- utiliser une IA pour accélérer une recherche ou explorer plusieurs pistes.
J'ai utilisé ces différents moyens selon les situations.
Je ne vois pas cela comme l'opposé de l'autonomie.
Au contraire.
L'autonomie ne consiste pas à connaître toutes les commandes Linux, toutes les particularités de Flutter et toutes les classes de Django de mémoire.
Elle consiste plutôt à savoir passer de :
Je ne sais pas encore.
à :
Je comprends suffisamment
pour prendre une décision,
tester une hypothèse
ou identifier la personne
avec qui je dois la valider.
L'IA peut accélérer ce chemin.
Elle peut expliquer un concept, aider à lire une erreur ou proposer plusieurs solutions.
Mais elle ne connaît pas automatiquement les contraintes exactes du projet.
Une réponse techniquement correcte peut être mauvaise dans notre contexte.
L'outil accélère donc la recherche.
Il ne supprime pas la nécessité de comprendre ce que l'on décide.
Cinquième responsabilité : découvrir que le déploiement est aussi un compromis
Le déploiement m'a particulièrement appris cette leçon.
Pour faire fonctionner l'application Django sur un serveur Linux, j'ai notamment dû travailler avec Gunicorn et systemd, puis rédiger la documentation permettant d'installer et d'exploiter l'application.
J'avais certaines idées sur la manière dont l'environnement Python devait être isolé.
L'administrateur système avait ses propres contraintes et une manière différente de gérer son infrastructure.
Nous n'étions pas forcément d'accord sur tous les choix.
Et ce désaccord était normal.
Le développeur peut regarder le problème depuis l'application :
Comment m'assurer que mon application
dispose exactement des dépendances
dont elle a besoin ?
L'administrateur système possède un autre périmètre :
Comment garder les serveurs
cohérents, maintenables
et exploitables ?
Les deux objectifs sont légitimes.
Ils peuvent néanmoins entrer en tension.
J'ai dû adapter certains choix, notamment autour des versions de Python et des dépendances compatibles avec l'environnement cible.
Cette expérience m'a rappelé qu'une architecture ne vit pas uniquement dans un diagramme.
Elle doit aussi fonctionner avec :
- l'infrastructure réellement disponible ;
- les règles d'exploitation ;
- les personnes qui administrent les serveurs ;
- les contraintes de maintenance.
Une solution techniquement élégante mais impossible à exploiter correctement n'est pas forcément une bonne solution.
Sixième responsabilité : documenter pour rendre le projet transmissible
Quand on développe soi-même une application, beaucoup de choses paraissent évidentes.
On sait pourquoi cette commande existe.
On sait dans quel ordre démarrer les composants.
On connaît les variables nécessaires.
On sait quelles étapes sont importantes et lesquelles relèvent simplement de l'habitude.
Puis il faut transmettre cette connaissance à quelqu'un d'autre.
Et tout à coup, ce qui semblait évident ne l'est plus.
Écrire la documentation d'installation m'a obligé à transformer une connaissance implicite en procédure explicite.
Par exemple :
Installation
↓
Configuration
↓
Base de données
↓
Dépendances
↓
Gunicorn
↓
systemd
↓
Démarrage
↓
Vérification
Cette documentation n'était pas un supplément à écrire "si j'avais le temps".
Elle faisait partie du fait de pouvoir réellement livrer et transmettre le projet.
Un logiciel que seule la personne qui l'a développé sait démarrer possède encore un problème.
La responsabilité qui m'a le plus fait progresser n'était pas technique
Si je devais choisir la responsabilité qui m'a le plus fait progresser, je ne citerais probablement ni Django, ni Flutter, ni Linux.
Je choisirais :
organiser et prioriser le projet.
Parce que lorsque les ressources sont limitées, chaque décision devient aussi une décision de temps.
Je pouvais avoir :
10 choses réellement utiles à faire
avec la capacité d'en terminer seulement :
2 ou 3 correctement
Il fallait donc choisir.
Et ce choix ne pouvait pas reposer uniquement sur l'intérêt technique d'une tâche.
Une fonctionnalité importante n'est pas forcément prioritaire
C'est probablement l'une des différences les plus importantes entre développer une fonctionnalité et participer davantage à la conduite d'un projet.
En tant que développeur, on peut naturellement penser :
Cette fonctionnalité est importante, donc il faut la faire.
Mais plusieurs fonctionnalités peuvent être importantes au même moment.
La question devient alors :
Laquelle produit le plus de valeur maintenant ?
Cela oblige à regarder d'autres critères.
Laquelle débloque les suivantes ?
Laquelle réduit un risque important ?
Laquelle peut être montrée rapidement au métier ?
Laquelle permet de vérifier que nous allons dans la bonne direction ?
Laquelle peut attendre sans réellement mettre le projet en danger ?
La priorisation m'a aussi appris à accepter quelque chose qui paraît simple mais ne l'est pas toujours :
Reporter une bonne idée ne signifie pas l'abandonner.
Parfois, son problème principal est simplement qu'une autre chose est plus importante aujourd'hui.
Sur un projet en retard, rendre la valeur visible peut devenir une priorité
Cette question était particulièrement importante dans notre contexte.
Le projet avait accumulé beaucoup de retard.
Il ne suffisait donc pas de construire correctement la nouvelle application. Il fallait aussi montrer progressivement que quelque chose avançait réellement.
Le portail web est devenu une priorité parce qu'il permettait d'obtenir plus rapidement un résultat visible.
Une des premières fonctionnalités utiles a été un export des données au format CSV.
Techniquement, ce n'était pas la fonctionnalité la plus spectaculaire du projet.
Mais elle répondait à un problème beaucoup plus important : permettre au métier de voir les données sous une forme familière et vérifier qu'elles correspondaient enfin à sa compréhension.
Cela a déclenché des remarques, des demandes de colonnes supplémentaires et des discussions plus précises sur le fonctionnement attendu.
Autrement dit, cette fonctionnalité ne produisait pas seulement un fichier.
Elle réduisait une barrière entre le système technique et les personnes qui devaient l'utiliser.
Elle permettait aussi de valider progressivement les choix de données avant d'aller plus loin.
Cette expérience a changé ma manière de définir un MVP.
Un MVP n'est pas forcément la version contenant mécaniquement le moins de fonctionnalités.
C'est parfois la plus petite version capable de réduire l'incertitude la plus importante du projet.
Dans notre cas, une partie de cette incertitude concernait la compréhension et la confiance autour des données.
Il faut parfois accepter une solution temporairement imparfaite
La priorisation a également changé ma manière de regarder le clean code et le refactoring.
Il m'est arrivé de savoir qu'une partie du code pouvait être mieux structurée.
Certaines vues pouvaient par exemple déléguer davantage de logique à d'autres composants.
Mais il existe une différence importante entre :
Ce code crée un risque important
et doit être corrigé maintenant.
et :
Ce code reste compréhensible
et maintenable,
mais pourrait être amélioré.
Lorsque le projet possède déjà beaucoup de retard, consacrer immédiatement plusieurs jours à une amélioration invisible peut parfois apporter moins de valeur que terminer une fonctionnalité permettant au métier de travailler ou de reprendre confiance dans le projet.
Cela ne veut pas dire abandonner la qualité.
Cela signifie décider consciemment :
Quel niveau de qualité est nécessaire maintenant, et quelle amélioration peut raisonnablement attendre ?
Le mot important est "consciemment".
Une amélioration reportée parce que son bénéfice est faible aujourd'hui n'est pas la même chose qu'un problème ignoré parce que personne ne veut le regarder.
Estimer quand on est aussi celui qui développe
J'ai également dû apprendre à estimer mon propre travail.
C'est un exercice moins simple qu'il n'y paraît.
Une fonctionnalité peut sembler représenter trois jours de développement lorsqu'on regarde uniquement son implémentation.
Mais le projet comporte aussi :
- les imprévus ;
- les autres demandes ;
- les dépendances ;
- les réunions ;
- les bugs ;
- l'apprentissage d'une technologie ;
- les changements métier ;
- les validations nécessaires.
Une estimation n'est donc pas :
nombre de lignes
×
temps moyen par ligne
Elle contient une part d'incertitude.
J'ai progressivement appris à distinguer :
temps nécessaire
si tout se déroule parfaitement
de :
délai raisonnable
que je peux réellement annoncer
L'estimation n'est pas une promesse mathématique.
C'est une manière d'exprimer ce que l'on sait du travail et le niveau de risque qui l'entoure.
Les démonstrations sont devenues un outil de développement
J'ai également pris l'habitude de présenter régulièrement l'avancement au métier.
Au départ, une démonstration peut sembler être seulement un exercice de communication :
Voici ce qui a été développé.
Mais elle peut devenir une partie du processus de conception.
Le métier peut répondre :
Oui, c'est exactement cela.
Mais il peut aussi répondre :
Ce n'est pas tout à fait ce que j'imaginais.
Et cette deuxième réponse est souvent extrêmement utile.
Le cycle devient alors :
Développer une partie
↓
Montrer
↓
Obtenir du feedback
↓
Corriger la direction
↓
Continuer
Une erreur découverte après quelques jours peut coûter peu.
La même erreur découverte après plusieurs mois de développement peut obliger à reprendre une partie importante du système.
La démonstration n'est donc pas seulement une manière de montrer ce qui est terminé.
Elle permet aussi de vérifier régulièrement que ce qui est en train d'être construit mérite réellement de continuer dans cette direction.
Faire plusieurs métiers ou simplement devenir plus autonome ?
Avec le recul, je pourrais dresser une longue liste :
- conception de base de données ;
- backend ;
- web ;
- mobile ;
- architecture ;
- déploiement ;
- documentation ;
- coordination ;
- relation avec le métier ;
- estimation.
Mais je ne pense pas que la bonne conclusion soit :
J'ai exercé dix métiers différents.
Ce serait exagéré.
Je préfère dire :
J'ai été développeur dans un contexte où le périmètre de responsabilité était large.
Je n'étais pas administrateur système.
J'ai travaillé avec un administrateur système.
Je n'étais pas designer.
Une autre personne m'a beaucoup aidé sur le maquettage.
Je n'avais pas nécessairement le titre de chef de projet.
Mais j'ai dû prendre une part importante dans l'organisation, la priorisation et certaines décisions du projet.
Cette distinction me semble essentielle parce qu'elle permet de parler d'autonomie sans effacer le rôle des autres compétences.
L'autonomie n'est pas l'absence de dépendance
Avant cette expérience, j'aurais peut-être associé l'autonomie à la capacité de tout faire soi-même.
Aujourd'hui, je la définirais autrement.
Être autonome consiste notamment à savoir distinguer :
Ce que je peux décider seul
Ce que je dois rechercher
Ce que je dois valider avec le métier
Ce que je dois discuter avec un spécialiste
Ce que je ne comprends pas encore assez
pour décider
et :
Ce qui doit simplement attendre
Cette dernière catégorie est probablement l'une des plus importantes.
Un projet possède presque toujours davantage d'idées que de temps.
Savoir avancer ne signifie donc pas uniquement savoir faire.
Cela signifie aussi savoir ne pas faire maintenant.
Ce que plusieurs casquettes ont réellement changé dans ma manière de développer
Je reste avant tout développeur backend.
C'est là que se trouve une grande partie de mon intérêt technique.
Mais cette expérience m'a montré que progresser dans ce métier ne signifie pas seulement apprendre davantage de frameworks ou de technologies.
À un certain moment, la progression consiste aussi à mieux comprendre :
- pourquoi on développe ;
- pour qui ;
- dans quel ordre ;
- avec quelles contraintes ;
- avec quels risques ;
- avec quelles personnes ;
- et avec quel temps disponible.
Le code reste essentiel.
Mais lorsqu'on commence à porter davantage la responsabilité d'un projet, une autre compétence devient centrale :
prendre une quantité limitée de temps et décider où elle produit le plus de valeur.
C'est probablement la casquette qui m'a le plus fait progresser.
Pas parce qu'elle m'a appris à tout faire.
Mais parce qu'elle m'a obligé à apprendre quelque chose de plus difficile :
choisir ce qu'il fallait faire maintenant, ce que je pouvais apprendre, ce que je devais déléguer ou valider, et ce qui pouvait attendre.