No exceptions, classes or frameworks: Creating a web application in python

published Apr 06, 2015 04:05   by admin ( last modified Apr 06, 2015 04:21 )

My current rules for creating a web application in python

Summary: No exceptions, no classes, no frameworks.

No frameworks

Framework fatigue A framework is a mode, a global pragma on how to express the code in your application. In order to be efficient you need to understand how that framework works and it is unlikley that its modus operandi covers all the things that you want to do in a way that is flexible enough to match standard python. Instead use libraries, that gets hooked into your code, and only have a local impact on syntax and configuration.

Coming from the Zope/Plone world, it is very nice to throw all frameworky stuff to the wind and just express things in pure python. Now, frameworks do have their place, when you are solving something that many people have already solved for you, such as a content management system. But the moment your customer starts suggesting/dreaming up unique features you start fighting the framework. I chose to go with the bottle micro framework (which technically is a framework), that mostly stays out of the way and the module in my code that uses bottle is as thin as possible, and isolates the rest of the code from it.

No exceptions

Exceptions break the flow of the code, and it is harder to follow the execution of it. Furthermore in a web application you sometimes want to communicate several errors to the user, and not just the first one. Currently I use an extra return value in the form of an error object, that contains info if there is an error, some text that describes the error in a human readable way, and sometimes a recommendation of what url to redirect to.

class Status:

    def __init__(self):
        self.error = False
        self.redirect_address = None
        self.messages = []

    def add_message(self, message):
        self.messages.append(message)

..and used in a function:

    status = Status()

    user_info = session.get_user_info_from_session(session_id)
    if not user_info:
        status.error = True
        status.add_message("Please log in.")
        status.redirect_address = '/login'
        return (None, status)

In this way I can add error messages, and then return from a function when enough error messages have been added. That is, I can add errors that are not caused by each other, before returning. This works well with server side validation, where you can list all the things that need to be corrected back to the user, and not just the first one you test for (although obviously you do client side validation too, for usability reasons. But you still need to untaint the input).

Using an explicit return value for error or success is used in the Go language instead of exceptions. Idiomatic scala uses the entire result you get back with a return value. The latter would be highly magical in Python, so a separate status value is used.

No classes

Objects are in practice highly unpredictable in when it comes to how you're supposed to interact with them, and get data in and out of them. In practice, objects forces you to learn a mini configuration language for each class, expressed as methods, parameters and whatever state changes happens as a result of those method calls. With pure functions that complexity is confined to the parameters going in and the return values coming out. I have heard from Java programmers that the complexity of how to interact with objects is less of a problem if you have declared interfaces and an IDE that can tell you what's going on with inputs and outputs. However there is still way to much freedom to express yourself as a class author when it comes to how you go about performing a task.

Objects all the way down can make for something akin to a Rube Goldberg machine:

But it is also a question of how to do simple things such as setting a configuration value. Is that done by just setting an attribute, or calling a setter, or using a configuration object that somehow interacts with something?

Objects are often used to store state, which if it is mutable also messes up scaling up the application, and makes testing more difficult. In a web app pure functions also automatically makes your application scalable, since http is sessionless and each request needs to retrieve its state anyway from cookies, urls and server side stored data.

I actually did end up using some objects, as can be seen from the Status object in one of the code listings above.