Comment gérez-vous l'extensibilité dans vos systèmes multi-locataires?

13

J'ai maintenant quelques gros produits multi-locataires basés sur le Web, et très bientôt je peux voir qu'il y aura beaucoup de personnalisations spécifiques au locataire.

Un champ supplémentaire ici ou là, peut-être une page supplémentaire ou une logique supplémentaire au milieu d'un workflow - ce genre de chose.

Certaines de ces personnalisations peuvent être intégrées au produit principal, et c'est formidable. Certains d'entre eux sont très spécifiques et gêneraient tout le monde.

J'ai quelques idées en tête pour gérer cela, mais aucune ne semble bien évoluer. La solution évidente est d'introduire une tonne de paramètres au niveau du client, permettant d'activer diverses «fonctionnalités» par client. L'inconvénient de cela, bien sûr, est la complexité et l'encombrement massifs. Vous pouvez introduire un nombre vraiment énorme de paramètres et, au fil du temps, divers types de logique (présentation, entreprise) peuvent devenir incontrôlables. Ensuite, il y a le problème des champs spécifiques au client, qui demande quelque chose de plus propre que d'ajouter simplement un tas de champs nullables aux tables existantes.

Alors, que font les gens pour gérer cela? Force.com semble être le maître de l'extensibilité; évidemment, ils ont créé une plate-forme à partir de zéro qui est super extensible. Vous pouvez ajouter à presque tout avec leur interface utilisateur Web. FogBugz a fait quelque chose de similaire en créant un modèle de plugin robuste qui, à bien y penser, aurait pu être inspiré par Force. Je sais qu'ils y ont consacré beaucoup de temps et d'argent et si je ne me trompe pas, l'intention était de l'utiliser réellement en interne pour le développement futur de produits.

Cela ressemble au genre de chose que je pourrais être tenté de construire, mais probablement pas. :)

Un investissement massif dans une architecture enfichable est-il la seule solution? Comment gérez-vous ces problèmes et quel type de résultats voyez-vous?

EDIT: Il semble que FogBugz ait géré le problème en construisant une plate-forme assez robuste, puis en l'utilisant pour assembler leurs écrans. Pour l'étendre, vous créez une DLL contenant des classes qui implémentent des interfaces comme ISearchScreenGridColumn, et qui devient un module. Je suis sûr que la construction a été extrêmement coûteuse compte tenu du fait qu'ils ont un grand nombre de développeurs et qu'ils y ont travaillé pendant des mois, et que leur surface est peut-être 5% de la taille de mon application.

En ce moment, je me demande sérieusement si Force.com est la bonne façon de gérer cela. Et je suis un noyau dur ASP.Net, donc c'est une position étrange pour me retrouver.

Brian MacKay
la source
3
Je devine que c'est la question de SO, ce qui rend celui - ci une post transversale identique. Ne faites pas cela, demandez la migration de la question SO ici, ou si vous cherchez des réponses différentes, dites-nous exactement pourquoi les réponses à la question SO ne sont pas satisfaisantes.
yannis
Vous avez raison, la question est meilleure sur les programmeurs, mais il semble toujours que vous ayez obtenu des réponses assez décentes. J'ai édité la question pour faire référence à la question SO.
maple_shaft

Réponses:

8

J'ai rencontré un problème similaire et je vais vous expliquer comment je l'ai résolu.

  1. Premièrement, il existe une bibliothèque ou un moteur "de base". Cela gère essentiellement le spectacle, comme vous l'avez déjà compris. Il gère des choses communes à chaque système, du rendu dynamique des formulaires, de la gestion des utilisateurs et des comptes, des rôles, vous le nommez, il le fait.

  2. Chaque partie du système est contenue dans un module. Un module a des dépendances (autres modules dont il dépend). Par exemple, le système «de base» a la sécurité (utilisateurs, groupes, rôles, politiques de mot de passe), les paramètres régionaux (traductions, pays, cultures), le référentiel de fichiers, le courrier électronique, etc., etc. Chaque module se définit à l'aide d'un fichier xml. Le fichier xml spécifie essentiellement les schémas, les tables, les classes de calcul, les définitions d'écran, etc. Ceux-ci sont lus au démarrage de l'application si la date du fichier a changé .

  3. Les modules spécifiques au client ont leurs propres fichiers xml et leur propre DLL. Tout cela en plus et fonctionne en conséquence et de manière transparente avec le reste du système. Jusqu'au remplacement des vues MVC existantes par des vues personnalisées, avec du code personnalisé et des modèles de vue personnalisés.

  4. Si un client souhaite étendre les fonctionnalités existantes, le xml / système fournit une méthode où je peux "dériver" un module d'un autre. Le nouveau module possède toutes les fonctionnalités existantes, mais avec les exigences spécifiques du client dans une nouvelle DLL et avec un fichier XML étendu qui peut effectuer les modifications. La mise en garde est, ils ne peuvent pas réellement supprimer les champs existants dans ce système, mais nous pouvons l'étendre et fournir des objets et des fonctionnalités entièrement nouveaux.

Moo-Juice
la source
+1: Cela semblait avoir pris une heure ou deux. :)
Brian MacKay
1
@BrianMacKay, eh bien, une fois le travail terminé (et c'était un slog), nos clients étaient très satisfaits de la vitesse à laquelle nous avons pu changer les personnalisations. Notez que le framework MVC (autant que les vues / pages sont concernées) ne se prête pas très bien au multi-projet. Nous avons contourné cela en utilisant les fonctionnalités de propriété de SVN et en faisant en sorte que les vues principales soient importées du référentiel principal, et avons utilisé CSS / layouts pour le personnaliser. Mais année, quelques bonnes heures: P
Moo-Juice
Juste curieux, combien de temps pensez-vous qu'il a fallu pour mettre en œuvre l'architecture elle-même et combien de développeurs ont été impliqués?
Brian MacKay
1
@BrianMacKay, c'était 5 mois. Un développeur d'interface utilisateur pour faire toutes les vues CSS / HTML / partielles, javascript, etc., et un développeur backend (moi-même) pour faire le reste.
Moo-Juice
4

Avoir beaucoup de logique de gestion des versions et de couches de code à gérer n'ajoute pas de valeur à votre application / site Web. Cela nécessite également plus de puissance cérébrale pour comprendre ce qui se passe et vous distrait du cœur de ce que vous faites.

Je conseille différemment. Je conseille de garder les choses simples sur complexes.

Maintenez une base de code unique qui est la même pour tout le monde. Chaque fonctionnalité que vous ajoutez est une fonctionnalité pour tous. Limitez uniquement le nombre d'articles ou de stockage ou quelque chose de quantifiable, pas de fonctionnalités. La raison en est la quantification de choses telles que le stockage, le nombre d'entrées de données, etc. Il ne doit être programmé que lors de l'ajout d'éléments au lieu de faire une logique de fonctionnalité. Et si les fonctionnalités sont liées à d'autres fonctionnalités? Il devient très compliqué de coder pour cela.

Pour qualifier ma réponse, j'ai construit un cadre de commerce électronique que j'ai pour de nombreux clients et j'ai appris la manière difficile d'essayer de maintenir toutes leurs particularités. J'ai fini par briser la chaîne et créé un site Web d'administration unique à plusieurs niveaux pour le commerce électronique. J'ai ensuite des sites Web qui récupèrent des données d'appels de service Web. Cela permet à différentes équipes dans différentes technologies de mettre en œuvre des fonctionnalités spécifiques pour les sites de commerce électronique pendant que je continue d'être payé chaque mois sur la même infrastructure et que je me fiche de ce qu'ils font. Je limite simplement l'utilisation par des nombres, pas par des fonctionnalités. C'est plus facile. Le client peut choisir son propre fournisseur pour construire son site Web et je ne participe plus à ces décisions.

J'ai également un service d'abonnement pour la gestion de contenu SAAS. Cela fonctionne également par niveaux d'utilisation et les clients peuvent ajouter leurs propres plugins s'ils le souhaitent tandis que mon équipe ajoute plus de fonctionnalités pour tous.

C'est juste mon expérience de me cogner la tête contre le mur après si longtemps, puis de tomber sur quelque chose de plus simple.

Si quelque chose va toujours être spécifique à chaque client, ne faites pas de cadre pour cela. Décomposez-le en ses parties les plus simples pour que la partie cadre fonctionne pour tous, puis découpez le reste afin de pouvoir l'étendre pour l'individu.

Jason Sebring
la source
+1 pour partager votre expérience. Une grande partie de ce que je semble entendre est "c'est un problème très difficile". La réalité à laquelle je fais face est que ce système aura des tonnes de personnalisations et qu'elles ne sont pas toutes appropriées pour tout le monde ... comme ils le souhaitent - j'ai au moins l'avantage d'écrire toutes les extensions en interne. Mais c'est toujours un gâchis à gérer (cntd)
Brian MacKay
La conclusion à laquelle j'arrive est que vous devez écrire une plate-forme qui prend en charge sa propre notion de composants d'interface utilisateur et de composition dynamique, puis créer l'ensemble de l'application à l'aide de cette plate-forme. Et donc je commence à penser qu'il serait intelligent d'écrire le tout dans force.com, car c'est ce qu'est force.com!
Brian MacKay
Brian, FYI kitgui.com et hubsoft.com si vous êtes curieux.
Jason Sebring
2

Le produit logiciel sur lequel je travaille comporte des champs supplémentaires pour l'extensibilité de l'utilisateur. Chaque élément de données de ces champs peut être associé à une ligne existante dans les tables principales de l'application. Par exemple, si votre logiciel contient des clients et chaque client une liste de commandes, la table de données personnalisable aura une colonne pour les clés étrangères de la table client et de la table de commande, dont une seule sera non nulle. Soit cela, soit un certain nombre de tables ayant chacune les champs personnalisés pour une table.

Il s'agit d'un moyen simple et performant de stocker des données supplémentaires pour l'utilisateur. Des informations supplémentaires devraient être stockées sur les noms et les types de ces champs.

Cela couvre les champs personnalisés pour un client. Pour un comportement personnalisé, une API de services Web permettrait des extensions.

spirc
la source
1

1) L'exécution du code de quelqu'un d'autre sur des boîtes que vous possédez est un problème assez difficile. Soit vous pouvez leur faire confiance, soit vous pouvez différer leur responsabilité de manière raisonnable, vous devrez mettre en sandbox leur code très fortement et vous consacrer à la sécurité plus que la moyenne. Au fur et à mesure que votre système de plugins permet plus de fonctionnalités, la difficulté de le sécuriser augmente. Des choses comme le déni de service (les plugins consomment trop de ressources), la fuite d'informations (les plugins peuvent accéder aux données d'autres locataires), etc. peuvent être très réels et gênants, je ne participerais pas à moins que je ne puisse familiariser les gens avec ces problèmes ou des gens très capables avec beaucoup de temps pour bien faire les choses.

2) Oui, la modularité et la personnalisation sont difficiles. Des choses telles que le modèle de stratégie peuvent aider (un nom de fantaisie pour les pointeurs de fonction; en Java, il est généralement implémenté en déclarant une interface que les utilisateurs de la classe peuvent implémenter pour personnaliser le comportement de votre code), mais vous voudrez très isolé et découplé code pour que cela fonctionne.

3) Sur le plan des données, cela pourrait être l'un des exemples de stockage sans schéma utile. Si vous avez un modèle de données relationnel, avoir des tables avec beaucoup de colonnes pour différents clients est problématique (oui, vous vous retrouvez avec beaucoup de colonnes annulables, ce qui est mauvais ; une des raisons est qu'il est difficile ou impossible de définir les contraintes correctes [c.-à-d. contraintes qui ne permettent pas aux combinaisons invalides de null d'apparaître]). Il est préférable d' ajouter des tables spécifiques au client (c'est-à users- dire et foo_users, en usersmaintenant les champs valides pour tous les clients et en foo_usersayant les fichiers spécifiques à Foo); vous pouvez facilement corriger les contraintes, mais votre SGBDR peut ne pas le gérer correctement (en raison de l'explosion des jointures, des limites sur le nombre de tables, etc.) et sera probablement laid dans votre code.

Vous pourriez finir par implémenter un magasin de valeurs-clés dans votre SGBDR, ce qui rend votre modèle de données moins relationnel et provoquera un inconfort (c'est-à-dire que les bases de données relationnelles fonctionnent mieux avec les modèles relationnels). Je ne sais pas si une solution NoSQL résoudra le problème dans son ensemble, mais la simplicité de la plupart des implémentations pourrait être un avantage.

alex
la source