The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Multi-Tenant MetaData, Business Logic :: Where To Begin?

I recently posted a question about per-customer customisation:-
http://discuss.joelonsoftware.com/default.asp?design.4.443107.4#discussTopic443406

I very much appreciated all the input and I was really taken by the "multi-tenant" customisation of everything through metadata solution. The single codebase stays the same for every customer, just their metadata changes.

The multi-tenancy of the database isn't my problem (there are several good articles about this), I have a handle on that, it's more the business logic/customisation that I'm struggling with.

The output file I want to customise (typically an XSD-defined XML document) is reasonably large. I created a "sample" XML file from the XSD with XMLSpy (great app BTW) containing no data, just the XML skeleton and it's 2820 lines long and nested up to 8 levels in places. The combinations and granularity that customer's can choose, not only with "optional" elements but also the format of the data between the elements makes the amount of metadata required potentially enormous, so I need a pointer to the best way of getting this working with the least amount of "up front" metadata.

The solution I'm contemplating is to have per-customer templates (XML files themselves I guess) with "tokens" that are filled somehow with customer-specific data. The problem is, if I don't want to code this into customer-specific application code I guess I'm going to need "clever" tokens which also include the format of the data and the source?

So instead of <DelDate>%%deldate%%</DelDate> and having bespoke code for each customer to populate the %%deldate%% token I'd have something like:

<DelDate><tok:token source="select dt from load where customer_id='%%cust%%'" format="dd-mmm-yyyy"></DelDate>

This method would need some serious thought because the number of SQL commands run against the database would be large. There must be a better method?

I guess I'll also need to create some tokens that can include/exclude the blocks of XML they enclose, based on customer-specific metadata? Does anyone with experience of this have any quick examples of the type of thing they've done that they could post? I'm not talking about complete solutions, just some "ideas" to get the thought process moving!

As a side thought, do you think some of the template-based code generators, like CodeSmith would be capable of being scripted to perform this task?

Thanks for your time.
Squidward Tentacles
Friday, February 02, 2007
 
 
Do you have to use XML languages? That's the first thing I would cut if I were you. IMHO, XML languages are good at markup up documents, but not really very good as data stores.

There's so much extra overhead in using XML languages as data stores, your app seems complicated enough as it is.
Steve Hirsch Send private email
Friday, February 02, 2007
 
 
Steve,

The output to most of the customers HAS to be in XML, nothing else does though.

Some customers have more sense and instead of a 2800 line (more when it contains "real" data) XML file they opt for a simple CSV!

This "system" I'm building really needs to handle all these output format options, industry-standard XSD'd XML, CSV, in-house custom-XML, etc but I'm working on the option with most take-up at the moment, the industry-standard XSD'd XML output.
Squidward Tentacles
Friday, February 02, 2007
 
 
OK, poor you. First thing to look at, something I always harp on, is that "using XML" is like eating a cookie cutter. Have the individual customers specified XSD's for you already, or do you have the ability to specify your own data structures?
Steve Hirsch Send private email
Friday, February 02, 2007
 
 
Steve,

The XSD's are pre-defined, industry-standard. In a way this is a good thing as it's one less thing I have to worry about defining!

The big issue (for me) is that a large amount of the XML is optional (in the XSD) although to be honest, if I can provide all the optional elements then customers are simply free to ignore them when they parse the message so I don't have to worry too much about customers NOT wanting some elements.

The biggest effort is the source of data for elements and the format of it.

Thus, customer A might have their own product codes which we maintain in a table at our end (don't ask why WE are maintaining a duplicate of THEIR codes, but we are) so when I generate their message it comes from a customer-specific table and is a 5-digit number.

Customer B might be happy with product specification (width, height, weight, colour) which the XSD has elements for and this information comes from our ERP system.
Squidward Tentacles
Saturday, February 03, 2007
 
 
OK, I'll give you a short, 2 part generic answer.

One, only output the required XML fields unless there is an overwhelming reason to output something not required.

Two, you'll need a metadata repository, and some way to generate code from that repository. Can you say dynamic SQL? (:=)
Steve Hirsch Send private email
Sunday, February 04, 2007
 
 
Whenever I'm working on a project that will ultimately produce validated XML, I ask myself:  can I drive the production off of the schema?

Can I build an XmlReader subclass that traverses the schema and builds the output from the data store as it goes?  Sometimes this is obviously a terrible idea.  But it's worth considering.

In your case, you could define an XML syntax for customer-specific metadata, put it in your own namespace, and decorate the XSD with the metadata, e.g.:

    <xs:element name="bar" minOccurs="0">
        <my:requestedBy customer="A"/>
        <my:requestedBy customer="C"/>
    </xs:element>

which indicates that customers A and C have requested this otherwise-optional element.

An XmlReader that hit this element would ignore it for customer B, but would generate it for the customers who requested it.  If you design your metadata properly, the number of possible states that the XmlReader has to handle can be quite small.

Another nice thing about storing the metadata in the schema is that you can generate more restrictive customer-specific versions of the schema via XSLT, e.g.:

    <xsl:template match="xs:element[@minOccurs='0']">
    <xsl:copy>
        <xsl:copy-of select="@name"/>
        <xsl:choose>
            <xsl:when test="my:requestedBy[@customer=$customer]">1</xsl:when>
            <xsl:otherwise>0</xsl:otherwise>
        </xsl:choose>
    </xsl:copy>
</xsl:template>

which will turn optional elements into required ones for the specified customer.  That way you can be sure that the XML you're emitting is not only conformant to the original schema but also implements all of the customer's added requirements.  (You'd validate the output against the original XSD too, just to make sure you don't have any defects in your transform.)
Robert Rossney Send private email
Wednesday, February 14, 2007
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz