Evolving existing APIs in backwards-compatible way (i.e. SOM and DOM)
Note: this entry has moved.
A couple days ago I posted about the inconvenience of an API that is designed to expose augmented data depending on its state. This is the case for the XmlSchema Object Model (SOM) in .NET and its Post-compilation infoset (PCI), as well as the DOM and its Post-schema validation infoset (PSVI). Dare Obasanjo aknowledged this issue, but is resigned, saying it's too late to fix any of this
.
I believe it's not. For classes that have grown too big, or became messy by mixing concepts like the two mentioned above, there's still room for improvement, without risk of breaking compatibility, which is a must in a serious framework such as .NET.
The "solution" involves creating new interfaces to hold the funcional subsets, and make the "legacy" class implement them as simple passthrough accessors to the cluttered "full" interface. In the case of the SOM, a new hierarchy of interfaces could be implemented, starting in a ICompiledXmlSchema
. The XmlSchema.Compile
method could return the new type:
public ICompiledXmlSchema Compile(System.Xml.Schema.ValidationEventHandler handler)
{
// Perform compilation as usual
return (ICompiledXmlSchema) this;
}
Code using the void
old version would remain unaffected, as they would be using:
XmlSchema xsd; //Load it somehow
// Perform compilation as usual
xsd.Compile(null);
In order to take advantage of the pre-compilation version subset a cast would be needed, for example to an IXmlSchema
:
IXmlSchema prexsd = (IXmlSchema) XmlSchema.Read(stream, null);
This interface would expose pre-compilation only members, such as XmlSchema.Items
, whereas the ICompiledXmlSchema
would replace it with XmlSchema.Elements
and XmlSchema.Attributes
and XmlSchema.SchemaTypes
instead.
This offers a more consistent programming model to the newer code taking advantage of these interfaces, while the "legacy" code keeps working. The typical case for read&compile schemas would be, therefore:
XmlSchema prexsd = XmlSchema.Read(stream, null);
ICompiledXmlSchema pcixsd = prexsd.Compile(System.Xml.Schema.ValidationEventHandler handler);
// Now I don't need to worry about pre vs post compilation members!