chemical-and-materials-engineering
Mise en œuvre du modèle de prototype pour permettre le clonage rapide des ensembles de données d'ingénierie pour les essais
Table of Contents
Comprendre le modèle de prototype en génie logiciel
Le modèle Prototype est un modèle de conception qui permet la création de nouveaux objets en clonant une instance existante plutôt que de construire des objets à partir de zéros dans des constructeurs ou des usines. Ce modèle est particulièrement précieux lorsque l'instantialisation des objets est coûteuse, complexe ou nécessite une configuration importante.
L'idée principale est simple : définir un objet de base qui sert de prototype. D'autres objets sont ensuite créés en copiant ce prototype, avec des modifications optionnelles. Cette approche évite le surcoût des objets initialisants qui partagent une grande quantité d'état par défaut. Le motif fait partie des modèles de conception classiques Gang of Four et est largement applicable dans les langages de programmation et les domaines.
Le défi des ensembles de données techniques pour les essais
Les ensembles de données techniques impliquent souvent des milliers ou des millions d'enregistrements, des structures imbriquées et des relations complexes.Par exemple, les séries chronologiques des capteurs, les paramètres de simulation, les métadonnées de modèles CAO ou les fichiers de configuration pour les équipements industriels. La création de ces ensembles de données à partir de zéro pour chaque scénario d'essai est peu pratique.
Les deux méthodes nuisent à la vitesse d'itération et découragent les essais complets. Le modèle Prototype offre un terrain intermédiaire – vous concevez un seul objet prototype bien conçu qui capture la structure essentielle et les valeurs par défaut valides. De ce prototype, vous clonez et modifiez uniquement les champs qui doivent différer pour chaque cas de test.
Comment fonctionne le modèle de prototype
Le motif repose sur une opération clone qui produit un nouvel objet avec le même état que l'original. Il existe deux formes distinctes de clonage : copie superficielle et copie profonde. Une copie superficielle reproduit les propriétés de haut niveau mais partage des références aux objets imbriqués. Une copie profonde crée des copies entièrement nouvelles de tous les sous-objets. Pour les ensembles de données techniques – qui contiennent souvent des tableaux imbriqués de lectures de capteurs, de dictionnaires de configuration ou d'état de simulation – une copie profonde est généralement nécessaire pour éviter un état partagé indésirable à travers les tests.
Dans les langues qui prennent en charge des interfaces explicites ou des classes abstraites, le modèle est implémenté comme suit :
- Définit une interface de prototype – Déclare une méthode (p. ex. ) qui renvoie une copie de l'objet.
- Mise en œuvre de prototypes de béton – Chaque classe qui représente un ensemble de données implémente la méthode clone, en exécutant la logique de copie profonde appropriée.
- Utilisez la méthode Clone – Les appelants obtiennent de nouveaux ensembles de données en clonant le prototype et en appliquant ensuite les modifications nécessaires.
Considérations relatives à la copie profonde
La mise en œuvre d'une copie profonde fiable est la partie la plus complexe du modèle. L'attribution simple champ par champ fonctionne pour les types primitifs, mais pour les références aux tableaux, objets ou autres types complexes, vous devez cloner récursivement chaque élément imbriqué. Beaucoup de langues fournissent des utilitaires natifs: pour les copies peu profondes, comme un hack rapide, ou des fonctions de clone profond dédiés comme dans JavaScript moderne. Cependant, ces approches génériques peuvent échouer avec des références circulaires, des objets spéciaux (Date, Carte, Set) ou des fonctions.
Mise en œuvre du modèle de prototype avec les ensembles de données d'ingénierie
Let , c'est une implémentation concrète utilisant le JavaScript moderne (TypeScript), qui est la langue qui alimente les extensions Directus et de nombreuses applications web d'ingénierie.
Étape 1: Définir l'interface de prototype
interface EngineeringDataSet <T> {
clone(): EngineeringDataSet<T>;
modify(partial: Partial<T>): EngineeringDataSet<T>;
}
Cette interface déclare deux méthodes : pour produire une copie profonde, et pour appliquer des modifications après clonage. Le paramètre générique permet à la classe de béton de spécifier sa forme de données.
Étape 2 : Mettre en œuvre la classe de béton
class SensorTimeSeries implements EngineeringDataSet<SensorTimeSeriesData> {
private data: SensorTimeSeriesData;
constructor(initialData: SensorTimeSeriesData) {
// Accept initial data, could also load from a prototype source
this.data = this.deepClone(initialData);
}
clone(): EngineeringDataSet<SensorTimeSeriesData> {
return new SensorTimeSeries(this.deepClone(this.data));
}
modify(partial: Partial<SensorTimeSeriesData>): EngineeringDataSet<SensorTimeSeriesData> {
const newData = this.deepClone(this.data);
Object.assign(newData, partial);
return new SensorTimeSeries(newData);
}
private deepClone(obj: any): any {
// Recursive deep copy handling Date, Map, Set, Array, Object
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof Map) {
const cloneMap = new Map();
obj.forEach((value, key) => cloneMap.set(key, this.deepClone(value)));
return cloneMap;
}
if (obj instanceof Set) {
const cloneSet = new Set();
obj.forEach(value => cloneSet.add(this.deepClone(value)));
return cloneSet;
}
if (Array.isArray(obj)) return obj.map(item => this.deepClone(item));
const cloneObj: any = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = this.deepClone(obj[key]);
}
}
const proto = Object.getPrototypeOf(obj);
if (proto !== Object.prototype) {
// Preserve prototype chain if needed
Object.setPrototypeOf(cloneObj, proto);
}
return cloneObj;
}
}
Dans cet exemple, la classe contient un objet de données de type . La méthode crée une nouvelle instance avec une copie complète des données internes. La méthode fournit un moyen fluide de produire des variantes. Ce modèle évite de muter le prototype original – une garantie de sécurité critique.
Étape 3: Créer et utiliser un prototype
// Define the prototype once
const baseSensorData: SensorTimeSeriesData = {
deviceId: "SENSOR-A-001",
readings: Array.from({ length: 1000 }, (_, i) => ({
timestamp: Date.now() + i * 1000,
value: 20 + Math.random() * 5
})),
calibrationParams: {
offset: 0.1,
scale: 0.98,
timestamp: new Date("2023-01-01")
},
metadata: new Map([["location", "bay-4"], ["unit", "celsius"]])
};
const prototype = new SensorTimeSeries(baseSensorData);
// Clone and modify for test cases
const testCase1 = prototype.clone();
// Baseline unchanged
const testCase2 = prototype.modify({
deviceId: "SENSOR-A-002",
readings: generateFaultReadings() // function returning different readings
});
Avec ce modèle, générer des dizaines ou des centaines de scénarios d'essai devient une question de clonage du prototype et d'application de modifications ciblées. Le prototype original reste vierge et réutilisable.
Applications du monde réel en ingénierie
Tests logiciels dans la boucle
Dans le test logiciel en boucle (SIL), vous transmettez les données de capteur simulées dans un calculateur de contrôleur. Chaque scénario de test peut nécessiter un ensemble de données légèrement différent : un avec fonctionnement normal, un avec pics de bruit aléatoire, un avec des échantillons manquants.
Validation de la configuration
Les systèmes d'ingénierie reposent souvent sur des objets de configuration complexes (JSON, YAML). Valider que le système gère toutes les configurations valides et non valides nécessite de nombreuses permutations. Le prototype peut être la configuration par défaut correcte; les clones peuvent alors introduire des erreurs spécifiques ou des conditions de bord.
Évaluation du modèle d'apprentissage automatique
Lors de l'entraînement et de l'évaluation des modèles ML, vous avez besoin de plusieurs tranches de données techniques – différentes fenêtres de temps, différentes combinaisons de capteurs, différentes étapes de prétraitement. Le prototype tient le jeu de données brutes. Le clonage et le filtrage sélectif ou la modification des attributs créent l'entraînement souhaité et les fractions de test sans recharger les fichiers bruts.
Jumelles numériques
Chaque instance de simulation peut être un clone de l'état initial du jumeau, avec des mutations indépendantes autorisées pour les analyses -What-if-. Le modèle assure que chaque jumeau commence à partir de la même base de référence.
Avantages au-delà de la vitesse
Alors que la vitesse est l'avantage le plus évident, le prototype Pattern offre d'autres vertus d'ingénierie:
- Consistance – Puisque tous les clones proviennent du même prototype, les invariants structurels sont automatiquement conservés. Vous ne pouvez pas accidentellement omettre un champ obligatoire.
- Déterminisme – Les tests deviennent plus reproductibles. Lorsqu'un test échoue, vous savez que ce n'était pas dû à des différences aléatoires dans la génération de données.
- Maintenabilité – La définition du prototype vit en un seul endroit. Si le schéma de données sous-jacent change (p. ex., un nouveau type de capteur ajouté), vous mettez à jour seulement le code de construction du prototype, pas tous les cas de test.
- Composabilité – Vous pouvez chaîner les modifications: clone à partir d'un prototype, appliquer une première transformation, puis cloner à nouveau pour une autre variante.
- Intégration avec contrôle de version – Le prototype peut être stocké sous forme de fichier JSON ou YAML dans votre dépôt. Les modifications au prototype sont suivies et tout test qui le clone utilise automatiquement le dernier schéma.
Intégrer le modèle de prototype avec Directus
Directus est un CMS sans tête qui peut servir de centre de stockage, de gestion et de livraison de données d'ingénierie. L'utilisation du modèle Prototype dans une extension ou un hook Directus apporte les mêmes avantages à vos pipelines de données.
Stockage de prototypes dans Directus
Définir une collection nommée où chaque élément représente un prototype. L'élément peut contenir un champ JSON contenant la structure de données par défaut. Un crochet Directus ou un paramètre personnalisé peut récupérer le prototype, le cloner en mémoire en utilisant le modèle ci-dessus, et appliquer des modifications basées sur les paramètres de requête ou demander une charge utile.
Exemple : Point d'extrémité de l'API pour la génération de données de test dynamique
Imaginez construire un paramètre Directus qui génère un ensemble de données de test sur demande:
import { defineEndpoint } from '@directus/extensions-sdk';
export default defineEndpoint({
id: 'generate-test-data',
handler: async (req, res, context) => {
const { Services, database } = context;
const { ItemsService } = Services;
const prototypeService = new ItemsService('data_set_prototypes', { schema: req.schema, accountability: req.accountability });
const prototypeItem = await prototypeService.readOne(req.query.prototypeId);
const prototypeData = prototypeItem?.data; // the JSON blob
if (!prototypeData) {
return res.status(404).json({ error: 'Prototype not found' });
}
// Deep clone using JavaScript's structuredClone
let testData = structuredClone(prototypeData);
// Apply modifications from request body
if (req.body.modifications) {
testData = applyModifications(testData, req.body.modifications);
}
// Store the generated data set for later reuse
const dataSetService = new ItemsService('test_data_sets', { schema: req.schema, accountability: req.accountability });
const newDataSet = await dataSetService.createOne({
prototype_id: prototypeItem.id,
generated_at: new Date(),
data: testData
});
res.json(newDataSet);
}
});
Ce paramètre permet aux coureurs de test frontal ou aux pipelines CI/CD de demander un nouveau jeu de données dérivé d'un prototype, avec des remplacements facultatifs. L'ensemble de données clonées est maintenu pour la traçabilité.
Utilisation des collections Directus comme modèles de prototype
Si vos données d'ingénierie sont relationnelles (p. ex., plusieurs tables associées pour les configs de capteurs, seuils, emplacements), vous pouvez toujours appliquer le modèle. Créez un enregistrement prototype dans une collection -configuration, et clonez tout son graphique relationnel en utilisant une routine recursive de récupération et de création. La même méthode peut être étendue pour traverser les relations via les champs relationnels de Directus.
Pièges et pratiques exemplaires
Bien que le modèle de prototype soit puissant, une implémentation inappropriée peut introduire des bogues subtils.
- Éviter les copies peu profondes pour les données complexes[ – Implémenter toujours le clonage profond pour les données qui contiennent des objets imbriqués.
- References circulaires à la main – Les données techniques ont rarement des cycles, mais si c'est le cas, une copie profonde récursive empilera le débordement. Utilisez une carte faible pour suivre les objets déjà fermés.
- Profil Performance – Le clonage profond peut être coûteux pour des ensembles de données très importants (en millions d'éléments).Dans ces cas, envisager le clonage paresseux: clone sur écriture, ou utiliser des structures de données immuables qui partagent des parties inchangées.
- Documenter le prototype – Décrivez clairement ce que représente le prototype et ce que signifie chaque champ. D'autres membres de l'équipe doivent comprendre quelles modifications sont sécuritaires.
- Version Vos prototypes – Lorsque le modèle de données évolue, les anciens prototypes peuvent devenir invalides. Utilisez un champ de version et des scripts de migration pour garder les prototypes à jour.
- Testez la méthode clone elle-même – Les tests unitaires doivent vérifier que le clonage produit un objet égal mais non identique (deep egal, mais différentes références).
Conclusion
En investissant dans un prototype bien conçu et un mécanisme de clonage profond robuste, les équipes peuvent accélérer leurs cycles d'itération, améliorer la couverture des tests et réduire le fardeau de maintenance associé aux données de test réalisées à la main. Que vous simuliez des réseaux de capteurs, validez des configurations ou construisiez des jumelles numériques, ce modèle permet des gains de productivité mesurables. Son intégration avec des plateformes modernes comme Directus amplifie encore sa valeur en permettant la génération et le stockage dynamiques de données issues de l'API.
Pour plus de détails sur les modèles, voir l'explication détaillée du Guru et l'original Gang of Four book[. Pour des conseils pratiques sur la mise en œuvre en JavaScript, la documentation MDN sur le Clone est une ressource fiable.