move "assertion policy" section to a more relevant place

[Imported from Trac: page CodingStandards, version 17]
davidsarah 2011-09-26 22:44:01 +00:00
parent 83ef120c62
commit ab1a5dd059

@ -96,45 +96,9 @@ def _assert_invariants(self):
Now you can put `assert self._assert_invariants()` everywhere in your class where the class ought to be in an internally consistent state. For example, at the beginning of every externally-callable method. This technique can be very valuable in developing a complex class -- it catches bugs early, it isolates bugs into specific code paths, and it clarifies the internal structure of the class so that other developers can hack on it without subtle misunderstandings.
* we actually appear to only have one instance of this pattern in Tahoe at time of writing, in `allmydata.util.dictutil`. It has the disadvantage of cluttering up the logic with calls to `_assert_invariants`, and should probably be used sparingly. -- DavidSarah
* we actually appear to only have one instance of this pattern in Tahoe at time of writing, in `allmydata.util.dictutil`. It has the disadvantage of cluttering up the logic with calls to `_assert_invariants`, and should probably be used sparingly. -- David-Sarah
=== configuration ===
==== minimizing configuration ====
* Do not implement configuration files for modules or libraries -- code that is going to be used by other code. Only applications -- code that is going to be used by humans -- have configuration files. Modules and libraries get "configured" by the code that calls them, for example by passing arguments to their constructors.
* If there are constant values which end-users do not need to modify, then do not make them configurable, but put them in all-caps variables at the beginning of the Python file in which they are used.
* Design algorithms so that they have as few "voodoo constants" and "tweakable parameters" as possible.
==== how to implement configuration ====
Whether in application code or in library code, never pass configuration values via a configuration object. Instead use Python parameters. For example -- here's another real-life example -- do not write
```
class BlockStore:
def __init__(self, confdict={}, recoverdb=True, name='*unnamed*'):
if confdict.has_key('MAX_MEGABYTES'):
self.maxspace = (2**20) * int(confdict.get('MAX_MEGABYTES'))
else:
self.maxspace = None
self.basepath = os.path.abspath(confdict.get("PATH", ""))
self.maintainertype = confdict.get("MAINTAINER", "rnd").lower()
self.backendtype = confdict.get("BACKEND", "flat").lower()
```
, but instead write
```
class BlockStore:
def __init__(self, maxspace=None, path="", maintainertype="rnd", backendtype="flat", recoverdb=True, name='*unnamed*'):
self.basepath = os.path.abspath(path)
self.maintainertype = maintainertype
self.backendtype = backendtype
```
.
#### assertion policy
==== assertion policy ====
One axis of interest is how time-consuming the checks are. Many precondition
checks can cause typical runtime to explode to O(n^2^) or O(n^3^), for example
@ -184,6 +148,42 @@ callers.
altogether) before committing.
### configuration
#### minimizing configuration
* Do not implement configuration files for modules or libraries -- code that is going to be used by other code. Only applications -- code that is going to be used by humans -- have configuration files. Modules and libraries get "configured" by the code that calls them, for example by passing arguments to their constructors.
* If there are constant values which end-users do not need to modify, then do not make them configurable, but put them in all-caps variables at the beginning of the Python file in which they are used.
* Design algorithms so that they have as few "voodoo constants" and "tweakable parameters" as possible.
#### how to implement configuration
Whether in application code or in library code, never pass configuration values via a configuration object. Instead use Python parameters. For example -- here's another real-life example -- do not write
```
class BlockStore:
def __init__(self, confdict={}, recoverdb=True, name='*unnamed*'):
if confdict.has_key('MAX_MEGABYTES'):
self.maxspace = (2**20) * int(confdict.get('MAX_MEGABYTES'))
else:
self.maxspace = None
self.basepath = os.path.abspath(confdict.get("PATH", ""))
self.maintainertype = confdict.get("MAINTAINER", "rnd").lower()
self.backendtype = confdict.get("BACKEND", "flat").lower()
```
, but instead write
```
class BlockStore:
def __init__(self, maxspace=None, path="", maintainertype="rnd", backendtype="flat", recoverdb=True, name='*unnamed*'):
self.basepath = os.path.abspath(path)
self.maintainertype = maintainertype
self.backendtype = backendtype
```
.
## official Python standards
These are listed in decreasing order of priority, so if a point in one of the latter guidelines contradicts a point in one of the earlier ones, then go with the earlier. The Tahoe-LAFS-specific guidelines above override all else, of course.