Comments on Django’s design decisions
In my talk about what Zope did wrong, I tried to tell the world not to repeat Zope’s mistakes, and I learned at PyCon 2008 that Django have repeated some of them. Mark Ramm also did his keynote on what Django can learn from Zope at last year’s DjangoCon. So I don’t know if it was intentional, but Jacob Kaplan-Moss’ talk about Django’s design decisions at this year’s PyCon felt to me like Django trying to defend itself a bit.
And without a doubt, Django is a good web framework. If it wasn’t, it wouldn’t be so popular. And although I think it needs some big changes to be “future-proof”, I must say that this is basically not very important. One thing I have realized is that when it comes to software choice, choose what works for you, today. Future-proofing is irrelevant, because you don’t know the future. So my comments here are not designed to scare anyone away from Django. Of course, it is partly a question of me sticking the Zope technologies in your face and screaming “Hey Look at This, isn’t this Fantastic!?” and maybe to an even bigger extent just a way to say “Been There, Done That, Not a Good Idea”.
Architecture and Morality
I agree with the basic decisions of Django. They chose Python, open source, of course, having sensible defaults instead of requiring loads of configuration for everything, and also that you shouldn’t have “architecture astronauts”. There is a type of programmer who likes complexity for it’s own sake, and if you let them write a framework, it’s going to be amazing, and amazingly complex to the point of being unusable. But the risk of ignoring architecture astronauts isn’t what Kaplan-Moss says, that you risk reinventing the wheel. The risk is that you paint yourself into a corner. This is not a problem for end user software, because you can always refactor it. But it is a problem for frameworks, because here other people are using the framework and when you refactor it, you break every body else’s software. This is why corners are hard to get out of when building frameworks, because when you walk over the wet paint, it’s not just your work that gets undone, it’s everybody else’s as well. And that’s what the architecture gurus are there for, coming up with a technique of building that means you don’t end up in corners. But yes,you still should be aware of the guys that want to put in flexibility without being able to explain what the use case for that flexibility is. Doing that can often give you complexity because you have flexibility in places where you don’t need it. Zope 3’s publisher has a hook for you to replace the type of object traversal that is done (i.e how you figure out which object is meant with a particular path). And the default traverser has a hook to change how traversal is done on a particular object. And the default object traverser will use __getitem__ to figure out subobjects. Which of course is overridable. That means that you have three places where you can change what the subobjects of your object will be. That is simply not needed. I’ve yet to find a case where the simplest one, __getitem__, isn’t enough.
One common mistake between Zope 2 and Django, is that some functionality, like object security, is handled by special methods or attributes on the content class. That works well, in the beginning, but then you end up wanting to change the way the security works to make it more flexible, and you introduce more attributes, but keep backwards compatibility to not break everybody else code, and you end up with a horrible mess of magic attribute names that change the objects behavior in subtle ways. Zope 2 did this is a big way, and not only with security. I noticed last year that Django did that as well, although not in a big way. Yet.
Full stack or slim waist
I can also not really criticize them for being a full-stack framework. I do disagree with Kaplan-Moss, the dichotomy between a full-stack framework and a “best of breed” framework definitely exists. And even if you, like any good developer, tries to make your full-stack framework consist of separate parts that can be used independently of the whole, unless you make sure it is used independently of the whole, dependencies are going to start to creep in. Zope 2 and Zope 3 where also full-stack frameworks, and for the same reason as Django: There just wasn’t anything else out there. Obviously, when Django started, there was something out there, Zope 2, and Twisted. But the only part that was truly independent of Zope 2 was the ZODB, and Django decided to go for an ORM, and Twisted refused to use thread pools, making it significantly slower, as it has to start a thread for each web request.
But Jacob Kaplan-Moss then goes on to criticize the best-of breed frameworks because you need “glue code” to clue the components together. This is partly true, of course, but it doesn’t distract from the fact that the components in the glued system still works separately and can be learned separately. And that comes into play when Kaplan-Moss talks about the learning curve of Django, and how you have to almost unlearn bits. This is nothing unique to Django. With Zope 2 we have the exact same phenomenon, which is in the Zope community known as “The Z-shaped learning curve”. Jacob claims that this is something that comes with a framework. I do not agree. I think it comes with full stack framework, where there aren’t good separation between different parts, and the internals are messy. But I do not believe this is true for a well designed best of breed framework.
My way or the plugin way
And I have to really protest about Jacob Kaplan-Moss’ criticism over pluggable components. First of all he completely misses the point, and says that it’s not possible to write an application with STORM and then flip a switch and use SQLAlchemy instead. Well, of course it isn’t, unless you actually write a wrapper for them, which seems more work than it’s worth. But the point is that you shouldn’t be stuck. In Zope 2, you can in practice use two templating systems. DTML, which was Zope 2’s first one, and ZPT, which was a much better one introduced some years later. But what if you don’t like them? What if you want to use something else. You might like Zope 2 as a whole, but really detest both DTML and ZPT. Well, in Grok, we have made it very easy to plug in other templating systems. Of course you can’t switch in a project, all your ZPT templates would have to be re-written. But for the next project, you can stick in Genshi or whatever you want. (In fact you can use all of them at the same time, but that’s not true for all types of pluggable components, so it’s besides the point). Pluggability gives you flexibility.
And here Jacob Kaplan-Moss claims that by having choices is bad. That is almost shocking. His main argument is that you force the new user to make choices that he aren’t able to make, which is completely incorrect, because, as he mentioned, Django has sensible defaults. Grok has that same philosophy, and when you start a Grok project ZPT will be there by default. If you want to use Genshi instead, please go ahead and do so. But the sensible default, ZPT, is there from the beginning, and the flexibility adds no extra complexity to the user who doesn’t want to switch, and you force no-one to make choices they can’t make.
Jacob also claims Django can set their own pace, by controlling the whole stack. This is partly correct, but when you make a best-of-breed framework, you will typically have central people involved as contributors to the components you use, and as a major user of that component, you can typically influence the direction and get releases more or less when you need them. And if you aren’t a big user, and won’t have a voice, well then you probably don’t have enough developers to do everything yourself anyway.
Is Django the new Zope 2?
Jacob Kaplan-Moss acknowledges the risk that Django will become Zope. Thanks to that acknowledgement I don’t think Django will become Zope, although they clearly have gone quite a long bit on that path already. Hopefully they have stopped. I don’t know if they need to backtrack, but at least they shouldn’t go much further on the Zope path if they want to continue to be relevant. Because if you go to far, you have a big job in backtracking to become relevant again.
Oh, and Jacob: ZODB is not an ORM. It’s a real OODB. ;-)