Posted Oct 20, 2008
4 out of 5 developers agree: XML configuration is teh fail
XML is not like violence: if it isn’t working, the answer is not to use more.
“XML is the wrong language for configuration files. It sucks. Don’t pretend that this isn’t true. It’s ugly, intimidating for non-techies, and error-prone.”
John DeRosa is right. WebLion spends much of its time teaching Plone, and the above aptly reflects the experience of our learners—and, for that matter, our developers. The various XML dialects used in Plone are more verbose, less documented, harder to write, and harder to read than straight Python, and every audience I contact seems to agree. At a recent user group meeting, I brought up an old-style Install.py briefly (and even somewhat ashamedly), and the audience of XML-trained recent adopters stopped me and peppered me with questions about how I managed to do all my installation and uninstallation so simply!
More languages are bad
I'm all for domain-specific languages when they deliver clear wins, but that is not what we have in Plone right now. Here's how these extra languages are hurting us:
- Adding languages adds to the burden on new users. ZCML and the other dialects in places like viewlets.xml and skins.xml are each another new language you have to learn to do Plone. They are used nowhere else in the world, so 0% of Zope inductees know them already, and any knowledge they gain is unportable. We already require them to learn TAL, METAL, and lots of disorganized API—along with HTML, CSS, and JavaScript—so we should be darn careful of making the load any heavier.
- Adding languages duplicates functionality. For example, take this repetition. This sort of thing happens all the time because ZCML has no looping construct. That might sound a little "out there" until you consider that it has already grown an "if" statement. Bizarre? Just wait a few iterations, and we'll have a pretty serviceable language in terms of flow control, except that it'll be useful only for configuring Zope sites, more verbose, less documented, and swallowed up inside a more mature language that should have kept doing the job in the first place.
- GenericSetup is no more declarative than Python install procedures. It's a snapshotting system that's been Frankensteined into an installation one. Indeed, many of the above demerits could be excused if GS delivered a true declarative installation system. We could have uninstall for free, and it could be lingually impossible to commit the kind of screwups possible in manual install procedures. Instead, we have an imperative list of instructions just as before, except with more punctuation and thus arguably more opportunity for error. GenericSetup executes its instructions mindlessly and serially, just like Python, and if you make a mistake in your uninstall profile, you get a broken Plone site, just as before.
4 out of 5 developers agree
This underground consensus is growing. In my XML-provoked anger, I tossed some comments into #plone the other day expecting a quick rebuff, but what I got was a cascade of hearty agreement (reformatted so you don't go insane):
- sm: ErikRose, your cause is just! I for one am with you! *sings a valorous song*
- trollfot backs ErikRose.
-
ErikRose: I find both [viewlets.xml and GenericSetup] equally difficult. I don't even differentiate.
james4765: oh good, it's not just me :P
- sixstring: +1 to ErikRose's cause.
- claytron, our number five, was a little reticent, observing that it's a nightmare to register a portlet in Python. I agree, and that very API nightmarishness is one of the main things we need to fix.
What to do?
- Use convention over configuration wherever possible. Lennart Regebro and friends have done some great work toward this with five.grok. Let's support them!
-
For the remaining configuration, let's do it in Python. It's one of the easiest to learn languages out there, and WebLion's beginners pick it up faster than GS XML. It's mature, has all the constructs we're likely to need, and, because the rest of the system is in Python, we won't be throwing up any big, brick walls that discourage refactoring.
For this to work, our API must excel (which it should anyway). There's been a disquieting trend to just throw more abstraction layers atop ugly APIs in the Zope world, and that has to stop—it leaves us with endless layers of cruft no one understands, incomprehensible tracebacks and weekend-long pdb sessions, and duplication of code (do you hear me, MembershipTool?). In addition, our functions should be very difficult to call incorrectly: when somebody screws up, we need to throw errors ASAP. For example, let's stay away from functions you can call a million different ways. Overloading functions doesn't go well in Python, since you need a pile of hard-to-read, error-prone branching logic at the top to infer what the caller was thinking.
-
STOP WRITING SO MUCH CODE! ZopeSkel is all well and good, but I'd like to see it all but killed by good APIs. Those pages of boilerplate that DIYPloneStyle used to generate? They should be made unnecessary by fixing Plone's APIs or else moved wholesale into Plone so they can be maintained OnceAndOnlyOnce. Folks can call them from their install procedures, which can be trimmed to a sliver of their former girth.
The above API fixes will also further this goal. We need to mercilessly redesign parts of the API that make doing the right thing prohibitively verbose. Needing to do this sort of thing to uninstall a simple skin is inexcusable.
- Once we have an excellent API, we can, as a bonus, design a proper declarative config language on top of it. This language should never be shown to the user and could better be classed a mere format: there should be tools for manipulating it (big green button?), perhaps repurposing the good work that's gone into GS snapshot-taking. Ideally, this format would be scarcely about state manipulation and almost entirely about layers of desires, each product telling the system how it would like things and the system brokering conflicts. On uninstall, a product's layers would be pulled out of the stack and simply stop taking effect. Uninstall profiles would be necessary for only the strangest of cases.
- It should have a pony.
What we need now is some proofs of concept to show that these admittedly ambitious goals are attainable. I'll race you to the repository!

No!
I can certainly understand that people are frustrated by poorly docmented languages, but it would a big mistake to perform configuration in Python. A fully-fledged programming language is not place to store configuration settings, much like the ZODB is a bad place to persist settings that are not reflected elsewhere (e.g. in GenericSetup). We've been there with Install.py and it's a mess. Developers end up copying boilerplate they don't understand, or writing code that's too clever by half.
Configuration should be dumb, system-parsable and easy to understand. If ZCML grew a looping construct, it'd be a disaster. If we dropped GS, we'd be back in the dark ages. (though many of the GS files should be better documented, I agree)
That said, I'm a big fan of the Grok-based convention-over-configuration for registering components. Components are code constructs, not configuration. Wiring of components does not need to be externalised (though the override of default wiring should still be externalisable), and reducing the number of files a developer needs to use for a given task is a worthy goal.
Martin