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

MOZtrosity

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.

So?

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 careers over the default 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

other files.

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 is going.

Here’s the main urls.py 1:

...
urlpatterns = patterns('',
    (r'', include('careers.urls')),
)
...

The main urls.py includes careers.urls which if you look at the above project layout, resolves to two different python packages:

  • careers/urls.py
  • careers/apps/careers/urls.py

Python chose the first, and therefore urls.py kept calling upon itself.

So what did we learn?

Do better.

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 (e.g. careers), but sometimes a lamer more generic name like common is better.

But really, the second point is moot if we just clean up.