Ici archive

Durant la dernière décennie, de nombreuses entreprises ont adopté un modèle Data Driven basé sur l’exploitation massive de données pour orienter leurs décisions business ou opérationnelles.  

Cette démocratisation de l’utilisation des données est notamment due à l’émergence des technologies Cloud qui ont permis d’exécuter des traitements complexes sur de très grands jeux de données et de conserver un TCO maîtrisable. Toutefois, un inconvénient majeur s’est rapidement présenté : le manque de maîtrise (ou de confiance) sur la localisation des données. Ce dernier point tend aujourd’hui à disparaître, puisque la majorité des cloud providers intègrent à présent dans leur offre le choix du data center, et donc du pays d’hébergement (localisation UE/US…). 

Remarque : la maîtrise de l’information d’entreprise mise sur le cloud (et plus largement internet) est au centre de l’actualité sur la sécurisation des usages de ChatGPT. À titre d’exemple, Microsoft intègre dans l’offre Azure Open AI la possibilité d’étancher l’utilisation des données d’entreprise pour améliorer la pertinence de l’IA sur ses cas d’usage internes, tout en garantissant que ces données (potentiellement confidentielles ou personnelles) ne seront jamais exposées en dehors de l’entreprise.  

Dans un même temps, les États (particulièrement en Europe) ont largement renforcé la règlementation visant à protéger l’utilisation de données personnelles. Ils ont imposé un cadre de protection et exploitation de données de plus en plus strict, comme en témoignent les sanctions prévues en cas de non-respect de cette règlementation. 

Quelques chiffres présentés ci-après permettent de mieux appréhender la mise en application de ces contrôles. Par exemple, en Europe, les sanctions s’établissaient à 1,2 Mds€ en 2021 contre plus de 2,92 Mds€ en 2022 (dont 100 M€ en France). 

Au-delà des quelques amendes historiques (comme celle infligée à Amazon pour 746 M€ en 2022 ou 405 M€ infligée à Meta pour manquement à la protection de données personnelles des enfants sur Instagram), la forte hausse du nombre de condamnations est notable. 

Autre fait marquant, la démocratisation des services d’intelligence artificielle auprès du grand public, qui pousse les instances de régulation Européenne à suivre de près le sujet. Nous pouvons citer par exemple une amende de 7 M£ donnée par l’ICO britannique à la société de reconnaissance faciale ClearView AI. 

Pour prévenir ces risques et promouvoir une image éthique de leurs activités, nombre de sociétés s’organisent pour améliorer la sécurité et confidentialité de leurs données, à fortiori celles revêtant un caractère personnel. Les entreprises les plus matures disposent d’un Data Controller – personne en charge de la supervision et de la qualification des traitements informatiques. Ce rôle vient en complémentarité du DPO (data privacy officer), qui a une responsabilité vis-à-vis des instances de contrôle pour faire appliquer la règlementation par l’entreprise. 

En effet, les techniques de traitement de la confidentialité sont multiples et plus ou moins complexes. Il apparait donc nécessaire de bien étudier chaque cas d’usage en amont et d’appliquer une solution adaptée. 

Dans la suite de l’article, nous proposons d’explorer certaines de ces approches.  

Panorama des solutions existantes  

Les approches les plus fréquemment utilisées sont :  

  • La gestion des identités et des accès ;  
  • Le cryptage ;  
  • L’anonymisation.

La gestion des identités et des accès (IAM) permet de limiter l’accès à un groupe défini de personnes. Nous recommandons de suivre le principe de moindre privilège, c’est-à-dire le fait de limiter les permissions d’accès aux ressources au juste nécessaire pour effectuer une tâche. Si besoin, il convient d’utiliser un modèle d’accès aux rôles de base (RBAC) qui peut être affiné via des listes de contrôle d’accès (ACL). 

Remarque : les Cloud providers intègrent nativement des fonctions de sécurisation dans leur offre de service à l’instar de VMs protégées proposées par Google Cloud.  

 La pseudonymisation est une technique qui permet de « masquer » la lecture directe des données confidentielles. Les données sont remplacées par un code (« tokenisation ») selon différentes techniques (chiffrement déterministe, conservant le format, clé cryptographique…). Ces techniques de chiffrements sont réversibles. Elles permettent donc de revenir à la donnée initiale. En conséquence, ces traitements doivent être soumis à déclaration auprès de la CNIL et ne perdurer que le temps de la finalité déclarée.  

Les clés de cryptage peuvent être utilisées sur des données personnelles ou pour des raisons de sécurité sur des systèmes de fichiers pour en protéger l’accès (en cas de vol par exemple).  

L’anonymisation est un concept plus complexe et abstrait que les solutions précédemment évoquées. Selon une définition de la CNIL, l’anonymisation consiste à « utiliser un ensemble de techniques de manière à rendre impossible, en pratique, toute identification de la personne par quelque moyen que ce soit et de manière irréversible. » 

Par exemple, les données peuvent être masquées via des techniques de hachage cryptographique, puis encodées. Cette technique permet de créer un jeton à sens unique, qui ne permet pas de revenir à la donnée d’origine.   

Mais dans certains cas, ces techniques ne sont pas suffisantes. Par recoupement entre différentes informations (internes ou par croisement avec des données externe), il peut arriver que l’identité ou les données personnelles liées à la personne puissent être retrouvées. Plusieurs exemples de croisement sont à ce titre devenus des cas d’école, comme l’identification d’une personne anonymisée sur la base d’attributs particuliers (ville, date de naissance…). 

Il est par conséquent indispensable de prendre en considération l’ensemble des attributs ou données qui par recoupement permettraient de retrouver une information devant être protégée dans une démarche d’anonymisation. 

La confidentialité différentielle : quel usage ?   

La confidentialité différentielle (DP) est une technique dont l’objet est de protéger la confidentialité en injectant du « bruit » dans les données : en modifiant certaines valeurs, il doit rester un doute sur la véracité de l’information même si l’identification de la personne est retrouvée par recoupement. 

Cette technique a donc un impact sur la précision de la base de données (des données sont faussées), mais reste totalement exploitable sur des usages analytiques ou statistiques (ou d’IA). L’approche consiste à substituer des valeurs des variables en utilisant un algorithme (plus ou moins simple).   

Par exemple, sur une valeur pour laquelle la réponse est binaire (vrai ou faux) : imaginons que l’on lance une pièce pour déterminer si la valeur initiale est modifiée ou pas. Si la pièce tombe sur face, la réponse reste « vrai ». Si cela tombe sur pile, un deuxième lancé est effectué. S’il tombe sur face, la réponse reste « vrai », et s’il tombe sur pile, la valeur devient « faux ». 

Les « variant twins » 

Ce concept consiste à hybrider les différentes techniques pour obtenir une information totalement anonymisée et optimisée pour différents usages (d’où l’idée de variants). 

 Il est notamment porté par des plateformes dédiées à la sécurisation des données, comme Anonos (white paper variant twins).

Les solutions sur étagère

Dans le domaine du marketing, nous voyons par exemple l’émergence de plateformes dédiées au partage de données publicitaires respectant les contraintes réglementaires.   

À ce titre, Google lance Ads Data Hub en 2017, suivi par les solutions de Facebook et d’Amazon. Aujourd’hui, ils sont tous les trois connus comme des « data clean rooms » : soit un environnement isolé et sécurisé au sein duquel les éditeurs et annonceurs peuvent combiner, faire correspondre et analyser des ensembles de données anonymisés, tout en collaborant. 

Pour aller plus loin  

Le respect de la confidentialité des données est un défi majeur pour tous les intervenants dans un écosystème data. Il nécessite la mobilisation de tous les acteurs comme les cloud ops, cloud architects, statisticiens, data analysts et data scientists et bien sur les « data controllers », dont la présence devrait se démultiplier rapidement dans les entreprises.  

Il est important de comprendre que, bien que les solutions à mettre en œuvre soient très techniques, la bonne tactique dépend avant tout de la portée fonctionnelle de l’information et des cas d’utilisation souhaités.  

Nos experts sont à votre disposition pour établir les diagnostics sur la sensibilité de vos données et vous guider vers les bonnes stratégies d’implémentation.  

  

Rédigé par Alexander MIKHEEV, Lead Tech Engineer au sein de notre département Data Driven

Avez-vous déjà essayé de comprendre du code source complexe et vous êtes retrouvé perdu dans un dédale de variables et de fonctions qui semblent écrites dans une langue inconnue ? Si tel est le cas, vous savez à quel point un code illisible peut être frustrant. Heureusement, il existe une solution : le clean code, une pratique de code qui peut aider les développeurs à écrire un code clair, simple et facile à comprendre. Dans cet article, nous allons vous expliquer ce qu’est le clean code, pourquoi il est important et comment vous pouvez l’appliquer à votre propre développement de logiciel. Que vous soyez un développeur chevronné ou simplement curieux de savoir comment fonctionne le code, cet article est pour vous ! 

Mais c’est quoi, le clean code ? 

Le clean code est une pratique de développement logiciel qui vise à produire du code lisible et maintenable. Il s’agit d’une approche axée sur la qualité qui encourage les développeurs à adopter des conventions de codage cohérentes et à se concentrer sur la clarté, la simplicité et la robustesse du code. 

En quoi est-ce important ? 

Le clean code permet de produire un logiciel de qualité supérieure. En écrivant du code clair, les développeurs peuvent simplifier leur travail et accélérer le processus de développement. De plus, le code propre est plus facile à tester, à déboguer et à améliorer au fil du temps, ce qui permet de garantir une meilleure qualité et une plus grande évolutivité du logiciel. En fin de compte, le clean code favorise une meilleure collaboration entre les développeurs et garantit la pérennité d’un projet. 

Les fondements du code propre : les cinq piliers du succès 

La philosophie du clean code peut-être résumée aux piliers suivants :  

1 – La lisibilité

Le code doit être facile à lire et à comprendre pour les autres développeurs. Pour améliorer la lisibilité, vous pouvez utiliser des noms de variables clairs et compréhensibles, éviter les abréviations et les acronymes obscurs, ajouter des commentaires si nécessaire et organiser votre code avec des espaces et une indentation claire. 

var x=10;y=20;if(x>y){console.log("x est plus grand que y");} 

Dans cet exemple, le code est mal formaté, difficile à lire et à comprendre. Les variables sont mal nommées et les blocs de code ne sont pas suffisamment bien formés pour apparaître au premier coup d’œil. 

const ageUtilisateur = 10; 
const ageMinimum = 18; 
 
if (ageUtilisateur < ageMinimum) { 
  console.log("Vous devez avoir au moins 18 ans pour accéder à ce contenu"); 
} 

Ici en revanche, le code est aisément lisible, avec des variables bien nommées et des blocs de code définis. Il est ainsi plus facile à comprendre pour les autres développeurs et à maintenir à l’avenir. 

2 – La simplicité

Chaque bloc de code doit être simple et élégant, sans fioritures inutiles. Pour simplifier votre code, vous pouvez utiliser des structures de contrôle de flux simples, éviter les structures de données complexes et les algorithmes compliqués et supprimer les variables inutiles. 

var x = 10; 
var y = 20; 
var result = 0; 
for (var i = 0; i < x; i++) { 
  result += y; 
} 
console.log(result); 

Dans cet exemple de mauvaise pratique, le code est plus complexe qu’il ne devrait l’être. Les variables sont mal nommées, les structures de contrôle de flux et les boucles sont utilisées inutilement pour effectuer une simple opération mathématique. 

const nombreRepetitions = 10; 
const nombreAjouts = 20; 
 
const resultat = nombreRepetitions * nombreAjouts; 
console.log(resultat); 

Dans cet exemple de bonne pratique, le code est simplifié en utilisant des variables clairement nommées et en évitant les boucles et les structures de contrôle de flux. Le code est plus facile à comprendre et à maintenir. De plus, le calcul est effectué en une seule ligne de code, ce qui le rend plus efficace. 

3 – La modularité

Le code doit être organisé en modules clairement définis, ayant des responsabilités précises. Pour rendre votre code plus modulaire, vous pouvez diviser votre code en petites fonctions réutilisables, utiliser des variables globales avec parcimonie et éviter les effets de bord (lorsqu’une fonction modifie une variable qui n’est pas passée en paramètre). 

var utilisateurs = []; 
 
function ajouterUtilisateur(nom, age) { 
  utilisateurs.push({nom: nom, age: age}); 
} 
 
function trouverUtilisateur(nom) { 
  for (var i = 0; i < utilisateurs.length; i++) { 
    if (utilisateurs[i].nom === nom) { 
      return utilisateurs[i]; 
    } 
  } 
} 
 
function supprimerUtilisateur(nom) { 
  for (var i = 0; i < utilisateurs.length; i++) { 
    if (utilisateurs[i].nom === nom) { 
      utilisateurs.splice(i, 1) ; 
      break;
    } 
  } 
} 

Dans cet exemple, toutes les fonctions manipulent une variable globale utilisateurs, ce qui rend le code difficile à comprendre et à modifier. 

class GestionUtilisateurs { 
  constructor() { 
    this.utilisateurs = []; 
  } 
 
  ajouterUtilisateur(nom, age) { 
    this.utilisateurs.push({nom: nom, age: age}); 
  } 
 
  trouverUtilisateur(nom) { 
    for (var i = 0; i < this.utilisateurs.length; i++) { 
      if (this.utilisateurs[i].nom === nom) { 
        return this.utilisateurs[i]; 
      } 
    } 
  } 
 
  supprimerUtilisateur(nom) { 
    for (var i = 0; i < this.utilisateurs.length; i++) { 
      if (this.utilisateurs[i].nom === nom) { 
        this.utilisateurs.splice(i, 1); 
        break; 
      } 
    } 
  } 
} 
 
const gestionUtilisateurs = new GestionUtilisateurs(); 
gestionUtilisateurs.ajouterUtilisateur("Jean", 30); 
const utilisateur = gestionUtilisateurs.trouverUtilisateur("Jean"); 
gestionUtilisateurs.supprimerUtilisateur("Jean"); 

Ici, nous avons défini une classe GestionUtilisateurs qui encapsule toutes les fonctions de gestion des utilisateurs. Les fonctions sont des méthodes de la classe, ce qui rend leur relation avec la classe plus explicite. Nous avons également utilisé le mot-clé this pour faire référence aux propriétés et méthodes de l’objet instancié à partir de la classe. L’utilisation d’une classe offre une abstraction plus élevée du code et facilite la réutilisation du code. La classe peut être facilement instanciée plusieurs fois, ce qui permet de gérer plusieurs listes d’utilisateurs indépendantes. 

4 – L‘évolutivité

Le code doit être conçu pour être facilement modifiable et extensible au fil du temps. Pour rendre votre code plus évolutif, vous pouvez prévoir des extensions futures, utiliser des structures de données et des algorithmes flexibles et isoler les parties du code qui sont susceptibles de changer. 

function calculerPrixTotal(articles) { 
  let total = 0; 
  for (let i = 0; i < articles.length; i++) { 
    total += articles[i].prix; 
  } 
  return total; 
} 

Dans cet exemple, la fonction calculerPrixTotal prend un tableau d’objets d’articles et calcule le prix total en additionnant le prix de chaque article. Bien que cette fonction fonctionne correctement pour le moment, elle n’est pas évolutive car elle ne prend pas en compte les futurs changements de spécifications. Par exemple, si vous souhaitez ajouter une remise ou un code promotionnel à la commande, vous devrez modifier cette fonction existante, ce qui peut entraîner des erreurs ou des bogues. 

class Commande { 
  constructor() { 
    this.articles = []; 
    this.remise = 0; 
  } 
  
  ajouterArticle(article) { 
    this.articles.push(article); 
  } 
  
  calculerPrixTotal() { 
    let total = 0; 
    for (let i = 0; i < this.articles.length; i++) { 
      total += this.articles[i].prix; 
    } 
  
    return total - this.remise; 
  } 
  
  appliquerRemise(codePromo) { 
    // logique de vérification du code promo 
    // si code valide, assigner la remise appropriée 
    this.remise = calculerRemise(codePromo, this.articles); 
  } 
} 
 
function calculerRemise(codePromo, articles) { 
 // logique de calcul de remise 
  return remise; 
} 

Ici, nous utilisons plutôt une classe Commande pour encapsuler la logique de commande, ce qui rend le code plus évolutif. La classe contient des méthodes pour ajouter des articles à la commande, calculer le prix total de la commande et appliquer une remise. La logique de calcul de remise a été extraite dans une fonction séparée, ce qui rend la classe Commande plus cohérente et facile à comprendre. Si nous voulons ajouter une nouvelle fonctionnalité à la commande, comme l’application d’une taxe de vente, nous pouvons simplement ajouter une nouvelle méthode à la classe Commande sans avoir à modifier la logique existante. Cela rend le code plus évolutif et plus facile à maintenir à long terme. 

5 – La robustesse

Le code doit être résistant aux erreurs et aux pannes et capable de gérer les situations imprévues de manière élégante. Pour cela, il est important de prévoir les cas d’erreurs et de les gérer de manière adéquate, de valider les entrées de l’utilisateur et de gérer les exceptions de manière appropriée. Un code robuste est capable de faire face à des situations imprévues sans plantage et de fournir des informations d’erreur claires et précises pour aider les utilisateurs à comprendre les problèmes rencontrés. 

function division(a, b) { 
  return a / b; 
} 

Dans cet exemple, si la variable b est égale à zéro, une erreur de division par zéro se produira. Cette erreur peut causer des plantages imprévus et des comportements indésirables du programme. 

function division(a, b) { 
  if (b === 0) { 
    throw new Error('Division par zéro impossible'); 
  } 
  return a / b; 
} 

Dans cet exemple, nous avons ajouté une vérification pour éviter la division par zéro. Si la valeur de b est égale à zéro, nous levons une exception avec un message clair pour informer l’utilisateur du problème. Ainsi, le programme ne plante pas et l’utilisateur est informé du problème. 

Le Clean Code, c’est donc penser à long terme

La qualité du code est une préoccupation constante pour tout développeur soucieux de produire des logiciels de qualité. Le clean code fournit des principes et pratiques qui permettent d’écrire du code clair, simple, lisible et facilement évolutif. En respectant ces principes, les développeurs peuvent créer des programmes durables, efficaces et évolutifs et ainsi contribuer à l’amélioration globale de la qualité du code dans leur entreprise ou leur communauté de développement.

En somme, le clean code est un moyen de travailler plus intelligemment et de créer des logiciels de qualité supérieure pour répondre aux besoins des utilisateurs finaux. L’adoption de ses pratiques est essentielle pour tout développeur qui souhaite améliorer sa productivité, son efficacité et son impact dans le domaine de la programmation.

Vous souhaitez en savoir plus ? Contactez notre équipe de développeurs à la Factory !

Rédigé par Daniel Azevedo, Manager et Lead Developer à la Factory