|
55 | 55 | pool_b = mgmt.tm.ltm.pools.pool.load(name='mypool', partition='Common') |
56 | 56 | pool_b.delete() |
57 | 57 |
|
| 58 | +Design Patterns |
| 59 | +~~~~~~~~~~~~~~~ |
| 60 | + |
| 61 | +I intend the SDK to be easy to use and easy to hack. These overarching goals |
| 62 | +have a strong influence on my thinking when I am reviewing contributions, this |
| 63 | +means it is in their own interest that I make them as explicit as possible! |
| 64 | + |
| 65 | +The original interface specification was given to me by Shawn Wormke, who I |
| 66 | +believe was influenced by the Jira and Django projects. At the time I was |
| 67 | +reading Brett Slatkin's 'Effective Python', and I tried to follow its advice |
| 68 | +where possible. |
| 69 | + |
| 70 | +List of Patterns For Contributing Developers |
| 71 | +-------------------------------------------- |
| 72 | + |
| 73 | +#. Hack this list to make it more correct/complete |
| 74 | + For list additions assign @zancas as the PR reviewer. |
| 75 | +#. The call operator ``()`` means: "Try to communicate with the device." |
| 76 | + This is a strong contract we offer the consumer of the SDK. If an SDK |
| 77 | + function is invoked with the call operator ``()`` the program is initiating |
| 78 | + a communication with the device. That communication may fail before |
| 79 | + reaching the wire, but it has nonetheless been initiated. Conversely, if |
| 80 | + an SDK user evaluates an SDK expression that *DOES NOT* invoke the ``()`` |
| 81 | + call operator, then the SDK does *NOT* initiate a communication with the |
| 82 | + device. Any extension to the SDK that is not consistent with this contract |
| 83 | + is unlikely to be incorporated into the supported repository. |
| 84 | +#. The SDK is stupid |
| 85 | + The SDK doesn't decide things for the consumer, it's |
| 86 | + simply an interface so that Python programs can manipulate device resources |
| 87 | + without implementing custom URI/HTTP/network logic. Implications: |
| 88 | + |
| 89 | + #. NO DEFAULTS |
| 90 | + The consumers of this library are themselves Python |
| 91 | + programs. The Application programmer must say what they mean in their |
| 92 | + SDK-using program. It violates a critical separation of concerns to add |
| 93 | + default values to the SDK. Don't do it! (Unless you have a good |
| 94 | + reason.) |
| 95 | + #. Failures generate exceptions |
| 96 | + If the SDK enters a surprising or |
| 97 | + unexpected state it raises an exception. That's it. It's not generally |
| 98 | + up to the SDK to implement decision logic that handles edge-cases.. |
| 99 | + EXCEPT where the SDK is smoothing known issues in the device REST |
| 100 | + server. (See below.) |
| 101 | + #. The SDK never interprets responses |
| 102 | + It just records whatever response |
| 103 | + the device returns as attributes of the relevant object. (Except where |
| 104 | + handling significant inconsistencies in the device interface.) |
| 105 | + |
| 106 | +#. public-nonpublic pairs |
| 107 | + e.g. 'create' and '_create' XXX add content here. |
| 108 | +#. Handle known issues in the device REST server. |
| 109 | + The SDK intends to provide |
| 110 | + a rational interface to consumers that does the right thing. This means |
| 111 | + that one case where it does NOT simply do the stupid thing is when it |
| 112 | + handles a known idiosyncrasy in the device REST server. For example, some? |
| 113 | + resources ignore 'disable' and 'enable' configuration options when they are |
| 114 | + set to 'False'. Rather than force a consumer to learn about this quirk in |
| 115 | + the server, the SDK guesses that '"disable": False' means '"enable": True' |
| 116 | + , and submits that value on the consumers behalf. |
| 117 | +#. Implement-Reimplement-Abstract |
| 118 | + Solve the problem concretely and simply, if |
| 119 | + the same problem arises again, solve it concretely, then take the two |
| 120 | + concrete solutions and use them as your specification to generate an |
| 121 | + abstraction. In the SDK this usually goes something like this: |
| 122 | + |
| 123 | + #. Add logic to a concrete subclass |
| 124 | + #. Add similar logic to another concrete subclass |
| 125 | + #. Create a new method in a mixin or Abstract 'resource.py' base class and |
| 126 | + have both concrete subclasses inherit and use that method. |
| 127 | + |
58 | 128 |
|
59 | 129 | Submodules |
60 | 130 | ~~~~~~~~~~ |
|
0 commit comments