MadMode

Dan Connolly's tinkering lab notebook

python, javascript, and PHP, oh my!

My habits for developing quality code in python are bumping up against the fact that the deployment platforms for the web client and server are javascript and PHP, respectively.

I love the python doctest module. uripath.py is a pretty good example of how I like to use it to simultaneously document and test code:

def splitFrag(uriref):
    """split a URI reference between the fragment and the rest.

    Punctuation is thrown away.

    e.g.

    >>> splitFrag("abc#def")
    ('abc', 'def')
[...]

def splitFragP(uriref, punct=0):
    """split a URI reference before the fragment

    Punctuation is kept.

    e.g.

    >>> splitFragP("abc#def")
    ('abc', '#def')
[...]

Another important way that python is self-documenting is that it meets the unambiguity requirement: you can pick up any .py file and trace every identifier back to what it refers to by following your nose:

  • for local variables, normal static scoping rules work; just scan up and look for an assignment or a function parameter
  • for imported names, find the relavent import statement. from foo import * is evil, of course.
  • global variables are explicitly declared as such

OK, full disclosure: you need to know the python built-ins, and when you see paramx.methody(z), you have an unbounded search for methody, which makes doctests that show what class paramx comes from pretty important. Mapping from the relevant import statement to the corresponding .py file may involve the usual search path nightmares; python doesn't solve that. redfoot's red_import is interesting. And I'm not sure if eggs are a step in the right direction or the wrong direction; gotta study them more. I try to ground import statements in the web a la:

import MySQLdb # MySQL for Python
               # http://sourceforge.net/projects/mysql-python
               # any Python Database API-happy implementation will do.

... so that you can follow your nose from the ImportError traceback to resolve the dependency.

Now timbl has started migrating the swap/cwm stuff to javascript. Let's look at uri.js:

/** return the protocol of a uri **/
function uri_protocol(uri) {
...

Thanks for trying to document each function, but that sort of comment isn't worthwhile; the risk that it'll get out of sync with the code is greater than the information it provides. Back to naming...

function URIjoin(given, base) {
...
    if (base<0) {alert("Invalid base URL "+ base); return given}

Where does alert come from? Is that in the ECMAScript standard? Or in some Netscape devedge stuff?

But more importantly: why not raise an exception? Javascript does have throw/catch, no? Is it not the norm to use them? As I argued in my contribution to the Python, Tcl and Perl, oh my! thread in 1996, the community norms are at least as important, if not more important, than the language features, when it comes to developing quality code.

I keep running into javascript and PHP code that I want to read and wishing for doctests because I can't figure out which end is up.

Whence comes kb in this bit from term.js? Do I face an unbounded search?

RDFFormula.prototype.fromNT = function(str) {
    var len = str.length
    var x
    if (str[0] == '<') return kb.sym(str.slice(1,len-1))

Maybe I just need to study the standard libraries a bit more, but I hear that the drupal project has coding conventions lots of people like for developing quality PHP code; I hope to study those. And the PEAR community must have some norms and best practices. I went looking for javascript testing stuff and ran into JSAN, a CPAN work-alike. That sort of infrastructure naturally reinforces quality norms.

See also: delicious tags , , , , .