Le projet Lingualeo a déjà 10 ans. Plus de 23 millions de personnes de Russie, de Turquie, d'Espagne et d'Amérique latine apprennent l'anglais grâce à notre service.
LinguaLeo a été créé à la fin des années 2000 et au début des années 10 et a utilisé les technologies et les méthodes les plus avancées à l'époque. Mais le temps a passé et ils sont devenus très dépassés. Nous avons donc décidé qu'il était temps de mettre à jour le système.
Nous avons demandé à notre responsable du développement backend, Oleg Pravdin, de nous expliquer comment lui et son équipe, parallèlement à la prise en charge du produit principal, ont assemblé une nouvelle structure de service modulaire basée sur PostgreSQL, transféré la logique métier vers des bases de données et migré avec des millions d'utilisateurs.
Problèmes de produits matures
«Je suis venu chez Lingualeo en août 2018 pour diriger le développement du backend. À l'époque, le support était assuré par une équipe de 8 développeurs et 2 administrateurs, qui maintenaient un monolithe de 1 million de lignes de code, principalement en PHP. Il a fallu 2 mois pour implémenter même une petite nouvelle fonctionnalité. Et les coûts d'infrastructure pour 10 000 utilisateurs actifs dépassaient 1 000 dollars par an.
Comment est-ce arrivé? Le fait est que plusieurs équipes de développement ont évolué dans le projet en 10 ans. De nouvelles personnes sont venues, comme moi, elles ont ajouté de nouveaux modules et fonctionnalités à leur manière. Les équipes ont changé, les nouveaux venus n'ont pas toujours compris comment fonctionnent les anciennes parties du système, du coup, le code Lingualeo s'est progressivement transformé en une boîte noire: logique opaque dans le backend, un front surchargé, une abondance de béquilles, de grandes lacunes dans la documentation.
Au total, nous avions 20 développeurs dans notre équipe, mais il était impossible de développer le produit: si quelque chose était ajouté, des problèmes inattendus surgissaient. Il a fallu à l'équipe 2-3 semaines pour tout réparer. Les développeurs maintenaient le code à partir de 2013 et il n'y avait aucune ressource pour mettre à jour la fonctionnalité.
Ce sont les défis auxquels sont confrontées un grand nombre d'entreprises qui développent des produits informatiques matures écrits dans des technologies d'il y a dix ans. Les tendances changent, mais en raison de l'ancienne architecture, tous les nouveaux éléments ne peuvent pas être utilisés.
Le produit se développe et devient envahi par les fonctions, mais ils n'ont pas le temps de les documenter en détail. Ces problèmes sont résolus de différentes manières, mais nous avons décidé de cette façon: vous devez créer un nouveau système à partir de zéro et conserver la logique produit maximale afin que l'expérience utilisateur dans Lingualeo ne change pas.
Étape 1. Assemblage d'un prototype de la nouvelle architecture
Nous avons dû trouver comment mettre à jour le composant technique du service et reconstruire Lingualeo en utilisant des technologies modernes. J'ai suggéré à la direction de changer complètement la philosophie du backend: transférer la logique métier vers la base de données, et remplacer la base de données MySQL par PostgreSQL.
J'ai commencé avec un prototype sur papier: j'ai dessiné une nouvelle architecture, expliqué comment je pourrais augmenter les performances et combien de ressources il faudrait pour la préparer. Il était difficile de protéger le projet, car il n'y avait pas d'histoires de réussite sans ambiguïté à portée de main: personne n'écrit sur la façon de migrer un service avec 20 millions d'utilisateurs sans arrêter l'entreprise. Mais Lingualeo a décidé de prendre le risque et a approuvé le plan de changement.
Diagramme d'architecture de pré-migration
PHP, , MySQL . JSON
SQL PostgreSQL, JSON. -, , JSON
2.
Lorsque nous avons partagé nos plans avec les développeurs, il est devenu clair que l'équipe n'était pas prête pour les changements. La plupart des gens ont quitté l'entreprise: seuls ceux qui sont venus récemment sont restés. Pour effectuer la migration, nous avons décidé de réassembler l'équipe de développement.
Nous recherchions des candidats ambitieux et prêts pour les changements, professionnels et responsables. Nous avons essayé de prêter attention non seulement à la qualité du code, mais aussi aux compétences générales. Nous reconstruisions l'architecture du service, nous avions donc besoin de personnes qui n'auraient pas peur des projets complexes et seraient prêtes à résoudre des problèmes auxquels elles n'avaient pas été confrontées auparavant.
Certaines personnes ont été trouvées par hasard, comme moi, par exemple: j'ai rencontré le PDG de Lingualeo Vladimir Sirotinsky dans l'avion. Vladimir a rencontré le futur leader du front-end lors d'une consultation avec une autre startup. Mais nous avons recruté la plupart des nouveaux développeurs du marché. Afin de pourvoir 8 postes vacants, nous avons étudié 1 118 candidatures et réalisé 124 entretiens: Un
entonnoir de candidats pour de nouveaux postes de développeur chez Lingualeo.
Étape 3. Simplification de la structure organisationnelle
Nous avons trois domaines de développement: web, backend et applications mobiles, nous avons également un département de testeurs. Trouver quelqu'un qui comprend toutes les industries à la fois est très difficile en peu de temps. Par conséquent, nous avons décidé d'abandonner le directeur technique et de rendre la structure organisationnelle de la nouvelle équipe aussi plate que possible. Il ne reste qu'un seul niveau de gestion dans l'entreprise - un leader dans chaque direction.
Nous tenons des réunions régulières et communiquons directement, donc le développement est devenu plus prévisible, le délai a été réduit. Le CTO peut prendre des décisions irrationnelles, comme une mauvaise répartition des responsabilités entre les équipes. Dans un système où les prospects communiquent sans une couche supplémentaire de gestionnaires, la probabilité de décisions irrationnelles est réduite: nous pouvons toujours discuter de n'importe quel problème dans une conversation personnelle.
Par exemple, si je comprends qu'il serait plus logique d'implémenter une fonction dans la nouvelle structure de la base de données, et non au début, j'écris dans le chat et discute de l'idée avec le leader du front-end. Pas besoin de prendre rendez-vous avec le CTO ou de préparer une présentation pour étayer votre idée.
Structure organisationnelle avant et après les changements: nous avons abandonné le CTO en développement et simplifié la structure du département produit. De nos jours, un concepteur de produit n'a pas besoin de communiquer avec deux niveaux de managers pour faire passer une idée au premier plan.
Étape 4. Transfert de la logique métier vers les bases de données
Auparavant, la logique métier de Lingualeo était au premier plan et dans les applications. Les fonctions du produit étaient gérées par des systèmes qui n'étaient pas conçus pour traiter des données, comme le code JavaScript ou PHP. Par conséquent, nous avons porté la logique métier Lingualeo sur les bases de données PostgreSQL.
Jungle
L'une des 4 sections principales du service Lingualeo est Jungle . Il s'agit d'un ensemble de documents dans une langue étrangère - textes, audio et vidéo - dans lesquels vous pouvez reconnaître la traduction de n'importe quel mot. Autrement dit, les utilisateurs étudient le contenu réel en anglais, et si quelque chose n'est pas clair, ils peuvent cliquer sur un mot dans le texte ou dans les sous-titres d'une vidéo et voir la traduction.
Texte dans la
vidéo de la jungle dans la jungle
Pour que la fonction de traduction de mots sur un clic fonctionne, le texte doit être divisé en mots, expressions et phrases. Ensuite - reportez-vous au dictionnaire et affichez la traduction dans une nouvelle fenêtre sur le texte à l'utilisateur. Il est assez difficile de diviser le texte pour la traduction: il y a des expressions fixes et des verbes à particule qu'il n'y a aucun sens à diviser en deux mots. Par exemple, décoller et prendre sont des unités de contenu différentes, bien qu'elles incluent le même mot.
Toute la logique de cette fonction, ainsi que les exceptions et les règles de division de texte complexes, était auparavant écrite en JavaScript au recto. La fonction était très lourde et la traduction pouvait prendre beaucoup de temps.
Nous avons implémenté cette fonctionnalité dans la base de données. Le support envoie un JSON prêt à l'emploi à l'avant, dans lequel le texte est déjà divisé en mots et expressions. Chaque mot et expression de la base de données se voit attribuer un identifiant, ce qui facilite la recherche d'une traduction. JSON prend également en compte les mots que l'utilisateur a dans le dictionnaire et ceux qui ne le sont pas encore. A l'avant, il ne reste plus qu'à afficher des informations et mettre en évidence des mots avec certains signes.
Dictionnaires
Nous avons fait de même avec la section Dictionnaires : tout le travail se déroule désormais dans la base de données. Nous avons des utilisateurs qui ont plus de 100 000 mots et expressions dans leur dictionnaire. Dans le dictionnaire, vous devez fournir une recherche pratique, diviser les mots en groupes et donner à l'utilisateur un large éventail de filtres.
Auparavant, la logique des dictionnaires était sur la face avant ou dans la couche PHP, mais maintenant le système dispose d'une API à part entière entre le front et le backend. Vous pouvez envoyer une requête avec un grand nombre de paramètres à la base de données, et un JSON prêt à l'emploi en viendra:
Filtres du dictionnaire: recherche par mots, choix des mots par type de formation, choix entre mots et phrases, filtre par mots appris et nouveaux
Cours
Le transfert de la logique métier vers la base de données a considérablement réduit la quantité de code et accéléré le service. Par exemple, le code backend de la page Cours a changé après la migration. Il est vu par les utilisateurs enregistrés, et les cours y sont sélectionnés par le système selon dix critères. Auparavant, une telle page était formée pendant 600 ms et envoyait 12 requêtes à la base de données, maintenant il n'y en a qu'une:
Étape 5. Tenez compte des commentaires des utilisateurs après la publication
Le développement a duré environ six mois: nous avons commencé la mise à jour fin 2018 et la publication a eu lieu en mai 2019. La plupart des utilisateurs ont estimé que le service commençait à fonctionner beaucoup plus rapidement. Auparavant, Lingualeo ne pouvait pas former plus de 2 000 personnes simultanément sans perdre de vitesse, mais le système peut désormais supporter des pics de plus de 100 000 utilisateurs.
Certaines personnes ont également remarqué des conséquences négatives. En migrant avec une boîte noire, il est difficile d'assurer la sécurité de cent pour cent des données, donc certains ont perdu des mots du dictionnaire, certains ont mal affiché la progression dans les cours.
Petit à petit, mon équipe et moi avons résolu tous les problèmes. Le principal résultat des changements est que nous ne travaillons pas maintenant avec une boîte noire, mais avec un système simple et transparent, il était donc beaucoup plus facile de travailler sur les retours.
Lingualeo
En avril 2020, lors de l'auto-isolement, la charge sur Lingualeo était cinq fois supérieure à la même période il y a un an. Cela n'a pas posé de problèmes: la vitesse du service n'a pas baissé, les utilisateurs n'ont rien remarqué. Je suis sûr que si nous n'avions pas mis à jour le système, le service aurait tout simplement échoué.
Le produit est devenu non seulement plus rapide pour les utilisateurs, mais aussi beaucoup plus facile à utiliser: il est désormais plus facile pour l'équipe d'introduire et de tester de nouvelles fonctionnalités. Nous avons rangé la documentation et le code est devenu environ 40 fois plus petit, afin que les nouveaux développeurs puissent facilement comprendre comment le service fonctionne.
Le produit est devenu moins cher, il faut donc louer moins de puissance de calcul. Le coût par utilisateur actif dans Lingualeo a diminué de plus de 50 fois, bien que le nombre d'utilisateurs actifs ait déjà doublé après les mises à jour.
Enfin, le produit est plus sûr. Auparavant, lorsque toute la logique métier était dans la couche PHP, les requêtes à la base de données étaient envoyées à partir de différentes fonctions. Une base de données ouverte aux requêtes SQL est un problème: vous pouvez faire une injection SQL et la forcer à exécuter du code dangereux, comme la suppression de données. Désormais, aucune requête SQL ne vient de l'extérieur, car nous avons déplacé toute la logique à l'intérieur. "
Nous voulons continuer à bloguer régulièrement sur le fonctionnement du développement dans la mise à jour de Lingualeo. Écrivez dans les commentaires ce dont il vaut la peine de parler en premier: notre équipe a changé, ainsi que la structure de gestion et la technologie. Nous serons heureux de répondre à toutes vos questions.