why django sucks, and how we can fix it
TRANSCRIPT
Why Django Sucks
A n d h o w w e c a n f i x i t
My Qualifications
Started using Django in 2006
Not a core developer
Early active involvement in Django apps
Helped out with the initial form of Pinax
Co-host of DjangoDose
Day job: mochigames.com
What Sucks?
Apps
Generic Foreign Keys
Memory usage and performance
Settings
Exclusionary establishment
Bad batteries
Apps
It’s a mess
My typical app discovery lifecycle“I need to let users upload avatars.”
“Cool! Looks like there’s an app called django-avatar.”
“Now I want to add an extra domain-specific field to each avatar.”
:(
Fork
The model problem
Apps which provide models are inflexible
Providing abstract model classes introduces configuration headache
Primary Key Assumptions
Everyone basically assumes PositiveIntegerField primary keys.
UUID primary keys have lots of advantages.
Especially for the user table.
To achieve this, you have to fork pretty much everything.
Field naming
{{ entry.body }}, {{ item.description }}
{{ post.content }}, {{ comment.comment }}
Different field names have emerged for the same “kind” of attribute.
To reuse template code, we’re forced to monkeypatch model code.
Classes to the rescue?
Wildly differing ideas on how to implement class-based views.
Little to no consensus on this front.
Where do you put customized view subclasses?
Trades complexity and configuration for flexibility.
Put customizations where?
Seriously, where do we put customized view subclasses?
Convention is in urls.py, but that will quickly become overloaded.
Create a new app? Now we have an extra level of indirection, making code less clear.
TODO: Tests & docs
Seriously, most apps suck.
P.S. I’m guilty of this too.
Base Problem
The app as the sole level of abstraction is too broad.
Generic Foreign Keys
Wrong solution
Generic Foreign Keys
Good for flexibility
Bad for configuration
Used way too much as configuration
Favorites, Ratings, Voting, Messages, etc.
These things should usually have concrete foreign keys.
Memory & Performance
Going the wrong way
Case Study: Blog App (Of Course)
Disclaimer: Lies, damn lies, and benchmarks.
Illustrative only, take my numbers with a grain of salt.
Kept everything the same except for the Django version. Completely the same code.
Memory
180
182.75
185.5
188.25
191
1.0 1.1 1.2
Memory (MB)
Performance
0
20
40
60
80
1.0 1.1 1.2
Requests/Second
In Effect
It’s gotten slower in every release since 1.0.
Every release has a larger memory footprint than the last one.
Monolithic Settings
Monolithic Settings
Can’t change it on a per-request basis in a thread-safe way
Makes multi-tenancy nearly impossible
Causes headaches for deployment
Prevents composition of Django projects
It’s essentially a global, which is something Django tends to shy away from*
Others get this right
Flask has an App object.
CherryPy has an Application object.
web.py has an application object.
Werkzeug encourages a make_app function.
Exclusionary Establishment
People feel un-welcome
Exclusionary Establishment
People have made real-life friends through the community. Being tight-knit is good!
But it’s bad if you feel you can’t join in.
Why would someone think the establishment is exclusionary?
django.contrib isn’t
No application ever created by a non-core-developer has ever been added to django.contrib.
It’s not really “contrib”, is it?
This sends a signal to the community.
django-core
Did you know that there’s a private mailing list just for the Django core developers?
Why does this exist?
What kinds of discussions go on in there?
Shouldn’t Django-related discussions happen out in the open?
This sends a signal to the community.
Case Study:Alex Gaynor
How is he still not a core developer?
He’s been contributing to Django in every way he can for over 3 years.
This sends a signal to the community.
Case study: truncatechars
It’s a tiny feature that’s been requested many, many times, by many different people.
It’s properly gone through all the right steps.
Every time someone brings it up again, it gets snarky responses from core team. Stays in Design Decision Needed.
This sends a signal to the community.
Badteries
Badteries: Auth
django.contrib.auth is unbelievably inflexible.
first_name, last_name is culturally limited.
Admin is coupled to user (is_staff.)
Integer primary key
get_profile() is inelegant and inefficient.
No way to use secure cookie instead of session.
Badteries: Webdesign
Web designers care about a lot more than just lorem ipsum.
Badteries: Databrowse
Despite what the docs say, it’s not very new anymore (3 years old.)
Doesn’t support pagination.
Why is this even in Django?
OK I’ll stop hatin’
I say these things because I care :)
How can we make it better?
Introduce focused abstraction layers
Late-binding configuration option
Monitor performance and memory changes
Rip off Flask
Kill contrib
Add more core developers
Move to a DVCS
Must apps suck?
This is the toughest one.
Must apps suck?
If the app as the sole level of abstraction is too broad...
Then we need to make abstractions with a narrower focus.
These narrower abstractions could be built on top of the current app abstraction.
Idea: Use models, don’t expose them
class Message(models.Model): from_user = models.ForeignKey(User) to_user = models.ForeignKey(User) msg = models.CharField(max_length=128)
Idea: Use models, don’t expose them
class Message(object):
def create(self, from_user, to_user, msg, **kw): # ...
def inbox(self, user, start=0, stop=20): # ...
def outbox(self, user, start=0, stop=20): # ...
Idea: Use models, don’t expose them
Now we can pass extra keywords to create().
We can swap out the model to include extra fields, etc.
We can swap out the implementation to use a different storage layer.
We can expose it over the network as a service layer.
FeinCMS
http://bit.ly/feincms
Example of a more focused abstraction, built on top of existing abstractions.
Page.create_content_type(RichTextContent)
Page.register_templates(...)
Page.register_extensions('navigation', 'titles')
Late Binding FKs
In models.py:
class Favorite(models.Model): item = LazyForeignKey(‘fave’) user = ForeignKey(User) date = DateTimeField(default=utcnow)
In settings.py:
LAZY_FKS = {‘fave’: ‘pages.models.Page’}
Late Binding FKs
This way we don’t need to use GenericFK
Still get the flexibility of attaching to whichever content object we want
Disadvantage: more configuration necessary, but it’s not too onerous.
Any app that Django provides should use these, to set the example.
Performance / Memory
Set up a performance and memory “test suite”, graphed over time, show it prominently.
Great start: http://github.com/jacobian/djangobench
Every patch already requires docs, tests, code.
Now it should require docs, tests, code, impact justification.
Performance / Memory
Provide mechanisms to shut of unused Django machinery
USE_I18N is a good example
USE_MAIL, USE_VALIDATION, and more?
Monolithic Settings
Flask (http://bit.ly/flask) gets this really, really right.
Let’s just rip it off wholesale.
You create an app object instance, and configure that object instance.
Flask
>>> app = Flask(__name__)>>> app.config['DEBUG'] = True>>> app.config.from_object('myapp.dev_settings')>>> app.config.from_envvar('SETTINGS')
# SAME INTERPRETER! MULTITENANCY!
>>> app2 = Flask(__name__)>>> app2.config['DEBUG'] = False>>> app2.config.from_object('myapp.prod_settings')
Kill Contrib
pip is good now.
Users are likely going to use pip on their first sit-down anyway (e.g. South)
If it doesn’t make sense to split it out, then call it like it really is: a core app.
Core apps: Sessions, Auth (not Admin, split that out)
Kill Contrib
We could release updates to the admin without releasing Django!
Each app could have different committers.
It would foster innovation in the community.
Might have to start “blessing” apps officially.
Add more core devs
“So, my recommendation (which surely is a turn-around of my *own* attitude in the past) is to give out more commit privileges sooner.”- Guido van Rossum
http://mail.python.org/pipermail/python-dev/2010-July/102306.html
Add more Core Devs
We have releases now, vast majority of people don’t run off of trunk.
Trunk can break sometimes and it’s not the end of the world.
Django’s bigger problem now isn’t quality control, it’s lack of participation.
Solution for this is to loosen the reigns a bit, and to add more core developers.
Can name 5 developers off the top of my head who should be considered.
Switch to Git/GitHub
Commit bit would be less important.
Much easier to do experimental branches.
Easier for people to stay up to date on what’s going on.
Frankly, marketing.
Throw Tomatoes Now
Questions?
Comments?