Which means, it is the most efficient way to maintain code. All kinds of documentation is right within the code. There are tools to get the documentation into different formats. Javadoc can do the same thing? Sorry folks, no. Look at how Python is an engineer friendly language, by actually supporting a __doc__ attribute for every module, class and function. This is much better than fooling around with slash-star-star ... star-slash.There's more in the post, going into the joys of the new (Python 2.2 or later)
A little too simplistic definition (07 Jul 2003)
help(obj)
function built into the Python interpreter which basically generates something like a man page based on the data in the object passed in (which may be an object instance, a class, a module, etc) (dir, help, and pprint).
Ah, pprint. This is a terrific Python module that "pretty prints" Python data structures. It comes in very handy when looking at large tuples (especially nested tuples), lists, and dictionaries. A module function that I've been using lately is pformat(object)
along with Zope's zLOG logging module to log what data is being sent to LDAP as part of the project I'm currently working on:
modlist = mod_entry_generator(old, rec, nodelete, mod_only) if __debug__: ## Avoided when Python is run with -O option zLOG.LOG("LDAP.Gateway", zLOG.BLATHER, "Modifying DN: %s" % dn, "%s\n" % pprint.pformat(modlist)) c.modify_s(dn, modlist)The modlist is a tuple of tuples in the form of
(OP, ATTR, VALUE)
. Since the modlist can grow quite long, or the VALUE items themselves can be quite long lists (for multi-value attributes), I get a (relatively) readable log entry:
((2, 'mail', ['bjones@example.com']), (2, 'mailAlternateAddress', ['barnabyjones@example.com', 'bjones@example.net', 'barnabyjones@example.net']))
There are a couple of small notes about the above code. First is the use of the if __debug__:
statement. When Python is run with the -O
or -OO
flags, __debug__ is set to false. It's advisable that when deploying Python programs that -O is set. This also removes assert statements from the compiled bytecodes. -OO does the regular optimizations and removes docstrings from the bytecodes as well.
Second is the use of zLOG.BLATHER. BLATHER is a -100 value in the zLOG level system. By default, anything less than zLOG.INFO (0) is not written to the logs. Using zLOG.BLATHER, zLOG.DEBUG (-200), and zLOG.TRACE (-300) are advisable ways of monitoring Zope operations and data during development time that can be disabled at deployment time. The new logger system in Python 2.3 has a similar but simpler set of levels. All of these can be used to your advantage as a developer to track data not only at development time, but after deployment. If something funny is happening, ratchet down the log level to show all of your trace/debug/etc messages. It's better than peppering code with print
statements whose behavior in a server situation is difficult to predict.
An interesting weblog post that came across my screen this morning is Is it High Time to Get Rid of Classes?. Personally - I don't think it is. At least, not necessarily. But it is high time to go away from deep, wide, and messy class hierarchies into shallow ones, with much of the generally inherited behavior replaced by collaborating objects.
I've harped on this before, especially when comparing the ZWiki code bases from Zope 2 to Zope 3. That post compares the single-class-with-heavy-hierarchy design of ZWiki for Zope 2 (a design pattern that most of Zope 2 (at least older Zope 2 code) is also guilty of) with the collaborating object design of ZWiki for Zope 3 (the component model based Zope).
I've been applying such patterns to my Zope 2 projects, the most recent being an LDAP application. The results have been generally successful. I have an application that can be generally built out of descriptions. There's the describing of web form/validation policies, which builds a strong user interface for us without me having to deal with writing HTML forms myself. And there's describing how to map LDAP data into simple Python structures and then sending those back to LDAP so that the higher-up application components never have to think about generating an LDAP mod list.
In these situations, it's still a fair amount of work getting a lot of the core components written and working. But it's a design decision to allow new attributes to be addable later. This design allows adding new ones in by basically updating the description components. Unless there's any major new business logic involved with the new attributes, that's all that is needed. The User Interface gets rebuilt and the LDAP communication code becomes aware of a new attribute it needs to watch out for on an object class.
The application is not absent of an inheritance hierarchy, but inside of the application the hierarchy is fairly shallow, usually two deep (at the most). The common abstract base classes used inside the application plug themselves into the Zope 2 hierarchy while ensuring that their subclasses have to worry little about said hierarchy. As such, I'm getting a nice set of reusable patterns and my own little framework going here to help build new applications fairly rapidly with a lot of strengths that weren't there previously (ie - weak (unvalidated) forms, etc).