(I’ve got a summary about an earlier talk he gave about this, btw).
He works for legalsense and makes sites for lawyers. Lots of smaller websites. Every website has small differences, which is relevant to this talk.
Django is great. It is modular, but integrated. Views, models, model admins, all tied together.
This talk is about reuse, but he doesn’t mean the framework-y stuff that django already does like south, model fields, template tags. It means reuse of apps.
What is an app? Something with a models.py, a couple of templates, an admin.py, urls a couple of views. That’s what we mean with an app as programmers. The customer doesn’t have this view. A customer sees “a blog” and “a customer list”. Things the customer can touch.
Reusing apps is a recurring theme. Perhaps it is even the holy grail.
Changing an app is often a part of reuse. So you need to change something in an app. For instance you want to add a Dutch social security number to django-authentication. None of their clients want to do that, except one. That’s the kind of very local per-site reuse they have to handle.
Adding just one field should not be too hard, right? Well, it is as we’ll see later on.
One part that works well in django regarding reuse is templates. In template directories with a higher preference (for instance the one in your site), you can override an application’s template. Easy as pie.
For other things, the “parameterize everything” solution is often the stated
solution. A view function gets a couple of parameters (
model=..., form=...) and you can configure those parameters in the
urls.py. But, say you change the model somewhere, you need to change it
everywhere. But what we normally do is use python strongest binding
mechanism: a simple direct import.
from .models import Something. You’re
hosed at that point.
Their solution: “eight spaces”. Class based everything. 369 lines of
code. Singleton objects with inheritance and with a concept of
The code in their reusable apps looks like this:
from .models import Models from .views import Views class App(object): def __init__(self): self.models = Models(self) self.views = Views(self)
This is the only place where the imports happen. Later on you can easily
self.models to be something else. The
Models class is something
that returns the actual models. And it is a class, so its behaviour can be
adjusted when you want to change it.
(In the end, most code is indented one level deeper than normally. The actual model code ends up indented eight spaces, hence the name.)
There are problems, though. There’s a certain lack of elegance due to the greater level of indentation and more lines. And you need to explicitly prepare your app this way. Circular imports are a real problem.
Success stories: their customers are happy. The last commit to the code happened half a year ago, so it Just Works. They’re continually using it.
Alternatives? Generic keys could help. Or you’d have to allow for lots more extension points in your apps and build them in from the start.
My name is Reinout van Rees and I work a lot with Python (programming language) and Django (website framework). I live in The Netherlands and I'm happily married to Annie van Rees-Kooiman.
Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):