Random Quotes on Business and Software

A Cooperative Organization:

(…) Gore has been a team-based, flat lattice organization that fosters personal initiative. There are no traditional organizational charts, no chains of command, nor predetermined channels of communication. Instead, we communicate directly with each other and are accountable to fellow members of our multi-disciplined teams. We encourage hands-on innovation, involving those closest to a project in decision making. Teams organize around opportunities and leaders emerge.

Continue reading

Best books of 2008

You might remember my beloved mantras: learning a new programming language and reading at least 6 relevant books every year. Following the 2007 edition, here’s the list of the 8 books I have enjoyed most in 2008, ordered by a purely subjective and absolutely irrational decreasing preference. I strongly recommend all of them!

Winner: Geekonomics: The Real Cost of Insecure Software by David Rice

Runner-up: The No Asshole Rule: Building a Civilized Workplace and Surviving One That Isn’t by Robert I. Sutton, PhD

And 6 more:

Continue reading

The Dirty Little Secret of iPhone Development

This is happening right now, at a web agency near you.

The dot-com boom of the 90′s spawned a brand new generation of coders and software developers, including me, by the way. While before that time the term of “software developer” might have been reserved to system programmers fluent in C, COBOL, C++ or other languages, right now the vast majority of developers I know spend their time writing web applications, either public or in a private intranet, in J2EE, ASP.NET, Rails, PHP, you name it.

I have said before that writing web applications should be taken as seriously as writing desktop systems. Call me names if you want, but I’m a big fan of Joel’s Test.

However, after all this years, after the Chaos reports, after Peopleware, after the Mythical Man Month, people still treat quality as an afterthought. And also complain about how much software sucks, how expensive it is, and how late it arrives, by the way. Now that the iPhone SDK is widely available, that the App Store is selling more apps that we could have had imagined 6 months ago, many web agencies want to jump to native iPhone development contracts, which are hype and nice and pricey and whatnot. Which is only going to make things worse.

The dirty little secret in this story is this: iPhone development looks more like developing applications for a desktop operating system, and less, much less than web development. And I’m frightened to see some small shops (and even bigger ones), who never attained a real level of professionalism or quality in their software tasks, starting projects and realizing, later, when they are over budget and behind schedule, that this kind of applications requires a different mindset.

Continue reading

Saving a Failing Project

In 2006 I had the opportunity to work as a “project leader” into a small failing project. Three developers were working in an ad hoc basis, creating a software application for an important client (a government office in Lausanne), without any kind of detailed formal specification, without any kind of design documentation, and with strong pressure from the management to release the application, even if not in an usable state. Needless to say, the project was also beyond budget.

I had just joined this company a couple of days ago, and the management asked me to take the project in charge. Not an easy task, particularly because it was my first experience of this kind. Continue reading

Quick spec from your Python tests

Using Python’s own unittest package, here’s a small script that can iterate over your test suite to output a small, quick, nice list of the tests in your application:

[source:python] import unittest

loader = unittest.TestLoader() tests = loader.loadTestsFromName(‘path.to.your.tests.package’) for test in tests.tests: print test._tests[0].class.name.replace(“Test”, “”) for method in test._tests: print ” %s” % method._testMethodName.replace(“test“, “”).capitalize().replace(“_”, ” “) [/source]

This would yield something like this: Business     Accounts have at least one entry     Clerks cannot close accounts Security     Users can create new accounts     Anonymous users cannot access private areas ...

Of course, you’ll get better results if you follow Google’s naming conventions for your tests… ;) This is not rspec (nor an alternative to it) but it might be useful to some of you.

Just as a reminder for Django users: you might need to

setenv DJANGO_SETTINGS_MODULE application.settings

or

export DJANGO_SETTINGS_MODULE=application.settings

in order to make the script work properly! At least I had to :)

REST + HTTP (Basic + Digest) Authentication support for Django’s test Client class

Django has a nice support for unit and functional testing; however, its django.test.client.Client class does not support PUT and DELETE requests, which might be useful if, like me, you’re doing some kind of REST implementation using that framework. There’s an open ticket about it, but for the time being, here’s my wrapper that supports those methods as well as GET and POST:

[source:python] from cStringIO import StringIO from django.test.client import Client as DjangoClient, encode_multipart from django.utils.http import urlencode import base64 import md5

class Client(DjangoClient): “”" Wrapper and drop-in replacement around Django’s own test “Client” class, providing PUT, DELETE and OPTIONS support, as well as HTTP Basic + Digest Authentication support. NOTE: the django.test.client.Client does not directly support PUT, DELETE or OPTIONS requests so we’re using the “request()” method directly… there’s an open ticket about it: http://code.djangoproject.com/ticket/5888 “”"

auth = { }
def http_basic_login(self, username, password):
    base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
    self.auth = { "HTTP_AUTHORIZATION": "Basic %s" % base64string }
def http_digest_login(self, method, url, params, response, username, password):
    (authmeth, auth) = response['WWW-Authenticate'].split(" ", 1)
    if authmeth.lower() != 'digest':
        return
    amap = {}
    for itm in auth.split(", "):
        (k, v) = [s.strip() for s in itm.split("=", 1)]
        amap[k] = v.replace('"', '')
    try:
        realm    = amap['realm']
        qop      = amap.get('qop', '')
        nonce    = amap['nonce']
        opaque   = amap['opaque']
    except:
        return
    cnonce = "01b6730aae57c007"
    nc = "00000001"
    query_string = "&".join(["=".join(item) for item in zip(params.keys(), params.values())])
    uri = url + "?" + query_string
    ha1 = md5.md5('%s:%s:%s' % (username, realm, password)).hexdigest()
    ha2 = md5.md5('%s:%s' % (method, uri)).hexdigest()
    if qop:
        chk = "%s:%s:%s:%s:%s:%s" % (ha1, nonce, nc, cnonce, qop, ha2)
    else:
        chk = "%s:%s:%s" % (ha1, nonce, ha2)
    response = md5.md5(chk).hexdigest()
    self.auth = {
        "HTTP_AUTHORIZATION": 'Digest username="%s", realm="%s", nonce="%s", uri="%s", response="%s", opaque="%s", qop=auth, nc=%s, cnonce="%s"' % (username, realm, nonce, uri, response, opaque, nc, cnonce),
    }
def http_logout(self):
    self.auth = {}
def pre_request(self, url, data):
    r = {
        'CONTENT_LENGTH':  None,
        'CONTENT_TYPE':    'text/html; charset=utf-8',
        "HTTP_USER_AGENT": "Django Unit Test HTTP Client",
        'PATH_INFO':       url,
        'QUERY_STRING':    urlencode(data, doseq=True),
    }
    r.update(self.auth)
    return r
def get(self, url, data, **extra):
    r = {}
    r.update(extra)
    r.update(self.auth)
    return DjangoClient.get(self, url, data, **r)
def post(self, url, data, **extra):
    r = {}
    r.update(extra)
    r.update(self.auth)
    return DjangoClient.post(self, url, data, **r)
def delete(self, url, data):
    r = self.pre_request(url, data)
    r["REQUEST_METHOD"] = "DELETE"
    return self.request(**r)
def options(self, url, data):
    r = self.pre_request(url, data)
    r["REQUEST_METHOD"] = "OPTIONS"
    return self.request(**r)
def put(self, url, data, form):
    BOUNDARY = 'BoUnDaRyStRiNg'
    MULTIPART_CONTENT = 'multipart/form-data; boundary=%s' % BOUNDARY
    encoded = encode_multipart(BOUNDARY, form)
    r = self.pre_request(url, data)
    r.update({
        'CONTENT_LENGTH': len(encoded),
        'CONTENT_TYPE':   MULTIPART_CONTENT,
        'REQUEST_METHOD': 'PUT',
        'wsgi.input':     StringIO(encoded),
    })
    return self.request(**r)
def hello(self, url, data, **extra):
    """Sends a fake 'HELLO' request which returns a 405 answer :)"""
    r = self.pre_request(url, data)
    r["REQUEST_METHOD"] = "HELLO"
    r.update(extra)
    return self.request(**r)

[/source]

Hope it helps! Of course you could extend this to support OPTIONS, HEAD or other HTTP methods you could find in the specification.

Update, 2008-03-05: Following Yoan’s comment below, I’ve DRYed the code a bit. Neat.

Update, 2008-03-11: I’ve added HTTP Basic Authentication support to the class (and changed the post title accordingly).

Update, 2008-03-13: Another modification: now the client supports HTTP Digest Authentication (Yay! To use it, make a first call to your server and then pass the response as a parameter to the http_digest_login method), plus support for the OPTIONS verb, plus another method which sends a method with a “HELLO” verb, which of course does not exist… and which will (normally) return a 405 response!

A Simple Recipe for Podcast Success

I am subscribed to quite a few podcasts and screencasts here and there. And I’ve come up with a very basic (albeit limited and you could even say irrational) way of determining which to keep listening and which to throw away immediately:

The quality of the material… and the voice of the speaker.

I’m not Pavarotti nor Alfredo Caruso, but some voices just irritate me. I just experienced this through the Heroku screencasts; the guy’s voice is not really nice (at all), kind of creepy even, hard to follow, I don’t know how to describe it. It is annoying to follow a 10-minute presentation like this; really, I’m sorry, but that’s how I felt it, even if his service seems really interesting and I might even try it in the future.

Compare now with Ryan Bates of Railscasts: his voice is adapted, serious yet young, with the right pitch and speed. It makes following the explanations easy, moreover taking into account that I’m not a native English speaker. The Railscasts are a perfect example of what I like in podcasts and screencasts: short descriptions (15 min max) of extremely useful features, with practical uses and with some background as well to get the idea. The site (and Ryan) is absolutely brilliant.

As I said, is a purely subjective point of view, but that’s (one) of the criteria I use to decide whether to keep listening to a podcast / screencast or not. The other being the contents, of course; throw in a nice voice spitting nonsense and you won’t have much better luck than the Heroku guy.

The notable exception to this rule must be obviously David Heinemeier Hansson; his first videos showing how to do a weblog in Rails in 15 minutes are just insane; the guy’s voice is really awful, too highly pitched and somehow disturbing. But the stuff he showed was great, and I stuck with that instead :)