Ich habe jetzt ein paar große, webbasierte Multi-Tenant-Produkte und sehr bald kann ich sehen, dass es eine Menge Anpassungen geben wird, die mandantenspezifisch sind.
Ein zusätzliches Feld hier oder da, vielleicht eine zusätzliche Seite oder eine zusätzliche Logik mitten in einem Workflow - so etwas.
Einige dieser Anpassungen können in das Kernprodukt übernommen werden, und das ist großartig. Einige von ihnen sind sehr spezifisch und würden allen anderen im Weg stehen.
Ich habe ein paar Ideen, um dies zu handhaben, aber keine davon scheint gut zu skalieren. Die naheliegende Lösung besteht in der Einführung einer Vielzahl von Einstellungen auf Client-Ebene, mit denen verschiedene "Funktionen" auf Client-Basis aktiviert werden können. Der Nachteil dabei ist natürlich die massive Komplexität und Unordnung. Sie könnten eine wirklich große Anzahl von Einstellungen vornehmen und im Laufe der Zeit könnten verschiedene Arten von Logik (Präsentation, Geschäft) außer Kontrolle geraten. Dann gibt es das Problem der kundenspezifischen Felder, die nach etwas Besserem verlangen, als nur eine Reihe von nullfähigen Feldern zu den vorhandenen Tabellen hinzuzufügen.
Was tun die Leute, um das zu handhaben? Force.com scheint der Meister der Erweiterbarkeit zu sein. Offensichtlich haben sie von Grund auf eine Plattform geschaffen, die super erweiterbar ist. Über die webbasierte Benutzeroberfläche können Sie fast alles ergänzen. FogBugz hat etwas Ähnliches gemacht, bei dem sie ein robustes Plugin-Modell erstellt haben, das, wenn man es sich überlegt, tatsächlich von Force inspiriert sein könnte. Ich weiß, dass sie viel Zeit und Geld dafür aufgewendet haben, und wenn ich mich nicht irre, war die Absicht, es tatsächlich intern für die zukünftige Produktentwicklung zu verwenden.
Hört sich so an, als könnte ich versucht sein, etwas zu bauen, sollte es aber wahrscheinlich nicht. :)
Ist eine massive Investition in steckbare Architektur der einzige Weg? Wie gehen Sie mit diesen Problemen um und welche Ergebnisse sehen Sie?
EDIT: Es sieht so aus, als hätte FogBugz das Problem gelöst, indem er eine ziemlich robuste Plattform erstellt und diese dann verwendet, um ihre Bildschirme zusammenzustellen. Zum Erweitern erstellen Sie eine DLL mit Klassen, die Schnittstellen wie ISearchScreenGridColumn implementieren und zu einem Modul werden. Ich bin mir sicher, es war enorm teuer zu bauen, wenn man bedenkt, dass sie viele Entwickler haben und monatelang daran gearbeitet haben, und dass ihre Oberfläche vielleicht 5% der Größe meiner Anwendung beträgt.
Im Moment frage ich mich ernsthaft, ob Force.com der richtige Weg ist, damit umzugehen. Und ich bin ein hartgesottener ASP.Net-Typ, also ist dies eine seltsame Position, in der ich mich wiederfinde.
quelle
Antworten:
Ich war mit einem ähnlichen Problem konfrontiert, und ich erzähle Ihnen, wie ich es gelöst habe.
Erstens gibt es eine "Kern" -Bibliothek oder Engine. Im Grunde läuft die Show so, wie Sie es bereits herausgefunden haben. Es behandelt Dinge, die jedem System gemeinsam sind, vom dynamischen Rendern von Formularen über die Benutzer- und Kontoverwaltung bis hin zu Rollen.
Jeder Teil des Systems ist in einem Modul enthalten. Ein Modul hat Abhängigkeiten (andere Module, von denen es abhängt). Das "Kern" -System verfügt beispielsweise über Sicherheit (Benutzer, Gruppen, Rollen, Kennwortrichtlinien), Gebietsschema (Übersetzungen, Länder, Kulturen), Dateirepository, E-Mail usw. Jedes Modul definiert sich selbst mithilfe einer XML-Datei. Die XML-Datei spezifiziert im Wesentlichen die Schemata, Tabellen, Berechnungsklassen, Bildschirmdefinitionen usw. Diese werden beim Start der Anwendung eingelesen, wenn sich das Dateidatum geändert hat .
Kundenspezifische Module haben eigene XML-Dateien und eine eigene DLL. Das alles ist von Vorteil und funktioniert dementsprechend und transparent mit dem Rest des Systems. Bis hin zum Ersetzen vorhandener MVC-Ansichten durch benutzerdefinierte Ansichten mit benutzerdefiniertem Code und benutzerdefinierten Ansichtsmodellen.
Wenn ein Kunde bestehende Funktionen erweitern möchte, bietet das XML / System eine Methode, mit der ich ein Modul von einem anderen "ableiten" kann. Das neue Modul verfügt über alle vorhandenen Funktionen, jedoch mit den spezifischen Anforderungen des Kunden in einer neuen DLL und mit einer erweiterten XML-Datei, die die Änderungen vornehmen kann. Die Einschränkung ist, dass sie vorhandene Felder in diesem System nicht entfernen können, aber wir können sie erweitern und völlig neue Objekte und Funktionen bereitstellen.
quelle
Das Verwalten vieler Versionslogiken und Codeebenen ist kein Mehrwert für Ihre Web-App / Website. Es erfordert auch mehr Gehirnleistung, um zu verstehen, was vor sich geht, und lenkt Sie vom Kern dessen ab, was Sie tun.
Ich rate anders. Ich rate, die Dinge einfach über komplex zu halten.
Pflegen Sie eine einzige Codebasis, die für alle gleich ist. Jedes Feature, das Sie hinzufügen, ist ein Feature für alle. Beschränken Sie nur die Anzahl der Artikel oder den Speicherplatz oder eine quantifizierbare Sache, nicht die Merkmale. Der Grund dafür ist, dass die Quantifizierung von Dingen wie Speicherplatz, Anzahl der Dateneinträge usw. so einfach zu programmieren ist und nur auf eine kleine Handvoll von Dingen angewendet werden kann, die den Benutzer wirklich daran hindern, mit Ihrer App wild zu werden. Es muss nur beim Hinzufügen von Elementen programmiert werden, anstatt eine Funktionslogik auszuführen. Was ist, wenn Funktionen mit anderen Funktionen verknüpft sind? Es wird sehr kompliziert, dafür zu programmieren.
Um meine Antwort zu qualifizieren, habe ich ein E-Commerce-Framework erstellt, das ich für viele Kunden habe, und die harte Art und Weise gelernt, alle ihre Eigenheiten zu bewahren. Am Ende habe ich die Kette gebrochen und eine einzige Verwaltungswebsite erstellt, die für den E-Commerce von mehreren Anbietern geeignet ist. Ich habe dann Websites, die Daten von Webservice-Aufrufen abrufen. Auf diese Weise können verschiedene Teams in verschiedenen Technologien bestimmte Funktionen für E-Commerce-Websites implementieren, während ich jeden Monat für dieselbe Infrastruktur bezahlt werde und es mir egal ist, was sie tun. Ich beschränke die Verwendung nur auf Zahlen, nicht auf Funktionen. Es ist viel einfacher. Der Kunde kann seinen eigenen Anbieter für die Erstellung seiner Website auswählen und ich bin an diesen Entscheidungen nicht mehr beteiligt.
Ich habe auch einen Abonnementservice für Content Management SAAS. Dies funktioniert auch nach Nutzungsstufen, und die Kunden können ihre eigenen Plugins hinzufügen, wenn sie dies wünschen, während mein Team weitere Funktionen für alle hinzufügt.
Dies ist nur meine Erfahrung, als ich nach so langer Zeit meinen Kopf gegen die Wand schlug und dann auf etwas Einfacheres stieß.
Wenn etwas für jeden Kunden immer spezifisch sein wird, dann machen Sie keinen Rahmen dafür. Teilen Sie es in die einfachsten Teile auf, damit der Rahmenteil für alle funktioniert, und schneiden Sie den Rest aus, damit Sie ihn für den Einzelnen erweitern können.
quelle
Das Softwareprodukt, an dem ich arbeite, verfügt über zusätzliche Felder für die Benutzererweiterung. Jedes Datenelement für diese Felder kann mit einer vorhandenen Zeile in den Haupttabellen der Anwendung verknüpft werden. Wenn Ihre Software beispielsweise Kunden und für jeden Kunden eine Liste von Aufträgen enthält, enthält die anpassbare Datentabelle eine Spalte für Fremdschlüssel zur Kundentabelle und zur Auftragstabelle, von denen nur einer nicht null ist. Entweder diese oder eine Reihe von Tabellen, von denen jede die benutzerdefinierten Felder für eine Tabelle enthält.
Dies ist eine einfache und performante Möglichkeit, zusätzliche Daten für den Benutzer zu speichern. Es müssten zusätzliche Informationen zu den Namen und Typen dieser Felder gespeichert werden.
Das deckt die benutzerdefinierten Felder für einen Kunden ab. Für ein benutzerdefiniertes Verhalten würde eine Webdienst-API Erweiterungen zulassen.
quelle
1) Das Ausführen des Codes eines anderen auf eigenen Boxen ist ein ziemlich schwieriges Problem. Entweder können Sie ihnen vertrauen, oder Sie können die Verantwortung vernünftigerweise aufschieben. Sie müssen den Code sehr stark schleifen und sich überdurchschnittlich der Sicherheit widmen. Da Ihr Plugin-System mehr Funktionen bietet, wird es immer schwieriger, es sicherer zu machen. Dinge wie Denial-of-Service (Plugins verbrauchen zu viele Ressourcen), Informationslecks (Plugins können auf die Daten anderer Mieter zugreifen) usw. können sehr real und problematisch sein. Ich würde nicht daran teilnehmen, wenn ich nicht die Leute kennenlernen könnte diese Probleme oder sehr fähige Leute mit viel Zeit, um es richtig zu machen.
2) Ja, Modularität und Anpassbarkeit sind schwierig. Dinge wie das Strategy-Muster können hilfreich sein (ein ausgefallener Name für Funktionszeiger; in Java wird dies normalerweise durch Deklarieren einer Schnittstelle implementiert, die Benutzer der Klasse implementieren können, um das Verhalten Ihres Codes anzupassen), aber Sie möchten sehr isoliert und entkoppelt sein Code, damit dies funktioniert.
3) In Bezug auf Daten kann dies eines der Beispiele für die Verwendung von schemenlosem Speicher sein. Wenn Sie ein relationales Datenmodell haben, ist es problematisch, Tabellen mit vielen Spalten für verschiedene Kunden zu haben (ja, Sie haben am Ende viele nullfähige Spalten, was schlecht ist ; ein Grund ist, dass es schwierig oder unmöglich ist, die richtigen Einschränkungen festzulegen [d. H Einschränkungen, die nicht zulassen, dass ungültige Kombinationen von Nullen angezeigt werden]). Hinzufügen von kundenspezifischen Tabellen (dh
users
undfoo_users
, wobeiusers
die Felder für alle Kunden gültig sind undfoo_users
Es ist besser, hinzuzufügen die Foo-spezifischen Dateien zu haben). Sie können leicht korrekte Einschränkungen haben, aber Ihr RDBMS kann dies möglicherweise nicht ordnungsgemäß handhaben (aufgrund von Join-Explosion, Begrenzung der Anzahl von Tabellen usw.) und wird in Ihrem Code wahrscheinlich hässlich aussehen.Möglicherweise implementieren Sie einen Schlüsselwertspeicher in Ihrem RDBMS, wodurch Ihr Datenmodell weniger relational ist und Unannehmlichkeiten verursacht (dh relationale Datenbanken funktionieren am besten mit relationalen Modellen). Ich bin mir nicht sicher, ob eine NoSQL-Lösung insgesamt zum Problem passt, aber die Schemalosigkeit der meisten Implementierungen könnte von Vorteil sein.
quelle