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.

Avatar for Daniel Greenfeld

Daniel Greenfeld

October 07, 2011
Tweet

More Decks by Daniel Greenfeld

Other Decks in Technology

Transcript

  1. 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
  2. Daniel Greenfeld @pydanny I’m stupid • Can’t figure things out

    • Can’t remember things • Too stupid not to ask stupid questions
  3. 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
  4. 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
  5. 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!
  6. 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
  7. 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
  8. 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
  9. 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.
  10. 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.
  11. 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
  12. Daniel Greenfeld @pydanny Docs/Sphinx Basics • pip install sphinx •

    make a docs directory •sphinx-quickstart • Follow instructions • Starting over is just removing your docs
  13. 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://[email protected]/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
  14. Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!

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

    http://readthedocs.org/docs/django-party-pack/en/latest/reference_polls.html
  16. 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
  17. Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!

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

    http://readthedocs.org/docs/django-party-pack/en/latest/reference_polls.html
  19. 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
  20. 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
  21. 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
  22. Daniel Greenfeld @pydanny I’m Lazy Are you testing enough? Yeah,

    some of the configuration is off. Will be fixed soon.
  23. 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
  24. 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
  25. 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!
  26. Daniel Greenfeld @pydanny I’m Lazy Are you testing enough? Yeah,

    some of the configuration is off. Will be fixed soon.
  27. 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
  28. 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
  29. 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
  30. 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?
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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