STATUS: current as of 9/13/2005
Coding Standards
These are just some guidelines I've been trying to
follow for this codebase since it started several years
ago. - Michal
Languages
We use python almost exclusively. There are many reasons for
this, but the main ones are the short learning curve,
restricted execution support, and general clarity of python
code.
General Style
the basics
(unless there's a real good reason not to - eg,
modifying or extending someone else's code)
- use cvs
- create test cases, and make sure everything passes before
you check code in to CVS [see testing, below]
- one statement per line
- comment heavily. In python, use """docstrings""" docstrings look like this:
Note: docstrings look like this:
def good():
"""
this is a nice docstring
"""
def bad():
"""this is ugly!"""
- better yet, write readable code!
- indent 4 spaces. no tabs.
- put 2 blank linkes between method / function defs
- If non-python code uses curly braces, put the curlies on their own lines, or put the top curlie on the same line as the if/loop/whatever statment.
- In general, optimize code for readability over
performance. If performance is crucial, and must be attained
at the cost of clarity, comment heavily - even to the extent
of several paragraphs per line of code, if necessary.
capitalization / punctuation
- ClassName
- instanceName / variableName
- CONSTANT / GLOBAL
- instance.methodName()
- instance.propertyName
- _protectedMember
- __privateMember (python mangles this with classname)
- SELECT * FROM table WHERE x=1 (but: don't use SQL, use the storage module)
avoid:
avoid names_like_this (except for get_, set_, test_, etc)
(2005: i've kind of drifted on this one.)
variable naming conventions
- dbc - database connection
- cur - database cursor
- clerk -
arlo.Clerk instance
- sql - string containing a sql statement. Always use this
if you're building a sql statement. eg, blah(sql) rather
than blah("select" + fields + " from " + table). This makes
debugging easier, especially on the web. ''(but again,
dont use SQL!!!)
Generic variables. (Only if there's not a more obvious/specific variable name):
- i - generic index in a range loop. eg, for i in range(10)
- j - same as above, but for nested loops
- k,v - key, value
- **kw - keyword argument catch-all. eg: def f(x, y=2, **kw) ...
- item - generic index in a list loop. ("for item in whatever:")
databases
- Tables that contain application data should have a numeric, primary key called ID.
- ID should be auto_incremented by the database software
- For 1:1 IS-A relationships, the subclass's table should
have the same ID as the parent class. (eg,
class.ID=subclass.ID) (2005: not sure on this... IS-A is
very rare anyway)
- Reference tables should have an ID field like the above,
except for tables mapping alphanumeric codes to
values. These tables should use "CD" for the code
field. (eg, "SELECT ID FROM fnorb" but "SELECT state FROM
ref_states WHERE CD='TX'")
- When using foriegn keys, use the tableID/tableCD
style. If a table has more than one reference to another
table, prefix it with a descriptive name and an underscore,
eg: manager_employeeID, assistant_employeeID.
- table names should be in the form: prefix_noun for
normal tables, or prefix_noun_noun for junction
tables. Prefix should be a 2 to 4 character string grouping
the tables (eg: "ref" or "iso" for reference tables, "lnk"
for linkwatcher, "rnt" for rantelope, etc)
Testing
We're big on unit testing. Every class should have at least
one test case. Probably quite a few. When writing programs,
code the unit test first.
We use an open source python testing tool called
PyUnit.
PyUnit is now part of the standard python distribution,
so if you have ptyhon you already have it. PyUnit allows
you to build test cases and compile them into test suites.
We have some standards:
(2005: most of the older code doesn't reflect these standards yet
- for every package, have a subdirectory called test
- ./test contains a variety of *Test.py files
- run
snake.py test to run the tests... (sdunit for older modules))
- also use
test_xxxx for all test names so each test file works with the default unittest configuration
include this code at the bottom of each test file
so it can be run directly without need for snake.py
:
if __name__=="__main__":
unittest.main()
IMPORTANT: TESTS SHOULD NOT CONNECT TO A DATABASE!
That's what arlo.MockClerk is there for.
It is also important to stick to this standard for the
purposes of a nightly distribution-bundling mechanism (STILL
not implemented) that will make the latest CVS code
available in a developer's tarball.
doctests
Doctests also run through snake.py and live in the ./spec
directory... These are XHTML files with embedded
doctest
transcripts.