J'adore démarrer divers projets parallèles, je pense que c'est l'un des meilleurs moyens d'apprendre quelque chose de nouveau et qui en vaut vraiment la peine. Et j'ai un grave défaut - je ne fais presque jamais rien. Il ne s’agit bien sûr pas de projets d’études pour lesquels je recevrai une note ou des tâches fixées par l’employeur. Je parle de mes propres idées avec lesquelles je m'illumine en dehors du travail ou des études constants. Chaque fois que je maîtrise une compétence complètement nouvelle que je considère comme recherchée et que je ne vois pas la perspective d'apprendre quelque chose d'autre comme ça, j'oublie du tout le projet. Mais cette fois, j'ai décidé de m'améliorer - de démarrer le projet, de le terminer et de raconter le chemin que j'ai parcouru.
Un peu de moi
J'ai une formation spécialisée, une licence en mathématiques, une maîtrise en informatique. Étonnamment, pas mal de choses que je maîtrisais à l'université m'ont été utiles, en particulier le master. Dans tous les cas, j'ai réussi à orienter mon cerveau dans la bonne direction afin d'absorber de manière productive les informations nécessaires, de bien me montrer dans ce domaine, de trouver un emploi et d'avancer dans ma carrière.
Pendant mes études, j'étais fan de C ++ et développeur de jeux. Ensuite, j'ai développé un moteur auto-écrit et écrit des jeux dessus, essayé. J'avais un diplôme en C et j'étais lié à l'utilisation de processeurs graphiques dans les calculs. Ensuite, je me suis intéressé au développement Java et Android. Il a réalisé plusieurs projets pédagogiques dans cette langue, puis, dans le cadre d'un projet étudiant, avec le soutien d'une société internationale, a écrit un utilitaire de console pour analyser les performances du programme. Tout cela est ensuite devenu une application Android avec la possibilité de tester votre téléphone en termes de performances et de le comparer avec les autres.
Le monde des python était à l'horizon. De manière inattendue, à la suggestion de mon bon ami, je me suis intéressé à la science des données et au python, c'était il y a plus de quatre ans. Par coïncidence, j'ai dû changer de poste et mes compétences ont été jugées appropriées pour commencer à travailler sur des backends pour des services d'analyse internes. Ainsi, grâce à l'analyse de données, je suis arrivé au développement Web dans ce langage.
Par devoir, je devais également être un développeur full-stack lorsque les vrais développeurs frontaux étaient extrêmement occupés ou lorsque les normes de qualité de l'interface utilisateur n'étaient pas en premier lieu.
Ceci est une description du chemin qu'il a fallu pour créer votre propre application Web à part entière sans immersion totale dans les détails techniques. Les liens vers les commits de mon référentiel seront supprimés en cours de route. En bref sur les étapes de ce voyage:
- UI
- , , CI
- production-
- production-
- https
- AWS. , .
Le choix du sujet de l'application est une autre histoire, le choix final s'est porté sur le suivi des habitudes. La page d'accueil aurait un ensemble de boutons avec des habitudes suivies. Nous avons fait une action - appuyé sur le bouton - et ainsi de suite. Les données doivent être enregistrées et affichées sur une page séparée sous la forme d'un tableau, des habitudes en lignes et des jours civils en colonnes, une cellule remplie indique que l'action requise a été effectuée ce jour-là. Comme un simple tracker d'habitude papier.
La pile technologique était pour moi une évidence: react, django, postgres, nginx, uwsgi.
Interface utilisateur initiale de la mise en page
J'ai décidé de partir de l'interface utilisateur et j'ai installé nodejs.org/en/download/package-manager , github.com/facebook/create-react-app , puis j'ai créé un projet:
npx create-react-app easytrack
Et j'ai commencé la mise en page. Depuis le tout début, je n'ai rien trouvé de plus facile que de coder en dur une liste d'objets de logique métier directement dans le programme et de les afficher sous forme de liste dans la balise ul. Ces objets sont: le groupe de sujets, l'élément suivi, les enregistrements de suivi réels pour un élément spécifique un jour spécifique.
Sur la première page, j'avais des groupes thématiques, et en cliquant sur l'un d'entre eux, une liste d'éléments pouvant être suivis était ouverte.
J'ai également créé une autre page, qui contenait un simple tableau avec des statistiques pour les derniers jours.
Développer un backend
À ce stade, un backend était nécessaire. Il est nécessaire pour enregistrer les objets dans la base de données, gérer les utilisateurs et différencier les droits. Je devais déjà utiliser Django pour mes propres projets (pas amené à sa conclusion logique, bien sûr), mais il y avait une difficulté - je devais utiliser Django Rest Framework, que je n'avais jamais traité du tout. Merci à Building Django 2.0 Web-applications [1]. Je l'ai parcouru de bout en bout, sauf pour le dernier chapitre, où ils ont créé des API sur DRF, je l'ai parcouru des yeux. Au cours de l'histoire, je me tournerai vers elle plus d'une fois.
Nulle part où aller, a ouvert la documentation www.django-rest-framework.org et a commencé à la fumer, et s'est également tournée vers le livre mentionné.
J'ai installé et activé l'environnement virtuel, installé Django et créé un projet django à la racine du projet:
virtualenv venv
. ./venv/bin/activate
pip install django
django createproject config
Je vais renommer le dossier principal en django, de sorte que par le nom tout ce qui concerne son contenu soit immédiatement clair. À l'intérieur, il y aura un module python appelé config, qui est également très pratique. Code frontal enveloppé dans le dossier react. C'est ainsi que s'est développée la structure générale des dossiers, qui a survécu jusqu'à ce jour ( regardez Github ).
A la racine du projet, j'ai créé l'application principale:
django createapp core
Création de classes de modèles de logique métier dans exactement le même format dans lequel je les ai codés en dur à l'avant, des sérialiseurs et des vues ( lien pour commettre dans Github ).
Nous ne nous soucions pas de la base de données et utilisons le SQLite par défaut. Grâce au panneau d'administration, j'ai téléchargé quelques échantillons de données de test que j'avais codés en dur plus tôt à l'avant. Nous essayons de nous connecter au frontend. python3 manage.py runserver dans un onglet, le fil démarre dans un autre et conduit.
Le serveur de développement React fonctionne sur le port 3000 et Django sur le port 8000. Rien de plus simple que d'écrire une requête fetch ('http: // localhost: 8000 / ...') à l'avant. Mais cela n'a pas fonctionné de cette façon à cause de cors-origin - une protection spéciale qui empêche tout site de faire des requêtes automatiques à n'importe quel serveur. Par conséquent, sans réfléchir à deux fois, je l'ai intégré dans le backenddjango-cors-headers ), l'a configuré - cela a fonctionné. Ce n'est qu'alors que j'ai deviné ajouter une section proxy à package.json et pointer vers le backend, puis fetch ('/ api / v1 / ...') a commencé à fonctionner normalement et aucun paramètre supplémentaire n'était plus nécessaire.
Au début, c'était terriblement naïf, car j'avais fait des requêtes asynchrones dans le constructeur - tout fonctionnait pour moi et d'accord. Ce n'est que plus tard que j'ai appris les méthodes du cycle de vie, où vous pouvez et où vous ne devriez pas faire ce genre de travail. Maintenant que les éléments étaient affichés, de nouveaux éléments pouvaient être créés.
Mettre en œuvre la gestion des utilisateurs et la séparation des droits
À ce stade, la seule chose qui manquait était la séparation des droits sur les éléments de données: ils ont tous été créés pour le compte d'un utilisateur anonyme non connecté. J'avais besoin de m'y intégrer d'une manière ou d'une autre sans briser l'écosystème django.
Pour commencer, j'ai codé en dur le login / mot de passe sur le frontend et j'ai formé l'en-tête Authorization avec la valeur 'Basic' + base64.encode (username + ":" + password). Ensuite, j'ai pensé à générer une chaîne au format base64 et à la sauvegarder sur le client lors de la saisie d'un nom d'utilisateur / mot de passe. Mais il y avait de gros doutes sur cette décision en termes de sécurité, je voulais essayer quelque chose de différent.
J'ai fouillé sur Internet pendant une courte période et j'ai découvert la technologie JWT et le module django-rest-framework-simplejwqui fournissait des classes d'authentification pour DRF et des vues pour obtenir une paire de jetons et pour mettre à jour un jeton d'accès.
Du côté frontal, il suffisait de sauvegarder quelques jetons dans localStorage et de passer l'en-tête Authorization avec la valeur "Bearer access-token". Enfin, j'ai présenté les pages de connexion et fermé tous les accès des utilisateurs non autorisés au site en utilisant des classes d'autorisation ( lien vers le commit Github ). Sur le front, s'il n'y avait pas de jeton d'actualisation, je suis redirigé vers la page de connexion ( lien vers le commit Github ).
Ensuite, j'ai rendu possible l'inscription sur le site, créé une vue sur le backend, aménagé une page, mis en place l'envoi de requêtes. Dans le futur, mon rêve était d'écrire l'activation de compte par mail.
Refactoriser, implémenter les fonctions de base manquantes, CI
En ce moment, une application peu utilisable s'est avérée et je voulais recueillir des commentaires. J'ai montré l'application à ma femme et j'ai demandé à l'utiliser sans une seule invite de ma part. L'inscription a été plutôt réussie, mais tout ne s'est pas déroulé comme je le pensais. Ensuite, j'ai réalisé que les dossiers thématiques ne devraient pas être au premier plan, mais devraient être un outil auxiliaire, et nous devons également ajouter des indices que nous créons un ensemble de boutons pour les appuyer une fois par jour. Elle s'attendait à ce que ce soit comme un tracker d'habitude papier ordinaire avec une feuille de calcul où vous devez peindre sur des cellules. Quand j'ai réalisé cela, j'ai commencé à refactoriser. Et à part ça, il y avait quelque chose à refactoriser. J'ai revu la structure du module presque à partir de zéro.
À ce stade, j'ai décidé d'ajouter de la beauté, des styles css et une mise en page réactive. En cela, je ne suis pas particulièrement fort et je me suis appuyé sur des cadres CSS. Le choix s'est porté sur Bulma , en fonction du nombre d'étoiles, des téléchargements de npmjs.com , malgré le fait que je ne voulais pas prendre Bootstrap. À tout le moins, j'ai fait face à cette tâche.
En parallèle, j'ai amélioré les fonctions du backend. Fabriqué un CRUD complet. Le rêve de confirmer l'inscription par courrier est également devenu réalité. J'ai compris les fonctions d'envoi de lettres, j'ai acquis la possibilité de tout déboguer via un serveur de messagerie de débogage.
python -m smtpd -n -c DebuggingServer localhost:1025
Pour la mise en scène, j'ai créé un compte Google indésirable et j'ai réussi à configurer l'envoi de lettres via Google mail.
En ce qui concerne la couverture des tests pour le backend, tout s'est plutôt bien passé pour lui-même, mais pour le frontend, tout est encore assez lent. Mais je ne désespère pas, du coup il s'avérera être ajusté.
L'étape suivante a été de configurer CI, j'ai démarré GithubActions pour exécuter les tests, utilisé les constructeurs de configuration pour le lancer, je l'ai un peu peaufiné et c'est tout.
Générer des paramètres pour l'environnement de production
Après une courte période de mise en ordre du code et des petits détails de la logique, j'ai dû commencer à former la configuration de production. Pour cela, je me suis inspiré du même livre [1]. J'ai divisé les fichiers de configuration django, les dépendances python en 3 parties ( lien vers le commit Github ):
- commun - tout ce dont vous avez besoin pour n'importe quel environnement
- dev —
- prod —
, .
uwsgi, nginx , dockerfile, .
[1] «1 — 1 », , , . phusion/baseimage, Ubuntu, .
, , postgres, . ( Github).
production-
, [1], AWS, . , - . , , , , . Free Tier, , , ? .
, AWS - , . , . , ECS.
Elastic Container Service
J'ai vu que le générateur Actions Github vous permet de créer une configuration pour une tâche de déploiement de conteneur continue sur AWS ECS. Disons que j'ai commencé à me plonger dans ce service et réalisé que dans la console locale, je dois créer un cluster, créer une définition de tâche et décrire le conteneur, après avoir précédemment enregistré son image dans un autre service AWS ECR, qui est Dockerhub par fonction. La console proposait 2 types de clusters: Fargate et EC2. La première technologie est totalement sans serveur, ce qui signifie que nous démarrons simplement le conteneur et que le runtime s'occupe de tout. Les conteneurs d'un cluster du deuxième type s'exécutent sur leur propre instance de machine virtuelle dans le cloud. Ne voulant pas m'y plonger pendant longtemps, j'ai créé un cluster basé sur Fargate. Mais je suis tombé sur le fait que je ne pouvais pas transmettre de valeurs secrètes au conteneur,à cause de cela, la tâche diminuait constamment.
Alors que j'essayais de mettre le conteneur en état de fonctionnement, le cluster fonctionnait depuis plusieurs heures et de l'argent a été ajouté à mon onglet avec le paiement des services. La technologie elle-même s'est avérée payante et ne s'applique pas à l'offre gratuite. J'ai payé le cluster et j'ai décidé de traiter le paiement un peu plus tard. J'ai lu dans la documentation que vous n'avez pas besoin de payer de supplément pour utiliser ECS au-dessus d'EC2, sauf pour utiliser les ressources EC2, mais EC2 est couvert par Free Tier et j'ai décidé d'essayer ce chemin.
Assistance AWS
En fin de compte, quelqu'un m'a menti et ils m'ont facturé un peu plus d'argent pour cette configuration. Un total de 0,32 $, bien qu'un peu, mais toujours dommage. Ensuite, j'ai écrit à l'appui, j'ai dit que j'avais des difficultés avec la configuration et que je pensais tout le temps que je rentre dans le Free Tier, mais rien n'a fonctionné pour moi, et l'argent a été retiré. J'ai demandé de l'aide. En réponse à mon appel, ils ont répondu avec joie, ont donné un bon de 1 $, qui couvrait toutes les dépenses imprévues. Bien.
En conséquence, j'ai dû oublier ce service de conteneurs et maîtriser EC2 dans sa forme la plus pure.
Cloud informatique élastique
EC2 — . Free Tier 750 . , , - , .
[1] docker-machine, . , EC2. docker .
, dockre-machine create… EC2. docker-compose up -d . 80 . , «Public DNS» , .
Relational Database Service
AWS RDS. . , ( postgres) , Free Tier, . , , .
Simple Email Service
J'ai également dû faire face au fait que les lettres n'avaient pas été envoyées. Le fait est que tous les services de messagerie interdisent les adresses IP qui correspondent aux instances EC2 afin de lutter contre le spam. Il était impératif d'utiliser SES. Un autre service AWS.
Je l'ai également configuré, indiqué les boîtes aux lettres à partir desquelles je vais envoyer des lettres, tout va bien. Cependant, tout n'est pas si rose jusqu'à présent. Les nouveaux comptes sont en mode sandbox par défaut, ce qui ne permet pas d'envoyer des e-mails à des boîtes aux lettres non confirmées. J'ai dû confirmer les boîtes pour mes bêta-testeurs.
Enregistrer un domaine et configurer un certificat pour l'accès https
Pour tester complètement l'application, il était nécessaire de configurer une connexion https, ce qui s'est avéré impossible sans enregistrer un domaine. Je ne voulais pas mettre en danger les adresses e-mail, les mots de passe et les jetons en les transférant via une connexion non sécurisée. Pour ce cas, j'ai cherché sur tout Internet. Certains bureaux d'enregistrement ne convenaient pas, car c'est cher, mais quelque part c'est très cher, en plus, beaucoup ont juste des critiques terribles. Pendant que je cherchais, le réseau publicitaire Yandex a compris ce que je voulais et m'a tout de suite proposé une entreprise où vous pouvez enregistrer un domaine pour 39 roubles. Il y avait plus d'avis sur ce service, alors j'ai créé un compte, choisi un domaine gratuit et l'ai enregistré pour moi.
Ensuite, afin d'accéder à mon instance EC2 à l'aide de ce domaine, j'ai créé une zone d'hébergement dans le service AWS Route 53, enregistré les paramètres DNS et réécrit les enregistrements NS dans le compte personnel du service où le domaine était enregistré sur Amazon.
J'ai utilisé le service Let's Encrypt pour créer le certificat. Je me suis arrêté à cette configuration: le nginx local fait un proxy_pass à l'adresse du conteneur, le conteneur tourne et est accessible via le port 8080. Il n'a pas été difficile d'utiliser l'utilitaire de console certbot, générer un certificat et configurer automatiquement https. Enfin, autorisez l'accès à la machine virtuelle sur le port 443.
Le développement du projet est arrivé à sa conclusion logique
, . , , SES , . , . , , , , , , , , . , , . :
- , , . .
- -
- ,
- , -
— , , . React , AWS, , , .
Mais la principale réalisation est que quelqu'un sur le terrain n'est pas du tout un guerrier. J'ai travaillé sur ce projet pendant plus de deux mois, de nombreuses heures pendant mon temps libre ... Et vous savez quoi? Je n'ai jamais cousu aussi terriblement. On remarque que plus on vieillit, moins on a envie d'apprendre quelque chose «comme ça», moins on a envie de travailler beaucoup sur des choses qui sont «simplement intéressantes». Mais en même temps, vous remarquez qu'il existe plus d'occasions de faire quelque chose pour le bien, pour le bénéfice. Vous commencez à apprécier les efforts ciblés, le travail d'équipe, ainsi que la relaxation, le temps passé avec des personnes proches.