05 Jan 2012 » Naming things and a recursion
Most Mozilla webdev projects have an awful project structure, and it's partially my fault. I'm attemtping to fix that, but I cringe every time someone creates a new playdoh (Mozilla's Django template) based project.
The typical python project
Your typical python project looks like this:
/my_project someotherstuff/ docs/ theactualthingicareabout/ setup.py LICENSE
We didn't have a good guide when we first started writing Django projects, so we opted for something like this:
theactualthingicareabout/ apps/ foo/ bar/ __init__.py urls.py settings.py LICENSE
In otherwords, the Django Project, which is a python module, is immediately checked out. If you check this out to an invalid directory, e.g. you do something like:
git clone github.com/davedash/myawesomeproject.git will.not.work\!
Bad things will happen.
To some people this seems like an easy thing to work-a-round, but when it takes three of my excellent coworkers a week to diagnose an issue, where this ended up being the root cause... well it becomes a higher priority issue.
So here's what happened this week, when we tried to deploy the new careers site to a VM hardware.
Our ops team sensibly checked out the project like so:
git clone https://github.com/mozilla/lumbergh.git careers
They did everything right. Sure, they were creative and chose
lumbergh, but they knew the shortcomings of our system and picked
a name that would resolve as a valid python package.
Unfortunately we'd hit some recursion error anytime we tried to hit a URL. So we knew there was an issue with the URL resolver, but we couldn't figure it out.
Here's what the project layout looked like:
careers/ # I could be called anything, but they chose careers __init__.py apps/ careers/ # I'm going to cause problems, # but neither devs nor ops will suspect a thing! mwahaha __init__.py models.py urls.py views.py settings.py urls.py
We configure our
apps/ directory to be part of our
PYTHON_PATH so we can
do things like
from careers import views... you can probably see where this
Here's the main
... urlpatterns = patterns('', (r'', include('careers.urls')), ) ...
careers.urls which if you look at the above
project layout, resolves to two different python packages:
Python chose the first, and therefore
urls.py kept calling upon itself.
So what did we learn?
First of all, we need a better project layout. This will continue to cause problems for even the brightest developers.
Secondly, if you don't do this at least name apps carefully.
Django's app model can be a bit much for
non third party apps. Sometimes there's one app which spans the entire
project, and it's tempting to call it the same name as the project
careers), but sometimes a lamer more generic name like
But really, the second point is moot if we just clean up.