Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Confessions of Joe Developer

Confessions of Joe Developer

Admitting my flaws and turning them into virtues! This is a full length talk given it at DjangoCon US 2011, PyCon Australia 2011, and LA Django. The earliest version was a lightning talk given at the 2011 Hollywood hackathon.

67e05420d4dd3492097aeb77f44f7867?s=128

Daniel Greenfeld

October 07, 2011
Tweet

More Decks by Daniel Greenfeld

Other Decks in Technology

Transcript

  1. Confessions of Joe Developer Daniel Greenfeld

  2. Daniel Greenfeld @pydanny Who am I? Daniel Greenfeld (@pydanny) Pythonista

    at Cartwheel Djangonaut at Revsys Co-lead of djangopackages.com & Packaginator (Open Comparison) Fiancé of Audrey Roy http://www.flickr.com/photos/pydanny/4442245488
  3. Why am I talking?

  4. I’m stupid and lazy

  5. None
  6. I’m stupid

  7. Daniel Greenfeld @pydanny I’m stupid • Can’t figure things out

    • Can’t remember things • Too stupid not to ask stupid questions
  8. Daniel Greenfeld @pydanny I’m stupid • If I get stuck

    for more than 30 minutes... • Find libraries that do it for me • Ask on Twitter for answers • Stack Overflow is also good, but watch for trolls. • IRC can be good, if you get a troll try a different channel. Can’t figure things out
  9. Daniel Greenfeld @pydanny I’m stupid Can’t figure things out #

    This sample gleefully taken from https://gist.github.com/973705 import urllib2 gh_url = 'https://api.github.com' gh_user= 'user' gh_pass = 'pass' req = urllib2.Request(gh_url) password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm() password_manager.add_password(None, gh_url, gh_user, gh_pass) auth_manager = urllib2.HTTPBasicAuthHandler(password_manager) opener = urllib2.build_opener(auth_manager) urllib2.install_opener(opener) handler = urllib2.urlopen(req) print handler.getcode() print handler.headers.getheader('content-type') # ------ # 200 # 'application/json' “Smart” people way # This sample joyfully taken from # https://gist.github.com/973705 import requests r = requests.get('https://api.github.com', auth=('user', 'pass')) print r.status_code print r.headers['content-type'] # ------ # 200 # 'application/json' PyDanny way
  10. Daniel Greenfeld @pydanny I’m stupid # This sample gleefully taken

    from # https://gist.github.com/973705 import urllib2 gh_url = 'https://api.github.com' gh_user= 'user' gh_pass = 'pass' req = urllib2.Request(gh_url) password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm() password_manager.add_password(None, gh_url, gh_user, gh_pass) auth_manager = urllib2.HTTPBasicAuthHandler(password_manager) opener = urllib2.build_opener(auth_manager) urllib2.install_opener(opener) handler = urllib2.urlopen(req) print handler.getcode() print handler.headers.getheader('content-type') # ------ # 200 # 'application/json' ‘Smart way’ aka hard way What is this? And this? What is an install opener? Finally we make the request!
  11. Daniel Greenfeld @pydanny I’m stupid Can’t figure things out #

    This sample joyfully taken from # https://gist.github.com/973705 import requests r = requests.get('https://api.github.com', auth=('user', 'pass')) print r.status_code print r.headers['content-type'] # ------ # 200 # 'application/json' ‘Stupid way’ aka easy way HTTP GET Username + Password
  12. Daniel Greenfeld @pydanny I’m stupid Can’t figure things out #

    This sample gleefully taken from https://gist.github.com/973705 import urllib2 gh_url = 'https://api.github.com' gh_user= 'user' gh_pass = 'pass' req = urllib2.Request(gh_url) password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm() password_manager.add_password(None, gh_url, gh_user, gh_pass) auth_manager = urllib2.HTTPBasicAuthHandler(password_manager) opener = urllib2.build_opener(auth_manager) urllib2.install_opener(opener) handler = urllib2.urlopen(req) print handler.getcode() print handler.headers.getheader('content-type') # ------ # 200 # 'application/json' “Smart” people way # This sample joyfully taken from # https://gist.github.com/973705 import requests r = requests.get('https://api.github.com', auth=('user', 'pass')) print r.status_code print r.headers['content-type'] # ------ # 200 # 'application/json' PyDanny way
  13. Daniel Greenfeld @pydanny I’m stupid • There are no stupid

    questions • Don’t try and impress the people around you by not asking questions. Too stupid not to ask stupid questions
  14. Daniel Greenfeld @pydanny I’m stupid Too stupid not to ask

    stupid questions You are at DjangoCon. If you don’t ask the question, you are wasting opportunity.
  15. Daniel Greenfeld @pydanny I’m stupid Too stupid not to ask

    stupid questions You are at DjangoCon. A positive trait good tech leads often look for is the ability to ask questions.
  16. Daniel Greenfeld @pydanny I’m stupid • Documentation makes me look

    good • Docstrings are awesome • Learn you some Restructured Text • Write down even the slide bullets! • https://github.com/pydanny/pydanny-event-notes Can’t remember things
  17. Daniel Greenfeld @pydanny Joe Developer Resources https://github.com/pydanny/django-party-pack http://django-party-pack.rtfd.org/ Where the

    code examples live!
  18. Daniel Greenfeld @pydanny I’m stupid http://readthedocs.org/docs/django-party-pack Sphinx makes me look

    good!
  19. Daniel Greenfeld @pydanny Docs/Sphinx Basics • pip install sphinx •

    make a docs directory •sphinx-quickstart • Follow instructions • Starting over is just removing your docs
  20. Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!

    http://readthedocs.org/docs/django-party-pack/en/latest/_sources/install.txt ============= Installation ============= .. note:: For things with **font like this** it means type it at the command line and hit enter. The Basics =========== 0. **git clone https://pydanny@github.com/pydanny/django-party-pack.git** 1. Make sure you have virtualenv installed. 2. change directory to the directory that contains this README.rst file. 3. **virtualenv pollaxe** and then **source pollaxe/bin/activate** 4. **pip install -r requirements.txt** 5. **mkdir pollaxe/coverage** Building the sphinx docs ========================= 1. change directory to docs 2. **make html** Running django-coverage ======================== 1. python manage.py test page header note block section headers
  21. Daniel Greenfeld @pydanny I’m stupid http://readthedocs.org/docs/django-party-pack Sphinx makes me look

    good!
  22. Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!

    http://readthedocs.org/docs/django-party-pack/en/latest/reference_polls.html
  23. Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!

    http://readthedocs.org/docs/django-party-pack/en/latest/reference_polls.html
  24. Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!

    http://readthedocs.org/docs/django-party-pack/en/latest/reference_polls.html ======================== Reference for Polls App ======================== The polls app is a copy of the Django tutorial with some mild PEP-8 cleanup. ``polls.models`` ================= .. automodule:: polls.models :members: ``polls.views`` ================= .. automodule:: polls.views :members: ``polls.tests`` ================= .. automodule:: polls.tests.test_models :members: :undoc-members: .. automodule:: polls.tests.test_views :members: :undoc-members: page header auto- model auto-model for undocumented items
  25. Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!

    http://readthedocs.org/docs/django-party-pack/en/latest/reference_polls.html
  26. Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!

    http://readthedocs.org/docs/django-party-pack/en/latest/reference_polls.html
  27. Daniel Greenfeld @pydanny Sphinx walk-through http://audreyr.posterous.com/how-to-create-sphinx-docs-the-python-github-r http://bit.ly/audreyr-sphinx or

  28. I’m lazy

  29. Daniel Greenfeld @pydanny I’m lazy • Don’t wanna do anything

    twice • Don’t wanna debug code when I had it working before • Don’t wanna upload zip files per document change
  30. Daniel Greenfeld @pydanny I’m lazy • If I write the

    same code twice I stick it in a function • Then I stick the function into a util module. • Then I put it on Github so I don’t lose it. • Isn’t this kinda the whole thing behind Open Source? Don’t wanna do anything twice
  31. Daniel Greenfeld @pydanny I’m Lazy • Manually testing code by

    watching it run is hard... • ...and boring... • ...and hence is error prone. • Meaning you have to do more work. Don’t wanna debug code when I had it working before
  32. Daniel Greenfeld @pydanny I’m Lazy Are you testing enough? Stick

    even the ‘basic stuff’ in the docs!
  33. Daniel Greenfeld @pydanny I’m Lazy Are you testing enough? Yeah,

    some of the configuration is off. Will be fixed soon.
  34. Daniel Greenfeld @pydanny Coverage Tricks • coverage.py is great •

    django-coverage runs coverage.py for Django • But you only want to test your own apps
  35. Daniel Greenfeld @pydanny PREREQ_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites',

    'django.contrib.messages', 'django.contrib.admin', 'django-debug-toolbar’, ) PROJECT_APPS = ( 'polls', ) INSTALLED_APPS = PREREQ_APPS + PROJECT_APPS COVERAGE_MODULE_EXCLUDES = [ 'tests$', 'settings$', 'urls$', 'locale$', 'migrations', 'fixtures', 'admin$', ] COVERAGE_MODULE_EXCLUDES += PREREQ_APPS COVERAGE_REPORT_HTML_OUTPUT_DIR = "coverage" HTML_OUTPUT_DIR = os.path.join(PROJECT_ROOT, "coverage") TEST_RUNNER = 'testrunner.OurCoverageRunner' settings.py import os.path PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) Super userful django or third- party-apps My custom apps INSTALLED_APPS See next page! exclude this stuff Output results here
  36. Daniel Greenfeld @pydanny testrunner.py # Make our own testrunner that

    by default only tests our own apps from django.conf import settings from django.test.simple import DjangoTestSuiteRunner from django_coverage.coverage_runner import CoverageRunner class OurTestRunner(DjangoTestSuiteRunner): def build_suite(self, test_labels, *args, **kwargs): return super(OurTestRunner,self).build_suite(test_labels or settings.PROJECT_APPS, *args, **kwargs) class OurCoverageRunner(OurTestRunner, CoverageRunner): pass This only runs the tests on apps we want tested and skips the rest!
  37. Daniel Greenfeld @pydanny I’m Lazy Are you testing enough? Yeah,

    some of the configuration is off. Will be fixed soon.
  38. Daniel Greenfeld @pydanny I’m Lazy Don’t wanna upload zip files

    per document change READ THE DOCS .ORG http://readthedocs.org / http://rtfd.org
  39. Daniel Greenfeld @pydanny I’m stupid • Documentation makes me look

    good • Docstrings are awesome • Learn you some Restructured Text • Write down even the slide bullets! • https://github.com/pydanny/pydanny-event-notes Can’t remember things • http://pydanny-event-notes.rtfd.org
  40. Daniel Greenfeld @pydanny I’m Lazy Host your docs on http://rtfd.org

    Import your project
  41. Daniel Greenfeld @pydanny I’m Lazy Host your docs on http://rtfd.org

  42. Daniel Greenfeld @pydanny I’m Lazy Host your docs on http://rtfd.org

    Admin Service Hook ReadTheDocs Active
  43. Daniel Greenfeld @pydanny I’m Lazy django-party-pack-rtfd.org

  44. Daniel Greenfeld @pydanny I’m Lazy pydanny-event-notes.rtfd.org

  45. Daniel Greenfeld @pydanny Sphinx Trick! /django-party-pack /docs /conf.py Makes Sphinx

    play nicely with Django
  46. Don’t be smart and lazy

  47. Daniel Greenfeld @pydanny Django Worst Practice INSTALLED_APPS += [p for

    p in os.listdir(BASE) if os.path.isdirr(p)] MIDDLEWARE_CLASSES = [...] def callback(arg, dirname, fnames): if 'middleware.py' in fnames: m = '%s.middleware' % os.path.split(dirnaame)[-1] MIDDLEWARE_CLASSES.append(m) urlpatterns = patterns('', ...) for app in settings.INSTALLED_APPS: if not app.startswith('django'): p = url('^%s/' % app, include('%s.urls') % app) urlpatterns += patterns('', p) ‘Magical configuration code’ Ugh. http://www.slideshare.net/jacobian/the-best-and-worst-of-django Magical settings code Magical urls code THIS CODE IS BROKEN
  48. Daniel Greenfeld @pydanny Fixed Django Practice PREREQ_APPS = [ #

    Django "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.sites", "django.contrib.messages", "django.contrib.humanize", "django.contrib.flatpages", # external "notification", # must be first "staticfiles", "uni_form", ... ] urlpatterns = patterns("", url(r"^$", homepage, name="home"), url(r"^accounts/", include("accounts.urls")), url(r"^admin/", include(admin.site.urls)), url(r"^about/", include("about.urls")), url(r"^profiles/", include("profiles.urls")), url(r"^notices/", include("notification.urls")), ... ) MIDDLEWARE_CLASSES = [ "django.middleware.common.CommonMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "reversion.middleware.RevisionMiddleware", "django.contrib.messages.middleware.MessageMiddleware", ... ] Explicit is better then Implicit This isn’t that much typing, is it?
  49. Daniel Greenfeld @pydanny Fixed Django Practice PREREQ_APPS = [ #

    Django "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.sites", "django.contrib.messages", "django.contrib.humanize", "django.contrib.flatpages", # external "notification", # must be first "staticfiles", "uni_form", ... ] urlpatterns = patterns("", url(r"^$", homepage, name="home"), url(r"^accounts/", include("accounts.urls")), url(r"^admin/", include(admin.site.urls)), url(r"^about/", include("about.urls")), url(r"^profiles/", include("profiles.urls")), url(r"^notices/", include("notification.urls")), ... ) MIDDLEWARE_CLASSES = [ "django.middleware.common.CommonMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "reversion.middleware.RevisionMiddleware", "django.contrib.messages.middleware.MessageMiddleware", ... ] Python’s design is predicated on the proposition that code is more often read than written. http://www.slideshare.net/jacobian/the-best-and-worst-of-django/44
  50. I’m stupid and lazy

  51. Daniel Greenfeld @pydanny Technical Debt • Documentation • unshared knowledge

    • Tests • attending to TODO statements • Code too confusing to be modified easily Postponed Activities http://bit.ly/technical-debt
  52. Advocacy

  53. Daniel Greenfeld @pydanny Why?

  54. Daniel Greenfeld @pydanny More fun community http://www.flickr.com/photos/pydanny/5851931370/

  55. Daniel Greenfeld @pydanny Jane Developer Advocacy • Now is the

    time • Empowerment through Education • Contribute to open source • If you don’t step up then no one will
  56. Daniel Greenfeld @pydanny Joe Developer Advocacy • Give your own

    time • Honor your promised commitments • Give kudos to the men who bring ladies! • Step back: Don’t try to run things. How to get involved with PyLadies as a man
  57. Daniel Greenfeld @pydanny Acme Corporation Advocacy http://en.wikipedia.org/wiki/File:Acme_anvil.gif

  58. Daniel Greenfeld @pydanny Acme Corporation Advocacy • Sponsor because it’s

    the right thing to do • Sponsor because you get a tax break • Sponsor because good developers notice • Mozilla • cars.com How to get involved as a company http://en.wikipedia.org/wiki/Acme_Corporation
  59. Daniel Greenfeld @pydanny Joe/Jane Developer Resources https://github.com/pydanny/django-party-pack/ http://django-party-pack.rtfd.org/ party-pack http://bit.ly/audreyr-sphinx

  60. Questions?