Ian Bicking: the old part of his blog

Little Apps Instead of Little Frameworks

We've been doing lots of infrastructure at work lately. A couple basic apps have been added to our internal system -- a login app, and an admin app. The login app logs you in. That's all it does -- it takes your username and password, sets a cookie, and redirects you to your destination. That's an application, with all the infrastructure an application implies. The admin application reads a common config file, finds all your admin tools (which are often embedded in other applications) and gives you a summary. That's all it does, one page.

It took me a little while to really commit to making these applications. They are so small, it didn't make sense. And yet it does; it's manageable and maintainable, the apps works, they do their function.

This has been a kind of vaguely defined goal of paste.deploy all along, though now that the tools are there I'm starting to see more of the potential and what it can mean. I wanted applications to be easy to install, upgrade, and compose, so that it would be reasonable to make really little applications. The quintessential application in my mind was the modest formmail script, that just emails all the fields off to someone. This classic application remains useful today, but I sure as heck wasn't going to set up a new Webware app server instance to do it. And sometimes I'd find myself writing to a database just to justify the infrastructure. Bad stuff.

The login and admin apps take it a bit further -- not only are they small, they are also useless on their own. But even though their utility is predicated on the existence of other apps, their functionality needn't be. And designing around that I find the applications have utility even in the context of a heterogeneous environment. I don't need to commit to Rewriting Everything In My Framework Of Choice.

We all know frameworks are a pain in the ass. A lot of people have approached this cloud-of-apps problem as a framework problem. Sometimes that framework takes the form of a "CMS". These are often not what Python people would think of as a CMS -- it's more like PostNuke. Other times you have to do really funky things to add in abstraction. Like Acquisition, or many of the "component" systems. I admit I've made such frameworks and plugins. It ain't pretty.

Applications are the new framework! This is kind of what REST implies, but those are high-minded ideas around some potentially very simple things, and there's still a lot of room in the simple end of things, with ad hoc communication on as as-needed basis, and complete decoupling whenever possible.

I personally really hope to see future tools emerge in this form. I don't mind a heterogeneous system. If someone makes a really great admin interface for SQLObject classes (something I'd like to see happen), I don't care if they write it in Myghty or CherryPy or Zope 3 if I can install and manage it easily. If it's done right (which to me means "Paste-Deploy enabled") then I should even be able to embed that application in my own and create a seemingly unified whole.

So far there's been very little app sharing in Python. We share frameworks (sometimes), but frameworks incur loathing. No wonder we reimplement all the time. Applications are a good alternative.

Created 07 Oct '05

Comments:

I really like this approach, especially as it relates to easily extending login types. I'm not really a fan of writing my own login/logout scheme for every new web application, plus more advanced login schemes could be done in an external small login webapp, like ISSO and all that single-sign-on stuff.

Of course, that leaves me wondering how such little apps would keep a consistence appearence that actually looks like part of the site they're used with. Probably the easiest way to let the app user decide, would be to intercept the login/logout call, do the function, then "inject" the form to login, etc into the web application. That way the person using the little app would be able to fit it in with their existing website however they wanted. That's just the first scheme that comes to mind though...

# Ben Bangert

I really like this approach, especially as it relates to easily extending login types. I'm not really a fan of writing my own login/logout scheme for every new web application, plus more advanced login schemes could be done in an external small login webapp, like ISSO and all that single-sign-on stuff.

I have noticed that the single-sign-on stuff tends to have a login process that is a lot more complicated than just asking for a username and password, and a login can take place over several HTTP requests. That's a really hard library to write. But a pretty simple app.

Of course, that leaves me wondering how such little apps would keep a consistence appearence that actually looks like part of the site they're used with. Probably the easiest way to let the app user decide, would be to intercept the login/logout call, do the function, then "inject" the form to login, etc into the web application. That way the person using the little app would be able to fit it in with their existing website however they wanted. That's just the first scheme that comes to mind though...

That is possible, if you make it possible to include other resources. I.e. <<include "/login/formfragment">> which does a subrequest and inserts the result (adapted to whatever your templating language). However, this gets complicated if there's any interaction -- it only really works for displaying the initial form, not the form action or any intermediate screens. And maybe that's okay. The actual form action should be directed automatically to the application, though if you were doing it as middleware you could also just capture some particular pattern.

For other applications, a simple method would be if there were good conventions for how to override templates. Like a template path, with local templates first on the path. You might have to replicate your appearance several times in several templating systems, but if there are good conventions that's not so hard. And it's a useful feature to have even if something better comes along, so I think it's a good start.

# Ian Bicking

i've been doing this kind of thing for a while now. the original impetus was a quiz building tool. we wanted users to be able to build an online quiz/survey (similar to survey monkey) that could be tied in to other applications (potentially written in any language and running on any machine). so i set up little REST services. when a quiz is created, the author fills in urls for login, verification, etc. services with little placeholders for variables in the urls. when a user goes to the quiz, they get redirected to the login service, they login there, and it sends them back to the quiz app along with a ticketid and username. the quiz app will then, on each subsequent request, ask a verification service if that ticketid/username combo is valid on a backchannel. so now, if we have an application that could use a quiz but has its own notion of users and authentication, the developer on that app just sets up login and verification services against the app's user database, creates a quiz, and plugs those service urls into the quiz's configuration. then we also have a couple stock services that can be used (one that authenticates against the university's id system, a "public" one that essentially allows anyone in, one that checks that the IP address is on campus, etc.)

it was mostly just expanding on the ideas of the CAS single-signon system: http://www.yale.edu/tp/auth/cas10.html (actually, on WIND, which is Columbia's clone of CAS).

the really nice thing about building systems this way is the complete flexibility of policy. if someone comes up with some crazy new authentication system that i couldn't have thought up, the quiz tool can still use it as long as they can encapsulate it in a couple simple services.

# anders

Ian, have you read Why I Hate Frameworks thread on JoS? It carries similar "no frameworks, please" message only authors talks about libraries, not apps.

I'm curious, how these apps actually look like? Does it have its own project tree in subversion, its own docs/tests, etc.?

# Max Ischenko

No, I haven't seen that; I'll give it a look.

Libraries don't work for some problems. Those that involve several repeated interactions with a browser -- like single-signon systems -- are one case. In that case, you starting needing a "framework", which is just "an abstracted application". And the abstraction is a pain in the butt.

As for what they look like: yes, they look like full projects -- separate tree, separate docs, tests, configuration, setup.py.

# Ian Bicking

Another swell buzz-word in this vein is 'aspects', like logging: distinct, orthogonal, reusable, unrelated, essential stuff.

# anonymous

I'm curious about your description of the login app. If all it does is set a cookie, doesn't that mean that your users could simply go to the final destination, skipping the login? If the final destination (and all further pages) needs to retrieve and process the cookie, isn't this the beginning of a framework, since each app-behind-the-login needs to know how the login was done and how to verify it?

Maybe I missed your point and the only goal is to maximize decoupling of implementation details?

# pierrebai

The cookie would be signed and checked for with WSGI middleware or some other intermediary (like mod_auth_tkt). How you get the cookie is not embedded into the application, and there is a CGI convention for where the unpacked cookie goes (REMOTE_USER); or it could be HTTP auth or whatever. All your app needs to know is to trust REMOTE_USER.

# Ian Bicking

Sometimes the login form is embedded into another page (the index page). In that case just let the main app handle the form. The login routine could work as middleware, operating just on that URL, processing the credentials if present, and setting a message for the main application ("success", "user not found", "invalid password"). Then if the application has a general way to display messages, it can convert the message to something more reasonable and display it.

# Mike Orr