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.
|
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 ===
|
==== assertion policy ====
|
||||||
|
|
||||||
==== 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
|
|
||||||
|
|
||||||
One axis of interest is how time-consuming the checks are. Many precondition
|
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
|
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.
|
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
|
## 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.
|
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