Comment réussir son projet avec une équipe IT externe?
Que votre projet soit urgent ou non, trouver LE bon partenaire numérique pour assurer le développement de votre projet est souvent un vrai casse-tête.
Tout d’abord, comprenons qu’avoir recours à de l’aide externe est une pratique courante.
Il faut savoir qu’en choisissant de faire appel à un prestataire, on peut y gagner sur de nombreux aspects :
Peu importe le besoin : développer un logiciel, créer une web app, une application mobile, développer un Saas, etc.., force est de constater que la plupart des PME / ETI et des grands groupes finissent par faire appel à un prestataire de services pour externaliser toutes ou certaines parties de leurs développements.
Reste à savoir maintenant quel prestataire choisir, et là, il en existe plusieurs sortes !
1. Quel type de prestataire de service choisir pour mon projet numérique?
Avant de vous orienter vers un partenaire numérique, il est important de prendre en compte plusieurs éléments.
Tout d'abord, si vous disposez déjà d'une équipe interne et souhaitez la renforcer avec des consultants externes, un freelance ou une ESN (SSII) pourront être de bons choix.
Ils peuvent fournir des ressources supplémentaires et apporter leur expertise et ainsi monter en compétences votre équipe actuelle.
Cependant, si votre projet est complexe et nécessite une expertise spécifique, il est préférable de faire appel à une agence digitale spécialisée dans le développement de solutions sur mesure.
Ces agences disposent d’équipes complètes de professionnels du numérique, tels que des designers UX/UI, des développeurs, des tech leads, QA, DevOps, project managers, etc.
Ils ont l’habitude de travailler ensemble et avec une organisation et des méthodes de travail qui ont été peaufinés au fil du temps et des projets passés.
Ils sont spécialisés dans la création et le déploiement de plateformes numériques de A à Z.
Regardez-les comme des partenaires : en choisissant une agence digitale, vous bénéficiez d'une expertise technique, d'une expérience professionnelle et d'une méthodologie de travail éprouvée.
Ils sont en mesure de comprendre vos besoins et de vous proposer des solutions sur mesure pour répondre à vos attentes.
De plus, les agences digitales sont souvent à la pointe des dernières technologies et peuvent vous aider dans le choix des outils et des plateformes les mieux adaptés à votre projet.
Comme on vient de le voir, le choix du prestataire de service pour votre projet numérique dépend de plusieurs facteurs
2. Quel modèle d’externalisation de service numérique choisir?
Maintenant que vous connaissez le type de prestataire dont vous avez besoin.
Il existe plusieurs façons d’engager les services de développement d’une agence digitale :
- Offshore
On appelle Offshore le fait d’engager les services d’un prestataire issu d’un pays plus éloigné géographiquement. Au plus souvent, c'est l’Inde qui est plébiscité par son faible coût. La Roumanie, la Tunisie et nouvellement l’Argentine sont aussi fréquemment demandées.
La principale (et l’une des seules) raison qui pourrait vous faire choisir l’Offshoring : le faible coût de la main d’œuvre.
Malheureusement, et même si le prix est souvent le critère principal aux yeux des acheteurs, il y a beaucoup de désavantages à cette méthode d’outsourcing.
- La qualité est très généralement médiocre. (absence de documentation, oubliez ici le CleanCode, les meilleures pratiques et les tests unitaires)
- La barrière de la langue. (même si souvent, c’est la langue anglaise qui est utilisée, il n’en est pas moins que la communication s’en trouvera très affectée)
- Le décalage horaire, rendant la coordination difficile
- Les changements d’équipe, qui vont ralentir les développements, car la connaissance fonctionnelle du prestataire va s’effriter (surtout s’il n’y a pas de documentation)
- La sécurité de vos données n’est pas assurée (sécurité de l'application)
Aussi, une application n’est pas juste l’aboutissement d’un projet initial. Elle vit, elle évolue avec le temps en fonction des besoins de votre entreprise et des utilisations. Il faut donc penser à son évolution:
- Comptez-vous y ajouter de nouvelles fonctionnalités dans le futur?
- Est-ce que la performance est importante pour vous et votre audience?
- Allez-vous faire reprendre ce projet par un partenaire plus local ou en interne?
Dans la majorité des cas, la faible qualité du code rendra obligatoire le développement d’une nouvelle plateforme et l’investissement n’en sera que plus important. Le gain que vous pensiez faire initialement se retournera alors contre vous.
- Nearshore
Bien plus proche que l’Offshore, on entend ici les sociétés de services basées dans un pays voisin ou frontalier.
Dans un cadre culturellement similaire, les coûts sont légèrement réduits et les consultants sont parfois mieux encadrés qu’en offshore.
Avec un décalage horaire moins ressenti, les méthodes de gestion peuvent être les mêmes que les vôtres.
Cependant, bien que les coûts soient inférieurs à un développement local et la communication plus simple qu’avec une société offshore, la qualité du code peut être moindre et les performances ainsi que les possibilités d'évolution du projet seront impactées.
En conclusion, le nearshore peut être un compromis intéressant pour les entreprises souhaitant externaliser leurs services de développement numérique, mais il est important de bien peser les avantages et les inconvénients avant de prendre une décision.
- Onshore
On fait ici appel aux services d’un partenaire local ou basé dans votre pays.
L’investissement varie selon votre région/ville, et les avantages sont aussi plus conséquents.
- Une facilité des échanges entre les équipes
- Une vraie protection de la propriété intellectuelle
- Du personnel qualifié
- Une équipe prête à challenger vos idées et vous conseiller
- Une assurance sur la qualité et les performances
- Un réel process de transmission de projet.
Avec toutes ces informations, vous devriez être en mesure de savoir quel mode convient le mieux pour votre projet numérique.
3. Les 10 questions à poser avant de s’engager avec un prestataire de service numérique
Vous avez sélectionné une ou plusieurs agences / entreprises de services numériques et êtes sur le point de les rencontrer.
Ces sociétés ne travaillent pas toutes de la même façon et n’ont pas toutes les mêmes compétences technologiques.
Confier partiellement ou en totalité un projet peut parfois donner la migraine, encore plus quand le prestataire est situé à l’autre bout de la planète.
Lors des premiers échanges, vous serez challengé, alors faites en de même! Posez-leur les bonnes questions :
- Quelles technologies vont être utilisées pour votre projet ?
(Php, Symfony, Javascript, Typescript, Node.js, React, React Native, Python, Angular, Flutter, Java, etc…) - Est-ce que le prestataire utilise les dernières versions de ces technos ? (Pensez aussi à la maintenance de votre future plateforme !)
- Allez-vous trouver facilement des ressources expertes sur ces technologies si vous avez besoin de recruter ou de changer de prestataire ?
- Le prestataire a-t-il des références de projet similaire au vôtre ?
- Si vous avez une équipe interne, le prestataire est-il en mesure de respecter vos normes de code ? cleancode ?
- Gestion de projet : travaille-t-il en méthodologies Agile ?
- Quid des tests unitaires, d’intégration, fonctionnels ?
- Est-il opérationnel sur des sujets DevOps ?
- Peut-il vous accompagner sur l’ergonomie de votre application (Design UX/UI) ?
- Quelle est la composition de l’équipe imaginée pour vous et depuis quand les membres sont-ils dans l’entreprise ? (Stabilité et séniorité de l’équipe)
- Etc…
Avec tous ces éléments en main, vous êtes maintenant capable de sélectionner la méthode la plus adéquate pour votre projet et avez toutes les clés pour choisir le bon partenaire.
Pour aller plus loin, vous pouvez aussi consulter notre article de blog : comment bien choisir son partenaire numérique.
Did this article start to give you some ideas? We’d love to work with you! Get in touch and let’s discover what we can do together.
Further Reading
Approche minimaliste de DataOps et MLOps avec DVC et CML
Dans cet article, nous examinerons l'importance cruciale de DataOps et MLOps dans le développement logiciel et en IA. Nous présenterons une approche MVP pratique, mettant l'accent sur l'utilisation de DVC (Contrôle de Version de Données) et CML (Apprentissage Automatique Continu), intégrés à Git, pour illustrer efficacement ces concepts.
- Approche Pratique : En utilisant DVC et CML, nous démontrerons une approche pratique de produit minimal viable (MVP) pour DataOps et MLOps.
- Intégration avec Git : En mettant en évidence l'intégration fluide de ces outils avec Git, nous montrerons comment les flux de travail familiers peuvent être améliorés pour la gestion des données et des modèles.
- Implémentation Efficace : Notre objectif est de fournir des directives claires pour implémenter efficacement les pratiques DataOps et MLOps.
Problèmes Courants dans les Projets AI & Data
- "Quelle Version de Données ?" Perdez-vous constamment la trace de la version de données utilisée pour l'entraînement du modèle ?
- "Le Nouveau Modèle Est-il Bon ?" Arrêtez de vous demander si votre dernier modèle bat l'ancien ou ce qui a changé entre eux.
- "Pourquoi Notre Dépôt Est-il Si Lourd ?" Dépôt GitHub surchargé avec des données ?
Compréhension de DataOps et MLOps
DataOps et MLOps sont des pratiques fondamentales pour le développement logiciel moderne, en particulier en IA. Ces approches sont essentielles pour gérer efficacement les cycles de vie des données et des modèles d'apprentissage automatique.
- Scalabilité : Gérer efficacement les données (DataOps) et les modèles d'apprentissage automatique (MLOps) est essentiel pour construire des systèmes d'IA évolutifs et robustes, cruciaux pour les projets de développement logiciel.
- Performance et Fiabilité : La mise en œuvre de ces pratiques garantit des performances système constantes et une fiabilité, ce qui est particulièrement vital pour les start-ups opérant dans des environnements dynamiques et contraints en ressources.
- Éviter les Pièges : De nombreuses équipes de développement ont besoin de versionner correctement les données et les modèles ou adoptent une approche réactive de la gestion système, ce qui entraîne des défis significatifs en matière de reproductibilité et d'augmentation des taux d'erreur, entravant la croissance et l'innovation.
Comprendre et intégrer DataOps et MLOps dans les flux de travail n'est pas seulement bénéfique ; c'est une nécessité stratégique.
L'Approche MVP
L'approche MVP (Produit Minimal Viable) en DataOps et MLOps consiste à s'aligner sur les principes fondamentaux du Manifeste Agile, en mettant l'accent sur la simplicité, l'efficacité et le déploiement.
- Principes Agiles : Mettez l'accent sur la simplicité, l'efficacité et les processus axés sur les personnes, favorisant la flexibilité et la réactivité dans la gestion de projet.
- Réduire la Dépendance aux Systèmes Complexes : Plaidez pour une minimisation de la dépendance aux systèmes SaaS complexes et propriétaires, maintenant ainsi le contrôle et la flexibilité dans votre développement.
- Outils Efficaces : Exploitez des outils comme DVC et CML qui s'intègrent avec les flux de travail Git familiers ; cette approche garantit une adoption fluide et améliore la collaboration et l'efficacité de l'équipe.
Adopter une approche MVP signifie créer des flux de travail en DataOps et MLOps plus agiles, adaptables et efficaces, permettant le développement de solutions robustes et évolutives sans être encombré par des complexités inutiles.
Pratique
Maintenant, nous plongeons dans les aspects pratiques de la mise en place d'un environnement Python et de l'utilisation d'outils essentiels comme DVC, CML et SciKit-Learn. Nous passerons par la configuration d'un dépôt GitHub pour un contrôle de version efficace et démontrerons la construction et l'évaluation d'un modèle en utilisant SciKit-Learn dans un calepin Jupyter.
- Configuration : Configurez un environnement Python et installez DVC, CML et SciKit-Learn.
- Construction de Modèle : Utilisez SciKit-Learn avec un ensemble de données intégré dans un calepin Jupyter pour une démonstration simple d'entraînement et d'évaluation de modèle.
- Processus Simplifié : Configurez GitHub et Git pour exécuter et évaluer votre modèle.
Installez l'Environnement Python
Nous utiliserons Poetry pour gérer notre environnement Python. Poetry est un outil de gestion de dépendances Python qui vous permet de créer des environnements reproductibles et d'installer facilement des packages.
# Install Poetry
pipx install poetry
# Init Poetry project
poetry init
# Add dependencies
poetry add dvc cml scikit-learn
Chargement des données
Nous utiliserons l'ensemble de données sur leBreast Cancer Data Set de UCI Machine Learning Repository.
Caractéristiques clés :
- Nombre d'Instances : 569
- Nombre d'Attributs : 30 attributs numériques prédictifs, plus la classe.
- Attributs : Mesures telles que le rayon, la texture, le périmètre, la zone, la régularité, la compacité, la concavité, les points concaves, la symétrie et la dimension fractale.
- Distribution des Classes : 212 Malignes, 357 Bénignes.
import sklearn.datasets
# Load dataset
data = sklearn.datasets.load_breast_cancer(as_frame=True)
print(data.data.info())
Mise en Œuvre de Paramètres Externes pour les Ajustements de Données et de ModèlesNous utiliserons des fichiers de configuration externes, comme settings.toml, pour ajuster dynamiquement les paramètres des données et du modèle. Cette approche ajoute de la flexibilité à notre projet et souligne l'importance de la versionnage et du suivi des changements, surtout lors de l'introduction de modifications intentionnelles ou de "bugs" à des fins de démonstration.
Dégradation des Données avec des Paramètres Externes
Parce que l'ensemble de données de démonstration fonctionne bien avec un modèle simple, nous allons dégrader artificiellement les données pour souligner l'importance du suivi des changements et de la versionnage.
- Configuration Externe : Utilisez settings.toml pour définir des paramètres comme num_features=1, qui dicte le nombre de fonctionnalités à utiliser à partir de l'ensemble de données.
- Manipulation des Données : Nous modifions dynamiquement nos données en lisant le paramètre num_features depuis settings.toml. Par exemple, en réduisant l'ensemble de données à une seule fonctionnalité :
python
import toml
settings = toml.load("settings.toml")
data.data = data.data.iloc[:, : settings["num_features"]]
print(data.data.info())
Entraînement du Modèle
We'll use SciKit-Learn to split the data and train a simple model.
python
import sklearn.model_selection
# Split into train and test
X_train, X_test, y_train, y_test = sklearn.model_selection.train_test_split(
data.data, data.target, test_size=0.3, random_state=42
)
python
import sklearn.linear_model
# Train a simple logistic regression model
model = sklearn.linear_model.LogisticRegression(max_iter=1000)
model.fit(X_train, y_train)
python
# Evaluate the model
predictions = model.predict(X_test)
accuracy = sklearn.metrics.accuracy_score(y_test, predictions)
print(f"Model Accuracy: {accuracy:.2f}")
Model Accuracy: 0.91
python
# View the classification report
report = sklearn.metrics.classification_report(y_test, predictions)
print(report)
# Export the report to a file
with open("report.txt", "w") as f:
f.write(report)
precision recall f1-score support
0 0.93 0.83 0.87 63
1 0.90 0.96 0.93 108
accuracy 0.91 171
macro avg 0.92 0.89 0.90 171
weighted avg 0.91 0.91 0.91 171
python
import seaborn as sns
import matplotlib.pyplot as plt
# Create a confusion matrix
confusion_matrix = sklearn.metrics.confusion_matrix(y_test, predictions)
# Plot the confusion matrix
sns.heatmap(confusion_matrix, annot=True, fmt="d")
# Export the plot to a file
plt.savefig("confusion_matrix.png")
Sauvegarde du modèle et des données
Nous allons sauvegarder le modèle et les données localement pour démontrer les capacités de suivi de DVC.
pythonCopy code
from pathlib import Path
# Sauvegarder les données
Path("data").mkdir(exist_ok=True)
data.data.to_csv("data/data.csv", index=False)
data.target.to_csv("data/target.csv", index=False)
pythonCopy code
import joblib
# Sauvegarder le modèle
Path("model").mkdir(exist_ok=True)
joblib.dump(model, "model/model.joblib")
Mise en œuvre de la versionnage des données et des modèles avec DVC
Jusqu'à présent, nous avons couvert les aspects standards du développement de l'IA et de l'apprentissage automatique. Nous entrons maintenant dans le domaine du versionnage des données et du suivi des modèles. C'est là que la véritable magie du développement efficace de l'IA se manifeste, transformant la gestion et l'évolution de nos projets de machine learning.
- Meilleures opérations : Le versionnage des données et le suivi des modèles sont cruciaux pour la gestion des projets d'IA.
- Versionnage des données : Gérer efficacement les changements de données et maintenir une précision historique pour la cohérence et la reproductibilité des modèles.
- Suivi des modèles : Commencer à suivre les itérations des modèles, identifier les améliorations et assurer un développement progressif.
Rationaliser le flux de travail avec les commandes DVC
Pour intégrer efficacement le contrôle de version des données (DVC) dans votre flux de travail, nous décomposons le processus en étapes distinctes, assurant une approche fluide et compréhensible du versionnage des données et des modèles.
Initialisation de DVC
Commencez par configurer DVC dans votre répertoire de projet. Cette initialisation pose les bases pour le versionnage et le suivi des données.
bashCopy code
dvc init
Configuration du stockage distant
Configurez un stockage distant pour DVC. Ce stockage hébergera vos données et modèles versionnés, assurant leur sécurité et accessibilité.
bashCopy code
dvc remote add -d myremote /tmp/myremote
Versionnage des données avec DVC
Ajoutez les données de votre projet à DVC. Cette étape versionne vos données, vous permettant de suivre les changements et de revenir en arrière si nécessaire.
bashCopy code
dvc add data
Versionnage des modèles avec DVC
De même, ajoutez vos modèles de ML à DVC. Cela garantit que vos modèles sont également versionnés et que les changements sont suivis.
bashCopy code
dvc add model
Validation des modifications avec Git
Après avoir ajouté des données et des modèles à DVC, validez ces changements avec Git. Cette étape lie votre versionnage DVC avec le système de contrôle de version de Git.
bashCopy code
git add data.dvc model.dvc .gitignore
git commit -m "Add data and model"
Pousser vers le stockage distant
Enfin, poussez vos données et modèles versionnés vers le stockage distant configuré. Cela sécurise vos données et les rend accessibles pour la collaboration ou la sauvegarde.
bashCopy code
dvc push
Marquage d'une version
Créez une étiquette dans Git pour la version actuelle de vos données :
bashCopy code
git tag -a v1.0 -m "Version 1.0 of data"
Mise à jour et versionnage des données
- Modifiez vos données : Modifiez votre
data.csv
si nécessaire. - Suivre les changements avec DVC : Exécutez de nouveau
dvc add
pour suivre les modifications :
bashCopy code
dvc add data
- Validez la nouvelle version avec Git : Validez le fichier DVC mis à jour avec Git :
bashCopy code
git add data.dvc
git commit -m "Update data to version 2.0"
- Marquer la nouvelle version : Créez une nouvelle étiquette pour la version mise à jour :
bashCopy code
git tag -a v2.0 -m "Version 2.0 of data"
Basculer entre les versions
- Rétablir une version précédente : Pour revenir à une version précédente de vos données, utilisez Git pour passer à l'étiquette correspondante :
bashCopy code
git checkout v1.0
- Revenir aux données avec DVC : Après avoir récupéré l'étiquette dans Git, utilisez DVC pour revenir aux données :
bashCopy code
dvc checkout
Comprendre le suivi des données avec DVC
DVC offre une approche sophistiquée de la gestion des données en suivant les pointeurs et les hachages des données plutôt que les données elles-mêmes. Cette méthodologie est particulièrement significative dans le contexte de Git, un système non conçu pour gérer efficacement les fichiers volumineux ou les données binaires.
Comment DVC suit les données
- Stockage des pointeurs dans Git : DVC stocke de petits fichiers
.dvc
dans Git. Ces pointeurs font référence aux fichiers de données réels. Chaque pointeur contient des métadonnées sur le fichier de données, y compris une valeur de hachage identifiant de manière unique la version des données. - Valeurs de hachage pour l'intégrité des données : DVC génère un hachage unique pour chaque version de fichier de données. Ce hachage assure l'intégrité et la cohérence de la version des données suivies. Toute modification des données entraîne un nouveau hachage, facilitant la détection des modifications.
- Séparation des données et du code : Contrairement à Git, qui suit et stocke chaque version de chaque fichier, DVC conserve les données réelles séparément dans un stockage distant (comme S3, GCS ou un système de fichiers local). Cette séparation des données et du code empêche de gonfler le dépôt Git avec des fichiers de données volumineux.
Importance dans le contexte de Git
- Efficacité avec les données volumineuses : Git rencontre des difficultés avec les fichiers volumineux, entraînant des performances lentes et un gonflement du dépôt. DVC contourne cela en déchargeant le stockage des données. Les développeurs peuvent utiliser Git comme prévu - pour le code source - tandis que DVC gère les données.
- Contrôle de version amélioré : DVC étend les capacités de contrôle de version de Git aux fichiers de données volumineux sans surcharger l'infrastructure de Git. Les équipes peuvent suivre les modifications des données avec la même granularité et simplicité que les modifications du code source.
- Collaboration et reproductibilité : DVC facilite la collaboration en permettant aux membres de l'équipe de partager facilement et de manière fiable des données via un stockage distant. La reproductibilité est améliorée car DVC garantit l'alignement correct des versions des données et du code, ce qui est crucial dans les projets de science des données et d'apprentissage automatique.
Utiliser DVC comme un magasin de fonctionnalités
DVC peut être un magasin de fonctionnalités dans les flux de travail de machine learning. Il offre des avantages tels que le contrôle de version, la reproductibilité et la collaboration, rationalisant la gestion des fonctionnalités à travers plusieurs projets.
Qu'est-ce qu'un magasin de fonctionnalités ?
Un magasin de fonctionnalités est un référentiel centralisé pour stocker et gérer les fonctionnalités - des morceaux de logique réutilisables qui transforment les données brutes en formats adaptés aux modèles de machine learning. Les principaux avantages d'un magasin de fonctionnalités incluent :
- Cohérence : Assure un calcul uniforme des fonctionnalités à travers différents modèles et projets.
- Efficacité : Réduit les calculs redondants en réutilisant les fonctionnalités.
- Collaboration : Facilite le partage et la découverte des fonctionnalités parmi les équipes de science des données.
- Qualité et conformité : Maintient une source unique de vérité pour les fonctionnalités, améliorant la qualité des données et aidant à la conformité aux réglementations de données.
Avantages de DVC dans la gestion des fonctionnalités
- Contrôle de version pour les fonctionnalités : DVC permet le contrôle de version des fonctionnalités, permettant de suivre l'évolution des fonctionnalités.
- Reproductibilité : Assure que chaque entraînement de modèle est traçable à l'ensemble exact des fonctionnalités utilisées.
- Collaboration : Facilite le partage des fonctionnalités entre les équipes, assurant la cohérence et réduisant la redondance.
Configuration de DVC en tant que magasin de fonctionnalités
- Organisation des données de fonctionnalités : Stockez les données de fonctionnalités dans des répertoires structurés dans votre dépôt de projet.
- Suivi des fonctionnalités avec DVC : Utilisez DVC pour ajouter et suivre les fichiers de fonctionnalités (par exemple,
dvc add data/features.csv
). - Validation des changements de fonctionnalités : Validez les modifications avec Git aux côtés des fichiers
.dvc
pour maintenir l'historique de l'évolution des fonctionnalités.
Utilisation de DVC pour les mises à jour et les retours en arrière des fonctionnalités
- Mise à jour des fonctionnalités : Suivez les changements en relançant
dvc add
sur les fonctionnalités mises à jour. - Retours en arrière : Utilisez
dvc checkout
pour revenir à des versions spécifiques des fonctionnalités.
Meilleures pratiques pour utiliser DVC comme un magasin de fonctionnalités
- Mises à jour régulières : Maintenez le magasin de fonctionnalités à jour avec des validations régulières.
- Documentation : Documentez chaque ensemble de fonctionnalités, en détaillant la source, la transformation et l'utilisation.
- Intégration avec les pipelines CI/CD : Automatisez les tests de fonctionnalités et le déploiement des modèles en utilisant des pipelines CI/CD intégrés avec DVC.
Mise en œuvre d'un magasin de fonctionnalités basé sur DVC dans plusieurs projets
- Stockage centralisé des données : Choisissez un stockage partagé accessible par tous les projets et configurez-le comme un stockage distant DVC.
- Versionnage et partage des fonctionnalités : Contrôlez la version des ensembles de données de fonctionnalités dans DVC et poussez-les vers le stockage centralisé. Partagez les fichiers .dvc entre les projets.
- Extraction des fonctionnalités dans différents projets : Clonez les dépôts et extrayez les fichiers de fonctionnalités spécifiques en utilisant DVC, permettant leur intégration dans divers flux de travail.
Meilleures pratiques pour gérer un magasin de fonctionnalités basé sur DVC à travers plusieurs projets
- Documentation : Maintenez une documentation complète pour chaque fonctionnalité.
- Contrôle d'accès : Mettez en place des mécanismes pour réguler l'accès aux fonctionnalités sensibles.
- Stratégie de versionnage : Développez une stratégie claire pour le versionnage des fonctionnalités.
- Automatisation des mises à jour : Utilisez des pipelines CI/CD pour mettre à jour et valider les fonctionnalités.
Rationaliser les flux de travail de ML avec l'intégration de CML
Intégrer le Continuous Machine Learning (CML) est une révolution pour le CI/CD dans le machine learning. Cela automatise les processus critiques et assure un flux de travail plus rationalisé et efficace.
Configuration des flux de travail CML
Créez un workflow GitHub Actions dans votre dépôt GitHub, en vous assurant qu'il est configuré pour s'exécuter à chaque push ou PR.
yamlCopy code
name: model-training
on: [push]
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Poetry
run: pipx install poetry
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
cache: "poetry"
- name: Install dependencies
run: poetry install --no-root
- uses: iterative/setup-cml@v2
- name: Train model
run: |
make run
- name: Create CML report
env:
REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "```" > report.md
cat report.txt >> report.md
echo "```" >> report.md
echo "![](./confusion_matrix.png)" >> report.md
cml comment create report.md
Conclusion : Améliorer les opérations logicielles et d'IA
Pour conclure, nous avons exploré le cœur des pratiques DataOps et MLOps, démontrant leur rôle vital dans le développement logiciel moderne, en particulier dans l'IA. En maîtrisant ces pratiques et outils comme DVC et CML, vous apprenez de nouvelles techniques et améliorez votre ensemble de compétences en tant que développeur logiciel.
- Restez agile et évolutif : Adopter DataOps et MLOps est essentiel pour se développer dans le monde rapide de l'IA et maintenir vos projets agiles et évolutifs.
- Exploitez des outils puissants : La maîtrise de DVC et CML vous permet de gérer les données et les modèles de manière efficace, vous rendant plus compétent et polyvalent.
- Apprentissage et application continus : Le voyage ne s'arrête pas ici. Le véritable potentiel est réalisé en appliquant et en affinant continuellement ces pratiques dans vos projets. Cela va au-delà de la simple amélioration des processus ; il s'agit d'améliorer vos flux de travail de développement pour répondre aux demandes évolutives de l'IA et de l'ingénierie logicielle.
Comment détecter « les angles morts » de votre application TypeScript
Vous codez en TypeScript. Tout est beau. Vous avez dit adieu à l'infâme undefined is not a function
de JavaScript et vous ne regrettez rien !
Et pourtant, une erreur s'affiche à votre écran :
Un instant … comment est-ce possible?!
Vous pensez, en tant que développeur TS légitimement confus : comment une telle erreur a-t-elle pu passer inaperçue ? Est-ce que quelqu’un a utilisé any
quelque part ?
Eh bien, non. Du moins, pas directement. C'est une bonne nouvelle.
La mauvaise nouvelle, c'est que vous avez certainement beaucoup … beaucoup plus d'angles morts dans votre application TypeScript. Et vous venez d'en découvrir un !
Des histoires comme celle-ci sont courantes. Parfois, elles peuvent avoir des conséquences terribles pour le produit, comme les unités principales Mazda qui ont été bloquées à cause d'une station NPR locale de Seattle en 2022 😅
Ces erreurs potentielles sont externes à votre logiciel, elles proviennent du « monde extérieur », chose qui ne se contrôle pas. Elles prennent différentes formes, mais ici je me concentrerai sur les 3 plus courantes :
- Les entrées clients
- Les réponses des API tierces
- L’extraction de données
Voyons comment aborder ces problèmes et ce qu'ils ont en commun.
Les angles morts sont partout
1. Les entrées clients
Le terme « Client » fait référence aux utilisateurs ou aux systèmes qui fournissent des entrées à votre système. Cela peut inclure :
- Un utilisateur final de votre application
- Une autre application qui utilise votre API
- Un développeur qui utilise votre CLI (Command-line interface)
Si vous avez le contrôle sur différents systèmes qui communiquent entre eux (par exemple, client <> serveur), vous devriez trouver un moyen de partager les types entre vos systèmes. tRPC est un excellent outil pour construire des API sûres sur le plan des types et obtenir une certaine sécurité du côté client. Il utilise également les techniques que je vous mentionne ci-dessous 😉
Maintenant, allez à la périphérie de vos systèmes et considérez les différents endroits où les utilisateurs externes vous fournissent des entrées au cours de la phase d’exécution (runtime).
Vous devez valider ces entrées en temps d’exécution
Vous connaissez peut-être déjà le dicton :
Ne jamais faire confiance aux entrées utilisateurs.
Il y a toujours un XKCD pertinent : https://xkcd.com/327/
Peu importe si l'utilisateur est malveillant, il y a une chose dont vous pouvez être sûr : TypeScript ne peut pas imposer les types sur les données en temps d'exécution. Vous devez valider ce qui entre dans votre système. Il est préférable que cela échoue rapidement si ça ne correspond pas aux types attendus.
Pour être plus précis, le type de l'entrée utilisateur est unknown
. Vous souhaiteriez qu'il s'agisse d'un string
ou qu'il suive une certaine interface d'objet. Mais vous ne pouvez pas obliger le client à faire ce qu'il faut. Quelque chose doit vérifier les données en temps d'exécution, et TypeScript ne peut le faire.
2. Réponses des API tierces
Il existe différents niveaux de confiance lorsque l’on travail avec une API externe :
🟢 Ils vous fournissent un « Typed SDK ».
🟡 Ils n'ont pas de « Typed SDK », mais ils ont une documentation en ligne !
🟠 Eh bien, ils ont une certaine forme de documentation dans un fichier .docx
🔴 Attendez, quelle documentation ? Oh, celle-ci est obsolète, désolé(e) !
La documentation des API tierces est facilement erronée, à moins qu'elle ne soit générée à partir du code source, ce qui, selon mon expérience, n'est pas chose courante. Pourtant, j'ai travaillé sur des projets TypeScript où les types de l'API externe étaient transcrits à partir de la documentation dans des fichiers .d.ts
.
Imaginez tomber sur ce fichier asana.d.ts
qui tente de compenser l’absence de SDK dans TypeScript :
// https://developers.asana.com/docs/taskexport interface AsanaTask { gid: string; resource_type: string; approval_status: 'pending' | 'approved' | 'rejected' | 'completed'; // …}
Eh bien, cela demanderait beaucoup de travail et d'optimisme.
En production, Asana peut rencontrer un problème et le champ resource_type
peut manquer à l’appel lors de l’entrée d’une réponse. Pourtant, notre code s'attend à ce que ce champ soit présent. Et ainsi, cela brise nos « attentes »... et possiblement notre application à un moment ultérieur. Retour au pays du JavaScript.
Alors, que pouvez-vous faire ?
Vous devez valider les réponses des API tierces en temps d'exécution.
Puisque vous ne pouvez pas être certain que Asana se comportera comme « documenté » dans toutes les situations au moment de l'exécution, vous devez constamment vérifier. La plupart du temps, Asana se comportera comme prévu, mais, si ce n’est pas le cas, vous la détecterez immédiatement et vous empêcherez que ce problème ait des répercussions sur votre système.
3. Extraction de données depuis la BD
Cela peut être moins évident. Les bases de données sont fiables. Mais le sont-elles vraiment ?
Eh bien, comme pour tout ce qui est suffisamment complexe dans la vie : ça dépend™.
Encore une fois, cela dépend de votre niveau de confiance et donc de vos réponses au questions suivantes :
- Y a-t-il des schémas stricts pour les données stockées ? Pensez aux bases de données SQL par rapport aux bases de données NoSQL.
- Les schémas sont-ils liés à vos définitions de types? (La vérité dupliquée peut se désynchroniser)
- Les gens peuvent-ils modifier les données sans utiliser votre application?
- Y a-t-il des scripts qui peuvent mettre à jour les données sans utiliser votre application?
- Y a-t-il d'autres applications qui peuvent mettre à jour les données sans utiliser votre application?
Vous voyez, tous les types dans votre backend TypeScript ne peuvent pas empêcher un acteur externe de se connecter directement à votre base de données et de perturber les données. Si la protection du type n'est pas au niveau de la base de données, vous pourriez ne pas extraire les types auxquels vous pensez accéder.
Les bases de données SQL correctement construites inspirent plus confiance que les documents NoSQL qui peuvent stocker n'importe quoi.
Si, comme moi, vous utilisez Firestore en ce moment, sachez que n'importe quel client a un accès direct à votre « base de données cloud NoSQL évolutive ». La saisie du code à propos de ce qui devrait être extrait d'un abonnement peut entraîner des erreurs en production.
db .collection('ad-campaigns') .onSnapshot( (snapshot) => { const campaigns = snapshot.docs.map( // ❌ This may be false and you won't handle it! (d) => d.data() as Campaign[] ) setAdCampaigns(campaigns) } )
Que faire lorsque vous ne pouvez pas être sûr que votre base de données n’à pas été altérée ?
Vous devez valider les données extraites de la base de données en temps d'exécution.
Je suis sûr que vous commencez à comprendre le schéma ici 😉
Maintenant, voyons comment vous pouvez facilement valider les données en temps d'exécution...
Zod à la rescousse !
Théoriquement, la validation des données en temps d'exécution consiste à :
- Déclarer ce type de données comme étant de type
unknown
- Vérifier le schéma des données et générer une erreur si ce n'est pas ce que vous attendiez
De cette façon, TypeScript s'assurera que nous ne formulons pas d'attentes que nous n'avons pas encore vérifiées.
app.get("/price", (req, res) => { const code = req.query.code as unknown; // We can't use code as a string here, TS would complain… if (typeof code !== 'string') { return res.sendStatus(400) } // Now we KNOW code is a string})
Nous pourrions le faire tout en construisant une collection de « helpers » qui réduisent le code redondant... ou nous pouvons utiliser une bibliothèque qui remplira cette tâche pour nous !
Il existe plusieurs bibliothèques de validation de données disponibles, telles que Joi ou Yup. Mais Zodest devenue assez populaire et a été conçue en premier lieu pour TypeScript.
L'utilisation de Zod pour valider les données se fait en 2 étapes :
- Définir le schéma
- L'utiliser pour analyser les données en temps d'exécution
app.get("/price", (req, res) => { const code = req.query.code as unknown; // We can't use code as a string here, TS would complain… if (typeof code !== 'string') { return res.sendStatus(400) } // Now we KNOW code is a string})
L'API Zod vous permet de déclarer un schéma de manière très similaire à la déclaration d'interfaces :
const userSchema = z.object({ username: z.string(), location: z.object({ latitude: z.number(), longitude: z.number(), }), strings: z.array(z.object({ value: z.string() })),});
Ainsi, vous pouvez commencer à définir le schéma et utiliser schema.safeParse(data)
pour valider ce qui se passe au moment de l'exécution :
app.get("/users", (req, res) => { const result = userSchema.safeParse(req.query.user); // Fail early if (!result.success) { return res.status(400).json(toErrorResponse(result.error)) } const user = result.data // Now we KNOW user follows the schema…})
Et en ce qui concerne la duplication?
Vous l’aviez peut-être remarqué, mais vous avez maintenant dupliqué la source de vérité :
- Dans votre type
User
existant - Dans votre nouvelle définition
userSchema
Vous voyez, Zod s'en occupe pour vous : il peut déduire le type à partir des schémas. Vous n'avez pas à maintenir les types et les schémas en parallèle, les types sont générés à partir des schémas :
type User = z.infer<typeof userSchema>// Now you can use this User type anywhere you need!
Et qu'en est-il de ma documentation d'API ?
Vous ne voulez pas être le fournisseur d'API tierces avec une documentation obsolète ? Super !
Le truc reste le même :
- Avoir une seule source de vérité
- Générer le reste à partir de celle-ci
Ici, nous traitons maintenant de :
- Types
- Schémas
- Spécifications d'API
La meilleure façon que j'ai trouvée pour les maintenir tous synchronisés est de partir des spécifications d'API. Je vous recommande d'utiliser la norme OpenAPI pour décrire à quoi ressemble votre API. En prime, vous pouvez utiliser des outils qui généreront une documentation interactive et esthétique comme Swagger.
Une fois que vous avez vos spécifications OpenAPI, vous pouvez utiliser https://github.com/drwpow/openapi-typescript pour générer des types TypeScript.
Maintenant que nous avons les spécifications d'API et les types, nous avons besoin d'un moyen de générer les schémas aussi. C'est là que https://github.com/fabien0102/ts-to-zod entre en jeu. Il générera des schémas Zod à partir des définitions de types TS, ce qui est pratique lorsque vous avez les types avant les schémas.
Investissez un peu de temps et vous devriez être en mesure de créer une seule commande qui régénérera vos types et schémas d'API chaque fois que vos spécifications OpenAPI seront mises à jour. Voilà 🎂
Ne saisissez pas ce que vous ne possédez pas
Lorsque vous n'avez pas le contrôle sur les données, il est plus sûr de les traiter comme étant de type unknown
. Autrement, cela peut créer des angles morts dans votre application et vous causer de gros problèmes à l'avenir.
- Validez les données qui entrent dans votre système en temps d'exécution.
- Générez des types à partir des schémas de validation.
« Devrais-je le faire partout ? »
Ça dépend™. Probablement pas. C'est une question de gestion des risques.
À quel point avez-vous confiance en ces types ? Quelles seraient les conséquences si les choses tournent mal ? Avez-vous déjà des erreurs de type en production ?
Commencez par les parties les plus risquées de votre application. Faites des itérations.
« Aurai-je moins d'erreurs d'exécution? »
Oui !
Eh bien, vous pourriez voir plus d'erreurs au début. C'est ce qui se produit lorsque vous mettez en évidence un problème : il devient évident pour tout le monde. Lorsque vous intégrez une nouvelle API tierce, vous vous rendrez compte que certaines de vos attentes ne correspondent pas à la réalité. Je dirais que c'est un avantage !
Cela vous donnera l'opportunité de corriger les erreurs qui, autrement, auraient été ignorées jusqu'à très tard dans le processus.
« Il y a cette autre équipe au travail qui casse notre application chaque fois qu'ils modifient l'API sans nous le dire...»
Vous êtes le client d'une API que vous ne possédez pas, même si la propriété est au sein de votre entreprise. C'est en fait un problème très classique. Les Context Maps de la conception orientée domaine peuvent vous aider à rendre ce problème visible pour tous.
Maintenant, devriez-vous faire confiance à l’API de l’autre équipe et mettre en place un schéma de validation ? Ça dépend™ 🌈
La validation des données en temps d'exécution a un coût. C'est plus de code à maintenir et plus de choses qui peuvent mal tourner. Lorsque vous n'avez pas le contrôle sur les données entrantes, cela en vaut la peine : Zod vous permet d’économiser du temps sur certains bugs que vous n'aurez pas à corriger.
Mais vous avez peut-être d'autres options !
Rappelez-vous ce que je vous ai dit si vous étiez responsable à la fois du client et du serveur : partagez les types entre eux. C'est moins de surcharge et vous obtiendrez les mêmes résultats.
Posez-vous donc ces questions :
- Pourraient-ils vous fournir un « typed SDK » qu'ils maintiennent ?
- Pourriez-vous partager les types avec cette autre équipe dont vous dépendez ?
- Si vous partagez les types mais qu'ils les cassent régulièrement, pourriez-vous introduire une sorte de versioning ? Pensez aux espaces de noms…
- Pourriez-vous mettre en place des tests de contrat entre vos équipes pour détecter toute incompatibilité avant qu'elle n'atteigne la production ?
Dans le pire des cas, vous traitez cette API comme ce en quoi vous ne pouvez pas avoir confiance et que vous ne possédez pas; donc validez les données en temps d'exécution.
Au moins, vous serez en mesure d'identifier la source du bug immédiatement (« L'équipe B a cassé notre application 5 fois ce trimestre »), et peut-être mettre en place une logique de secours pour protéger vos utilisateurs finaux.
Astuces et meilleures pratiques pour Flutter
Au cours des dernières années, Flutter a gagné en popularité. Et pour de bonnes raisons : il s'agit d'un incroyable framework de développement d'applications multiplateformes qui vous permet de créer des applications pour les appareils mobiles, Web, de bureau et intégrés, le tout à partir d'une seule base de code. L'une des principales raisons pour lesquelles de nombreuses entreprises envisagent aujourd'hui d'utiliser Flutter est notamment due au fait qu'il fonctionne dès sa mise en place, qu'il est open source et qu'il est plus facile à comprendre que d'autres alternatives, ce qui le rend idéal pour les MVP (produit minimum viable).
Je travaille avec Flutter depuis plus d'un an maintenant. Je n'avais aucune expérience préalable avec les frameworks mobiles et Flutter a été ma première plongée dans le monde mobile. Je suis une développeuse Full Stack chez Osedea avec une formation en JavaScript, j'avais une relativement bonne base pour commencer avec Dart (langage de programmation derrière le framework Flutter). Dart est un langage relativement nouveau qui compile le code source à la fois en avance (AOT) et juste à temps (JIT). Il est similaire à JavaScript, mais le SDK Dart autonome est livré avec une machine virtuelle Dart et possède son propre « package manager » appelé pub.
Voici certaines choses que vous devez savoir si vous commencez, ou envisagez de commencer à travailler avec Flutter.
Connaître la langue
Tout d'abord et le plus important c’est de connaître votre langage. Bien que Dart soit très similaire à JavaScript, vous devez tout de même connaître les bases : l’étendue des variables et des méthodes, la sécurité nulle et l'opérateur bancaire, l'opérateur clé et l'utilisation de late
pour les variables non nullables. Comme JavaScript, Dart est un langage à « thread » unique, il utilise async/wait avec isolates . Les Isolates sont particulièrement utiles pour les tâches de longue durée que vous souhaitez gérer sans bloquer l'interface utilisateur. Découvrez-en plus dans la documentation officielle de Dart et comment cela s'applique à Flutter. Apprenez-le et utilisez-le s'il convient à votre projet.
Astuce : parfois, cette tâche de longue durée doit être effectuée par le backend ou un service séparé à la place.
Les widgets
Là encore, ce sont les bases, mais assurez-vous de bien les comprendre car vous les utiliserez tout le temps. Si vous avez déjà commencé à jouer avec Flutter, vous savez probablement ce que sont les widgets, avec et sans état, et à quel point il est facile de faire apparaître votre premier « Hello World » sur Android et iOS.
Assurez-vous également d'apprendre et d’explorer avec les gestures et les widget controllers. Il est également important de se familiariser avec les Layout widgets pour vous aider à créer une bonne structure dès le départ.
Suivez les mises à jour
Lorsque j'ai commencé à travailler sur le projet, nous n'avions pas encore tous les atouts de Sound Null Safety qui a été publié avec Flutter 2.0. Heureusement, l'équipe et le client étaient de notre côté et nous avons réussi à mettre à jour Flutter et à intégrer ses dernières fonctionnalités. Maintenant, nous voyons const
partout dans notre code. Ce qui est formidable, car le compilateur connaît à l'avance const
, il n'en conservera donc qu'une seule copie référencée à tout moment et ne la reconstruira pas. C'est là une amélioration de performances.
La mise à niveau vers la dernière version du framework, du langage et des bibliothèques utilisées peut entraîner des gains de performances, plus de fonctionnalités et, bien sûr, plus de sécurité, ne négligeons pas cela. En le gardant à jour, vous vous assurez de tirer le meilleur de Flutter, en résolvant potentiellement certains problèmes et en commençant à utiliser de nouveaux widgets. Et hé, Flutter pour le Web ça sonne excitant, n’est-ce pas ?
Quelques extras astucieux
Voici quelques éléments supplémentaires qui peuvent vous aider à gagner du temps :
- Capturer l'état de l'application : utilisez
didChangeAppLifecycleState
, il capture l'état de l'application si elle est en arrière-plan ou au premier plan. Par exemple, si un utilisateur avait sa caméra ouverte pendant que quelqu'un l'appelait ou s'il changeait simplement d'avis et décidait de mettre votre application en arrière-plan. Dans ce cas, vous souhaitez probablement disposer de votre contrôleur de caméra ou arrêter et reprendre certains services en fonction de l'état de l'application,didChangeAppLifecycleState
vous permettra d'attraper cet état. - Modifier la conception de la barre d'état : utilisez
SystemChrome.setSystemUIOverlayStyle
ClipRRect
est idéal pour arrondir les coins. Mais pas dans tous les cas. Si vous voulez jouer avec la forme d'un conteneur, la meilleure pratique serait d'utiliser ladecoration : BoxDecoration(…)
à la place. Et si vous avez besoin d'un avatar de forme circulaire, Flutter a un joli widget pour cela,CircleAvatar
.
J'ai partagé mon expérience avec Flutter en espérant que cela vous à été utile! Si vous avez des questions, n'hésitez pas à nous contacter!
Crédit Photo: Kelly Sikkema
Le plaisir de travailler dans un dev shop
Nous avons tous nos raisons personnelles d’aimer (espérons-le) notre boulot. Certains développeurs rêvent à l'atteinte d’un résultat précis, voir les produits prendre vie et et apporter de la valeur aux utilisateurs. D’autres sont passionnés par les moindres détails, la conception des algorithmes complexes pour le simple plaisir de résoudre des problématiques. Je suppose que la plupart des développeurs sont un mélange des deux, avec un petit quelque chose en plus. J’ai pris le temps de réfléchir sur cette question. Voici un aperçu de mon opinion à ce sujet.
Rien ne dure éternellement
Je suis passionnée par mon métier, je veux contribuer sur le long terme. Mais, la vérité est que la passion s’estompe.
Ici je ne me réfère pas à la passion de collaborer avec son équipe, mais plutôt à notre relation avec les projets et produits qui évoluent avec le temps. Travailler sur des projets reliés aux médias sociaux était peut-être ce qui nous motivait à démarrer notre journée il y a deux ans. Aujourd’hui, c’est peut-être le fait de collaborer avec une organisation à but non lucratif qui vous motive..
Comment gérer cette chute libre de notre passion pour un produit quand on aime les gens et l’ambiance de travail ? À un certain moment, on souhaite autre chose, contribuer pour avoir un impact sur le monde, tout en savourant notre café du matin.
L’expérience dans les Dev Shops (agences de développement de logiciels) est tout le contraire. Nous prenons un moment dans nos vies pour réaliser un projet, peut-être quelque chose de petit et sans signification émotionnelle ou d’énorme et ardu, puis nous le livrons et passons le bâton à nos clients. Le produit n’est jamais réellement à nous, mais nous agissons tout de même comme s’il l’était. Ce qui est particulier, c'est que nous n’avons pas carte blanche sur les priorités et le travail que nous devons accomplir. Nous ne choisissons pas qui vient frapper à notre porte avec une idée et une passion, mais nous l’acceptons quand même. C’est un cycle de découverte, de confort, de joie, puis de perte.
Si vous aimez quelque chose, libérez-le. La suite ne se résume pas aux tâches à effectuer. Il y a les personnes avec qui nous avons collaboré, les connexions que nous avons établies et les connaissances et l’expertise partagées qui constituent notre succès.
Le monde ne bouge pas vite, nous oui.
Les voitures vont vite aux yeux des gens debout.
Je me suis souvent questionnée sur la durée de vie de nos compétences techniques. Lors de mon premier emploi dans le domaine des logiciels, on m’a dit que les grands programmeurs ne sont jamais dépassés, ils s’adaptent au monde qui les entoure. La triste vérité est que la grande majorité des programmeurs ne sont pas « extraordinaires ». Nous ne passons pas 20 heures par semaine à lire le dernier livre d’informatique, et nous ne nous mettons pas en quatre pour être toujours à la pointe du nouvel outil qui a piqué la curiosité des gens sur les réseaux sociaux. Nous mettons en œuvre les spécifications qui nous sont données avec un succès modéré et nous nous assurons que nous en savons juste assez pour passer à l’itération suivante. Mais que se passe-t-il lorsque tout change et les besoins de l’entreprise ne sont pas en parfaite harmonie avec nos connaissances ?
C’est là que les agences sont avantageuses pour ceux qui peuvent apprendre en permanence, car elles nous placent sur la voie rapide de l’autoroute de l'apprentissage.
Sauter d’un projet à l’autre est… difficile (c’est le moins qu’on puisse dire). La gestion du stress est une compétence requise, ainsi qu’une bonne gestion de la charge mentale. Mais une fois que ces compétences deviennent acquises, l’adaptation devient la norme, nous avançons à la vitesse maximale.
Le grand T
Dans le contexte d'une firme de développement logiciel sur mesure, l’équipe de développement s'identifie facilement à l’expression « Masters of none, jack of all trades » (personne capable de tout faire, mais expert en aucun domaine). La raison en est simple : il est difficile de devenir extraordinaire dans un domaine lorsque l’on doit se débrouiller dans une variété de compétences. Le développement de compétences techniques avancées prend du temps et de l'énergie. Avec la tendance Full Stack 2.0, les développeurs doivent comprendre (au moins) les technologies front-end, back-end, mobile, DevOps, etc. L'énergie et le temps consacrés à une variété des domaines peuvent diluer la maîtrise d’un domaine en particulier.
Mais les concepts ne bougent pas trop, n’est-ce pas ? Les modèles de conception/architecture dont nous sommes tous si excités aujourd’hui (ahem CQRS) ne sont pas si jeunes ou nouveaux qu’on le croit. D’un niveau débutant à expert, le terrain de jeu devient de plus en plus facile. D’après mon expérience, les développeurs dans une agence de développement peuvent commencer à prendre le fameux T-Shape après trois ans d’expérience.
Au-delà de la compétence en matière de développement de logiciels. Il est tout aussi important de se développer dans d’autres domaines. Comprendre les coûts au-delà de ce qui a été mentionné lors du dernier sprint, ainsi que les compétences générales nécessaires pour traiter avec des entreprises partenaires. Apprendre comment fonctionnent la conception et la gestion de projets numériques.
Alors, quel cadre moyennement digne de ce titre voudrait des développeurs qui ne font pas que du développement ? Ils sont payés pour coder, pas pour discuter !
Je crois fermement qu’il y a une limite à l’avance qu’une équipe peut prendre lorsque nous ne comprenons pas ce que font les autres. Mon équipe ne comprend pas seulement les autres développeurs, mais aussi les équipes de conception UX/UI, les gestionnaires de projets, les comptables, les architectes, etc., l’ensemble de l’équipe, voire de l’entreprise, évolue lorsque nous nous comprenons les uns les autres.
Ce qu'il faut retenir
À mon humble avis, l’aspect le plus important d’une agence de développement est le service qu’ils vendent. Je ne peux pas parler des autres compagnies, mais chez Osedea, ce n’est pas notre temps qui compte, mais notre culture et notre approche.
Bien sûr, nous programmons. Nous sommes des développeurs de logiciels après tout ! Mais, je pense que ce n’est qu’une partie de la solution et de ce qui nous rend exceptionnels. Notre offre va au-delà de ça : notre équipe se souci de la qualité du travail et les personnes avec qui nous collaborons; nous allons loin parce que nous avançons ensemble; nous évoluons vite parce que c’est ce que nous sommes; nous valorisons la diversité non seulement des personnes, mais aussi des idées et des solutions. Nos clients ne sont pas simplement des clients, mais des partenaires, que nous allons aider à réaliser des grandes choses.
Le tout est plus grand que la somme des parties et c’est pour cela que je choisis de travailler dans une firme de développement de logiciels sur mesure.
Photo : Chris J. Davis
Quoi ne PAS corriger dans une base de code héritée
La maintenance d'une base de code héritée n’est pas chose facile. Très souvent, il y a une quantité impressionnante de codes à refactoriser et si peu de temps pour le faire. Quand choisissez-vous de refactoriser ou de laisser tomber? Vous ne pouvez pas passer la majeure partie de votre temps à nettoyer: vous devez aussi fournir des fonctionnalités et corriger les bogues. Mais si vous ne prenez pas, ne serait-ce qu’un peu de votre temps, pour nettoyer votre code, les choses peuvent rapidement devenir plus compliquées. Vous serez ralenti dans vos progrès et vous risquez de créer plus de bogues que d'autres choses…
Des réponses comme « mesurer le coût de la dette technique » ne sont pas si utiles si elles ne vous disent pas le pourquoi du comment. En pratique, vous ne pouvez pas comparer le coût de la refactorisation à la non-refactorisation d'un morceau de code particulier. Sera-t-il changé régulièrement? Combien de temps sera-t-il maintenu? Qui va travailler dessus? Est-ce que cela causera des bogues? Très rarement vous obtiendrez des réponses précises pour ce type de question, la majorité du temps se sera plutôt des estimations intuitives. Il est cependant difficile de s’en tenir à ces «intuitions» lorsque vos collègues vous demandent si une refactorisation est de mise.
Je n'ai pas de réponse simple à ces questions. Comme souvent dans le développement logiciel, It Depends™.
Cependant, je vous propose de regarder le problème sous un autre angle! Et si nous pouvions commencer en énumérant les choses qui ne valent PAS la peine d’être réparées? Tous les problèmes n’ont pas le même impact sur votre travail. Lorsque vous traitez votre «legacy codebase», vous devez en laisser une partie de côté afin de pouvoir concentrer vos efforts sur ce qui reste.
Ne réécrivez pas tout
J'ai vu un tas de projets qui suivent ce modèle :
- La base de code se développe à mesure que l'entreprise demande des fonctionnalités et des corrections de bogues
- Les anciens développeurs quittent progressivement le projet, de nouveaux développeurs se joignent au projet
- La base de code vieillit ce qui rend le travail de l’équipe plus difficile
- L'équipe (principalement constitué de récents développeurs) veut réécrire la base de code en utilisant des outils plus modernes
À ce stade, le plan est de remplacer la «base de code héritée» existante par une nouvelle. Si l'équipe parvient à faire accepter le projet de réécriture™, le reste se passe comme suit :
- l'équipe commence à réécrire le projet ailleurs, en utilisant différents outils (encore une fois, yay!)
- Parce que la réécriture prend beaucoup de temps, l'équipe doit fournir un certain support pour l'ancien système (corrections de bogues urgents, fonctionnalités critiques, etc.). Ceux-ci qui doivent également être implémentés dans la nouvelle base de code.
- Au bout d'un moment, l'équipe essaie de remplacer l'ancien système par le nouveau. Rapidement, de nombreux problèmes sont signalés. Plus de temps est nécessaire jusqu'à ce que le remplacement puisse être effectué.
- Les anciens développeurs quittent progressivement le projet, de nouveaux développeurs rejoignent l’équipe.
- La nouvelle base de code vieillit et à nouveau le travail de l’équipe s’en retrouve affecté.
- L'équipe (principalement composé de développeurs récents) veut réécrire la base de code, en utilisant des outils plus modernes 🙃
Je ne plaisante pas! J’ai déjà passé à travers toutes ces étapes, en passant de la maintenance d’une base de code héritée jusqu’à sa tentative de réécriture, toutes deux exécutées en production. L'idée de redémarrer en remplaçant l’ancien code par des outils plus récents a été fréquemment évoquée lors des réunions.
Lorsqu'il s'agit de systèmes hérités qui servent des clients en production, une Big Bang Rewrite est rarement la solution. Non pas qu'il ne faille PAS moderniser le code. Mais, il est très naïf de penser que nous pouvons remplacer tout un système sans que les clients ne remarquent la différence.
Que faire à la place
D'après mon expérience, une meilleure approche consiste à réduire la portée de la réécriture. Identifiez une partie du système hérité et réécrivez-la. Juste ça.
Les réécritures incrémentielles peuvent être mises en production plus rapidement.
J'aime utiliser La technique du navire de Thésée pour ce faire. Elle porte aussi le surnom "The Strangler Fig Pattern” et ressemble à ceci:
Si vous recherchez un exemple réel, je vous recommande cette conférence de Adrianna Chang qui l'a appliqué sur Shopify 🪖
Ne répare pas ce qui ne fait pas entrave à ta progression
Pour être honnête, je ne pense pas que ce soit un grand dicton. C'est facile de ne pas bien le comprendre et de l'utiliser pour entraver les changements 😬
Le but n'est pas d'empêcher nos semblables de changer la façon dont les choses sont faites aujourd'hui. Je crois que les progrès doivent l'emporter sur la cohérence, mais les nouvelles normes doivent être explicites. Ainsi, je pense que c'est bien de changer quelque chose qui n'est pas « cassé » si c'est un pas vers l'état souhaité.
Cependant, cela peut rapidement devenir une distraction si vous n'êtes pas attentif.
Peut-être avez-vous déjà été dans cette situation auparavant :
- Vous voyez une ancienne syntaxe/modèle lors de la lecture du code
- Vous décidez de le moderniser au fur et à mesure
- Plus tard, lorsque vous poussez votre version, une problème est signalée
- Vous devez annuler cette modification et corriger le bogue au plus vite
- Enfin, vous passerez beaucoup plus de temps sur ce code que vous ne le pensiez
J’ai passé par là plusieurs fois. En général, c'est parce que je ne fais pas attention à l'étape 2. Par exemple, quand j'oublie de tester si mon changement a introduit une régression, peut-être que je n'étais même pas conscient du réel #oops 🤦
Cependant, nous ne devrions pas conclure qu’il faut éviter de moderniser le code après cette petite aventure.
Moderniser le code que vous devez maintenir est souhaitable. Si vous avez besoin de modifier du code, il serait sage de passer d'abord un peu plus de temps pour faciliter le changement. Mais, en tant que professionnel, vous devez être conscient des changements que vous apportez. Introduisez-vous une régression? Quel est le comportement actuel? Les tests automatisés sont généralement le moyen le plus rapide d'obtenir continuellement ces informations. Sans tests, vous devez soit les écrire (c'est long la première fois), soit les tester manuellement (c'est long à chaque fois), soit laisser quelqu'un d'autre les tester (c'est ainsi que vous êtes dérangé pour faire des corrections de bogues urgentes).
Par conséquent, ma version de ce conseil est la suivante :
Si cela n’affecte pas la valeur commerciale de votre produit, ne le corrigez pas.
Nous ne factorisons pas le code pour le plaisir. Nous factorisons le code afin de pouvoir continuer à ajouter de la valeur au logiciel sans introduire de bogues.
Plusieurs parties du code qui ne datent pas d’hier peuvent sembler très moches, mais cela n’a pas d’importance à moins que vous ne devez les lire et les mettre à jour sur une base régulière. Ne perdez pas de temps à refactoriser du code simplement parce qu'il n'est pas propre. C'est une distraction qui peut vous coûter très cher en temps. Pire : cela peut donner un mauvais goût au « refactoring », conduisant votre équipe à ne plus faire le nécessaire.
Que faire à la place
Mon point c’est qu'il faut du temps pour apporter des modifications sûres à une base de code héritée. Ainsi, vous devez réduire le nombre de modifications que vous apportez. Lorsque le temps est compté, faites des compromis sur la quantité et non sur la qualité.
Restez concentré sur la cible. Faites une chose à la fois et faites-le bien.
Votre temps est mieux utilisé pour ajouter des tests manquants et refactoriser le code qui vous gêne réellement. Rester concentré.
Si vous avez du mal à le faire, je vous recommande d'essayer la Méthode Mikado. Elle fournit une recette claire à suivre lorsque vous plongez dans l’inconnu, afin que vous restiez sur la bonne voie.
Des commits plus petits et plus fréquents peuvent également aider.
Ne perdez pas de temps avec des refactorings simples
Celui-ci est plus subtil. Il s'agit de prioriser le type de refactorisation à aborder en premier.
Certaines refactorisations sont plus faciles à réaliser que d'autres. Certains ont plus d'impact que d'autres. La difficulté et l' impact des refactorings ne sont pas nécessairement corrélés. Le piège consiste à n'opter que pour les plus faciles et à ne pas tenir compte de l'impact de ceux-ci.
Encore une fois : votre temps est compté. Il y a tellement de choses que vous devez faire avant la date limite à venir. Lorsqu'il ne vous restera plus de temps, vous aurez tendance à prendre des raccourcis quelques fois plus risqués. En règle générale, les tests sont abandonnés lorsque le temps presse. C'est pourquoi il ne faut pas perdre trop de temps sur des refactorings insignifiants qui pourraient être abordés plus tard.
Passez plutôt du temps sur les refactorisations nécessaires qui rendront le code testable. Cela sera payant car vous pourrez vous déplacer plus en sécurité et plus rapidement dans le code à mesure que les exigences changent et que la date limite approche!
Il est préférable d'expédier une refactorisation percutante plutôt que 50 petites qui n'ont que peu ou pas d'impact sur la valeur commerciale de votre produit.
Que faire à la place
Pour vous aider à identifier les parties du système hérité sur lesquelles vous feriez mieux de dépenser votre énergie, je vous recommande d'effectuer une analyse de votre code et de sélectionner les hotspots.
Vous avez besoin de 2 choses pour exécuter une telle analyse :
- Un moyen de mesurer la complexité du code. Si votre langue ne dispose pas d'un tel outil, vous pouvez utiliser le niveau d'indentation comme une métrique suffisante.
- Métadonnées de contrôle de version. Si votre projet utilise git, vous êtes prêt à partir.
Avec cela, vous pouvez rapidement rédiger un profil de votre base de code, ce qui vous aidera à prioriser le code que vous devez refactoriser en premier, en fonction de l'impact que ce refactoring aura sur votre vélocité:
En bref : concentrez-vous sur le code qui nécessite des modifications fréquentes.
Les refactorisations qui aident le plus sont les suivantes :
- Extraire la logique dans des fonctions pures que vous pouvez nommer, tester et refactoriser
- Rendre visibles les effets secondaires. En particulier, le code séparé qui renvoie une valeur du code qui effectue des effets secondaires (le principe CQS).
- Améliorer les noms. Ceci est généralement une refactorisation facile car elle peut être automatisé par votre éditeur de code (par exemple, F2 sur VS Code). Pourtant, c'est un élément clé à ne pas manquer.
- Supprimer la duplication des concepts. La duplication est moins chère à maintenir que la mauvaise abstraction. Mais, lorsque vous remarquez que les choses changent toujours ensemble, vous avez alors un bon candidat pour la refactorisation.
Enfin, je voudrais ajouter une nuance à ce conseil. Parfois, il est bon de commencer par quelques refactorisations faciles pour s'échauffer. C'est une raison valable de le faire. Mais, si vous cherchez à rendre la base de code plus facile à utiliser, ne perdez pas votre temps sur ces refactorisations trop longtemps 😉
Si vous souhaitez découvrir d'autres conseils et astuces pour améliorer votre productivité, consultez cette section de notre blogue.
Merci à Nicolas Carlo pour cette collaboration. Vous pouvez lire d’autres de ses articles sur son blogue Understand Legacy Code et le suivre sur Twitter @nicoespeon.
Crédit photo: Markus Spiske.
Allumer et éteindre une lumière de manière intelligente
Une de mes passions est d'intégrer différentes choses ensemble. Donc, en tant que projet d'été, j'ai décidé de m'essayer de faire de l'automation de maison avec des circuits électroniques et des senseurs. Je suis ici pour dire que c'est plus facile et moins dispendieux que vous le pensez. Voici un tutoriel que j'aurais aimé avoir avant de commencer.
La première chose que j'ai essayé de faire est d'allumer et d'éteindre une lumière en appuyant sur un bouton. Tout ce dont vous avez besoin est de batteries, d'une lumière, d'un bouton et voilà!
Pas très intéressant. Mais c'est correct, nous allons le faire de manière intelligente.
Le Raspberry Pi
Ceci est un Raspberry Pi. C'est un ordinateur complet qui se vend pour $45 CAD. Pour son prix, il est remarquablement bien fourni. Autre que de pouvoir exécuter le système d'exploitation Linux, il possède:
- 4 ports USB
- Ethernet Gigabit
- Une prise d'écouteurs 3.5mm
- WiFi
- Bluetooth
- Jusqu'à 8GB de mémoire de vive, dépendant des variantes
- Jusqu'à 2 prises HDMI supportant chacun des écrans 4K, dépendant des variantes
- Une tête d'entrée / sortie à usage général (en anglais: General-Purpose Input / Output, ou GPIO)
C'est cette tête GPIO qui est particulièrement intéressante pour l'automatisation. La tête GPIO est composée d'une série de 40 broches (ou pins en anglais) qui peuvent soit:
- Générer 3.3 volts
- Générer 5 volts
- Est mis-à-terre (grounded en anglais)
- Possède l'habileté de contrôler le voltage d'une broche ou bien d'obtenir le voltage appliqué à la broche à partir d'un logiciel (appelé les broches GPIO)
Chaque broche est généralement identifiée par un nombre. Voici un schéma qui identifie ces broches (ceci va être utile plus tard) :
Il existe un schéma de numérotation alternatif, mais nous allons garder les choses simples dans ce tutoriel. Notez aussi que les broches GPIO supportent au plus 3.3 volts, donc il n'est pas possible de raccorder une broche 5 volts à une broche GPIO. Très important à savoir pour ne pas griller votre Raspberry Pi…
Voltages et GPIOs
Le voltage peut être décrit comme une différence d'énergie potentielle. Une bonne analogie est celle de la chute d'eau: l'eau en haut de la chute possède une forte énergie potentielle, et durant sa chute, son énergie potentielle baisse. On dit que c'est de l'énergie potentielle puisque l'eau d'elle même ne possède aucune énergie, mais des tâches peuvent être accomplies avec de l'eau qui tombe: il est possible de mettre une turbine pour générer de l'électricité, de mettre des roches en dessous pour éventuellement les éroder, etc. S'il n'y avait pas de différence de hauteur entre le haut et le bas de la chute d'eau (essentiellement du sol plat), il n'y aurait pas de libération d'énergie potentielle. La hauteur de la chute d'eau peut être considérée comme le voltage dans un circuit électronique.
Quand on dit qu'une source électrique fournit 3.3 volts, on y décrit la différence entre l'état élevé d'énergie potentielle (référencée par +
, 1
ou HIGH
) et l'état bas d'énergie potentielle (référencée par -
, 0
ou LOW
). Dans le Raspberry Pi, les broches de mise-à-terre (ou ground en anglais) représentent l'état bas d'énergie potentielle et les broches qui fournissent 3.3 volts possèdent une énergie potentielle relative à la mise-à-terre. Les broches identifiées comme GPIO peuvent être contrôlées à partir d'un logiciel pour émettre soit un état HIGH
ou LOW
, ou bien pour lire le voltage appliquée à la broche.
Comprendre les platines d'expérimentation
Même si son nom semble complexe, les platines d'expérimentation sont un outil simple pour prototyper des circuits électroniques. Les circuits prototypées sur une platine d'expérimentation peuvent être convertis en un circuit électronique qu'on peut retrouver dans des jouets par exemple.
La platine d'expérimentation (breadboard en anglais) est une série de trous connectés d'une manière spécifique en dessous. Des personnes voulant prototyper un circuit vont prendre des fils et connecter les trous du dessus ensemble. Depuis le dessous, le courant électrique peut parcourir deux chemins. Si nous nous concentrons sur la moitié de gauche de la platine, le courant parcourt les deux colonnes de trous de gauche. Ces deux colonnes transportent généralement le +
et le -
. Puis, les ensembles de cinq trous de droite sont connectés en ligne. Chaque ligne est indépendante des autres. La même configuration est inversée sur le côté droit de la platine d'expérimentation.
Il est fréquent de connecter la source d'alimentation aux colonnes +
et-
, d'utiliser des fils de petite taille pour transporter le courant des deux colonnes vers des lignes spécifiques, et finalement de connecter les composantes électroniques sur les lignes. Voici un exemple d'un circuit fermé, ce qui veut dire que le courant passe de 3.3 volts sur la broche 1 directement vers la mise-à-terre à la broche 9:
Allumé et éteint
Maintenant que nous avons établis les bases, nous allons commencer par allumer et éteindre une lumière à partir d'un logiciel. Pour accomplir cette tâche, nous devons pouvoir envoyer un signal HIGH
et LOW
à la lumière en utilisant une broche GPIO controllable par un logiciel. La broche GPIO 3 va être utilisée pour cet usage, et la broche 9 va être utilisée comme mise-à-terre ou LOW
. Notez que n'importe quel broche identifié comme GPIO et ground aurait pu être utilisé à cet usage. Un autre fait intéressant est que la longue broche de la lumière doit être connectée au +
. La lumière que vous utilisez dans le circuit doit être compatible avec un signal de 3.3 volts, sans quoi il est nécessaire d'inclure des résistances dans le circuit. Voici le schéma du premier circuit.
Et voici une photo du premier circuit:
Nous allons maintenant porter notre attention au logiciel. Nous allons utiliser le langage de programmation Python pour contrôler l'état de la lumière, mais rien de très avancé. Il existe plusieurs tutoriels pour installer Python. Vous aurez ensuite besoin d'installer la librairie appelée RPi.GPIO pour contrôler les broches GPIO. Pour se faire, roulez la commande suivante: pip install RPi.GPIO
Voici le code que nous allons utiliser pour allumer et éteindre la lumière:
import RPi.GPIO as GPIO
from time import sleep
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(3, GPIO.OUT, initial=GPIO.LOW)
state = GPIO.LOW
while(True):
if(state == GPIO.HIGH):
state = GPIO.LOW
else:
state = GPIO.HIGH
sleep(1)
print(f'Sending {state} to GPIO 3')
GPIO.output(3, state)
Voici une décomposition du code:
Lignes
Description1, 2Import de librairies, particulièrement la librairie RPi.GPIO qui va permettre de contrôler les lumières.4Nous disons à la librairie que nous allons utiliser un schéma de numérotation de la tête GPIO spécifiques qui commence avec 1 pour la broche en haut à gauche, consistent avec le schéma utilisé dans ce tutoriel5Nous retirerons les avertissements concernant l'utilisation de la tête GPIO dans différents logiciels puisque nous allons exécuter ce code plusieurs fois.6Voici la partie intéressante. Nous signalons au Raspberry Pi que nous voulons utiliser la broche GPIO 3 en mode de sortie, ou output. Ce mode permet de mettre la broche GPIO en mode HIGH
(donc 3.3 volts relatif à la mise-à-terre) ou LOW
(donc 0 volts relatif à la mise-à-terre). Nous mentionnons aussi que nous désirons commencer avec le mode LOW
pour que la lumière ne commence pas déjà allumée.8Nous déclarons une variable state
pour garder l'état de la lumière.9Ceci est une boucle événementielle. Si vous avez déjà programmé des jeux videos, vous serez familier avec ce concept. C'est la boucle d'exécution principale dans notre logiciel qui va s'exécuter jusqu'à l'arrêt du logiciel.10, 11, 12, 13Ceci est une logique simple pour changer le contenue de la variable state
, soit HIGH
or LOW
14Nous mettons sur pause l'exécution du logiciel pour une seconde (ou 1 Hertz). Combinée avec la boucle d'exécution, ceci veut dire que la lumière va s'allumer et s'éteindre une fois par seconde.15Impression de la variable state
que nous nous apprêtons à envoyer à la lumière.16Nous disons au Raspberry Pi d'envoyer un signal HIGH
ou LOW
(respectivement 3.3 volts ou 0 volts, dépendant du contenue de la variable state
) à la broche 3.
Et voici le résultat!
Ajouter un bouton
Nous allons complexifier les choses légèrement en ajoutant un bouton au circuit. Ce bouton va contrôler l'état de la lumière: appuyer sur le bouton va allumer la lumière, et le relâcher va éteindre la lumière.
Un bouton ne fait que fermer un circuit lorsqu'il est appuyé. Le voltage appliqué au bouton ne va pas être transmis lorsque le bouton n'est pas appuyé, et va le transmettre lorsque appuyé (agissant comme un fil). Nous allons devoir envoyer 3.3 volts à la pôle +
du bouton, et connecter la pôle -
du bouton à une broche GPIO qui est capable de lire le voltage sortant du bouton. Quand le bouton va être appuyé, la broche GPIO va être capable de lire que 3.3 volts (ou un signal HIGH
) est reçu du bouton. Pour accomplir cette tâche, nous allons utiliser la broche 1 pour le signal 3.3 volts et la broche 13 comme la broche qui va lire le voltage. Encore une fois, n'importe quelle broche GPIO aurait pu fonctionner. Notez qu'avec ce modèle particulier de bouton, le dessous montre quel pôle est positive et négative.
Voici le schéma que nous allons implémenter. Notez qu'il n'y a aucun changement concernant le circuit de la lumière.
Et voici le résultat sur la platine d'expérimentation:
Le résultat est quelque peu chaotique, surtout en photos. Toutefois, les fils jaunes représentent le circuit de la lumière, et les fils bleus représentent le circuit du bouton.
Nous allons aussi changer le code que nous avons utilisé précédemment pour pouvoir lire le voltage provenant du bouton. Le changement le plus important est que nous allons utiliser l'état du bouton pour déterminer l'état de la lumière.
import RPi.GPIO as GPIO
from time import sleep
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(3, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
state = GPIO.LOW
previous_state = GPIO.LOW
while(True):
sleep(0.05)
state = GPIO.input(13)
GPIO.output(3, state)
if(state != previous_state):
print(f'State went from {previous_state} to {state}')
previous_state = state
Voici l'explication du code. Pour garder les choses brèves, l'emphase va être mise sur les changements principaux comparée à l'autre explication du code.
Lignes
Description7Nous disons au Raspberry Pi de s'attendre à une entrée sur la broche 13. Nous disons aussi d'ignorer les valeurs de voltages entre 0 et 3.3 volts en disant que la broche 13 est raccordé à un bouton poussoir (Pull Up-Down button)12Notre boucle événementielle précédente s'exécutait une fois par seconde. Dans ce cas, nous exécutons la boucle à chaque 0.05 seconds (ou 20 fois par seconds, ou 20 Hertz)13Nous obtenons l'état de la broche GPIO 13. Puisque nous avons configuré la broche 13 comme un bouton poussoir, nous pouvons nous attendre à un résultat HIGH
ou LOW
.14Nous donnons le résultat obtenu à la ligne 13 à la broche 3 qui contrôle la lumière.
Et voici le résultat!
Seulement le début
Personne n'utiliserait une méthode si élaborée pour allumer et éteindre une lumière en appuyant sur un bouton: Comme mentionné dans l'introduction, une batterie, une lumière et un bouton ferait l'affaire. Toutefois, considérez ceci: J'ai montré comment lire une entrée en Python, et comment donner un signal en sortie à partir de Python. La même logique serait applicable pour une multitude de senseurs pour ainsi créer votre propre IoT / périphérique intelligent. Voici quelques exemples de senseurs provenant d'un ensemble de 37 senseurs à $45 CAD:
Le senseur de niveau d'eau envoi un voltage différent de zéro s'il y a de l'eau détectée. Le senseur d'alarme émet un son lorsqu'un voltage est appliqué. Le relai laisse passer 120 volts (le même voltage que les articles électroménagers en Amérique du Nord) seulement lorsqu'un signal de 3.3 volts est appliqué sur les petites broches.
Avec ces trois modules, vous pouvez facilement fabriquer un système qui détecte s'il y a une fuite d'eau, émet un son, coupe l'électricité aux électroménagers proches et envoie une notification à l'aide du WiFi. Par conséquent, votre imagination (et la variété de senseurs qui existent) est la limite.
Image d'en-tête par Carlos Alberto Gómez Iñiguez
Icônes de bouton poussoir et de diode crées par smashingstocks - Flaticon