summaryrefslogtreecommitdiff
path: root/docs/designdefense.rst
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-05-30 03:24:20 -0400
committerChris McDonough <chrism@plope.com>2011-05-30 03:24:20 -0400
commit8f521b387bcf28c9819c753856e33d1d782d3645 (patch)
treef893fd409ceeefbb6bf489932ec8669e68fa805d /docs/designdefense.rst
parentb90b9e03bb3ce56197c9fe8ed6c414853979805e (diff)
downloadpyramid-8f521b387bcf28c9819c753856e33d1d782d3645.tar.gz
pyramid-8f521b387bcf28c9819c753856e33d1d782d3645.tar.bz2
pyramid-8f521b387bcf28c9819c753856e33d1d782d3645.zip
add design defense entry for simpler traversal
Diffstat (limited to 'docs/designdefense.rst')
-rw-r--r--docs/designdefense.rst61
1 files changed, 61 insertions, 0 deletions
diff --git a/docs/designdefense.rst b/docs/designdefense.rst
index 136b9c5de..0321113fa 100644
--- a/docs/designdefense.rst
+++ b/docs/designdefense.rst
@@ -1011,6 +1011,67 @@ which returns Zope3-security-proxy-wrapped objects for each traversed object
(including the :term:`context` and the :term:`root`). This would have the
effect of creating a more Zope3-like environment without much effort.
+.. _simpler_traversal_model:
+
+Pyramid has Simpler Traversal Machinery than Does Zope
+------------------------------------------------------
+
+Zope's default traverser:
+
+- Allows developers to mutate the traversal name stack while traversing (they
+ can add and remove path elements).
+
+- Attempts to use an adaptation to obtain the "next" element in the path from
+ the currently traversed object, falling back to ``__bobo_traverse__``,
+ ``__getitem__`` and eventually ``__getattr__``.
+
+Zope's default traverser allows developers to mutate the traversal name stack
+during traversal by mutating ``REQUEST['TraversalNameStack']``. Pyramid's
+default traverser (``pyramid.traversal.ResourceTreeTraverser``) does not
+offer a way to do this; it does not maintain a stack as a request attribute
+and, even if it did, it does not pass the request to resource objects while
+it's traversing. While it was handy at times, this feature was abused in
+frameworks built atop Zope (like CMF and Plone), often making it difficult to
+tell exactly what was happening when a traversal didn't match a view. I felt
+it was better to make folks that wanted the feature replace the traverser
+rather than build that particular honey pot in to the default traverser.
+
+Zope uses multiple mechanisms to attempt to obtain the next element in the
+resource tree based on a name. It first tries an adaptation of the current
+resource to ``ITraversable``, and if that fails, it falls back to attempting
+number of magic methods on the resource (``__bobo_traverse__``,
+``__getitem__``, and ``__getattr__``). My experience while both using Zope
+and attempting to reimplement its publisher in ``repoze.zope2`` led me to
+believe the following:
+
+- The *default* traverser should be as simple as possible. Zope's publisher
+ is somewhat difficult to follow and replicate due to the fallbacks it tried
+ when one traversal method failed. It is also slow.
+
+- The *entire traverser* should be replaceable, not just elements of the
+ traversal machinery. Pyramid has a few "big" components rather than a
+ plethora of small ones. If the entire traverser is replaceable, it's an
+ antipattern to make portions of the default traverser replaceable. Doing
+ so is a "knobs on knobs" pattern, which is unfortunately somewhat endemic
+ in Zope. In a "knobs on knobs" pattern, a replaceable subcomponent of a
+ larger component is made configurable using the same configuration
+ mechanism that can be used to replace the larger component. For example,
+ in Zope, you can replace the default traverser by registering an adapter.
+ But you can also (or alternately) control how the default traverser
+ traverses by registering one or more adapters. As a result of being able
+ to either replace the larger component entirely or turn knobs on the
+ default implementation of the larger component, no one understands when (or
+ whether) they should ever override the larger component entrirely. This
+ results, over time, in a "rusting together" of the larger "replaceable"
+ component and the framework itself, because people come to depend on the
+ availability of the default component in order just to turn its knobs. The
+ default component effectively becomes part of the framework, which entirely
+ subverts the goal of making it replaceable. In Pyramid, typically if a
+ component is replaceable, it will itself have no knobs (it will be "solid
+ state"). If you want to influence behavior controlled by that component,
+ you will replace the component instead of turning knobs attached to the
+ component.
+
.. _microframeworks_smaller_hello_world:
Microframeworks Have Smaller Hello World Programs