Rethinking the Reusable Apps

Embed Size (px)

Citation preview

  • 8/8/2019 Rethinking the Reusable Apps

    1/31

    Rethinking the Reusable

    Application ParadigmAlex Gaynor

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    2/31

    I work here.Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    3/31

    I work with these guys.Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    4/31

    We do a lot of this.Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    5/31

    You have been sold alie!

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    6/31

    By this man!Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    7/31

    The dangerous lie:

    defmy_view(request, pk, template_name="my_app/my_page.html", form_class=MyForm,

    redirect_url="/home/place/"):

    # magical view stuff here return HttpResponse()

    This does not, a reusable app, make.

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    8/31

    That doesnt mean its useless.

    But it doesnt solve all the problems.What the hell are the problems were trying to solveanyways?

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    9/31

    Similar patterns across many sites (tagging, voting,commenting, etc.).

    Write once, use everywhere.

    No need to reinvent the wheel.

    Why Reusable Apps?

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    10/31

    The problems.

    Differing business logic.

    Everyone wants comments, but can anonymous userscomment, is there a comment preview page?

    Differing data storage

    Does a forum belong to a group, does it need a slug? Docategories have an icon?

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    11/31

    The Solutions

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    12/31

    Class based views

    See Ben Firshman at 2:20: Alternate ViewsSimple view functions dont provide entry points forchanging logic, besides what you create a parameter for.

    Subclass to change the logic, e.g. the admin.

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    13/31

    django.contrib.admin

    classArticleAdmin(admin.ModelAdmin):

    defsave_model(self, request, obj, form, change):

    obj.user = request.userobj.save()

    Theres like 30 of these.

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    14/31

    Do Less

    aka: reusable frameworksCreate a framework, so other people can write their buisnesslogic around it.

    Example: badges.

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    15/31

    Badges

    Can badges have multiple levels?How do you know if a user has received a given badge, at agiven level?

    Can a user receive a badge more than once?

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    16/31

    The stuff everyone needs...

    Templatetags for getting badge count or list of badges for auser.

    Queueing of computations, when theyre expensive.

    Persistence.

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    17/31

    brabeionclassPointsBadge(Badge):

    slug ="points"

    levels = [

    "Bronze",

    "Silver",

    "Gold",

    ]events = [

    "points_awarded",

    ]

    multiple =False

    defaward(self, user, **state):

    points = user.profile.points

    if points >10000:

    return BadgeAwarded(level=3)

    elif points >7500:

    return BadgeAwarded(level=2)

    elif points >5000:

    return BadgeAwarded(level=1)

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    18/31

    Be flexible

    You cant predict all the ways people want to use yoursoftware.

    But you know what the common way is (probably whatever

    you wanted to do in the first place).So provide a default, but let people swap it out.

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    19/31

    django-taggit

    classEvent(models.Model):

    title = models.CharField(max_length=100)

    date = models.DateField()

    tags = TaggableManager()

    Common case: I want some tags on my stuff.

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    20/31

    Uncommon cases

    Non-integer primary keys (IntegerField for the

    GenericForeignKey, by default)

    Per-user tags.

    Official tags.Custom caching managers, or anything else.

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    21/31

    classEventTaggedItems(BaseTaggedItem):

    event = models.ForeignKey("Event")

    classEvent(models.Model):

    title = models.CharField(max_length=100, primary_key=True)

    date = models.DateField()

    tags = TaggableManager(through=EventTaggedItems)

    Swap out the intermediary model (also the Tag model)

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    22/31

    Custom backends

    django-registration

    django.core.cache

    django.contrib.auth

    django.core.files

    django.contrib.sessions

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    23/31

    django-registrationclassSimpleBackend(object): defregister(self, request, **kwargs):

    username, email, password = kwargs['username'], kwargs['email'], kwargs['password1']

    User.objects.create_user(username, email, password)

    # authenticate() always has to be called before login(), and

    # will return the user we just created.

    new_user = authenticate(username=username, password=password)

    login(request, new_user)

    signals.user_registered.send(sender=self.__class__,user=new_user,

    request=request)

    return new_user

    defactivate(self, **kwargs):

    raiseNotImplementedError

    defregistration_allowed(self, request):

    returngetattr(settings, 'REGISTRATION_OPEN', True)

    defget_form_class(self, request):

    return RegistrationForm

    defpost_registration_redirect(self, request, user):

    return (user.get_absolute_url(), (), {})

    defpost_activation_redirect(self, request, user):

    raiseNotImplementedError

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    24/31

    Libraries

    Not everything is business logic

    Tools for other people

    e.g.: django.forms

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    25/31

    django-filtersclassProductFilterSet(django_filters.FilterSet):

    classMeta:

    model = Product

    fields = ['name', 'price', 'manufacturer']

    Create filters like the admins list_filter.Built on top of django.forms

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    26/31

    Other Tools

    django-fixture-generator

    Generate fixtures programatically.django-templatetag-sugar

    A declarative API for creating templatetags.

    django_compressor

    Compress and combine static media (CSS + JS)

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    27/31

    When to ignore all ofthis

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    28/31

    Well defined problem spaces.

    Extremely common use cases.

    You just dont care about the 20% (internal apps?)

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    29/31

    user_messages

    Internal Eldarion app

    Allows user to send messages to other users.

    Almost no customizability.

    Only control is to enable multi-user messaging or not.

    Dead simple to use.

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    30/31

    0 flexibility, 0 work

    Add to INSTALLED_APPSAdd to urls.py

    Write templates.

    Done.

    Monday, September 6, 2010

  • 8/8/2019 Rethinking the Reusable Apps

    31/31

    Questions?

    http://alexgaynor.net

    http://alexgaynor.net/http://alexgaynor.net/http://alexgaynor.net/