Indépendance par rapport à la source de données

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

Je suis en ce moment en stage dans une boite d'informatique sur Paris qui me demande de développer une app. Je ne vais pas rentrer dans les détails de celle-ci car c'est peu intéressant pour le problème que j'expose ici, mais un des principes de l'app est qu'elle soit réutilisable et ré-adaptable. Pour faire cela, elle doit notamment être indépendante du type de données qu'elle va traiter.

Donc, on peut imaginer recevoir des données en XML, JSON, depuis des fichiers statiques, ou depuis des bases de données en réseaux, etc. En effet, prenons un exemple simple :

  • Un client A veut qu'on lui développe une app, mais il utilise son propre back end, en XML, ou JSON, ou autre,
  • Un client B veut qu'on lui développe une app, mais on doit également s'occuper du back end, …
  • Etc.

Je ne sais pas si je suis très clair, mais en gros, il faut vraiment que je crée une couche indépendante du type de données qu'elle reçoit .

Existe-t-il des "bonnes pratiques" pour réaliser cela ? Des conseils précis ? Je dois avouer que je ne sais pas vraiment comment m'y prendre pour BIEN réaliser une telle généricité.

Pour moi, le principe "global", de façon un peu caricaturale, ce serait par exemple pour des données concernant un objet X, une classe X qui retourne des objets, toujours structurés pareillement, quelle que soit la façon dont elle a reçu les données permettant de construire l'objet. Mais réellement d'un point de vue programmation, je ne sais pas vraiment comment implanter cela de façon propre, soignée.

Des idées / conseils / bonnes pratiques à me fournir ?

Merci d'avance !

Édité par Ikikn

+0 -0

J'ai un peu de mal à voir comment produire un code générique au sens théorique du terme. La syntaxe des fichiers de données étant ce qu'elle est, à moins de réaliser un moteur d'analyse syntaxique, tu vas être obligé de gérer ça au cas par cas…

1
2
3
4
5
6
7
8
Si données en XML
    alors traitement XML
Sinon si données en JSON
    alors traitement JSON
Sinon si format exotique
    alors traitement exotique
Sinon si format inconnu
    alors erreur

Après, respecter une architecture MVC peut être une très bonne pratique pour isoler le traitement du fichier de données du traitement de la donnée elle-même.

Lu'!

Globalement, l'idée pour pouvoir être indépendant du type de données reçues est d'avoir une structure capable d'au moins la même expressivité que les formats que tu es susceptible d'avoir en entrée. Si tu veux limiter la quantité de choses à faire du côté de cette structure de données (et on veut le limiter), il va falloir que ta structure soit plus simpliste mais composable.

Et cela ne change en rien que pour chaque format que tu voudras traiter, il faudra un module de traduction du format d'entrée vers ta structure de données.

Mais ce que tu as à faire reste assez flou. Le problème général est intéressant mais c'est presque plus scientifique qu'applicatif, et je doute que ce soit le but recherché. Plus de détails peut être sur le type d'application visé ?

First : Always RTFM - "Tout devrait être rendu aussi simple que possible, mais pas plus." A.Einstein

+0 -0

D'après moi, je dirais qu'il faut choisir un modèle de représentation de base, puis à partir de là proposer une factory par source ou format différent à traiter.

ET optionnellement, une méthode pour désigner une source ou reconnaître un format facilement, afin qu'avec quelque chose de simple tu sois en mesure d'instancier la bonne factory qui te permettra de récupérer les bonnes données

En gros on aurait de la factory à deux niveaux. Voire trois si tu dois être indépendant à la fois de la source et du format.

Exemple rapide en pseudo java :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Entity {
// Là tu décris ton modèle de base
}

interface EntityFactory {
public Entity readEntity ();
}


class XMLEntityFactory implements EntityFactory {
public XMLEntityFactor (URL xmlFileURL) ;
public Entity readEntity () ;
}

class MySQLEntityFactory implements EntityFactory {
public MySQLEntityFactory (String host, String username, String password, String tablePrefix) ;
public Entity readEntity () ;
}

Et pour le second niveau on peut imaginer passer des URI par exemple :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class EntityFactoryFactory {
public EntityFactory getInstance (String  uri)  {
if (uri.matches("^http://.*\\.xml$")) return new XMLEntityFactory(...);
else if (uri.matches("http://.*\\.json$")) return new JSONEntityFactory(...);
else if (uri.startsWith("mysql://")) return new MySQLEntityFactory(..);
else if ...
else if ...
else return null; // ou throw new IllegalARgumentException("Unrecognized URI: " +uri);
}
}

Après le plus dur c'est probablement de créer la représentation de base. IL faut à la fois tenir compte de la spécificité de chaque source ou format et limiter les pertes entre représentation d'origine et représentation convertie générique, mais en même temps on ne peut pas toujours garder tous les détails et il faut faire des compromis à perte.

Le deuxième niveau devient notamment utile si on doit pouvoir ajouter des extensions après coup sans toucher aux classes de départ.

Après si ça doit être encore plus générique que ça, je ne sais pas… à mon avis difficile de alors mieux faire que de la simple conversion XML->JSON->ORM pour les différentes DB->fichiers sérialisés->etc.; ça ça existe déjà donc pas besoin de se casser la tête.

Ma plateforme avec 23 jeux de société classiques en 6 langues et 13000 joueurs: http://qcsalon.net/ | Apprenez à faire des sites web accessibles http://www.openweb.eu.org/

+0 -0
Staff

Je pense qu'il faudrait tout de même plus de détails sur l'application. Par exemple si les entrées sont de types XML ou JSON, ce sont deux formats conceptuellement proche, faire une abstraction de ces formats n'est probablement pas compliqué. Par contre si l'appli doit avoir comme source à la fois du JSON ou se brancher sur un serveur SQL, là ça se complique. L'un est totalement hiérarchisé avec une structure libre et généralement non typé alors que l'autre va être découpé par table, avec une structure figé. Et en plus de la structure il y a la quantité de données. Si on a juste des JSON de quelques milliers de lignes, on peut prévoir que le modèle charge tout en mémoire (le problème revient alors à juste avoir des surcharge de fonctions d'ouverture par format) mais si tu as une base avec des milliards d'éléments dedans, cela devient impossible et il faut que l'abstraction permet de faire un minimum de requêtes sélectives.

Tout ça pour dire que dans le cas général il y a beaucoup trop de paramètres pour qu'on puisse donner une solution conceptuel parfaite. Il faut un peu plus de détails sur les formats principaux et la quantité de données.

+2 -0

[HS] @QuentinC : Ton deuxième niveau de factory viole l'OCP, il vaut mieux une fonction d'enregistrement recevant une factory avec son pattern de reconnaissance et une map pour faire la liaison. [\HS].

First : Always RTFM - "Tout devrait être rendu aussi simple que possible, mais pas plus." A.Einstein

+0 -0
Auteur du sujet

Merci pour vos réponses. En très gros, je dois réaliser un réseau social facilement adaptable pour diverses implémentations. Donc exemple simple : quel que soit le réseau social, il y aura toujours des posts. Sauf que certains voudront des posts "simples (juste du texte), d'autres voudront une possibilité de "liker" les posts, d'autres voudront la psosibilité de faire des posts photos, bref un ensemble de modules qui doivent pouvoir être assemblés et désassemblés très aisément; (et les sources de données peuvent être multiples). Bref, j'avoue que je ne sais pas trop comment implémenter ça de façon propre et efficace !

+0 -0

[HS] @QuentinC : Ton deuxième niveau de factory viole l'OCP, il vaut mieux une fonction d'enregistrement recevant une factory avec son pattern de reconnaissance et une map pour faire la liaison. [\HS].

Bien vu… en C++ j'aurais plutôt sûrement fait ça de cette façon, effectivement, vu qu'à un moment ou à un autre il faut faire de la découverte de DLL/SO et il n'y a pas de façon plus simple d'instancier des implémentations d'interfaces à priori inconnues.

Je suis parti sur Java et en Java on a un mécanisme qui permet de rechercher automatiquement les factory du genre de mon second niveau et qui les instancie. Voir la doc sur les service providers. Du coup d'une part c'est plus simple comme ça et d'autre part on n'a pas vraiment besoin d'une fonction d'enregistrement. Si tu ajoutes un jar avec une nouvelle factory dans le classpath, elle apparaîtt toute seule dans la boucle de parcours des différentes instances, si le jar est correctement construit (sauf erreur un fichier dans /META-INF/services)

Je n'en mettrais pas ma main au feu mais il me semble que JDBC procède un peu de cette manière pour découvrir les différents moteurs disponibles; JavaSound aussi pour les différents formats recconus; les providers XML/SAX/DOM aussi; les algorithmes de crypto aussi… c'est un système fourni par Java et propre à lui.

IL n'a pas indiqué le langage dans lequel il travail, alors forcément, j'ai pris celui dans lequel je suis le plus à l'aise. En PHP on ferait encore autrement, je ne pense pas qu'on se casserait la tête avec une fonction d'enregistrement mais en essaierait d'utiliser l'autoload ou des include bien sentis, à moins qu'on opte pour une conf ou un stockage en base.

Ma plateforme avec 23 jeux de société classiques en 6 langues et 13000 joueurs: http://qcsalon.net/ | Apprenez à faire des sites web accessibles http://www.openweb.eu.org/

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte