Design-heavy languages like Java try and convince us that what we want is an object model that represents every facet of the problem. But what we really want is to remain nimble and adaptable.
A lesson learned from both scripting and functional languages is that the best high level data structure is something lightweight. Perl’s hashes and arrays or Lisp’s lists. Even Python and Ruby’s objects are skinny.
This object or something like it replaces entire object models in seconds:
class Bag: pass
From PyAmazon.
or, with a bit more syntactic sugar:
class Storage: def __init__(self, initial=None): if initial: for k in initial.keys(): setattr(self, k, initial[k]) def __getattr__(self, k): if hasattr(self.__dict__, k) or ( k.startswith('__') and k.endswith('__')): # special keyword return getattr(self.__dict__, k) raise AttributeError, repr(k) def __repr__(self): return ''
From web.py.
Better, you can create objects from your data store quickly and easily with no boilerplate required:
/** * Runs a SQL statement against the specified database and returns * the result. * * @param $sql SQL to run against database. * @param $host Host to attach to. * @param $usr Username for db. * @param $pwd Password for db. * @param $db MySQL database to attach to. * @return true if insert/update succeeded, false on error, * array of associative arrays (rows) if select succeeded * (may have 0 entries if no rows to fetch). */ function db($sql, $db="bbdb", $host="localhost", $usr="root", $pwd="rootpass") { mysql_connect($host, $usr, $pwd); @mysql_select_db($db) or die("Unable to select database: " . $db); $res = parse_result(mysql_query($sql)); mysql_close(); return $res; } /** * Parses the result of a SQL query and returns an appropriate var. * * @res Result to parse. * @return true if insert/update succeeded, false on error, * array of associative arrays (rows) if select succeeded * (may have 0 entries if no rows to fetch). */ function parse_result($res) { if (is_bool($res)) { return $res; } $arr = array(); $i = 0; while ($row = mysql_fetch_array($res)) { $arr[$i++] = $row; } return $arr; } # Usage: # # $myobj = db("SELECT name, company FROM employee WHERE id = 12"); # print $myobj['name'] . " works for " . $myobj['company'];
You could argue that this couples the database and the program’s representation of data too closely. But for the spring in your step you get when coding, I think it’s a worthwhile trade off. This is approximately how Rails does things, but with a layer in between for exceptions where you can override the database.