All Unkept
Posted in: Christianity, Django, Python, Software projects, Web development  —  1 April 2008

Bible memorisation web app

I recently decided to get more serious about memorising parts of the Bible. I've found I can learn one a day fairly easily, with the right system, and realised I needed two things:

  • A system for ensuring I have a good coverage of topics.
  • A method for keeping track of what I have memorised so far

It is now just about ready for public consumption, so I present my:

Bible Memorisation Schemes

It should be fairly self explanatory. (read: I haven't had time to write any help yet). At the most basic level, it is a set of pages with verse lists. But if you register and log in, check boxes appear which you can use to indicate verses you have already learnt, and this data is stored on the server.

Details

I solved the first of my two aims with a set of YAML documents that define sets of verses and a hierarchy of topics, along with some Python scripts that combine them (into pages on my personal wiki first of, and now into an HTML version), allowing me to see what I'm missing.

YAML proves to be very convenient for this type of thing: you can use search and replace to do changes to more than one area, and can easily add new functionality. For example, the scheme definitions are perfectly readable in English, but exceptional easy to turn into nice data structures in Python to manipulate the data. The Python scripts generate the actual schemes, which makes it very easy to add new verses and still have schemes that are balanced and varied (or focused, if that's what your scheme definition says).

The web app is written in Python, using CGI. (It is a very basic app, which talks only JSON, and uses just two database tables—so I didn't want to rely on a heavy framework that would have special hosting requirements). I started using web.py at first, but had two problems with it:

  • For an AJAX CGI app, it is much too heavyweight, as "hello world" on my server took about 1.2 seconds due to everything that was being imported.

  • Frankly, I thought it sucked. I have been spoilt by the lovely design of Django. web.py really has a different niche to Django, but given Aaron's dismissiveness of Django's API design I was expecting he would have learnt more from it, such as:

    • Views are functions. Using classes which have 'GET' and 'POST' methods may seem like a good idea, but often it isn't due to the duplication between the two responses. Going from a function based system to a class based system is very easy (just implement SomeBaseClassForViews.__call__()). But going the other way around is ugly.

    • View functions simply take request objects and return response objects. In web.py, parts of the request path are passed into the function, as in Django, but you have to call web.input() to get query data and posted data (where web is a module, not an object passed in). But, even worse, you call web.header() to write headers, while the body of the response is 'print'ed out (or returned as a string in version 0.3). This is horrible.

      With Django's method, you can do amazing things like the @login_required decorator (it is very cool -- seamlessly persists any posted data, passing it along to the view once the user has successfully logged in [EDIT - see comment below]). And the implementation is robust and straightforward, not magical (though not completely simple either, due to the nature of the case). You can also do cache control decorators, and write a validator middleware etc. This is simply from following standard good programming practice, in which side effects are avoided where possible, and function outputs depend only on inputs.

    Some of Aaron Swartz's design decisions just niggled me too. It is claimed that "web.py lets you write web apps in Python", but to me it seems more like something which is reminiscent of Python, but sloppier. Take for instance the definition of URLs. If it had been this:

    urls = [
        ('/(.*)', 'hello')
    ]
    

    ...I would have understood it straight away. Instead, I stared at this for a while:

    urls = (
          '/(.*)', 'hello'
      )
    

    ...and eventually found that the explanation is it'd be a lot more typing to do it the sensible way. I guess readability doesn't count for anything.

So anyway, I happily ditched web.py, wrote my own Django-inspired mini framework that does just what I need, and fixed my performance problem (the 'framework' is in webutils.py, see the views.py file for example usage. Most of it was developed using TDD, which turned out to be a big timesaver—it's just so quick to make big changes and be sure you haven't broken anything.

Anyway, it has been a nice little project, and I'm hoping that it will actually prove useful to me and others!

Comments §

§ On 2 April 2008, Doug wrote: 310
One small comment: @login_required doesn't persist 'POST' data, but rather 'GET' data. And 'persist' may not be a fair description, maybe 'retains' would be a better choice, as the data is only remembered via the redirected URL sent back to the browser.

If you redirect a POST, the POST data in the header will be dropped. This is because browsers treat a 302 response as a 303 response and will GET the redirected resource, dropping any POST data in the original request header.

Anyway, interesting write-up. I kicked web.py around for a little bit but landed on Django as it fit me better.

§ On 2 April 2008, luke wrote: 311
Doug: I was sure that you were wrong about that, but I checked the sources and you were right. It turns out I was thinking about the 'staff_member_required' decorator used in the admin:

http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/views/decorators.py?rev=7397#L50


I remember ages ago I was about to implement this, but discovered it already in the Django sources, so I just ripped it off for my own purposes :-)

§ On 3 April 2008, casseen wrote: 312
Psalm 137:9 and Deuteronomy 3:6 should definitely be high on your list.

"Happy shall he be, that taketh and dasheth thy little ones against the stones."

"And we utterly destroyed them, as we did unto Sihon king of Heshbon, utterly destroying the men, women, and children, of every city."

§ On 5 April 2008, luke wrote: 315
casseen: The verses I'm adding are ones that are useful summaries and are key to understanding and thinking about important teachings in scripture. The ones you have highlighted are often difficult to understand without knowledge of the Old Testament historical context (see http://www.christian-thinktank.com/qamorite.html for more). In fact, they also do not express the *full severity* of God's judgement, which becomes more clear in the New Testament.

So for verses which teach the justice and wrath of God, I would prefer these:

Psalm 7:11 - "God is a just judge, and God is angry with the wicked every day"

Nahum 1.2 - "The LORD is a jealous and avenging God; the LORD takes vengeance and is filled with wrath. The LORD takes vengeance on his foes and maintains his wrath against his enemies."

Jesus' words referring to himself:

Luke 20:17-18 "The stone that the builders rejected has become the cornerstone. Everyone who falls on that stone will be broken to pieces, and when it falls on anyone, it will crush him. "

This description of hell:
Revelation 14:11 - "And the smoke of their torment goes up forever and ever, and they have no rest, day or night, these worshippers of the beast and its image, and whoever receives the mark of its name. "

These have to be understood in the context of another couple of crucial texts regarding God's own attitude to this wrath:

Lamentations 3:33 - "he does not willingly afflict or grieve the children of men."

Ezekiel 33:11 - "Say to them, As I live, declares the Lord God, I have no pleasure in the death of the wicked, but that the wicked turn from his way and live; turn back, turn back from your evil ways, for why will you die, O house of Israel? "

And I could not fail to mention under the same section the horrific judgement which fell on Jesus Christ, inflicted by God himself:

Isaiah 53: 5,10 "But he was wounded for our transgressions;
he was crushed for our iniquities;
upon him was the chastisement that brought us peace,
and with his stripes we are healed.
 ...Yet it was the will of the Lord to crush him;
he has put him to grief; "

§ On 6 April 2008, casseen wrote: 316
Sorry for bothering you, this was just my own little way to express my disgust for hate speech. And be sure that I know most of it. No need for teaching me.

I shouldn't have posted those lines above in the first place. It some times just overcomes me.

Add comment

Format:

  • Javascript has to be on to get past my spam protection, and cookies, and there is a delay, sorry for any inconvenience!
  • I reserve the right to moderate comments.