Share
Embed
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.
Daniel Greenfeld
October 07, 2011
Transcript
60 slides
-
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 -
Daniel Greenfeld @pydanny I’m stupid • Can’t figure things out
• Can’t remember things • Too stupid not to ask stupid questions -
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 -
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 -
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! -
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 -
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 -
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 -
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. -
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. -
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 -
Daniel Greenfeld @pydanny Docs/Sphinx Basics • pip install sphinx •
make a docs directory •sphinx-quickstart • Follow instructions • Starting over is just removing your docs -
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 -
Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!
http://readthedocs.org/docs/django-party-pack/en/latest/reference_polls.html -
Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!
http://readthedocs.org/docs/django-party-pack/en/latest/reference_polls.html -
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 -
Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!
http://readthedocs.org/docs/django-party-pack/en/latest/reference_polls.html -
Daniel Greenfeld @pydanny I’m stupid Sphinx makes me look good!
http://readthedocs.org/docs/django-party-pack/en/latest/reference_polls.html -
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 -
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 -
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 -
Daniel Greenfeld @pydanny I’m Lazy Are you testing enough? Stick
even the ‘basic stuff’ in the docs! -
Daniel Greenfeld @pydanny I’m Lazy Are you testing enough? Yeah,
some of the configuration is off. Will be fixed soon. -
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 -
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 -
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! -
Daniel Greenfeld @pydanny I’m Lazy Are you testing enough? Yeah,
some of the configuration is off. Will be fixed soon. -
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 -
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 -
Daniel Greenfeld @pydanny I’m Lazy Host your docs on http://rtfd.org
Import your project -
Daniel Greenfeld @pydanny I’m Lazy Host your docs on http://rtfd.org
Admin Service Hook ReadTheDocs Active -
Daniel Greenfeld @pydanny Sphinx Trick! /django-party-pack /docs /conf.py Makes Sphinx
play nicely with Django -
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 -
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? -
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 -
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 -
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 -
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 -
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