Re: RFC: Proposal Dexterity API - two variants

"Jens W. Klein" <jens-/[email protected]>
Newsgroups gmane.comp.web.zope.plone.devel
Organization Klein & Partner KG
Message-ID <[email protected]>
Hi Martin,

thanks for passing in the original design decisions! Unfortunately 
nobody was aware of them and plone.app.dexterity, plone.app.contenttypes 
and many addons available theses days are were built completly different.

On 2014-11-05 17:57, Martin Aspeli wrote:
> Hi,
>
> When Dexterity was first designed this was the thinking:
>
>   - Anything that belongs to "your" content type is in "your" schema and
> is available as attributes on "your" type.

The availabilty of attributes is the most pythonic way we can have. But 
it introduces so many problems starting with namespace clashes over 
problems to get transparent validation and/or permission checks (i.e. on 
write) in. Not speaking about acquisition side effects.

So I opt in for a solution where the access to the values is directed to 
one property which does the job. We did it this way on all ``node`` 
based packages we wrote (used in Plone, Pyramid and more) and it works 
fine and feels right from a develper point of view.

>   - If you personally want to reuse among your types, just use
> subclassing. Simple, effective.

Thats interesting. I always got the impression that exact this 
subclassing is not best practice while using dexterity.

>   - Behaviours are a way for programmers to build things that
> non-programmers can use TTW. That is, behaviours lets you declaratively
> opt into certain things (the canonical example was "versioning") without
> having to understand how they're implemented.

In fact this is also my impression.

>   - Behaviours can work either adapter-like (data stored elsewhere, e.g.
> in annotations or centrally somewhere) or marker-interface-like (data
> stored on the object).

Behaviors are indeed a great way to do things. Anyway I thing masking 
their lookup would help a lot to make the developer experience much 
better. The first proposal tries exact this.

Anyway they introduce one big problem: How do I know what API to use? It 
needs digging through code distributed over several namespaces. And the 
main schema (as I call the types direct schema) is not that different 
from a behavior with schema only ok, except plone.supermodel allows us 
to define it as XML).

This is also what Steve McMahon addresses in his central question. Its 
out of scope of our draft API proposals. But we should think about a 
solution here. In fact main schemas are not really useful in practice, 
as plone.app.contenttypes shows.

> I think where maybe we've gone a bit wrong is that we seem to have made
> the decision to ship with very fine-grained behaviours that form part of
> the primary API to objects when we think about the Dublin Core metadata.

Well, DCMD is divided into several behaviors (imo fine) and then joined 
for convinience into one (not ok, causes confusion). This is 
plone.app.dexterity btw.

> That is a special case and arguably one that should be handled with only
> one or a small number of behaviours, which should by and large be of the
> market interface variety. So, if you are writing very generic code, then

I'am sure its the very common case - at least if we're talking about 
Plone. And I doubt its practical to debate about dexterity in non-plone 
context.

> you may want to check or do an explicit adaptation (remember that you
> can adapt to an interface that is directly provided by an object without
> an explicit adapter registration).

i dont know why i want to do explicit adapt at all. Usally all ZCA makes 
things much more difficult for newbies. Hiding adapter lookups them 
under a very easy to understand API would help to lower the barriere and 
increase developer happiness.

And the fact that directly provided interfaces are resulting in direct 
adaption does not make it easier.

> Most people don't write very generic code, though, they write specific
> code to their specific usecase. That's probably one of three things:
>   - Some custom fields that are reusable. Use a shared baseclass and
> direct attribute access, behaviours give you little benefit.

I have at least now 3 projects where this is not true: we use behaviors 
for reuse.

>   - Some reusable thing that you want to publish for generic use by
> third parties. Write behaviours and use the adaptation pattern for
> safety. I don't really see this as "yet another field", I see this as
> something with more functionality like rendering additional stuff or
> something event-driven (there's a reason we called it "behaviours" not
> "fields").

Well, your POV differs from mine. My practical experience tells me 
something completly different.

>   - Some reusable thing you want non-technical users in your project to
> reuse TTW. Special case of the one above.
>
> I don't like the idea of having a dict-like API and an attribute-like
> API. That's neither very Pythonic nor very clear. Reminds me of the

I never said we want to have an attribute like api. Attribute like API 
just dont work (reasons above)

> myriad ways we can acquire values in Zope 3 land. It seems to add a lot
> of complexity for very marginal benefit.

Acquisition is a bad thing in zope2. with direct attribute access you 
expose the access to acquisition. In fact to be sure to get the real 
value you have to write context.aq_base.myfieldname to be sure you get 
what you asked for. With the access over some explicit property it 
becomes also acquisition safe.

best regards and thanks

Jens

> Martin
>
> On 5 November 2014 15:44, Jens W. Klein
> <jens-/[email protected]
> <mailto:jens-/[email protected]>> wrote:
>
>     ======================
>     Proposal Dexterity API
>     ======================
>
>     We, Robert Niederreiter and Jens Klein, wrote this proposal as an entry
>     to a discussion for an future Dexterity API (read: Dexterity 3). We
>     followed two different pathes and we are curios which one gets more
>     +1 ;)
>
>     Both of them are implementable and also both are in the perspective of
>     speed almost the same.
>
>
>     Explicit behaviors proposal: expose behaviors explicitly
>     ========================================================
>
>     Basic principles
>     ----------------
>
>     * Duplicate attribute names are allowed by different behaviors
>     * Programmer always addresses effected behavior explicit
>
>
>     Pros
>     ----
>
>     * More reliable and readable code
>     * Explicitness
>     * Easy migration
>
>
>     Cons
>     ----
>
>     * Steeper learning curve (developer needs to learn which behaviors
>     exists)
>     * More code
>
>     Implementation implications
>     ---------------------------
>
>     * think of behavior inheritance and how default behaviors can be
>     overwritten
>
>
>     API usage example
>     -----------------
>
>     Read Attribute::
>       >>> context.behavior('basic').title
>
>     Write Attribute::
>       >>> context.behavior('basic').title = u'My Title'
>
>     Behavior information::
>       >>> context.behaviors
>     {
>           'basic': {
>               'title': 'Basic',
>               'description': 'Foo',
>               'attributes': {
>                   'title': {
>                       'label': 'Title',
>                       'description': 'Title of the object',
>                       '...'
>                   },
>                   ...
>               }
>           }
>           ...
>     }
>
>       >>> repr(context.behaviors)
>     - basic
>           -title
>           -description
>     ...
>
>     Unrestricted access::
>       >>> context.behavior('basic').unrestricted('title')
>
>
>     Shadowed Behaviors Proposal: Simplified value access
>     ====================================================
>
>     Basic principles
>     ----------------
>
>     * implemented as one property directly on
>     plone.dexterity.content.DexterityContent which acts as a
>     zope.interface.mapping.IFullMapping (read: dict-like) to work with all
>     values and methods coming from the main schema, behavior schemas and
>     behavior factories.
>     * Programmer does not need to know about behavior names when
>     accessing data
>     * Set/get of main schema values is same as schemas form behaviors.
>     * Duplicate attribute names are NOT allowed any more and enforced
>     (checked on FTI creation time, i.e. XML import, TTW setting) This is
>     important!
>     * factory methods/properties from behaviors are exposed when a factory
>     is given instaed of direct attribute access.
>
>
>     Pros
>     ----
>
>     * Simple entry for new developers
>     * pythonic
>     * natural dict-like API is first principle
>     * no accicdential override of attributes stored
>     * behavior inheritance (i.e.IDublicCoreMetadata is not a problem at all)
>
>
>     Cons
>     ----
>
>     * duplicate fieldnames in existing code needs migration (not in core)
>     * behaviors are kind of hidden to developers, so misunderstandings may
>     occur (needs good documentation)
>
>
>     Open for discussion
>     -------------------
>
>     * should validation be enforced?
>
>
>     Important
>     ---------
>
>     * lots of caching of schemas and intermeidate results
>
>
>     API usage example
>     -----------------
>
>       >>> context.values['title']
>     'My Document'
>
>       >>> context.values['title'] = 'Jensens Document'
>       >>> context.values['some_factory_property'] = 'Foo'
>       >>> context.values['some_factory_property']
>     'Foo'
>
>       >>> context.values['some_factory_method'](param1, param2='foo')
>     ...
>
>       >>> context.values.keys()
>     ['title', 'description', ....]
>
>       >>> context.update({'title': 'Jensens Updated Document',
>     'description':
>     'A new easy to understand API for dx'}
>       >>> context.values.items()
>     [('title': 'Jensens Updated Document', 'description': 'A new easy ...',
>     ....)]
>
>     other dict-api methods are implemented too (need to finish this, but you
>     can imagine how it looks like, )
>     active access to restricted values which checks the read/write
>     permission!
>
>       >>> context.restricted_values['title']
>     Traceback ...
>     ....
>     Unauthorized(...)
>
>
>     Legacy Proposal
>     ------------------------
>
>     * rename dexterity to devilstick
>     * use wording molecule instead of behavior
>     * the values are atoms
>     * ignore this legacy proposal ;D
>
>     -------------------------------------------------------------------------
>
>     happy commenting
>
>     Jens and Robert
>     --
>     BlueDynamics Alliance
>
>
>     ------------------------------------------------------------------------------
>     _______________________________________________
>     Plone-developers mailing list
>     Plone-developers-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
>     <mailto:Plone-developers-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
>     https://lists.sourceforge.net/lists/listinfo/plone-developers
>
>
>
>
> ------------------------------------------------------------------------------
>
>
>
> _______________________________________________
> Plone-developers mailing list
> Plone-developers-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
> https://lists.sourceforge.net/lists/listinfo/plone-developers
>


-- 
Klein & Partner KG, member of BlueDynamics Alliance


------------------------------------------------------------------------------
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.