Writing reusable applications

James Bennett


DjangoCon, Mountain View, CA,
September 6, 2008
The extended remix!
The fourfold path

 Do one thing, and do it well.
 Don’t be afraid of multiple apps.
 Write for flexibility.
 Build to dis...
1
“   Do one thing, and do it well.




                                         ”
                             -- The UNIX ...
Application ==
encapsulation
Keep a tight focus

 Ask yourself: “What does this application
 do?”
 Answer should be one or two short
 sentences
Good focus

 “Handle storage of users and authentication
 of their identities.”
 “Allow content to be tagged, del.icio.us
...
Bad focus

 “Handle entries in a weblog, and users who
 post them, and their authentication, and
 tagging and categorizati...
Warning signs

 A lot of very good Django applications are
 very small: just a few files
 If your app is getting big enoug...
Warning signs
 Even a lot of “simple” Django sites
 commonly have a dozen or more
 applications in INSTALLED_APPS
 If you’...
Case study: user
  registration
Features


 User fills out form, inactive account created
 User gets email with link, clicks to activate
 And that’s it
User registration

 Different sites want different information
 Different types of users
 Different signup workflow
 Etc.,...
Some “simple” things
  aren’t so simple.
Approach features
   skeptically
Should I add this
feature?

 What does the application do?
 Does this feature have anything to do with
 that?
 No? Guess I...
Top feature request in
 django-registration:
     User profiles
“
What does that have to do with user
          registration?




                                 ”-- Me
The solution?
django-profiles

 Add profile
 Edit profile
 View profile
 And that’s it.
2
Don’t be afraid of
 multiple apps
The monolith mindset
 The “application” is the whole site
 Re-use is often an afterthought
 Tend to develop plugins that h...
The Django mindset


 Application == some bit of functionality
 Site == several applications
 Tend to spin off new applica...
Django encourages this
 Instead of one “application”, a list:
 INSTALLED_APPS
 Applications live on the Python path, not
 ...
Should this be its own
application?
 Is it completely unrelated to the app’s
 focus?
 Is it orthogonal to whatever else I’...
Unrelated features

 Feature creep is tempting: “but wouldn’t it
 be cool if...”
 But it’s the road to Hell
 See also: Par...
I’ve learned this the
      hard way
djangosnippets.org

 One application
 Includes bookmarking features
 Includes tagging features
 Includes rating features
Should be about four
   applications
So I wrote a book
telling people not to do
        what I did
Page 210, in case you
  were wondering.
Orthogonality
 Means you can change one thing without
 affecting others
 Almost always indicates the need for a
 separate ...
Reuse

 Lots of cool features actually aren’t specific
 to one site
 See: bookmarking, tagging, rating...
 Why bring all t...
Case study: blogging
I wanted a blog
 Entries and links
 Tagging
 Comments with moderation
 Contact form
 “About” page
 Etc., etc.
I ended up with
 A blog app (entries and links)
 A third-party tagging app
 contrib.comments + moderation app
 A contact-f...
Advantages


 Don’t keep rewriting features
 Drop things into other sites easily
Need a contact form?
urlpatterns += (‘’,
    (r’^contact/’, include(‘contact_form.urls’)),
)
And you’re done
But what about...
Site-specific needs

 Site A wants a contact form that just
 collects a message.
 Site B’s marketing department wants a
 b...
3
Write for flexibility
Common sense


 Sane defaults
 Easy overrides
 Don’t set anything in stone
Form processing


 Supply a form class
 But let people specify their own if they
 want
class SomeForm(forms.Form):
    ...

def process_form(request, form_class=SomeForm):
    if request.method == ‘POST’:
    ...
Templates


 Specify a default template
 But let people specify their own if they
 want
def process_form(request, form_class=SomeForm,
                 template_name=’do_form.html’):
    ...
    return render_t...
Form processing

 You want to redirect after successful
 submission
 Supply a default URL
 But let people specify their ow...
def process_form(request, form_class=SomeForm,
                 template_name=’do_form.html’,
                 success_url...
URL best practices

 Provide a URLConf in the application
 Use named URL patterns
 Use reverse lookups: reverse(),
 permal...
Working with models

 Whenever possible, avoid hard-coding a
 model class
 Use get_model() and take an app label/
 model n...
from django.db.models import get_model

def get_object(model_str, pk):
    model = get_model(*model_str.split(‘.’))
    re...
Working with models

 Don’t hard-code fields or table names;
 introspect the model to get those
 Accept lookup arguments y...
Learn to love managers

 Managers are easy to reuse.
 Managers are easy to subclass and
 customize.
 Managers let you enca...
Advanced techniques

 Encourage subclassing and use of
 subclasses
 Provide a standard interface people can
 implement in ...
The API your
 application exposes is
just as important as the
   design of the sites
     you’ll use it in.
In fact, it’s more
    important.
Good API design
 “Pass in a value for this argument to change
 the behavior”
 “Change the value of this setting”
 “Subclas...
Bad API design
 “API? Let me see if we have one of
 those...” (AKA: “we don’t”)
 “It’s open source; fork it to do what you...
No, really. Your
gateway interface is
   not your API.
4
Build to distribute
So you did the tutorial

 from mysite.polls.models import
 Poll
 mysite.polls.views.vote
 include(‘mysite.polls.urls’)
 my...
Project coupling kills
       re-use
Why (some) projects
suck
 You have to replicate that directory
 structure every time you re-use
 Or you have to do gymnast...
A good “project”


 A settings module
 A root URLConf module
 And that’s it.
Advantages

 No assumptions about where things live
 No tricky bits
 Reminds you that it’s just another Python
 module
It doesn’t even have to
    be one module
ljworld.com

 worldonline.settings.ljworld
 worldonline.urls.ljworld
 And a whole bunch of reused apps in
 sensible locati...
What reusable apps
look like
 Single module directly on Python path
 (registration, tagging, etc.)
 Related modules under ...
And now it’s easy

 You can build a package with distutils
 or setuptools
 Put it on the Cheese Shop
 People can download ...
General best practices

 Be up-front about dependencies
 Write for Python 2.3 when possible
 Pick a release or pick trunk,...
Templates are hard

 Providing templates is a big “out of the
 box” win
 But templates are hard to make portable
 (block s...
I usually don’t do
default templates
Either way


 Document template names
 Document template contexts
Be obsessive about
documentation

 It’s Python: give stuff docstrings
 If you do, Django will generate
 documentation for ...
“
If the implementation is hard to explain,
 it’s a bad idea. If the implementation is
  easy to explain, it may be a good...
Documentation-driven
development
 Write the docstring before you write the
 code
 Rewrite the docstring before you write t...
Advantages

 You’ll never be lacking documentation
 It’ll be up-to-date
 It’s a lot easier to throw away a docstring
 than...
Django will help you

 Docstrings for views, template tags, etc.
 can use reStructureText formatting
 Plus extra directive...
Recap:

 Do one thing, and do it well.
 Don’t be afraid of multiple apps.
 Write for flexibility.
 Build to distribute.
In the beginning...


 There was Django.
 And Ellington.
 And a couple other open-source apps.
...PyCon 2007...


 A few people presented/announced things
 they’d developed
 Sort of a watershed moment
...DjangoCon 2008

 Search for “django” on Google code
 hosting: 848 projects
 djangosites.org lists 1,636 sites
 And thos...
“   This is Django’s killer feature.




                                       ”
                                       -...
Good examples

 django-tagging (Jonathan Buchanan,
 http://code.google.com/p/django-
 tagging/)
 django-atompub (James Tau...
More information
 django-hotclub (http://
 groups.google.com/group/django-
 hotclub/)
 Jannis Leidel’s django-packages (ht...
Questions?
Photo credits

 quot;Purple Sparkly Pony Ridequot; by ninjapoodles, http://www.flickr.com/photos/ninjapoodles/
 285048576/...
Reusable Apps
Reusable Apps
Reusable Apps
Reusable Apps
Reusable Apps
Reusable Apps
Upcoming SlideShare
Loading in...5
×

Reusable Apps

1,606

Published on

Published in: Technology
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,606
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
55
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide

Reusable Apps

  1. 1. Writing reusable applications James Bennett DjangoCon, Mountain View, CA, September 6, 2008
  2. 2. The extended remix!
  3. 3. The fourfold path Do one thing, and do it well. Don’t be afraid of multiple apps. Write for flexibility. Build to distribute.
  4. 4. 1
  5. 5. “ Do one thing, and do it well. ” -- The UNIX philosophy
  6. 6. Application == encapsulation
  7. 7. Keep a tight focus Ask yourself: “What does this application do?” Answer should be one or two short sentences
  8. 8. Good focus “Handle storage of users and authentication of their identities.” “Allow content to be tagged, del.icio.us style, with querying by tags.” “Handle entries in a weblog.”
  9. 9. Bad focus “Handle entries in a weblog, and users who post them, and their authentication, and tagging and categorization, and some flat pages for static content, and...” The coding equivalent of a run-on sentence
  10. 10. Warning signs A lot of very good Django applications are very small: just a few files If your app is getting big enough to need lots of things split up into lots of modules, it may be time to step back and re-evaluate
  11. 11. Warning signs Even a lot of “simple” Django sites commonly have a dozen or more applications in INSTALLED_APPS If you’ve got a complex/feature-packed site and a short application list, it may be time to think hard about how tightly- focused those apps are
  12. 12. Case study: user registration
  13. 13. Features User fills out form, inactive account created User gets email with link, clicks to activate And that’s it
  14. 14. User registration Different sites want different information Different types of users Different signup workflow Etc., etc.
  15. 15. Some “simple” things aren’t so simple.
  16. 16. Approach features skeptically
  17. 17. Should I add this feature? What does the application do? Does this feature have anything to do with that? No? Guess I shouldn’t add it, then.
  18. 18. Top feature request in django-registration: User profiles
  19. 19. “ What does that have to do with user registration? ”-- Me
  20. 20. The solution?
  21. 21. django-profiles Add profile Edit profile View profile And that’s it.
  22. 22. 2
  23. 23. Don’t be afraid of multiple apps
  24. 24. The monolith mindset The “application” is the whole site Re-use is often an afterthought Tend to develop plugins that hook into the “main” application Or make heavy use of middleware-like concepts
  25. 25. The Django mindset Application == some bit of functionality Site == several applications Tend to spin off new applications liberally
  26. 26. Django encourages this Instead of one “application”, a list: INSTALLED_APPS Applications live on the Python path, not inside any specific “apps” or “plugins” directory Abstractions like the Site model make you think about this as you develop
  27. 27. Should this be its own application? Is it completely unrelated to the app’s focus? Is it orthogonal to whatever else I’m doing? Will I need similar functionality on other sites? Yes? Then I should break it out into a separate application.
  28. 28. Unrelated features Feature creep is tempting: “but wouldn’t it be cool if...” But it’s the road to Hell See also: Part 1 of this talk
  29. 29. I’ve learned this the hard way
  30. 30. djangosnippets.org One application Includes bookmarking features Includes tagging features Includes rating features
  31. 31. Should be about four applications
  32. 32. So I wrote a book telling people not to do what I did
  33. 33. Page 210, in case you were wondering.
  34. 34. Orthogonality Means you can change one thing without affecting others Almost always indicates the need for a separate application Example: changing user profile workflow doesn’t affect user signup workflow. Make them two different applications.
  35. 35. Reuse Lots of cool features actually aren’t specific to one site See: bookmarking, tagging, rating... Why bring all this crap about code snippets along just to get the extra stuff?
  36. 36. Case study: blogging
  37. 37. I wanted a blog Entries and links Tagging Comments with moderation Contact form “About” page Etc., etc.
  38. 38. I ended up with A blog app (entries and links) A third-party tagging app contrib.comments + moderation app A contact-form app contrib.flatpages Etc., etc.
  39. 39. Advantages Don’t keep rewriting features Drop things into other sites easily
  40. 40. Need a contact form?
  41. 41. urlpatterns += (‘’, (r’^contact/’, include(‘contact_form.urls’)), )
  42. 42. And you’re done
  43. 43. But what about...
  44. 44. Site-specific needs Site A wants a contact form that just collects a message. Site B’s marketing department wants a bunch of info. Site C wants to use Akismet to filter automated spam.
  45. 45. 3
  46. 46. Write for flexibility
  47. 47. Common sense Sane defaults Easy overrides Don’t set anything in stone
  48. 48. Form processing Supply a form class But let people specify their own if they want
  49. 49. class SomeForm(forms.Form): ... def process_form(request, form_class=SomeForm): if request.method == ‘POST’: form = form_class(request.POST) ... else: form = form_class() ...
  50. 50. Templates Specify a default template But let people specify their own if they want
  51. 51. def process_form(request, form_class=SomeForm, template_name=’do_form.html’): ... return render_to_response(template_name, ...
  52. 52. Form processing You want to redirect after successful submission Supply a default URL But let people specify their own if they want
  53. 53. def process_form(request, form_class=SomeForm, template_name=’do_form.html’, success_url=’/foo/’): ... return HttpResponseRedirect(success_url)
  54. 54. URL best practices Provide a URLConf in the application Use named URL patterns Use reverse lookups: reverse(), permalink, {% url %}
  55. 55. Working with models Whenever possible, avoid hard-coding a model class Use get_model() and take an app label/ model name string instead Don’t rely on objects; use the default manager
  56. 56. from django.db.models import get_model def get_object(model_str, pk): model = get_model(*model_str.split(‘.’)) return model._default_manager.get(pk=pk) user_12 = get_object(‘auth.user’, 12)
  57. 57. Working with models Don’t hard-code fields or table names; introspect the model to get those Accept lookup arguments you can pass straight through to the database API
  58. 58. Learn to love managers Managers are easy to reuse. Managers are easy to subclass and customize. Managers let you encapsulate patterns of behavior behind a nice API.
  59. 59. Advanced techniques Encourage subclassing and use of subclasses Provide a standard interface people can implement in place of your default implementation Use a registry (like the admin)
  60. 60. The API your application exposes is just as important as the design of the sites you’ll use it in.
  61. 61. In fact, it’s more important.
  62. 62. Good API design “Pass in a value for this argument to change the behavior” “Change the value of this setting” “Subclass this and override these methods to customize” “Implement something with this interface, and register it with the handler”
  63. 63. Bad API design “API? Let me see if we have one of those...” (AKA: “we don’t”) “It’s open source; fork it to do what you want” (AKA: “we hate you”) def application(environ, start_response) (AKA: “we have a web service”)
  64. 64. No, really. Your gateway interface is not your API.
  65. 65. 4
  66. 66. Build to distribute
  67. 67. So you did the tutorial from mysite.polls.models import Poll mysite.polls.views.vote include(‘mysite.polls.urls’) mysite.mysite.bork.bork.bork
  68. 68. Project coupling kills re-use
  69. 69. Why (some) projects suck You have to replicate that directory structure every time you re-use Or you have to do gymnastics with your Python path And you get back into the monolithic mindset
  70. 70. A good “project” A settings module A root URLConf module And that’s it.
  71. 71. Advantages No assumptions about where things live No tricky bits Reminds you that it’s just another Python module
  72. 72. It doesn’t even have to be one module
  73. 73. ljworld.com worldonline.settings.ljworld worldonline.urls.ljworld And a whole bunch of reused apps in sensible locations
  74. 74. What reusable apps look like Single module directly on Python path (registration, tagging, etc.) Related modules under a package (ellington.events, ellington.podcasts, etc.) No project cruft whatsoever
  75. 75. And now it’s easy You can build a package with distutils or setuptools Put it on the Cheese Shop People can download and install
  76. 76. General best practices Be up-front about dependencies Write for Python 2.3 when possible Pick a release or pick trunk, and document that But if you pick trunk, update frequently
  77. 77. Templates are hard Providing templates is a big “out of the box” win But templates are hard to make portable (block structure/inheritance, tag libraries, etc.)
  78. 78. I usually don’t do default templates
  79. 79. Either way Document template names Document template contexts
  80. 80. Be obsessive about documentation It’s Python: give stuff docstrings If you do, Django will generate documentation for you And users will love you forever
  81. 81. “ If the implementation is hard to explain, it’s a bad idea. If the implementation is easy to explain, it may be a good idea. ” -- The Zen of Python
  82. 82. Documentation-driven development Write the docstring before you write the code Rewrite the docstring before you write the code And write doctests while you’re at it
  83. 83. Advantages You’ll never be lacking documentation It’ll be up-to-date It’s a lot easier to throw away a docstring than to throw away a bunch of code
  84. 84. Django will help you Docstrings for views, template tags, etc. can use reStructureText formatting Plus extra directives for handy cross- references to other components you’re using
  85. 85. Recap: Do one thing, and do it well. Don’t be afraid of multiple apps. Write for flexibility. Build to distribute.
  86. 86. In the beginning... There was Django. And Ellington. And a couple other open-source apps.
  87. 87. ...PyCon 2007... A few people presented/announced things they’d developed Sort of a watershed moment
  88. 88. ...DjangoCon 2008 Search for “django” on Google code hosting: 848 projects djangosites.org lists 1,636 sites And those are just the ones we know about so far...
  89. 89. “ This is Django’s killer feature. ” -- Me
  90. 90. Good examples django-tagging (Jonathan Buchanan, http://code.google.com/p/django- tagging/) django-atompub (James Tauber, http:// code.google.com/p/django-atompub/) Search for “django” on code hosting sites
  91. 91. More information django-hotclub (http:// groups.google.com/group/django- hotclub/) Jannis Leidel’s django-packages (http:// code.google.com/p/django- reusableapps/) Django Pluggables: http:// djangoplugables.com/
  92. 92. Questions?
  93. 93. Photo credits quot;Purple Sparkly Pony Ridequot; by ninjapoodles, http://www.flickr.com/photos/ninjapoodles/ 285048576/ “Stonehenge #2” by severecci, http://www.flickr.com/photos/severecci/129553243/ “sookiepose” by 416style, http://www.flickr.com/photos/sookie/41561946/ quot;The Happy Couplequot; by galapogos, http://www.flickr.com/photos/galapogos/343592116/
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×