Wednesday, April 3rd, 2013

Why DRY programming is so important

With the introduction of DRY(Don't Repeat Yourself) programming model, lots of existing programming languages and their associated frameworks have been jumping on broad. Some frameworks such as Ruby on Rails and Django were built from the ground up to use DRY. Django includes so many DRY helpers that creating a full featured application takes no longer than a couple days of work. With the introduction to DRY programming, it's hard to believe why so many developers still choose to use tools which include so much manual labor... Why are these programmers reinventing the wheel every single day? One of the most common tasks done in web development and design is building a data-driven form. I recently downloaded a plugin from the wordpress website to see just exactly how far this framework has progressed over the years in terms of developer friendliness and DRY principals. I was truly disappointed to see a simple Contact form require so much code. The code itself is a total of 90.6KB, a whopping 1,280 lines(with comments and blank lines). This code also contains the front-end layer for the admin interface in Wordpress along with how it's suppose to integrate with the website. In comparsion, here is the Django DRY version of a contact form(easily extendable to include new fields and includes Captcha as well):

# contact_form.py
from django import forms
from django.views.generic.edit import FormView
from django.core.mail import mail_admins
from django.contrib import messages
from django.template.loader import render_to_string
from captcha.fields import ReCaptchaField

class ContactForm(forms.Form):
    your_name = forms.CharField()
    your_email = forms.EmailField()
    message = forms.CharField(widget=forms.Textarea)
    captcha = ReCaptchaField()
    def send_email(self, ipaddr):
        body = render_to_string('contact.txt', {'name':self.cleaned_data['your_name'],
                                                'email':self.cleaned_data['your_email'],
                                                'ipaddr':ipaddr,
                                                'message':self.cleaned_data['message']})
        mail_admins('Website contact form', body)

class ContactView(FormView):
    template_name = 'contact_form.html'
    form_class = ContactForm
    success_url = '/'
    def form_valid(self, form):
        form.send_email(self.request.META['REMOTE_ADDR'])
        messages.success(self.request, "Your message has been sent!")
        return super(ContactView, self).form_valid(form)
    def form_invalid(self, form):
        messages.error(self.request, "There was an error submitting the form, please review and try again.")
        return super(ContactView, self).form_invalid(form)

That's really it, I added some extra functionality to it, and it's easy to add new fields. The best part is, when adding new fields, you don't even need to touch the HTML code, it's all inclusive. You can see this exact form live on this website. Here is the most basic template without all the bootstrap magic:

          <form action="{% url 'contact-form' %}" method="post">{% csrf_token %}
              <legend>Contact form</legend>
              {{form.as_p}}
              <button type="submit">Send Message</button>
          </form>

There are a few different form formatters you can use, table, p, and ul. You can also make your own and include that into any template with a form. Here is one for bootstrap:

{% for field in form %}
<div class="control-group{% if field.errors %} error{% endif %}">
  <label class="control-label" for="{{field.id_for_label}}">{{field.label}}</label>
  <div class="controls">
    {{field}}
    {% if field.errors %}<span class="help-inline">{% for err in field.errors %}{{err}}{% endfor %}</span>
    {% else %}{% if field.help_text %}<span class="help-inline">{{field.help_text}}</span>{% endif %}{% endif %}
  </div>
</div>
{% endfor %}

All the error messages are provided by their respective FormFields, if the email address entered isn't really an email address, then the user will automatically see an appropriate error message. I only needed to write the user facing HTML code once for the bootstrap look and feel. Then for each form on the website you see there, I merely include this bootstrap look and feel, the Django forms system takes care of the rest regardless of what fields the form has. If you create an account and use the website a bit, you see some dynamic forms controlled using jQuery, still using that same template above, just a different Django form field or widget. My consulting website's Quote form has a form that uses TinyMCE and a jQuery UI date dropdown. All of this was added to these websites in way under 1,000 lines of code. Django takes care of all the repetitive details for me. This is also why I don't charge an arm and a leg for a web development job, as the job with Django compared to some other frameworks out there is super easy! With the bootstrap-ajax jQuery plugin, you can effortlessly submit forms over AJAX. Their example code is made in Django by the way(This definitely shows the growing popularity of Django).

Now, I normally don't do comparisons on this website, but after peeking at a wordpress plugin and seeing how not DRY it was, I needed to show prospect Django developers what they will be in for, if they plan on moving to a DRY framework. I do hope to add some tutorials and other articles soon showing how to create full applications using Django with less code than competing frameworks out there. Once you go Django, you seriously won't go back. I never did, and now I am a very proud Django web developer who advocates not re-inventing the wheel. Other fun DRY features of Django besides forms and forms based on database tables, is:

Pagination
Pagination is widely used in web applications, and Django includes both a low-level Paginator class that can be used with almost any data types. This class is the basis for the pagination used in the generic views for paginating database tables.
Built-in role-based permission system
Controlling access to resources couldn't be easier than in Django. You can easily restrict users based on either what group they are in or what fine-grained permissions they have on a particular database table. The permissions themselves are assigned and managed easily through an automatically generated interface. The API to check for permissions is very easy to use and can be used in either the Python source code or the HTML templates.
Validators
With custom easy to create validators, you can extend your database table and forms to only accept specifically formatted data from the user. Existing validators exist for Email addresses, IP addresses, URLs, and number ranges. A custom validator can effortlessly be attached to a data model, such a database field or form.
Signals
Signals are used to run specific functions when a specific event in the application occurs. It can be used to uncache something which was recently modified for example. You can even build your own signals, which is normally used in 3rd party apps to allow developers an easy API to watch and react to specific application events.
Caching
With caching support and a set of pluggable backends, you can easily cache data in your application for a variety of purposes. Caching can occur at any level, you can cache every single page request, cache specific URLs, only cache anonymous requests, specific blocks in a template, or even Python objects at the lowest level. Mastering this component will speed up your application and prevent any unneeded database queries. If you cache page requests, you can even use a supporting web server to serve the cached item and bypass Django entirely for some requests, speeding up your application even more.

Since all of these components are shared with an entire Django project, each app, both yours and 3rd party ones are free to communicate with one another with little effort. You can easily create related database fields to a 3rd party app, such as a blog, forum, eShop, etc... All these apps will share the same user information, allowing your users to use a single identity throughout. Since all the data easily relatable, analytics couldn't be easier. You can more easily create a unified product, where users on your forum can easily link a post to a discussion about an item in the eShop. The forum post can contain most, if not all the metadata from the item being sold for easy reference. Users of the website can like an eShop item and this information can be displayed in the forum with little work required. The users can also have a unified profile, where it contains a list of their forum posts, their eShop likes, recent purchases, and reviews on products. Why should a user need to have 2 or more accounts on a single website? I see this a lot, and I absolutely hate it. This is why DRY is so important! It's not only beneficial for the developer, but it can also help the end user's experience as well.

Comment #1: Posted 1 year, 5 months ago by martinbc

Great post. The beauty of DRY, Django code is an excellent resource to learn to code in a DRY way.

Comment #2: Posted 1 year, 4 months ago by Jason McCreary

To be fair, you're comparing apples and oranges (PHP vs Python). Furthermore, you're comparing against arguably the worst possible apples (WordPress plugins).

Good article and compelling code sample.

About Me

My Photo
Names Kevin, hugely into UNIX technologies, not just Linux. I've dabbled with the demons, played with the Sun, and now with the Penguins.




Kevin Veroneau Consulting Services
Do you require the services of a Django contractor? Do you need both a website and hosting services? Perhaps I can help.

This Month

If you like what you read, please consider donating to help with hosting costs, and to fund future books to review.

Python Powered | © 2012-2014 Kevin Veroneau