move "assertion policy" section to a more relevant place
[Imported from Trac: page CodingStandards, version 17]
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.
|
||||
|
|
Loading…
Reference in a new issue