diff options
Diffstat (limited to 'docs/designdefense.rst')
| -rw-r--r-- | docs/designdefense.rst | 164 |
1 files changed, 78 insertions, 86 deletions
diff --git a/docs/designdefense.rst b/docs/designdefense.rst index afeaba70c..92358ef0c 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -426,31 +426,27 @@ decision to use the ZCA registry: Conclusion ++++++++++ -If you only *develop applications* using :mod:`pyramid`, there's -not much to complain about here. You just should never need to -understand the ZCA registry or even know about its presence: use -documented :mod:`pyramid` APIs instead. However, you may be an -application developer who doesn't read API documentation because it's -unmanly. Instead you read the raw source code, and because you haven't -read the documentation, you don't know what functions, classes, and -methods even *form* the :mod:`pyramid` API. As a result, you've -now written code that uses internals and you've pained yourself into a -conceptual corner as a result of needing to wrestle with some -ZCA-using implementation detail. If this is you, it's extremely hard -to have a lot of sympathy for you. You'll either need to get familiar -with how we're using the ZCA registry or you'll need to use only the -documented APIs; that's why we document them as APIs. - -If you *extend* or *develop* :mod:`pyramid` (create new ZCML -directives, use some of the more obscure "ZCML hooks" as described in -:ref:`hooks_chapter`, or work on the :mod:`pyramid` core code), you -will be faced with needing to understand at least some ZCA concepts. -The ZCA registry API is quirky: we've tried to make it at least -slightly nicer by disusing it for common registrations and lookups -such as unnamed utilities. Some places it's used unabashedly, and -will be forever. We know it's quirky, but it's also useful and -fundamentally understandable if you take the time to do some reading -about it. +If you only *develop applications* using :mod:`pyramid`, there's not much to +complain about here. You just should never need to understand the ZCA +registry or even know about its presence: use documented :mod:`pyramid` APIs +instead. However, you may be an application developer who doesn't read API +documentation because it's unmanly. Instead you read the raw source code, and +because you haven't read the documentation, you don't know what functions, +classes, and methods even *form* the :mod:`pyramid` API. As a result, you've +now written code that uses internals and you've painted yourself into a +conceptual corner as a result of needing to wrestle with some ZCA-using +implementation detail. If this is you, it's extremely hard to have a lot of +sympathy for you. You'll either need to get familiar with how we're using +the ZCA registry or you'll need to use only the documented APIs; that's why +we document them as APIs. + +If you *extend* or *develop* :mod:`pyramid` (create new ZCML directives, use +some of the more obscure "ZCML hooks" as described in :ref:`hooks_chapter`, +or work on the :mod:`pyramid` core code), you will be faced with needing to +understand at least some ZCA concepts. In some places it's used unabashedly, +and will be forever. We know it's quirky, but it's also useful and +fundamentally understandable if you take the time to do some reading about +it. Pyramid Uses Interfaces Too Liberally ------------------------------------- @@ -700,21 +696,20 @@ the code that calls into the database lives somewhere in the ZODB object graph (or at least is a :term:`view` related to a node in the object graph), and traversal is required to reach this code. -I'll argue that URL dispatch is ultimately useful, even if you want to -use traversal as well. You can actually *combine* URL dispatch and -traversal in :mod:`pyramid` (see :ref:`hybrid_chapter`). One -example of such a usage: if you want to emulate something like Zope -2's "Zope Management Interface" UI on top of your object graph (or any -administrative interface), you can register a route like ``<route -name="manage" path="manage/*traverse"/>`` and then associate -"management" views in your code by using the ``route_name`` argument -to a ``view`` configuration, e.g. ``<view view=".some.callable" -context=".some.Model" route_name="manage"/>``. If you wire things up -this way someone then walks up to for example, ``/manage/ob1/ob2``, -they might be presented with a management interface, but walking up to -``/ob1/ob2`` would present them with the default object view. There -are other tricks you can pull in these hybrid configurations if you're -clever (and maybe masochistic) too. +I'll argue that URL dispatch is ultimately useful, even if you want to use +traversal as well. You can actually *combine* URL dispatch and traversal in +:mod:`pyramid` (see :ref:`hybrid_chapter`). One example of such a usage: if +you want to emulate something like Zope 2's "Zope Management Interface" UI on +top of your object graph (or any administrative interface), you can register +a route like ``<route name="manage" pattern="manage/*traverse"/>`` and then +associate "management" views in your code by using the ``route_name`` +argument to a ``view`` configuration, e.g. ``<view view=".some.callable" +context=".some.Model" route_name="manage"/>``. If you wire things up this +way someone then walks up to for example, ``/manage/ob1/ob2``, they might be +presented with a management interface, but walking up to ``/ob1/ob2`` would +present them with the default object view. There are other tricks you can +pull in these hybrid configurations if you're clever (and maybe masochistic) +too. Also, if you are a URL dispatch hater, if you should ever be asked to write an application that must use some legacy relational database @@ -734,13 +729,13 @@ just like you do in :term:`Zope`. Pyramid Views Do Not Accept Arbitrary Keyword Arguments ------------------------------------------------------- -Many web frameworks (Zope, TurboGears, Pylons, Django) allow for their -variant of a :term:`view callable` to accept arbitrary keyword or -positional arguments, which are "filled in" using values present in -the ``request.POST`` or ``request.GET`` dictionaries or by values -present in the "route match dictionary". For example, a Django view -will accept positional arguments which match information in an -associated "urlconf" such as ``r'^polls/(?P<poll_id>\d+)/$``: +Many web frameworks (Zope, TurboGears, Pylons 1.X, Django) allow for their +variant of a :term:`view callable` to accept arbitrary keyword or positional +arguments, which are "filled in" using values present in the ``request.POST`` +or ``request.GET`` dictionaries or by values present in the "route match +dictionary". For example, a Django view will accept positional arguments +which match information in an associated "urlconf" such as +``r'^polls/(?P<poll_id>\d+)/$``: .. code-block:: python :linenos: @@ -766,7 +761,7 @@ callable, the Zope request object's GET and POST namespaces are searched for keys which match the names of the positional and keyword arguments in the request, and the method is called (if possible) with its argument list filled with values mentioned therein. TurboGears -and Pylons operate similarly. +and Pylons 1.X operate similarly. :mod:`pyramid` has neither of these features. :mod:`pyramid` view callables always accept only ``context`` and ``request`` (or just @@ -835,7 +830,7 @@ written. If you don't like this, it doesn't mean you can't use :mod:`pyramid`. Just ignore this feature and avoid configuring an authorization or authentication policy and using ACLs. You can build -"Pylons-style" applications using :mod:`pyramid` that use their own +"Pylons-1.X-style" applications using :mod:`pyramid` that use their own security model via decorators or plain-old-imperative logic in view code. @@ -864,14 +859,13 @@ pyramid/ (except for ``pyramd/tests and pyramid/paster_templates``) 539K -The actual :mod:`pyramid` runtime code is about 10% of the total size -of the tarball omitting docs, helper templates used for package -generation, and test code. Of the approximately 19K lines of Python -code in the package, the code that actually has a chance of executing -during normal operation, excluding tests and paster template Python -files, accounts for approximately 5K lines of Python code. This is -comparable to Pylons, which ships with a little over 2K lines of -Python code, excluding tests. +The actual :mod:`pyramid` runtime code is about 10% of the total size of the +tarball omitting docs, helper templates used for package generation, and test +code. Of the approximately 19K lines of Python code in the package, the code +that actually has a chance of executing during normal operation, excluding +tests and paster template Python files, accounts for approximately 5K lines +of Python code. This is comparable to Pylons 1.X, which ships with a little +over 2K lines of Python code, excluding tests. Pyramid Has Too Many Dependencies --------------------------------- @@ -903,7 +897,7 @@ distribution dependencies. The number of dependencies required by :mod:`pyramid` is many times fewer than Grok (or Zope itself, upon which Grok is based). :mod:`pyramid` has a number of package distribution dependencies comparable to similarly-targeted frameworks -such as Pylons. +such as Pylons 1.X. We try not to reinvent too many wheels (at least the ones that don't need reinventing), and this comes at the cost of some number of @@ -1027,7 +1021,7 @@ possible by the use of the :term:`Zope Component Architecture` and fundamental application behavior to be overriden or extended. - The original developer may optionally choose to anticipate an - application-specific set of plugpoints, which will may be hooked by + application-specific set of plugpoints, which may be hooked by a deployer. If he chooses to use the facilities provided by the ZCA, the original developer does not need to think terribly hard about the mechanics of introducing such a plugpoint. @@ -1150,12 +1144,12 @@ access. I like this, because it means: #) When I use the security proxy machinery, I can have a view that conditionally displays certain HTML elements (like form fields) or - prevents certain attributes from being modified depending on the - depending on the permissions that the accessing user possesses with - respect to a context object. + prevents certain attributes from being modified depending on the the + permissions that the accessing user possesses with respect to a context + object. #) I want to also expose my model via a REST API using Twisted Web. If - If Pyramid performed authorization based on attribute access via Zope3's + Pyramid performed authorization based on attribute access via Zope3's security proies, I could enforce my authorization policy in both :mod:`pyramid` and in the Twisted-based system the same way. @@ -1371,29 +1365,27 @@ yourself in as an application developer: you probably didn't even know you signed up for the job, because the documentation offered by decorator-based microframeworks don't warn you about it. -Python application programmers do not control the module scope -codepath. Anyone who tries to sell you on the idea that they do is -simply mistaken. Test runners that you may want to use to run your -code's tests often perform imports of arbitrary code in strange orders -that manifest bugs like the one demonstrated above. API documentation -generation tools do the same. Some (mutant) people even think it's -safe to use the Python ``reload`` command or delete objects from -``sys.modules``, each of which has hilarious effects when used against -code that has import- time side effects. When Python programmers +Python application programmers do not control the module scope codepath. +Anyone who tries to sell you on the idea that they do is simply mistaken. +Test runners that you may want to use to run your code's tests often perform +imports of arbitrary code in strange orders that manifest bugs like the one +demonstrated above. API documentation generation tools do the same. Some +(mutant) people even think it's safe to use the Python ``reload`` command or +delete objects from ``sys.modules``, each of which has hilarious effects when +used against code that has import-time side effects. When Python programmers assume they can use the module-scope codepath to run arbitrary code -(especially code which populates an external registry), and this -assumption is challenged by reality, the application developer is -often required to undergo a painful, meticulous debugging process to -find the root cause of an inevitably obscure symptom. The solution is -often to rearrange application import ordering or move an import -statement from module-scope into a function body. The rationale for -doing so can never be expressed adequnately in the checkin message -which accompanies the fix or documented succinctly enough for the -benefit of the rest of the development team so that the problem never -happens again. It will happen again next month too, especially if you -are working on a project with other people who haven't yet -internalized the lessons you learned while you stepped through -module-scope code using ``pdb``. +(especially code which populates an external registry), and this assumption +is challenged by reality, the application developer is often required to +undergo a painful, meticulous debugging process to find the root cause of an +inevitably obscure symptom. The solution is often to rearrange application +import ordering or move an import statement from module-scope into a function +body. The rationale for doing so can never be expressed adequnately in the +checkin message which accompanies the fix or documented succinctly enough for +the benefit of the rest of the development team so that the problem never +happens again. It will happen again next month too, especially if you are +working on a project with other people who haven't yet internalized the +lessons you learned while you stepped through module-scope code using +``pdb``. Folks who have a large investment in eager decorator-based configuration that populates an external data structure (such as @@ -1593,7 +1585,7 @@ not logically global*: # this is executed if the request method was GET or the # credentials were invalid -The `Pylons <http://pylonshq.com>`_ web framework uses a similar +The `Pylons 1.X <http://pylonshq.com>`_ web framework uses a similar strategy. It calls these things "Stacked Object Proxies", so, for purposes of this discussion, I'll do so as well. |
