paint-brush
Mon parcours de 4 ans pour créer un réseau social en tant que développeur solopar@mariostopfer
655 lectures
655 lectures

Mon parcours de 4 ans pour créer un réseau social en tant que développeur solo

par Mario Stopfer2022/10/18
Read on Terminal Reader
Read this story w/o Javascript

Trop long; Pour lire

Vise à donner aux créateurs de contenu la possibilité de s'engager avec leur communauté et de les faire contribuer au processus de création de contenu, tout en étant en mesure de monétiser leurs efforts, le tout en un seul endroit. L'idée de créer une plate-forme de médias sociaux est venue du désir non seulement de créer du contenu en tant qu'individus, mais aussi de s'engager avec la communauté. La plate-forme elle-même, si elle voulait être accessible au plus grand nombre de personnes possible, devrait être un site Web et avec presque aucune expérience en développement Web, rien de tout cela ne semblait réalisable. Dire que cela n'allait pas être facile serait un euphémisme du siècle.
featured image - Mon parcours de 4 ans pour créer un réseau social en tant que développeur solo
Mario Stopfer HackerNoon profile picture
0-item


Ceci est une histoire, un exposé complet, de mon projet de développement solo, Immersive Communities - une plate-forme de médias sociaux pour les créateurs de contenu, que j'ai repris début 2018 et terminé en 2022.


J'espère qu'il servira de guide à quiconque démarre un grand projet ou est en train d'en construire un et a besoin de motivation pour continuer.

L'idée

Au début de 2018, des voix faibles ont commencé à émerger. Les gens ont commencé à exprimer leur opinion sur l'état du Web et des médias sociaux en général.


Certaines personnes n'étaient pas satisfaites de Facebook et de ses politiques sur la confidentialité des utilisateurs, d'autres se plaignaient de YouTube et de ses pratiques de monétisation, tandis que d'autres tournaient leur opinion contre les plates-formes mêmes où elles exprimaient leur opinion comme Medium.com.


Mais à quoi ressemblerait l'alternative à tout cela ?

Le projet Solo-Dev - L'histoire en devenir

L'idée de créer une plate-forme de médias sociaux est née du désir de donner aux créateurs de contenu la possibilité, non seulement de créer du contenu en tant qu'individus, mais aussi de s'engager avec leur communauté et de les faire contribuer au processus de création de contenu tout en étant en mesure de monétiser leurs efforts. ; tout en un seul endroit.


La plate-forme doit être libre d'utilisation et tout le monde doit pouvoir s'y joindre. Il va sans dire que les créateurs, qui investissent du temps dans leur travail, qui éduque et divertit les gens du monde entier, doivent aussi pouvoir vivre de ce qu'ils aiment faire.


Est-ce que cela résoudrait tous les problèmes auxquels nous sommes confrontés aujourd'hui en ligne ? Non, mais c'est une alternative, et c'est ce qui compte. C'est une graine, qui peut avec le temps, se transformer en quelque chose de beau.


En tant que technologue, je me demandais aussi si tout cela pouvait être fait par une seule personne.


Serait-il réellement possible pour une seule personne de relever le défi et de fournir une plate-forme robuste au niveau de l'entreprise que les gens aimeraient utiliser, et si oui, que faudrait-il pour fournir un tel système ?


Pour être tout à fait honnête, je n'avais pas de réponse à ces questions, mais j'ai décidé de relever le défi.


Au début de 2018, j'avais environ 6 ans d'expérience professionnelle en tant que développeur de logiciels, principalement du back-end .NET et un peu de WPF sur le front-end.


J'ai également vécu à Tokyo, où j'ai déménagé il y a moins de 3 ans, et les heures supplémentaires étaient la norme ; l'idée de prendre du travail supplémentaire, à toutes fins pratiques, était pour le moins déraisonnable.


La plate-forme elle-même, si elle voulait être disponible pour le plus grand nombre de personnes, devrait être un site Web et avec presque aucune expérience en développement Web, rien de tout cela ne semblait réalisable.


Le fait que cela semblait impossible était exactement la raison pour laquelle j'ai décidé de commencer le plus tôt possible. Tout cela serait-il une énorme perte de temps ? Seul le temps nous le dira, mais plus tôt je commencerais, plus tôt je trouverais la réponse.


Puis, le 1er février 2018 , j'ai commencé à planifier.

2018 — Le régime

La première chose que j'ai décidé de faire a été de me dire que penser que cela n'allait pas être facile, serait l'euphémisme du siècle. Je n'avais jamais rien fait de tel auparavant, donc je n'avais littéralement aucune idée de ce dans quoi je m'embarquais.


Cela signifiait pas de passe-temps ou quoi que ce soit qui ressemble à une vie jusqu'à ce que cette chose soit terminée. Faire des heures supplémentaires à mon travail à temps plein, puis rentrer à la maison et travailler sur ce projet, va devenir la nouvelle norme.


Est-ce que je prendrais des vacances et voyagerais à un moment donné ? Oui, mais je devrais aussi passer ces vacances à travailler surtout.


Si j'ai appris quelque chose de mon expérience précédente, c'est qu'être organisé est ce qui fait ou défait votre projet et vous maintient sur la bonne voie. Plus vous préparez et concevez à l'avance, moins vous aurez à faire de travail d'essais et d'erreurs par la suite.


Réfléchir et planifier sont certainement plus faciles que de construire et prennent moins de temps, donc plus j'en fais dans la phase de planification, moins j'aurais à découvrir pendant la phase de développement proprement dite, qui nécessite plus de ressources en termes de temps.


Les ressources étaient quelque chose que je n'avais pas, j'ai donc dû compenser cela avec la planification et la conception. Je savais aussi que le Web était l'endroit où aller quand je serais bloqué, mais j'ai décidé de ne pas utiliser Stack Overflow pour ce projet et de poser de nouvelles questions.


Le raisonnement derrière cette décision était assez simple. Vu qu'il y aura beaucoup à apprendre ici, si j'allais juste demander à quelqu'un de résoudre tous mes problèmes, je n'acquérirais aucune expérience.


Plus le projet avancera, plus il deviendra difficile et je n'aurai pas acquis d'expérience pour l'aborder par moi-même.


Par conséquent, j'ai décidé de rechercher uniquement sur le Web des réponses déjà existantes, mais de ne pas poser de nouvelles questions afin de résoudre mes problèmes. Une fois le projet terminé, je pourrais m'engager à nouveau avec Stack Overflow, mais pour cet objectif de développement particulier, ce serait interdit.


J'utiliserais l'approche OOAD pour concevoir le système que je voulais construire. Le système me dirait comment chaque partie fonctionne et comment elle interagit avec les autres parties du système. De plus, j'extrayais des règles métier que j'implémenterais plus tard dans le code.


J'ai alors commencé à prendre des notes et j'ai réalisé qu'il y avait deux points principaux sur lesquels je devais me concentrer :


  • Conception de projet
  • Pile technologique


Comme je savais qu'il n'y avait que 24 heures dans une journée, et que je passerais la plupart de celles-ci au travail ou en voyage, je devais optimiser soigneusement mon temps.

Conception de projet

Pour la partie Project Design, afin de maximiser mon temps, j'ai décidé de regarder quels produits fonctionnaient déjà bien et de les utiliser comme source d'inspiration.


De toute évidence, le système doit être rapide et accessible à tous et comme je n'ai pas le temps d'écrire du code pour plusieurs plates-formes, le Web était la réponse.


Je me suis alors tourné vers le design. Apple étant bien connu pour ses pratiques de conception bien acceptées a été une source d'inspiration immédiate. Ensuite, je me suis tourné vers Pinterest et j'ai décidé que c'était la conception la plus simple possible qui fonctionnait bien. L'idée derrière ma décision était le vieil adage.


Le contenu est roi. - Bill Gates, 1996.


Cela m'a donné l'idée de supprimer autant de détails de conception inutiles que possible et de me concentrer sur la présentation du contenu. Si vous y réfléchissez, les gens viendront une fois sur votre site Web parce qu'il a un beau design, mais ils ne reviendront pas à moins que vous n'ayez un bon contenu.


Cela a eu pour effet de réduire le temps nécessaire à la conception du front-end.


Le système lui-même devait être simple. Chaque utilisateur doit pouvoir créer et posséder sa propre communauté. D'autres utilisateurs devraient pouvoir se joindre en tant que membres et écrire des articles pour contribuer au contenu de cette communauté. Cette fonctionnalité serait inspirée de Wikipédia, où de nombreux utilisateurs peuvent modifier le même article.


S'il y a beaucoup de gens qui s'engagent ensemble sur un certain sujet, cela nous indique que ce que nous avons sous la main est une communauté et, en tant que telle, devrait être séparée du reste.


En ce qui concerne les fonctionnalités, les utilisateurs devraient être en mesure d'écrire non seulement des articles réguliers et de les connecter comme le fait Wikipedia, mais aussi d'écrire des critiques, ce qui nécessiterait un type d'article différent.


Ainsi, les articles réguliers seraient appelés "Intérêts" et seraient de nature factuelle et informative, n'importe qui pouvant les modifier.


D'autre part, les "avis" seraient basés sur chaque intérêt, et seul l'auteur de l'avis pourrait le modifier.


En bref, les gens pourraient écrire en collaboration sur un film, disons "The Matrix", et éditer cet article quand ils le souhaitent. Ils pouvaient ajouter toute information factuelle à l'article qu'ils souhaitaient.


Ensuite, chaque utilisateur pourrait écrire sa propre critique de ce film. Naturellement, l'article original afficherait alors une liste de toutes les critiques écrites pour ce film.


Il était clair pour moi que je devais également ajouter deux fonctionnalités plus importantes. La première serait une option de recherche qui chercherait des articles dans chaque communauté. L'autre fonctionnalité était les recommandations, que les utilisateurs recevraient en fonction de ce qu'ils aimaient une fois qu'ils auraient défilé jusqu'à la fin de l'article.


Chaque utilisateur devrait également pouvoir publier de courtes mises à jour ou "Activités" sur son profil, ce qui agirait comme un mur sur Facebook. C'était le schéma de base que j'ai fait avant de commencer à penser aux technologies que je pourrais utiliser pour réaliser le projet.

La pile technologique

La deuxième chose sur laquelle je me suis concentré était la Tech Stack. Depuis que j'ai déjà décidé que j'allais construire un projet basé sur le Web, j'ai décidé d'écrire toutes les technologies populaires et modernes les plus couramment utilisées à cette époque. Je choisirais alors ceux qui étaient techniquement les plus proches de ce que j'utilisais déjà dans ma carrière afin de passer le moins de temps possible à apprendre de nouvelles technologies.


De plus, l'idée qui m'a le plus guidé durant cette phase était de prendre de telles décisions de conception qui me demanderaient d'écrire le moins de code possible, ce qui me ferait gagner du temps.



Après des recherches approfondies, j'ai opté pour la pile technologique principale suivante :



De plus, en choisissant les services SaaS, je gagnerais encore plus de temps car je n'aurais pas besoin d'implémenter ces fonctionnalités par moi-même. Les services que j'ai choisis étaient les suivants.



Ce sont les principales technologies que j'ai dû apprendre le plus rapidement possible pour même commencer à travailler sur le projet. Tout le reste devrait être appris en cours de route.


À ce stade, j'ai commencé à apprendre de nouvelles technologies. Pour les principaux et les plus importants, j'ai commencé à lire les livres suivants.



J'ai décidé de travailler sur mon travail à temps plein pendant la journée, mais les soirées étaient un jeu équitable. Quand je rentrais à la maison, je pouvais étudier jusqu'à ce que je m'endorme. En ce qui concerne le sommeil lui-même, je serais réduit à 6 heures pour gagner un peu plus de temps pour étudier.


J'avais initialement prévu qu'il ne me faudrait qu'un an pour construire ce projet. Puis, après presque un an d'apprentissage de nouvelles technologies, c'était en décembre 2018 et je venais de terminer le matériel de lecture principal, tout en ayant écrit exactement 0 lignes de code.

Le développement commence

En décembre 2018, j'ai enfin commencé à développer. J'ai configuré Visual Studio Code et commencé à créer mon environnement de développement.


Il était clair pour moi dès le premier jour que je ne serais pas en mesure de maintenir tous les serveurs nécessaires à un projet d'une telle envergure. Pas seulement d'un point de vue technique, mais aussi du point de vue budgétaire. J'ai donc dû trouver une solution.


Heureusement, j'ai trouvé la solution sous la forme de DevOps et de l'approche Serverless de l'infrastructure back-end.


Il m'est apparu immédiatement, avant même que ces approches ne se généralisent comme elles le sont aujourd'hui, que si nous pouvons décrire quelque chose de manière succincte avec du code, nous pouvons également l'automatiser, économisant ainsi du temps et des ressources.


Avec DevOps, j'unifierais et automatiserais le développement front-end et back-end, tandis qu'avec Serverless, je supprimerais le besoin de maintenance du serveur et réduirais également le coût de fonctionnement.


Cette philosophie allait clairement dans le sens de ma réflexion et la première chose que j'ai décidé de mettre en place a été un pipeline CI/CD avec Terraform.


La conception comprenait 3 branches, Développement, UAT et Production. Je travaillais chaque jour et une fois le travail terminé, je validais simplement les modifications apportées à la branche Development dans AWS CodeCommit et cela déclenchait AWS CodeBuild pour créer mon projet.


Je garderais un exécutable Terraform dans le référentiel, à la fois pour macOS, pour les tests locaux, et un exécutable basé sur Linux, pour les builds sur CodeBuild.


Une fois le processus de construction démarré, l'exécutable Terraform serait invoqué dans CodeBuild et il récupérerait les fichiers de code Terraform, construisant ainsi mon infrastructure sur AWS.


Toutes ces parties devraient alors être connectées et automatisées, ce que j'ai fait en utilisant AWS CodePipeline, qui déplacerait le code de CodeCommit vers CodeBuild chaque fois que je ferais un commit.


Cela m'aiderait à garder mon code et mon infrastructure synchronisés. Chaque fois que j'étais prêt à aller de l'avant, je fusionnais simplement la branche Développement avec UAT, ou l'UAT avec Production pour synchroniser mes autres environnements.

2019 — Succès COVID-19

Une fois que j'aurais terminé le pipeline CI/CD pour le back-end, je me tournerais vers la configuration du site Web réel localement afin de commencer à développer le front-end.


La première étape de la configuration du front-end consistait à créer un projet basé sur Aurelia. La décision d'utiliser Aurelia et non React, qui était et est toujours le choix le plus populaire pour un framework JavaScript, était due au modèle MVVM .


Le modèle MVVM est largement utilisé dans les applications de bureau WPF avec lesquelles j'ai eu de l'expérience. Ainsi, apprendre React aurait pris plus de temps que de simplement s'appuyer sur ce que je savais déjà.


D'un autre côté, la décision d'utiliser Aurelia et non Angular ou Vue était basée sur la philosophie derrière Aurelia qui est de faire en sorte que le framework vous échappe. En d'autres termes, il n'y a pas d'Aurelia dans Aurelia.


Ce que vous utilisez essentiellement, lors du développement avec Aurelia, c'est HTML, JavaScript et CSS, avec quelques fonctionnalités supplémentaires telles que la liaison de données aux attributs, que je connaissais déjà.


La décision était donc définitive. Ensuite, venant du monde C # qui est typé statiquement, j'ai décidé d'utiliser TypeScript plutôt que JavaScript.


Vient ensuite WebPack. Il était clairement nécessaire de diviser l'application en morceaux, ce qui faciliterait le chargement paresseux. Comme je savais déjà qu'il y aurait de nombreuses fonctionnalités dans l'application, il était impératif de la construire en tant que SPA capable de charger des pièces à la demande.


Sinon, l'expérience utilisateur serait inacceptable.


Pour faciliter la gestion de la configuration de WebPack, j'ai décidé d'ajouter Neutrino.JS au mélange et d'utiliser son interface fluide pour configurer WebPack.


Il était bien connu que la navigation Web mobile était à la hausse même en 2019. Pour être prêt pour le Web moderne, l'approche de développement a été définie comme suit.



Cela a été facilité par deux technologies principales - Tailwind CSS et PWA. En ce qui concerne le style, afin de simplifier encore plus le système, j'ai ajouté Tailwind CSS, qui s'est avéré être l'une des meilleures décisions que j'ai prises, car il est d'abord mobile par défaut.


De plus, il est basé sur l'utilité, donc il a une grande réutilisabilité, ce qui était exactement ce que je recherchais.


De plus, comme j'essayais d'offrir une expérience de type natif, mais que je n'avais pas le temps de créer des applications natives, j'ai décidé d'opter pour la meilleure chose suivante : une application qui peut être installée directement à partir du navigateur et fonctionner hors ligne.


C'est ce que les applications Web progressives (PWA) visent à donner à l'utilisateur, mais une configuration manuelle serait trop sujette aux erreurs et prendrait trop de temps, j'ai donc décidé d'utiliser Google WorkBox qui a les fonctionnalités d'installation, hors ligne et de mise en cache de Service Worker intégré.


Une fois le noyau mis en place, il était temps de l'emmener faire un tour en ligne. Il était clair que le site Web devait être accessible à tous à tout moment, les pannes n'appartiennent pas à un système moderne, j'ai donc décidé de configurer le système de la manière suivante.


Premièrement, les fichiers HTML et JS seront servis à partir d'un compartiment AWS S3. Afin de le rendre disponible avec une faible latence à l'échelle mondiale, il sera présenté par AWS CloudFront CDN Network.


Un léger revers, dans ce cas, a été lorsque j'ai également décidé d'utiliser le Serverless Framework car la configuration des fonctions AWS Lambda était plus facile qu'avec Terraform, j'ai donc introduit une nouvelle technologie dont je devais m'occuper.


Une fois la configuration terminée, j'ai acheté les domaines dans AWS Route 53, que j'ai utilisés pour les tests et le domaine de production - https://immersive.community .


L'idée derrière le nom vient d'un réseau communautaire du même nom - Mighty Networks . J'ai simplement opté pour le mot "immersif" car à cette époque, il commençait à être très tendance sur Google.


Puisque „immersive.networks“ et „immersive.communities“ étaient déjà pris, j'ai opté pour „immersive.community“.


Maintenant que j'avais lancé le front-end, il était temps de commencer à travailler sur la base de données. Même si j'étais habitué aux bases de données relationnelles basées sur SQL dans le passé, elles étaient clairement trop lentes pour ce projet particulier, j'ai donc décidé d'opter pour une base de données NoSQL. J'ai choisi AWS DynamoDB en raison de son offre sans serveur.


Pour accéder à la base de données, j'ai choisi AWS AppSync, qui est une implémentation GraphQL gérée et est également sans serveur.

Un système multi-locataires

À ce stade, il était temps de commencer à résoudre l'un des plus gros problèmes auxquels j'étais confronté, à savoir :


Comment permettre aux utilisateurs de rejoindre plusieurs communautés tout en gardant les données privées ou restreintes, dans chaque communauté, séparées les unes des autres ?


Le moyen le plus simple de résoudre ce problème serait de créer plusieurs bases de données, mais cela a des limites claires car, à un moment donné, nous manquerions de bases de données que nous pourrions créer.


Il s'avère que chaque compte AWS a des limites sur le nombre de ressources que vous pouvez créer, donc ce n'était pas une solution viable.


Je résoudrais enfin ce problème en attribuant une colonne de type à chaque entrée de la base de données DynamoDB. Chaque utilisateur aurait son type défini sur "utilisateur", tandis que chaque communauté serait simplement définie sur "web".


J'indiquerais alors qu'un utilisateur a rejoint une communauté en ajoutant une nouvelle ligne où la clé de cette ligne est désignée comme "user#web_user#web". Étant donné que l'utilisateur et le nom de la communauté seraient uniques, cette clé serait également unique, de sorte que l'utilisateur ne pourrait pas rejoindre la communauté plusieurs fois.


Si je veux effectuer une action qui ne peut être effectuée que si un utilisateur a rejoint une communauté, j'utiliserais simplement les fonctions de pipeline fournies par AppSync qui vous permettent d'interroger plusieurs lignes dans DynamoDB.


Je voudrais alors interroger et vérifier si l'utilisateur est membre d'une communauté et seulement s'il l'est, autoriser l'utilisateur à effectuer l'action.


Cela a résolu le problème de la multilocation , mais l'un des plus gros problèmes à résoudre était imminent.

Architecture hautement disponible

Il va sans dire qu'un système au niveau de l'entreprise est construit avec la tolérance aux pannes et la haute disponibilité à l'esprit. Cela permettrait aux utilisateurs de continuer à utiliser le système, même en cas de défaillance de certains de ses composants.


Si nous voulons mettre en œuvre un tel système, nous devons le faire en gardant à l'esprit la redondance.


Mes recherches m'ont conduit à la solution optimale dans ce cas, qui est une architecture Active-Active Highly Available . Il s'avère que la plupart des services sur AWS sont déjà hautement disponibles, mais AppSync lui-même ne l'est pas. J'ai donc décidé de créer ma propre implémentation.


Le Web n'offrait pas de solution à ce problème, j'ai donc dû créer le mien. J'ai commencé à penser globalement. Cela signifie que mes visiteurs viendraient de différentes régions, et si je devais placer mon AppSync aux États-Unis, les visiteurs en Asie auraient une latence plus élevée.


J'ai résolu le problème de latence et de haute disponibilité de la manière suivante. J'ai décidé de créer 10 API AppSync différentes dans toutes les régions disponibles à ce moment-là. Actuellement, les API sont situées aux États-Unis, en Asie et en Europe.


De plus, chaque API doit être connectée à la base de données DynamoDB correspondante, située dans la même région. Ainsi, j'ai ensuite créé 10 tables DynamoDB supplémentaires.


Heureusement, DynamoDB propose une fonctionnalité de table globale qui copie les données entre les tables DynamoDB connectées et les maintient synchronisées.


Désormais, quel que soit l'endroit où un utilisateur écrit dans la base de données, un utilisateur d'une région différente pourra lire les mêmes informations après la synchronisation des données.


La question qui se posait alors était la suivante.


Comment les utilisateurs seraient-ils acheminés vers l'API la plus proche ? Non seulement cela, mais si une API devait échouer, comment acheminerions-nous immédiatement l'appel vers la prochaine API disponible ?


La solution est née sous la forme des fonctions CloudFront et Lambda@Edge . C'est une fonctionnalité étonnante de CloudFront qui peut déclencher des fonctions Lambda@Edge dans la région où se trouve l'appelant.


Il devrait être clair que si nous savons où se trouve l'utilisateur, nous pouvons choisir l'API, à l'intérieur de la fonction Lambda@Edge, en fonction de l'origine de l'appel.


De plus, nous pouvons également obtenir la région de la fonction Lambda@Edge en cours d'exécution, ce qui nous permet de choisir l'API AppSync dans cette même région. La première étape pour implémenter cette solution consistait à envoyer par proxy les appels AppSync via CloudFront.


Par conséquent, désormais, les appels seraient directement passés à CloudFront au lieu d'AppSync.


J'ai ensuite dû extraire l'appel HTTP des paramètres CloudFront à l'intérieur de la fonction Lambda@Edge. Une fois que j'avais la région et la requête AppSync, extraite des paramètres CloudFront, je faisais un nouvel appel HTTP à l'API AppSync correspondante.


Lorsque les données revenaient, je les renvoyais simplement à CloudFront via la fonction Lambda@Edge. L'utilisateur obtiendrait alors les données demandées.


Mais nous n'avons pas encore résolu l'exigence Active-Active. L'objectif était maintenant de détecter le moment où une API est indisponible, puis de passer à une autre. J'ai résolu ce problème en vérifiant le résultat de l'appel AppSync. S'il ne s'agissait pas d'une réponse HTTP 200, l'appel a clairement échoué.

Je choisirais alors simplement une autre région dans une liste de toutes les régions disponibles, puis j'appellerais la prochaine API AppSync dans cette région. Si l'appel réussit, nous renvoyons le résultat, et s'il échoue, nous essayons la région suivante jusqu'à ce que nous réussissions.


Si la dernière région échoue également, nous renvoyons simplement le résultat d'échec.


Il s'agit simplement de l'implémentation Round Robin de l'architecture Active-Active Highly Available. Avec ce système maintenant en place, nous avons en fait implémenté les trois fonctionnalités suivantes :


  • Faible latence globale
  • Équilibrage de charge basé sur la région
  • Haute disponibilité actif-actif


Nous avons clairement une faible latence, en moyenne, pour chaque utilisateur global, puisque chaque utilisateur sera acheminé vers la région la plus proche à partir de laquelle il appelle l'API. Nous avons également un équilibrage de charge basé sur la région, car les utilisateurs seront acheminés vers plusieurs API dans leur région.


Enfin, nous avons une haute disponibilité active-active, puisque le système restera fonctionnel même si certaines de ses API ou bases de données échouent car les utilisateurs seront acheminés vers la prochaine API disponible.


Il ne suffirait en fait pas de gérer simplement la haute disponibilité des API. Je voulais l'avoir pour toutes les ressources, y compris les fichiers HTML et JavaScript qui étaient servis à partir de CloudFront.


Cette fois, j'ai utilisé la même approche mais créé 16 compartiments AWS S3. Chaque compartiment servirait les mêmes fichiers, mais serait situé dans des régions différentes.


Dans ce cas, lorsque l'utilisateur visite notre site Web, le navigateur effectue plusieurs appels HTTP vers des fichiers HTML, JS, JSON ou image. Le Lambda@Edge devrait, dans ce cas, extraire l'URL actuellement appelée.


Une fois que j'aurais l'URL, je devrais déterminer le type de fichier de ce fichier et effectuer un nouvel appel HTTP au compartiment S3 correspondant dans la région.


Inutile de dire que si l'appel réussit, nous renverrons le fichier, tandis que s'il échoue, nous utiliserons le même système de routage que précédemment, fournissant ainsi également un système actif-actif hautement disponible.


Avec ce système maintenant en place, nous avons franchi une nouvelle étape et placé un autre élément de la pierre angulaire de notre infrastructure au niveau de l'entreprise. C'était de loin le système le plus difficile à développer et il a fallu 3 mois pour le terminer.


En fin de compte, nous avions plus de problèmes à résoudre et ce système s'avérerait à nouveau utile.

Manifeste PWA dynamique

PWA est une technologie Web incroyable et sera utilisée par de plus en plus de sites Web au fil du temps, mais en 2019, les choses ne faisaient que commencer.


Depuis que j'ai décidé de servir chaque communauté sur un sous-domaine distinct, je voulais également donner aux utilisateurs la possibilité d'installer leur PWA de marque, avec un titre et une icône d'application appropriés.

Il s'avère que le fichier PWA Manifest, qui définit toutes ces fonctionnalités, ne fonctionne pas en fonction des sous-domaines. Il ne peut définir qu'un seul ensemble de valeurs en fonction du domaine à partir duquel il est servi.


Le fait que je pouvais déjà envoyer des appels HTTP par proxy à l'aide de CloudFront et Lambda@Edge s'est également avéré utile ici.


L'objectif était maintenant de proxy chaque appel au fichier manifest.json. Ensuite, selon le sous-domaine d'où provient l'appel, pour obtenir les données communautaires correspondantes, qui seraient l'icône de l'application, le titre, etc., nous remplirions alors dynamiquement le manifest.json avec ces valeurs.

Le fichier serait ensuite servi au navigateur et la communauté serait alors installée en tant que nouvelle application PWA sur l'appareil de l'utilisateur.

Passer au front-end

Une fois que j'ai compris ces étapes cruciales, il était temps de commencer à travailler sur le front-end. Conformément à l'exigence précédente basée sur le sous-domaine, nous avons également dû trouver comment charger une communauté différente et ses données en fonction du sous-domaine.


Cela nécessiterait également le chargement de différentes mises en page de sites Web, qui seraient utilisées dans chaque communauté.


Par exemple, la page d'accueil devrait répertorier toutes les communautés disponibles, tandis que d'autres sous-domaines devraient répertorier les articles de chacune de ces communautés.


Il va sans dire que pour résoudre ce problème, nous ne pouvons pas simplement créer plusieurs sites Web différents à partir de rien. Cela ne serait pas évolutif, donc à la place, nous aurions besoin de réutiliser autant de commandes et de fonctionnalités que possible.


Ces fonctionnalités seraient partagées entre ces deux types de communauté et ne seraient ensuite chargées que si elles sont nécessaires. Afin de maximiser la réutilisabilité du code, j'ai défini tous les contrôles en 4 types différents.


  • Composants
  • Les contrôles
  • pages
  • Communautés


Les plus petits éléments HTML personnalisés tels que <button> et <input> ont été définis en tant que composants. Ensuite, nous pourrions réutiliser ces composants dans les contrôles qui sont des ensembles de ces éléments plus petits, par exemple, le contrôle des informations de profil afficherait l'image du profil de l'utilisateur, son nom d'utilisateur, ses abonnés, etc.


Nous serions alors à nouveau en mesure de réutiliser ces éléments dans des éléments de niveau supérieur, qui dans notre cas sont — Pages.


Chaque page représenterait essentiellement un itinéraire, par exemple, la page Tendance, où nous pourrions voir toutes les activités ou la page Intérêt où le texte réel de l'article serait affiché. Je composerais ensuite chaque page à partir de ces petits contrôles.


Enfin, les éléments de plus haut niveau seraient définis dans les Communautés, en fonction de leur type. Chaque élément communautaire définirait alors simplement toutes les pages de niveau inférieur dont il a besoin.


Le routeur Aurelia s'est avéré utile dans ce cas, car vous pouvez charger les routes de manière dynamique. La mise en œuvre s'est déroulée de la manière suivante.


Quel que soit le sous-domaine, lorsque le site Web commence à se charger, nous enregistrons les deux branches principales, qui sont implémentées en tant que composants Aurelia. Celles-ci représentent deux types de communautés différents. J'ai ensuite défini deux types ou mises en page Web différents :


  • Principal
  • Article


Le type "principal" représente simplement la mise en page du site Web qui sera chargée lorsque l'utilisateur atterrira sur la page principale https://immersive.community . Ici, nous afficherons toutes les communautés avec tous les contrôles correspondants.

D'autre part, une fois que l'utilisateur navigue vers un sous-domaine, nous aurions alors besoin de charger une mise en page différente. En d'autres termes, au lieu de communautés, nous chargerions des articles et les fonctionnalités et itinéraires correspondants, par exemple, la possibilité de publier et d'éditer des articles.


Cela activerait ou désactiverait certaines routes, en fonction du type de communauté dans laquelle nous nous trouvions.


Notre configuration Aurelia et WebPack divise le JavaScript en morceaux appropriés, de sorte que les itinéraires et les fonctionnalités qui ne seront pas nécessaires ne soient pas du tout chargés, améliorant ainsi la vitesse et économisant sur la bande passante.

À ce stade, une fois que nous avons déterminé sur quel sous-domaine nous nous trouvons, nous chargeons la communauté et les données utilisateur pour cette communauté spécifique, ayant ainsi implémenté la solution avec succès.

La disposition de la maçonnerie

C'était mon raisonnement que nous devrions essayer de garder la conception aussi simple que possible. Ainsi, puisque les utilisateurs viennent sur le site Web pour le contenu, nous nous concentrerons sur l'affichage du contenu, par opposition aux fonctionnalités secondaires.


Les articles devraient être affichés dans des listes, mais ils ne devraient pas avoir l'air périmés, j'ai donc décidé que chaque article se composerait simplement des éléments suivants.


  • Une photo de couverture
  • Le titre de l'article
  • Catégorie d'articles
  • Date à laquelle l'article a été publié ou modifié
  • Profil de l'auteur


La principale façon dont je me suis assuré que la liste des articles n'aurait pas l'air obsolète était de m'assurer que l'utilisateur pouvait choisir le format d'image de chaque photo de couverture pour son article. L'inspiration est venue de la façon dont Pinterest affiche ses épingles, de sorte que chaque article aurait également un rapport d'aspect différent.


Cela m'a obligé à implémenter la disposition de la maçonnerie, qui ne peut pas être choisie prête à l'emploi dans CSS Grid ou FlexBox.

Heureusement, il existe plusieurs implémentations open source utiles que j'ai essayées et utilisées pour la mise en page. J'ai dû ajouter plusieurs améliorations, comme le chargement de données paginées et la mise à l'échelle avec la taille de l'écran.


Et alors…


En novembre 2019, les premiers signes de COVID-19 ont commencé à apparaître. Le monde fut bientôt plongé dans la tourmente et personne n'avait la moindre idée de ce qui se passait, mais cela allait changer le monde et la façon dont nous interagissions les uns avec les autres d'une manière que personne ne pouvait imaginer.

Peu de temps après, nous commencions à travailler à domicile. Cela aurait un grand impact sur mon processus de développement puisque je n'avais plus à me déplacer pour aller travailler. Ironiquement, le monde s'est effondré, alors que j'ai eu la pause dont j'avais besoin !

Intérêts et avis

De retour dans le monde du développement, l'idée derrière la rédaction d'articles sur les communautés immersives était basée sur la collaboration. À cette fin, je suis allé avec Wikipedia comme base pour l'effort de collaboration.


En outre, les sites Web communautaires comme Amino Apps et Fandom.com et le site Web de blogs HubPages.com ont également joué leur rôle.


Écrire des articles de blog en tant que personne seule peut être un bon début, mais nous pouvons aller au-delà en demandant aux gens d'écrire des articles ensemble.


Une fois que nous avons ajouté des hyperliens au texte et connecté ces articles écrits par différentes personnes, nous créons essentiellement une communauté où les gens se réunissent pour s'engager sur des sujets qui les intéressent.


J'ai décidé de définir deux types d'articles, à savoir,


  • Intérêts
  • Commentaires


Les intérêts seraient des articles courts, env. Des articles de 5000 caractères décrivant de manière factuelle tout intérêt particulier qu'une personne pourrait avoir. Ensuite, chaque personne pourrait écrire une critique, avec une note de cet intérêt particulier.


La page d'intérêt principale contiendrait alors une référence à toutes les critiques écrites pour cet intérêt particulier. La principale différence serait que n'importe qui peut modifier les centres d'intérêt, mais seule la personne qui a rédigé une critique peut la modifier, ajoutant ainsi une touche personnelle à chaque article.


Ici, notre décision antérieure d'utiliser CloudFront pour proxy AppSync est revenue nous mordre. Il s'avère que CloudFront ne prend en charge que les longueurs de chaîne de requête jusqu'à 8 192 octets , nous ne pouvons donc pas enregistrer de données plus longues que cela.


En ce qui concerne chaque article, chaque intérêt pourrait être aimé et commenté. Ainsi, les utilisateurs pourraient se réunir et discuter de la manière dont chaque article sera écrit et édité. De plus, chaque intérêt peut être ajouté à la page de profil de l'utilisateur, pour un accès rapide.


Une fois toutes ces fonctionnalités en place, la fin de l'année est arrivée. La situation semblait bonne et j'étais certain que le projet serait terminé l'année prochaine. Cette hypothèse ne s'est pas avérée exacte, c'est le moins qu'on puisse dire.

2020 — A toute vitesse

L'année a plus ou moins bien commencé. L'économie a encore résisté quelque peu, mais après un certain temps, elle a commencé à baisser. Les marchés ont commencé à réagir à la pandémie et de même, les prix ont commencé à augmenter.


Début 2020 a été l'année où j'ai beaucoup travaillé mais où je n'avais pas de produit vraiment fonctionnel. Il restait encore beaucoup à faire, mais j'étais confiant dans le résultat, alors j'ai continué à avancer.


À mon travail de jour, les heures de travail étaient également prolongées et nous devions respecter nos délais plus rapidement que d'habitude. Il va sans dire que j'ai dû réorganiser mon emploi du temps et la seule façon de gagner un peu plus de temps serait de ne dormir que 4 heures par nuit.


L'idée était de rentrer à la maison vers 18 ou 19 heures et d'aller directement travailler sur le projet. Je pouvais alors travailler jusqu'à 3 ou 4 heures du matin puis m'endormir. Je devrais alors me réveiller vers 7 heures du matin et me rendre rapidement à mon travail de jour.


Bien sûr, ce ne serait pas assez de sommeil chaque nuit, mais je me suis dit que je rattraperais ce temps en dormant 12 heures le week-end. J'ai également programmé tous les jours de vacances et les jours fériés pour le travail.


Le nouveau système a été mis en place, et j'ai procédé comme prévu.

L'éditeur Markdown

Il va sans dire qu'un site Web de rédaction d'articles doit disposer d'un éditeur de texte facile à utiliser. Au début de 2020, Markdown est devenu un moyen très populaire d'écrire du texte. J'ai décidé qu'Immersive Communities devrait le soutenir dès le départ.


Cela m'obligerait non seulement à écrire le Markdown, mais aussi à l'afficher au format HTML. La bibliothèque Markdown-It serait utilisée pour transformer Markdown en HTML. Mais il y avait une exigence supplémentaire, donc la liste complète des différents médias que nous devrions afficher est la suivante.


  • Texte
  • Image
  • Vidéo
  • Intègre


De plus, les images et les vidéos doivent être affichées sous forme de curseur où les utilisateurs peuvent glisser des images comme sur Instagram. Cela nécessiterait un mélange de Markdown et d'autres éléments HTML.


L'éditeur serait divisé en plusieurs parties où il y avait deux types d'entrées, le champ texte et le champ média. Chaque champ de l'éditeur peut être déplacé vers le haut ou vers le bas, ce qui était assez facile à mettre en œuvre avec Sortable.js .


En ce qui concerne les champs de saisie, le champ Markdown était assez simple à créer avec un élément <textarea>. L'éditeur charge également la police Google Inconsolata qui donne au texte en cours de saisie l'aspect d'une machine à écrire.

De plus, afin de styliser réellement le texte, une barre a été implémentée qui ajouterait Markdown au texte. La même chose a été faite en utilisant des raccourcis clavier en utilisant Mousetrap.js . Maintenant, nous pouvons facilement ajouter du texte en gras sous la forme de balises ** Markdown en utilisant Control + B, etc.


Lors de la frappe, il est naturel que l'élément <textarea> se développe à mesure que la quantité de texte augmente, j'ai donc utilisé la bibliothèque Autosize.js pour implémenter cette fonctionnalité.


Le champ multimédia pourrait afficher des images, des vidéos ou des iframes qui contiendraient des sites Web intégrés. Le type de champ de média changerait en fonction du type de média lui-même. J'ai utilisé Swiper.js pour implémenter le balayage entre les images.


Le composant vidéo a été implémenté à l'aide de la bibliothèque Video.js .


Les problèmes ont commencé à survenir au moment de télécharger les médias. En ce qui concerne les images, il était facile d'utiliser l' API File du navigateur pour charger des photos et des vidéos à partir de votre appareil. Ce que j'ai ensuite dû faire, c'était d'abord transformer des images, qui auraient pu être au format HEIC en JPEG.


Ensuite, je les compresserais avant de les télécharger sur le back-end. Heureusement, les bibliothèques Heic-Convert et Browser-Image-Compression ont bien servi cet objectif.


Un autre problème est survenu lorsque j'ai dû choisir le bon format d'image et le recadrer avant de le télécharger. Cela a été implémenté à l'aide de Cropper.JS mais malheureusement, cela n'a pas fonctionné immédiatement sur le navigateur Safari.


J'ai passé beaucoup de temps à définir le CSS approprié pour que l'image ne déborde pas du conteneur. Au final, l'utilisateur peut facilement charger une image depuis son appareil, effectuer un zoom avant et arrière, et également recadrer l'image avant de la télécharger.


Une fois que tout était terminé, les médias seraient téléchargés sur Cloudinary, qui est un service de gestion des fichiers multimédias.


Il était alors temps de rassembler tout cela et de le présenter à l'utilisateur sous forme d'articles. J'ai eu la chance qu'Aurelia ait un élément <compose> qui peut charger dynamiquement du HTML.


Par conséquent, selon le type d'entrée, je chargerais soit des éléments multimédias, soit des éléments Markdown, qui seraient transformés en HTML.


Il faudrait alors styliser ce HTML avec du CSS, notamment les tableaux HTML que je transformerais en fonction de la taille de l'écran. Sur les écrans plus grands, les tableaux seraient affichés dans leur disposition horizontale habituelle, tandis que sur les écrans plus petits, ils seraient affichés dans une disposition verticale.


Cela nécessiterait une approche événementielle qui nous indiquerait quand et comment la taille de l'écran change. La meilleure bibliothèque à utiliser dans ce cas était RxJs , qui gérait les événements "redimensionner", et j'ai pu formater la table en conséquence.

Améliorer la saisie des données

Je suis ensuite revenu aux articles. J'ai dû changer la façon dont les articles étaient enregistrés dans la base de données car plusieurs personnes pouvaient modifier l'article en même temps.


J'enregistrerais alors le nouvel article en tant que type d'article initial, mais les données réelles de chaque article seraient enregistrées en tant que version. Je serais alors en mesure de suivre quel utilisateur et quand chaque article a été modifié.


Cela m'a permis d'empêcher l'enregistrement d'une nouvelle version si l'utilisateur n'a pas chargé la dernière version en premier. De plus, si une certaine mise à jour était inappropriée, elle pourrait être désactivée et une version précédente serait alors à nouveau visible. Les brouillons de chaque article seraient sauvegardés de la même manière.


En ce qui concerne la saisie de données réelle, j'ai décidé de l'implémenter sous forme de pop-up. Les fenêtres contextuelles elles-mêmes n'apparaîtraient pas simplement à l'écran, mais glisseraient vers le haut depuis le bas. De plus, il serait possible de glisser à l'intérieur de la fenêtre contextuelle.


Pour cela, j'ai réutilisé la bibliothèque Swiper.Js, tandis que toutes les autres animations ont été réalisées à l'aide de la bibliothèque Animate.CSS .


La pop-up n'était pas simple à mettre en place car elle nécessitait une mise à l'échelle avec la taille de l'écran. Ainsi, sur des écrans plus grands, cela prendrait 50% de la largeur de l'écran alors que sur des écrans plus petits, cela prendrait 100% de la largeur.


De plus, dans certains cas, comme avec la liste des followers, j'ai implémenté le scroll pour qu'il soit contenu dans la pop-up. Cela signifie que la liste que nous faisions défiler ne s'arrêtait pas en haut mais disparaissait lors du défilement.


J'ai également ajouté un style supplémentaire et atténué l'arrière-plan et désactivé le défilement ou le clic en dehors de la fenêtre contextuelle. D'autre part, la fenêtre contextuelle Aperçu du système d'édition d'articles se déplace avec l'écran.


Cela a été inspiré par l'application Raccourcis d'Apple et la façon dont ses fenêtres contextuelles apparaissent, ce qui vaut également pour les boutons de pilule et les titres au-dessus des éléments.

La barre de navigation

L'une des fonctionnalités les plus importantes de l'interface utilisateur que j'ai implémentée a été inspirée par l'iPhone, qui est sa barre de navigation. J'ai remarqué que presque toutes les applications mobiles ont une barre de navigation assez basique, avec des icônes simples et petites qui ne correspondent pas vraiment à la conception globale de l'application.


J'ai décidé de reproduire simplement la barre iOS et de l'utiliser sur tout le site Web. Inutile de dire qu'il ne devrait pas toujours être visible, mais devrait plutôt disparaître lorsque nous défilons vers le bas et apparaître lorsque nous défilons vers le haut.


Lorsque l'utilisateur fait défiler vers le bas, nous supposons qu'il est intéressé par le contenu et qu'il ne va pas quitter la page actuelle, nous pouvons donc masquer la barre.


D'un autre côté, si l'utilisateur fait défiler vers le haut, il pourrait chercher un moyen de quitter la page, alors autant montrer à nouveau la barre.


Il y a quatre boutons sur la barre et ils permettent à l'utilisateur de naviguer vers les quatre parties principales du site Web. Le bouton Accueil permet d'accéder à la page d'accueil de chaque communauté. Le bouton Tendances navigue vers la page Tendances où l'utilisateur peut voir toutes les activités récentes que d'autres utilisateurs ont publiées.


Le bouton suivant est le bouton Engager qui permet d'accéder à la liste de toutes les fonctionnalités et paramètres proposés par la communauté. Enfin, le bouton Profil nous amène à notre page de profil.


Il était également nécessaire de prendre en compte des écrans plus grands, de sorte que la barre se déplace en fait vers la droite de l'écran lorsqu'elle est affichée sur un grand écran. Il devient collant et ne bouge plus à ce stade.

Traitement par lots en temps réel

Une fois le travail le plus important sur le front-end effectué, il était temps de visiter à nouveau le back-end. Cette partie du système s'avérerait être l'une des plus complexes à mettre en œuvre mais finalement, très importante et permettrait également de passer assez facilement à d'autres fonctionnalités.


Dans la programmation orientée objet , il existe un concept de séparation des préoccupations , où nous gardons nos fonctions simples et leur faisons faire une seule chose, ce qu'elles sont censées faire.


De plus, l'idée de la programmation orientée aspect concerne spécifiquement la séparation des préoccupations, où nous devons séparer la logique métier des autres préoccupations transversales.


Par exemple, l'enregistrement d'un utilisateur dans une base de données doit naturellement s'accompagner d'une journalisation, pendant que l'enregistrement de l'utilisateur est en cours de traitement. Mais le code de ces deux fonctionnalités doit être séparé.


J'ai décidé d'appliquer ce raisonnement à tous les niveaux et d'extraire autant de fonctionnalités de l'interface utilisateur, qui ne sont pas importantes pour l'utilisateur, et de les déplacer vers le back-end.


Dans notre cas, nous sommes principalement concernés par la sauvegarde des données dans la base de données, qui concerne les communautés, les articles, les commentaires, les likes, etc.


Si nous voulons garder une trace du nombre de likes d'un article, nous pourrions avoir un processus qui compte tous les likes pour chaque article et les met à jour périodiquement.


Étant donné que nous traitons ici d'une grande quantité de données stockées dans la base de données et potentiellement d'une grande quantité de données qui circulent constamment dans la base de données, nous devrons utiliser un traitement de données en temps réel pour gérer cette situation.

J'ai choisi AWS Kinesis pour cette tâche. Kinesis est capable d'ingérer de grandes quantités de données en temps réel et nous pouvons également écrire des requêtes SQL pour interroger et regrouper ces données en temps quasi réel. Par défaut, Kinesis regroupe les données pendant 60 secondes ou le lot atteint 5 Mo, selon la première éventualité.


Ainsi dans notre cas, nous allons interroger les données entrantes, c'est-à-dire la création de nouvelles communautés, l'ajout ou la suppression d'articles, d'utilisateurs, d'activités, etc., et mettre à jour la base de données chaque minute avec de nouvelles données. La question qui se pose maintenant est de savoir comment introduire les données dans Kinesis en premier lieu ?


Notre base de données de prédilection, DynamoDB, est en fait capable de définir des déclencheurs qui sont invoqués, sous la forme de fonctions Lambda, chaque fois que les données sont ajoutées, supprimées ou modifiées. Nous récupérons ensuite ces données et les envoyons à Kinesis pour traitement.


Il se trouve que l'une de nos décisions antérieures rendrait ce processus légèrement plus difficile à mettre en œuvre car nous ne traitons pas avec 1 base de données, mais en fait avec 10 bases de données.


Par conséquent, une fois les données ajoutées, les fonctions Lambda seront appelées 10 fois au lieu d'une fois, mais nous devons gérer chaque cas car les données peuvent provenir de n'importe quelle base de données car elles sont situées dans des régions différentes.


J'ai résolu ce problème en filtrant les données copiées par opposition aux données d'origine qui ont été ajoutées à la base de données par l'utilisateur.


La colonne « aws:rep:updateregion » nous donne cette information et nous pouvons déterminer si nous avons affaire aux données de la région où elles ont été insérées ou si elles représentent des données copiées.


Une fois ce problème résolu, nous filtrerions simplement, soit l'ajout de nouvelles données, soit leur suppression. De plus, on filtrerait les données en fonction de leur type, c'est-à-dire qu'il s'agit soit de données représentatives d'une communauté, d'un article, d'un commentaire, etc.


Nous collectons ensuite ces données, les marquons comme « INSERER » ou « SUPPRIMER » et les transmettons à Kinesis. Ces idées issues de l'approche Domain-Driven Design sont appelées Domain Events et nous permettent de déterminer quelle action s'est produite et de mettre à jour notre base de données en conséquence.




Nous tournons ensuite notre attention vers Kinesis. Ici, nous avons dû définir trois parties principales du système


  • Flux de données AWS Kinesis
  • AWS Kinesis Firehose
  • Analyse de données AWS Kinesis


Les Kinesis Streams nous permettent d'ingérer des données en temps réel en grandes quantités. Kinesis Analytics est un système qui nous permet d'interroger ces données par lots et de les agréger sur la base d'une fenêtre temporelle glissante.


Une fois les données agrégées, nous poussions chaque résultat plus loin dans Kinesis Firehose, qui peut gérer de grandes quantités de données et les stocker dans un service de destination, qui dans notre cas, est un compartiment S3 au format JSON.


Une fois que les données atteignent le compartiment S3, nous déclenchons une autre fonction Lambda et traitons ces données afin de mettre à jour la base de données DynamoDB.


Par exemple, si 5 personnes ont aimé un intérêt à la dernière minute, nous trouverions ces données dans notre fichier JSON. Nous mettrons alors à jour le nombre de semblables pour cet intérêt et augmenterons ou décrémenterons le nombre de semblables. Dans ce cas, nous l'incrémenterions simplement de 5 likes.


En utilisant ce système, les statistiques de chaque communauté resteraient à jour en une minute.


De plus, nous n'aurions pas besoin d'écrire et d'exécuter des requêtes complexes lorsque nous avons besoin d'afficher des données agrégées, puisque le résultat exact est stocké dans la base de données rapide DynamoDB dans chaque enregistrement, augmentant ainsi la vitesse de requête pour chaque enregistrement.


Cette amélioration est basée sur l'idée de localité des données

Cloudinaire

Il était maintenant temps de commencer à implémenter des services tiers qui géreraient les fonctionnalités dont j'avais besoin, mais il était plus facile d'acheter un abonnement que de créer moi-même. Le premier service que j'ai implémenté était Cloudinary, qui est un service de gestion des médias.


J'ai configuré tous les préréglages sur Cloudinary pour transformer avec impatience les images pour les points d'arrêt d'écran réactifs suivants.


  • 576 pixels
  • 768 pixels
  • 992 pixels
  • 1200 pixels


Il s'agirait également de points d'arrêt définis dans Tailwind CSS où notre site Web se conformerait à différentes tailles d'écran pour les téléphones mobiles, les petites tablettes, les grandes tablettes et les écrans d'ordinateur.


Ensuite, en fonction de la taille actuelle de l'écran, nous appellerions de manière appropriée des images créées avec impatience à partir de Cloudinary en utilisant l'attribut scrcset sur l'élément <image>.


Cela nous aiderait à économiser de la bande passante et à raccourcir le temps de chargement des images sur les appareils mobiles.


En ce qui concerne la fonctionnalité vidéo, après sa mise en œuvre, j'ai décidé de l'abandonner car le prix des vidéos chez Cloudinary était trop cher. Ainsi, même si le code est là, la fonctionnalité n'est actuellement pas utilisée mais pourrait devenir disponible plus tard.


Cela m'obligera à créer un système personnalisé sur AWS à l'avenir.

Embed.ly

J'ai décidé d'utiliser Embed.ly pour intégrer le contenu de sites Web populaires tels que Twitter, YouTube, etc.


Malheureusement, cela n'a pas fonctionné sans problèmes, j'ai donc dû utiliser plusieurs techniques pour supprimer manuellement les scripts Facebook et Twitter du site Web, car ils interféreraient avec le contenu intégré après qu'il ait été chargé plusieurs fois.

Algolie

En ce qui concerne la recherche, j'ai choisi Algolia et mis en place la recherche de communautés, d'activités, d'articles et d'utilisateurs. La mise en œuvre frontale était assez simple.


J'ai simplement créé une barre de recherche qui, une fois cliquée, cacherait le reste de l'application et pendant que nous tapons, afficherait le résultat pour le sous-domaine spécifique que nous parcourons actuellement.


Une fois que nous appuyons sur "Entrée", la maçonnerie sur la page d'accueil affiche les articles qui correspondent à la requête. Il va sans dire que j'ai également dû implémenter la pagination qui chargerait les résultats de manière incrémentielle, pour imiter l'apparence de Pinterest.


Le problème est survenu lorsque j'ai réalisé qu'il n'y avait aucun moyen de rechercher les activités à moins de stocker l'intégralité du texte dans Algolia, ce que je voulais éviter. J'ai donc décidé de ne stocker que les balises pertinentes pour chaque activité, mais la question était de savoir comment extraire les balises pertinentes de chaque activité.


La réponse est venue sous la forme d' AWS Translate et d'AWS Comprehend . Étant donné que la quantité d'éléments qui seraient ajoutés à la base de données serait importante et que nous aimerions ajouter ces données à Algolia, nous pourrions surcharger l'API si nous devions ajouter chaque enregistrement séparément.


Nous aimerions plutôt les gérer en temps réel et par lots, donc nous utiliserions à nouveau Kinesis comme solution.


Dans ce cas, chaque ajout d'un nouvel élément à la base de données déclencherait une fonction Lambda qui enverrait ces données à Kinesis Data Streams, qui à son tour enverrait les données à Kinesis Firehose (pas besoin d'Analytics cette fois) et les stockerait davantage. dans un compartiment S3.


Une fois les données stockées en toute sécurité, nous déclencherions une fonction Lambda qui les enverrait à Algolia, mais avant cela, nous aurions besoin de traiter ces données.


En particulier, nous aurions besoin de traiter des activités, à partir desquelles nous supprimerions le texte Markdown à l'aide de la bibliothèque markdown-remover . Il nous resterait alors du texte en clair. Une fois que nous avons le texte réel, nous pouvons procéder à l'extraction des balises pertinentes qui seront utilisées pour la recherche.


Cela peut être facilement fait en utilisant le service AWS Comprehend, mais le problème est qu'il ne prend en charge que certaines langues. Ainsi, si un utilisateur écrit dans une langue qui n'est pas prise en charge, nous ne pourrons pas extraire les balises.


Dans ce cas, nous utilisons simplement AWS Translate et traduisons le texte en anglais. Ensuite, nous procédons à l'extraction des balises, puis nous les traduisons dans la langue d'origine.


Maintenant, nous stockons simplement les balises dans Algolia comme prévu.

Recombée

L'une des fonctionnalités les plus importantes de Pinterest est son moteur de recommandation. Une fois que l'utilisateur clique sur une épingle, il voit immédiatement l'image en taille réelle de l'épingle, tandis que sous l'image, nous pouvons voir les recommandations que l'utilisateur pourrait aimer, en fonction de l'épingle actuelle.


C'est un très bon moyen d'augmenter la rétention des utilisateurs et de les inciter à continuer à naviguer sur le site Web. Afin d'implémenter cette fonctionnalité, qui dans mon cas devrait montrer des articles similaires aux utilisateurs, j'ai choisi Recombee — qui est un moteur de recommandation SaaS.


La mise en place a été cette fois plus facile contrairement à Algolia puisque j'ai repris les mêmes principes. Étant donné que nous devrons recommander des communautés, des articles et des activités, pour chaque nouvel élément créé par un utilisateur, j'utiliserais Kinesis pour regrouper ces éléments et les envoyer à Recombee.


Le processus de recommandation est basé sur les vues, ce qui signifie que chaque fois qu'un utilisateur voit un article, nous envoyons cette vue pour cet utilisateur spécifique et l'article à Recombee.


Nous pouvons également attribuer d'autres actions aux éléments dans Recombee, en fonction de la manière dont l'utilisateur interagit avec eux. Par exemple, l'écriture d'un nouvel intérêt serait mappée à un ajout de panier pour cet intérêt. Si un utilisateur aime un intérêt, cela serait un ajout à la note.


Si un utilisateur rejoint une communauté, cela sera mappé au signet de cette communauté.


Sur la base de ces données, Recombee créerait des recommandations pour les utilisateurs.


Sur le front-end, j'obtiendrais simplement l'article que l'utilisateur lit actuellement et j'obtiendrais les données de recommandation pour cet article spécifique et l'utilisateur. Cela serait affiché au bas de chaque article, sous forme de liste de maçonnerie paginée.


Cela donnerait à l'utilisateur une liste d'articles potentiels qu'il pourrait être intéressé à lire.

Localiser

Étant donné que le site Web visait dès le départ une audience mondiale, j'ai également dû mettre en œuvre la localisation. Pour la version initiale, j'ai décidé d'opter pour 10 langues et j'ai opté pour un service SaaS - Locize, qui est implémenté sur la base du framework de localisation i18next .


Nous devrons localiser les mots en fonction de la quantité, c'est-à-dire au singulier ou au pluriel, et nous devrons également localiser le temps. Vu que nous affichons l'heure à laquelle chaque article a été créé ou mis à jour pour la dernière fois.


J'ai choisi l'anglais comme langue par défaut et j'ai traduit tous les mots à l'aide de Google Translate dans d'autres langues comme l'allemand, le japonais, etc. Il est encore une fois très pratique qu'Aurelia prenne également en charge la localisation.


Une fois toutes les traductions effectuées, j'ai importé les fichiers JSON traduits dans l'application et les ai divisés en fonction du type de communauté, afin de ne pas charger de texte inutile qui ne sera pas utilisé.


Aurelia nous permet alors d'utiliser simplement des modèles et des reliures qui traduiraient automatiquement le texte. Mais j'ai également utilisé des convertisseurs de valeur qui formateraient l'heure, pour montrer depuis combien de temps un article a été écrit, au lieu d'afficher une date réelle.


De plus, je devais également formater les nombres, donc au lieu d'afficher le nombre 1000, j'afficherais 1K. Toutes ces fonctionnalités étaient gérées par des bibliothèques telles que Numbro et TimeAgo .

Twilio

Un site Web communautaire nécessite une communication, mais pas seulement en public. Cela nécessite également une communication privée. Cela signifiait qu'un chat privé en temps réel devrait également être quelque chose que je devais offrir. Cette fonctionnalité a été implémentée à l'aide du service Twilio Programmable Chat.


Chaque utilisateur peut avoir une conversation privée avec n'importe quel autre utilisateur dans chaque communauté spécifique. L'implémentation back-end était assez facile à implémenter à l'aide des bibliothèques Twilio. En ce qui concerne le front-end, j'ai décidé de styliser le chat en fonction d'Instagram car il avait un design épuré et simple.

Pré-rendu du SPA

J'ai également choisi un service appelé Prerender à utiliser pour pré-rendre le site Web afin de le rendre disponible pour les robots des moteurs de recherche. Après avoir réalisé que le prix pouvait être un problème, j'ai décidé de créer moi-même le système de pré-rendu.


À cette fin, j'ai trouvé une bibliothèque appelée Puppeteer , qui est une API Headless Chrome.


Cette bibliothèque pourrait être utilisée pour charger des sites Web par programme et renvoyer un code HTML généré avec du JavaScript exécuté, ce que les robots de recherche ne faisaient pas à l'époque. L'implémentation chargerait Puppeteer dans une fonction Lambda, qui chargerait un site Web, le rendrait et renverrait le code HTML.


J'utiliserais Lambda@Edge pour détecter quand mon utilisateur était en fait un robot d'exploration, puis je le transmettrais au Lambda de pré-rendu. C'était assez simple à faire en détectant l'attribut "user-agent" dans les paramètres CloudFront. Il s'est en fait avéré que Lambda ne pouvait pas charger la bibliothèque Puppeteer car elle était trop volumineuse.


Ce n'était pas un obstacle puisque j'ai ensuite trouvé la bibliothèque chrome-aws-lambda , qui a fait tout ce travail hors de la boîte et serait beaucoup plus petite car elle n'utilise que le noyau Puppeteer, qui était nécessaire à mes fins.


Une fois le système terminé, les moteurs de recherche étaient déjà suffisamment puissants et ont également commencé à exécuter JavaScript. Ainsi, même si j'ai terminé cette fonctionnalité, je l'ai désactivée et j'autorise simplement les moteurs de recherche à explorer mon site Web par eux-mêmes.

Bande

L'une des principales caractéristiques d'Immersive Communities est son système de partage des revenus, dans lequel les utilisateurs partagent 50 % des abonnements des membres et des revenus publicitaires.


Comme indiqué précédemment, nous devons permettre à nos créateurs non seulement de créer leur contenu, mais aussi de le monétiser. La question était maintenant de savoir comment mettre en œuvre ce système. Il va sans dire que le choix par défaut était Stripe, j'ai donc procédé comme suit.


J'ai décidé de concevoir le système de partage des revenus en fonction de chaque communauté. De cette façon, un utilisateur peut créer plusieurs communautés et gagner en fonction de chaque communauté. Les revenus de chaque communauté proviendraient de deux sources.


  • Abonnements des membres
  • Annonces en libre-service


Les abonnements des membres étaient les plus faciles à mettre en œuvre. Je créerais trois niveaux de prix pour les abonnements des membres, 5 $, 10 $ et 15 $ par mois. Les membres de chaque communauté peuvent alors soutenir le propriétaire de la communauté sur une base mensuelle, et en retour, aucune publicité ne sera diffusée.


Le système publicitaire était basé sur les mêmes abonnements mensuels, mais oscillait entre 100 $ et 1 000 $ par mois. L'entreprise qui souhaite faire de la publicité dans une communauté particulière peut simplement choisir le montant du paiement mensuel et définir la bannière publicitaire.


En supposant qu'il y ait plusieurs annonceurs dans une même communauté, les publicités seraient choisies au hasard à chaque chargement de page ou changement d'itinéraire. La façon dont l'annonceur peut augmenter la fréquence de diffusion de ses annonces, par rapport aux autres annonceurs, en augmentant le montant du paiement mensuel.


Nous aurions également besoin de montrer à l'annonceur les performances de ses annonces. J'ai donc de nouveau utilisé une configuration Kinesis pour mesurer à la fois les vues et les clics. Ce système mettrait alors à jour les statistiques comme d'habitude et j'ai ensuite utilisé la bibliothèque Brite Charts pour afficher les statistiques.


La partie la plus importante était la fonctionnalité de partage des revenus. Cela a été simplement implémenté par la fonctionnalité Stripe Connect . L'utilisateur doit simplement ajouter son compte bancaire et se connecter à Stripe Express et le système aurait alors toutes les informations nécessaires pour envoyer des paiements.



J'aurais alors un système Lambda planifié qui obtiendrait tous les utilisateurs quotidiennement et mettrait à jour les transactions et s'assurerait que 50% de chaque transaction (soit l'abonnement des membres ou le paiement des publicités) soit transférée au propriétaire de la communauté où le paiement est fabriqué.

AWSCognito

Le dernier service à implémenter était Auth0 , ce qui aiderait à l'authentification des utilisateurs. Après quelques recherches, j'ai opté pour une configuration sans mot de passe, basée sur les messages SMS.


Étant donné que nous sommes maintenant dans un monde axé sur le mobile, il était logique de renoncer aux mots de passe et de baser l'authentification sur quelque chose que tout le monde possède déjà : son téléphone portable.


Il s'est avéré que l'implémentation Auth0 de l'authentification sans mot de passe n'était pas optimale car elle redirigerait vers leur site Web à chaque fois et serait basée sur des paramètres d'URL, ce que je voulais éviter.


La tarification ne serait pas non plus adaptée à quelque chose comme un réseau social, j'ai donc décidé de créer ma propre implémentation à l'aide d'AWS Cognito.


C'était assez pratique que Cognito ait des déclencheurs qui peuvent être connectés aux fonctions Lambda, ce que j'ai utilisé pour déclencher l'authentification. Les fonctions Lambda seraient utilisées pour collecter des données utilisateur lors de l'inscription.


À ce stade, l'utilisateur n'a qu'à fournir son numéro de téléphone et son nom d'utilisateur pour s'inscrire.

Au cours de la procédure de connexion, la fonction Lambda collecterait le numéro de téléphone de l'utilisateur et enverrait un message SMS contenant un code de vérification à l'utilisateur, à l'aide d' AWS SNS .


L'utilisateur taperait alors simplement ce code pour être vérifié via Cognito et serait redirigé vers sa page de profil.


Bien sûr, une fois que l'utilisateur est autorisé et que les données de validation sont renvoyées au frontal, nous devrons les chiffrer avant de pouvoir les stocker. Les mêmes données d'autorisation sont cryptées avant d'être stockées sur le back-end.


De plus, lors de chaque inscription et connexion, nous stockons l'adresse IP de l'utilisateur.


Il s'est avéré plus tard que les utilisateurs auraient en fait du mal à donner leurs numéros de téléphone portable, j'ai donc décidé de remplacer les SMS par des e-mails.


Il y avait un problème avec les messages en double lorsque je voulais utiliser AWS SES , alors je suis passé à SendGrid de Twilio afin d'envoyer des e-mails aux utilisateurs.


Une fois ce système terminé, l'année était terminée et le projet que j'avais commencé il y a 2 ans était loin d'être terminé. Il n'y avait pas d'autre choix que de continuer à travailler et d'essayer de le terminer le plus tôt possible. Je ne savais pas que les plus grands défis étaient encore à venir.

2021 — Pas de fin en vue

C'est à ce moment-là que tout devait se mettre en place, mais travailler en tant que développeur solo sans aucune rétroaction pendant si longtemps vous fait douter de la direction que prend le projet.


La question que tout développeur qui se trouve actuellement au même endroit en ce moment pourrait se poser la question suivante.


Comment puis-je rester motivé et capable de continuer, même si je ne vois aucune fin en vue ?


La réponse est assez simple.


Vous ne devriez tout simplement pas remettre en question vos décisions, peu importe ce que vous pensez actuellement du projet. Vous ne pouvez pas permettre à votre état émotionnel actuel de déterminer comment vous agirez.


Vous pourriez ne pas avoir envie de continuer maintenant, mais vous pourriez en avoir envie plus tard et vous vous sentirez certainement mal si vous arrêtez réellement.


Donc si vous arrêtez, vous n'aurez plus le projet et tout le travail aura servi à rien. Donc, la seule chose à faire est simplement de continuer à avancer, quoi qu'il arrive.


La seule chose à garder à l'esprit pour le moment est que chaque fonctionnalité fournie, chaque pression sur le clavier, vous rapproche de l'objectif.


Au cours de ce projet, j'ai en fait changé de travail 3 fois, à chaque fois assez impliquant, mais même si je devais passer des entretiens d'embauche, je rentrais toujours chez moi, m'asseyais derrière mon bureau et continuais à travailler sur mon projet.


Ce que vous devez vous demander, si vous manquez de motivation, est le suivant.


Si vous arrêtez maintenant, où irez-vous ? La seule façon de retourner, après avoir arrêté, c'est de retourner d'où vous venez. Mais vous savez déjà ce qu'il y a derrière. Vous savez déjà à quoi cela ressemble, et vous ne l'avez pas aimé, c'est pourquoi vous vous êtes lancé dans ce voyage en premier lieu. Donc, vous savez maintenant pertinemment qu'il n'y a nulle part où retourner. La seule façon d'aller, c'est d'avancer. Et la seule façon d'avancer, c'est de continuer à travailler.


C'est toute la motivation que j'avais à disposition durant ce projet, comme je l'ai déjà dit, c'était soit ça, soit retourner là où j'étais déjà, alors j'ai décidé de continuer à avancer.

Le système d'administration

Il était maintenant temps de commencer à rassembler les choses et pour commencer, j'ai décidé de mettre en place le système d'administration qui serait utilisé pour maintenir chaque communauté. Chaque propriétaire de communauté serait en mesure de prendre des décisions concernant la suppression de contenu dans sa communauté.


Cela impliquerait que nous puissions désactiver les publicités, les articles et les activités et bannir les utilisateurs si leurs actions ne sont pas conformes aux règles de conduite.


Le propriétaire de chaque communauté peut également accorder des droits d'administration à d'autres utilisateurs. Mais nous devons également permettre aux administrateurs de la communauté principale d'administrer toutes les autres communautés.


De plus, ces administrateurs pourraient complètement désactiver les autres utilisateurs de toutes les communautés et même désactiver la communauté dans son ensemble.


Afin de faciliter le travail des administrateurs, j'ai introduit le système de signalisation, où chaque élément peut être signalé aux administrateurs. Les utilisateurs peuvent désormais signaler tout ce qu'ils jugent inapproprié sur le site Web.


La validation réelle des autorisations pour chaque utilisateur serait décidée par le back-end. Je créerais simplement une fonction Lambda qui serait invoquée dans chaque appel AppSync qui validerait chaque demande.


De plus, le frontal utiliserait l'autorisation basée sur le routage qui est fournie par Aurelia. Je définirais simplement des règles qui autoriseraient ou interdiraient à l'utilisateur actuel de suivre un certain itinéraire.


Par exemple, vous ne pourrez pas voir votre profil si vous avez été banni d'une certaine communauté. Mais ce système pourrait également être utilisé pour empêcher quelqu'un de naviguer vers une page de profil s'il n'est pas connecté, à la place, il serait redirigé vers la page de connexion.

Le tableau de bord analytique

Une autre fonctionnalité qui serait utile pour les utilisateurs serait la page du tableau de bord Analytics. Chaque propriétaire de communauté peut voir des graphiques qui affichent exactement le niveau d'interaction qui se produit dans sa communauté.


Pour ce cas particulier, je réutiliserais les données agrégées par Kinesis et les afficherais avec des graphiques à l'aide de la bibliothèque Brite Charts .


De plus, je prendrais également les données Stripe et afficherais le nombre d'abonnés, d'annonceurs et les revenus totaux de cette communauté.


Le seul problème à résoudre était la conception réactive, c'est-à-dire comment afficher les graphiques sur les petits et les grands écrans. Encore une fois, j'ai utilisé RxJs pour détecter l'événement "redimensionner" et appliquer un style basé sur les points d'arrêt d'écran définis dans Tailwind CSS.

La sécurité

Un niveau de sécurité supplémentaire était également au programme et j'ai décidé de mettre en place un WAF devant mes distributions CloudFront.


J'ai utilisé AWS Marketplace et je me suis abonné au système Imperva WAF qui proxy mon trafic et s'assure de n'autoriser que le trafic qui a été validé comme sûr.


La solution était assez facile à mettre en œuvre, mais une fois le premier mois écoulé, la facture était bien trop lourde à gérer, j'ai donc déconnecté le système et décidé de me fier simplement à ce que CloudFront avait à offrir par défaut.

La refonte de dernière minute

À ce stade, j'ai dû commencer à regarder tout ce que j'avais fait et commencer à résoudre les petits problèmes qui restaient. De nombreuses choses devaient encore être peaufinées, mais la chose la plus importante à modifier était la configuration de la base de données DynamoDB.


Il s'avère que ma configuration initiale, qui n'était pas celle que j'utilise actuellement, n'allait pas bien s'adapter. C'est pourquoi j'ai décidé de le repenser complètement et de commencer à utiliser le séparateur "#" pour indiquer le branchement dans l'identifiant de l'enregistrement.


Auparavant, je faisais des enregistrements séparés et j'utilisais AppSync Pipelines pour localiser chaque enregistrement associé, ce qui était clairement non durable. Cela a également eu un effet sur la configuration des services Kinesis et tiers comme Algolia et Recombee.


À son tour, il a fallu 3 mois pour repenser complètement le système pour qu'il fonctionne correctement. Une fois cela fait, j'ai pu continuer avec les nouvelles fonctionnalités.

L'été le plus chaud jamais enregistré

Les étés à Tokyo sont chauds et humides. C'est tout un défi de rester au point avec tout ce que vous faites, surtout en juillet et en août.


Pendant ce temps, les Jeux olympiques se déroulaient à Tokyo et le 7 août, il a été signalé que la température la plus chaude avait été enregistrée dans l'histoire des Jeux olympiques .


Inutile de dire qu'aller au travail en train n'aurait plus de sens car le temps serait trop épuisant, me laissant épuisé et incapable de travailler le soir. J'ai réalisé que je devais gagner un peu plus de temps en prenant un taxi pour aller travailler à la place.


Cela m'a donné plus de temps pour dormir et m'a évité d'être trop fatigué pour travailler une fois de retour à la maison.

Notifications en temps réel

PWA est une excellente technologie et elle nous offre un moyen d'envoyer des notifications aux utilisateurs à l'aide de notifications push. J'ai décidé que ce serait un système qui serait également nécessaire et j'ai procédé à la mise en œuvre.


Le système de notification serait mis en œuvre en fonction de l'utilisateur qui est suivi. Si vous suivez un utilisateur, alors lorsqu'il crée une nouvelle activité ou un article, vous devez être averti.


Actuellement, le seul problème avec les notifications push est qu'au moment d'écrire ces lignes, elles ne sont toujours pas prises en charge par le navigateur Safari sur les appareils iOS. Au lieu des notifications push natives, j'ai opté pour l' API de notification du navigateur.


En arrière-plan, je créerais une nouvelle instance d' AWS API Gateway et la configurerais pour qu'elle fonctionne avec des données en temps réel.


Sur le front-end, j'établirais une connexion à l'aide de l' API WebSocket avec la passerelle API. Une fois que l'utilisateur qui est suivi publie un nouvel article, ces données seront envoyées à Kinesis. Encore une fois, en utilisant le traitement par lots, nous obtenons tous les utilisateurs qui suivent l'auteur, puis utilisons la passerelle API pour envoyer les notifications au frontal.


Sur le front-end, la connexion WebSocket est déclenchée, que nous utilisons à son tour pour appeler l'API de notification du navigateur et afficher la notification.


De plus, en ce qui concerne les commentaires que les utilisateurs peuvent écrire sur chaque article, nous devons garder une trace et montrer à l'utilisateur où il est actuellement engagé dans les discussions.


J'ai également implémenté un indicateur non lu qui montrerait quelle section de commentaire contient de nouveaux commentaires que l'utilisateur n'a toujours pas lus.


Cela serait vérifié lorsque l'utilisateur charge l'application sans utiliser le mot clé await lors de l'appel de l'AppSync. Cela garantirait que l'exécution n'attend pas que l'appel soit terminé, mais à la place, les données les plus importantes soient chargées en premier.


Une fois l'appel renvoyé, nous mettrions simplement à jour l'interface utilisateur et afficherions la notification à l'utilisateur.

J'utiliserais également des notifications sous forme de pop-ups pour signaler à l'utilisateur lorsqu'une action a été réalisée avec succès ou non.


Par exemple, je créerais un message contextuel qui indiquerait à l'utilisateur si la mise à jour de l'article a échoué.

Validation frontale

Étant donné que la validation back-end a été effectuée, nous avons dû offrir à l'utilisateur une expérience encore meilleure en implémentant la validation sur le front-end pour donner à l'utilisateur un retour plus rapide.


Heureusement, Aurelia dispose d'un plug-in de validation et est correctement implémenté avec une interface fluide. Cela facilitait la création de règles métier qui limitaient, par exemple, le nombre de caractères que l'utilisateur pouvait saisir dans un champ <input>, pour un nom d'article.


J'utiliserais le système de liaison de propriété Aurelia pour collecter les messages de validation, puis les afficher sur l'interface utilisateur. Je devrais en outre intégrer cela au système de localisation et m'assurer que les messages sont affichés dans la bonne langue.

Finaliser le travail

Le reste de l'année consistait à travailler sur de petits détails. Cela m'a obligé à créer des choses comme charger des espaces réservés. J'ai spécifiquement décidé que je ne voulais pas afficher les espaces réservés de chargement en tant qu'éléments d'écran séparés.


Au lieu de cela, je voulais indiquer à l'utilisateur qu'un élément est en cours de chargement. C'est pourquoi j'ai utilisé le contour de l'élément en cours de chargement et leur ai donné une animation de chargement transparente à la place. Cela a été inspiré par l'application mobile Netflix qui fonctionne de la même manière.


À ce stade, la fin de l'année est arrivée et je travaillais maintenant sur la page d'accueil principale. Cette page n'afficherait que toutes les communautés que nous avons actuellement. Heureusement, le système à base de composants que j'ai créé plus tôt a permis de réutiliser assez facilement la plupart du code que j'ai écrit, de sorte que la tâche a été accomplie rapidement.


L'année s'est enfin terminée et j'étais satisfait du travail qui a été fait. Même si le projet n'était pas encore terminé, je savais que le succès était à ma portée.

2022 — Le dernier kilomètre

Cette année devait être la dernière année. Je ne savais pas si j'allais réellement mettre en œuvre tout ce que je voulais, mais je savais que je devais le faire quoi qu'il arrive.


Je ne voulais pas répéter le travail pendant l'été comme je l'ai fait l'année dernière car il était plus probable qu'il fasse encore plus chaud que l'année dernière.


Ma prédiction s'est réalisée et il s'est avéré que Tokyo avait la température estivale la plus chaude en 2022, mesurée au cours des 147 dernières années !

La conception de la page de destination

J'ai commencé par concevoir la page de destination. La question était la suivante.


Comment est-ce que je veux que mes utilisateurs se sentent lorsqu'ils visitent ma page de destination ?


Je ne voulais pas que les utilisateurs aient l'impression que ce serait trop sérieux d'un site Web, mais plutôt une communauté amicale et collaborative.


J'ai remarqué que ces derniers temps, les pages de destination comportaient des illustrations plutôt que des photographies de personnes réelles, il serait donc logique de suivre cette voie. C'est pourquoi j'ai opté pour un jeu d'illustrations que j'ai acheté sur Adobe Stock .


La page de destination devait être simple et devrait également décrire rapidement tout ce que le site Web propose. Cela devait également être localisé, j'ai donc utilisé la fonction de localisation pour traduire tous les titres et sous-titres de la page de destination qui sont affichés.


Le seul problème technique qui devait être surmonté était de savoir comment introduire de la couleur à l'intérieur du texte. Heureusement, j'ai pu utiliser la fonction de style dans les définitions de traduction, puis utiliser Markdown pour générer dynamiquement le code HTML qui serait affiché sur la page de destination.


Les données requises, telles que la « Politique de confidentialité » et les « Conditions d'utilisation » ont été achetées en ligne et traduites en plusieurs langues à l'aide de Google Traduction.

Attendez-vous à l'inattendu

Il était maintenant temps de résoudre tous les problèmes, j'ai donc passé le reste du temps à m'assurer que la journalisation était présente dans toutes les fonctions Lamda du back-end. Cela m'aiderait à m'assurer que si des problèmes devaient survenir, je saurais ce qui se passait.


Au moment où je terminais, la guerre en Ukraine avait commencé. Cela a encore accru l'incertitude de l'économie mondiale, mais j'ai continué à travailler et à rester concentré sur l'objectif final.

N'ayant pas tenu à jour l'implémentation de la PWA, je devais m'assurer que toutes les fonctionnalités fonctionnaient, et donc, des développements supplémentaires étaient nécessaires pour améliorer JavaScript et la mise en cache des images.


La fonction hors ligne a finalement été activée et l'application se comportait désormais correctement comme une application hors ligne.


J'ai également dû déplacer les modifications que j'avais apportées à l'arrière-plan et diffuser les modifications que j'avais apportées sur AppSync à d'autres régions. Comme il serait trop lourd de le faire pendant le développement, je n'ai apporté aucune modification aux autres régions depuis que j'ai commencé à développer.


Il en va de même pour les environnements. Cela aurait fait perdre trop de temps à construire constamment les trois environnements, j'ai donc finalement pris du temps pour synchroniser tous les environnements et déplacer le code vers UAT et Production.


Enfin, j'ai dû implémenter le domaine https://immersive.community, qui devrait fonctionner sans le sous-domaine "www" et rediriger correctement vers la page d'accueil.


À ce stade, nous étions aux petites heures du matin du 25 avril 2022 . Mon projet de 4 ans était enfin terminé. J'ai créé le premier message sur le site Web et je me suis endormi. Je savais que j'avais finalement réussi. Non seulement j'ai fini ce que j'avais prévu de faire, mais je l'ai aussi fait avant l'été.

Derniers mots

Ironiquement, les derniers mots de mon aventure, c'est que ce n'est pas la fin, mais juste le début. Maintenant que le système est en ligne, le contenu qui doit être créé et la promotion et la publicité qui seront nécessaires pour la notoriété de la marque seront une toute nouvelle aventure.


Mais qu'ai-je réellement appris de cet exercice ?


Eh bien, beaucoup. Tout d'abord, je peux dire avec confiance que je ne le ferai plus jamais.


Non pas que je ne sois pas content du résultat, bien au contraire, je suis très satisfait, mais c'est le genre de chose qu'on fait une fois dans sa vie et ça n'aurait pas de sens d'essayer de se surpasser, simplement pour prouver que vous pouvez le faire encore mieux.


Je voulais savoir s'il était possible de construire un système au niveau de l'entreprise en tant que développeur solo et j'ai montré que cela pouvait être fait avec la pile technologique que nous avons à notre disposition.


Plus que tout, il s'agit d'une déclaration à tous les développeurs travaillant sur leur projet parallèle ou envisageant d'en démarrer un.


Est-ce que je recommanderais cette approche à d'autres développeurs ? Absolument. Pas parce que c'est une façon optimale de faire les choses, ce n'est certainement pas le cas.


Ne pas demander de l'aide lorsque vous êtes bloqué n'est certainement pas le moyen le plus rapide de résoudre un problème, mais cela vous aidera à découvrir vos limites.


Une fois que vous avez décidé de faire quelque chose comme ça, et que vous avez réussi, vous saurez que tout ce que vous avez décidé de faire après cela sera plus facile à réaliser.


Je crois que mon histoire vous motivera à terminer tout ce que vous avez commencé, peu importe ce que vous ressentez et même si vous ne voyez pas la fin de la route que vous empruntez maintenant, rappelez-vous simplement que "là-bas" n'est pas là où vous voulez être .


Si vous avez trouvé cette histoire inspirante, abonnez-vous à ma chaîne YouTube car je vais commencer à suivre un cours de programmation avancé "Full Stack Dev" où j'entrerai dans les détails de toutes les technologies que j'ai utilisées pour créer des communautés immersives.


Ce que je n'ai pas abordé dans cet article, ce sont les fondements philosophiques et les justifications de la façon dont j'ai abordé chaque problème et les techniques que j'ai utilisées pour analyser et concevoir les solutions à chaque problème.


C'était un élément encore plus important que de simplement connaître les technologies et comment les utiliser. La façon dont vous abordez un problème et votre processus de réflexion, qui vous amène à la solution, est quelque chose que j'approfondirai dans mes vidéos YouTube.


Ce sera un excellent moyen pour les développeurs d'apprendre la programmation de quelqu'un qui a créé un système réel et qui est prêt à partager ses connaissances. À bientôt sur YouTube !


Également publié ici