RFC: Proposal Dexterity API - two variants

classic Classic list List threaded Threaded
25 messages Options
12
Jens W. klein-2 Jens W. klein-2
Reply | Threaded
Open this post in threaded view
|

RFC: Proposal Dexterity API - two variants

======================
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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Asko Soukka Asko Soukka
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants


> Explicit behaviors proposal: expose behaviors explicitly
> ========================================================

+1

Implicit magical shadowing would cause weird issues sooner or later.

Dexterity does not prevent implementing custom attributes directly in custom baseclass (yet still allow enabling and disabling visible fields with behaviors). E.g. the default dexterity Item and Container implement DublinCore fields in their baseclass, even those fields are not visible by default.

The new default contenttypes already have custom base classes. So, I wonder, why couldn't they implement their default fields similarly DC is implemented with the base types.

-Asko
------------------------------------------------------------------------------
_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Martin Aspeli Martin Aspeli
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Jens W. klein-2
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.
 - If you personally want to reuse among your types, just use subclassing. Simple, effective.
 - 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.
 - 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).

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.

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 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).

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.
 - 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").
 - 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 myriad ways we can acquire values in Zope 3 land. It seems to add a lot of complexity for very marginal benefit.

Martin

On 5 November 2014 15:44, Jens W. Klein <[hidden email]> 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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Dylan Jay Dylan Jay
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Jens W. klein-2
Any api that has attribute assignment ie context.blah = 'value' will not work in restricted python and can't be used in ZPT, python scripts or Plomino plus a few dozen other places where restricted python is used.


~~~~~~~~~~~~~~~~~~~~~~~~~~
Dylan Jay
Chief Technology Officer
PretaGov AU - Open Source CMS SaaS for government
Sydney | London

A: Level 6, 99 York St, Sydney, 2000
P: +61-2-9955-2830
Skype ID: dylan_jay


On 5 Nov 2014, at 4:44 pm, Jens W. Klein <[hidden email]> 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
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/plone-developers


------------------------------------------------------------------------------
_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Steve McMahon Steve McMahon
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Martin Aspeli
I've a challenge for those who have looked at the dexterity interface with plone.app.contenttypes installed:

Try to see if you can describe -- or document -- the difference between fields and behaviors to Dexterity's principle audience. That's people starting content-type development TTW.

I fear we are currently in a situation where this is close to impossible.

The problem with attribute access is a symptom of this. We are bringing in a lot of fields via behavior. We have the potential for namespace collision if those fields are simple attributes, and the problem of API complexity if they aren't.

I think I understand why the current plone.app.contenttypes is doing so much via behaviors. It's a way to solve the problem of having the standard content types be relatively customizable. If the fields were frozen in schema or Python-package-base model files, you wouldn't be able to turn fields on and off.

I'm fearing, though, that it's not the right solution. Consider one of the most common varieties of customization a TTW user might wish to make: changing the title or description of a field like the title or description.

I can think of some possible solutions; I'll be others can come up with some, too. But, first step, do we agree we've got a problem here?

Steve


On Wed, Nov 5, 2014 at 8:57 AM, Martin Aspeli <[hidden email]> 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.
 - If you personally want to reuse among your types, just use subclassing. Simple, effective.
 - 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.
 - 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).

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.

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 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).

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.
 - 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").
 - 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 myriad ways we can acquire values in Zope 3 land. It seems to add a lot of complexity for very marginal benefit.

Martin

On 5 November 2014 15:44, Jens W. Klein <[hidden email]> 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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers



------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Martin Aspeli-3 Martin Aspeli-3
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

My view, not informed by being involved in the p.a.contenttypes work at all, is that we should have a small number of coarse grained behaviours, which are in Python composed of more granular interfaces, and use the marker interface variety to also allow direct attribute manipulation as this is what DC expects.

That makes the interfaces reusable in Python and even allows someone to separately register them as behaviours if they really need that. However I think for the TTW use case simplicity, ease of understanding of concepts and sensible defaults should win.


Sent from Mailbox


On Wed, Nov 5, 2014 at 7:04 PM, Steve McMahon <[hidden email]> wrote:

I've a challenge for those who have looked at the dexterity interface with plone.app.contenttypes installed:

Try to see if you can describe -- or document -- the difference between fields and behaviors to Dexterity's principle audience. That's people starting content-type development TTW.

I fear we are currently in a situation where this is close to impossible.

The problem with attribute access is a symptom of this. We are bringing in a lot of fields via behavior. We have the potential for namespace collision if those fields are simple attributes, and the problem of API complexity if they aren't.

I think I understand why the current plone.app.contenttypes is doing so much via behaviors. It's a way to solve the problem of having the standard content types be relatively customizable. If the fields were frozen in schema or Python-package-base model files, you wouldn't be able to turn fields on and off.

I'm fearing, though, that it's not the right solution. Consider one of the most common varieties of customization a TTW user might wish to make: changing the title or description of a field like the title or description.

I can think of some possible solutions; I'll be others can come up with some, too. But, first step, do we agree we've got a problem here?

Steve


On Wed, Nov 5, 2014 at 8:57 AM, Martin Aspeli <[hidden email]> 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.
 - If you personally want to reuse among your types, just use subclassing. Simple, effective.
 - 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.
 - 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).

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.

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 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).

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.
 - 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").
 - 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 myriad ways we can acquire values in Zope 3 land. It seems to add a lot of complexity for very marginal benefit.

Martin

On 5 November 2014 15:44, Jens W. Klein <[hidden email]> 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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers




------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Robert Niederreiter Robert Niederreiter
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Steve McMahon
I think we need to clarify the context of what we are talking about.

Dexterity has been choosen beeing the replacement for archetypes and the content type story. As such i expect all the features at least in a similar way i had with archetypes. From a programmers point of view.

It feels that the TTW aspect gets focused as the most important one here, and in my opinion, it's not. We still are writing our addons, customer implementations, contents types, views in python eggs, with GS integrations, tests and such.

All the TTW stuff is a nice thing to get started with, for small installations and for prototyping, but when it comes to long term maintainable applications, at least i have not seen a big plone project which gets maintainerd TTW only. Especially when it comes to complex data and security schemes.

And i think one of the most important takling points for plone is the reliability on - even if somewhat strage looking - stable and secure model and code.

As developer working on plone projects since 2004, i see behaviors as a replacement to archetypes.schemaextender with the advantage that each behavior typically comes along with an interface set on the content intstance once this behavior is applied. And here is the big strength - now i'm able to integrate into the application in terms of components, with respective data adapters, views, field permissions, event subscribers, indexing, etc.

And i think this is the context in which this API discussion has been started, and in which the advantages and disadvantages should be discussed.

When it comes to to the explanation between TTW fields and behaviors, we need to see the behaviors as what they are; components adding a more or less complex functionality to content objects, including all the surrounding (as described above), and a field is simply a snippet of data, without much application semantics bound to it.

To answer complaints about restricted python and access to a dedicated data holding attribute as mentioned in a prior post, it's possible to explicitely expose attributes to restricted code. see https://pypi.python.org/pypi/RestrictedPython#examples as starting point

Robert

Am 2014-11-05 um 20:02 schrieb Steve McMahon:
I've a challenge for those who have looked at the dexterity interface with plone.app.contenttypes installed:

Try to see if you can describe -- or document -- the difference between fields and behaviors to Dexterity's principle audience. That's people starting content-type development TTW.

I fear we are currently in a situation where this is close to impossible.

The problem with attribute access is a symptom of this. We are bringing in a lot of fields via behavior. We have the potential for namespace collision if those fields are simple attributes, and the problem of API complexity if they aren't.

I think I understand why the current plone.app.contenttypes is doing so much via behaviors. It's a way to solve the problem of having the standard content types be relatively customizable. If the fields were frozen in schema or Python-package-base model files, you wouldn't be able to turn fields on and off.

I'm fearing, though, that it's not the right solution. Consider one of the most common varieties of customization a TTW user might wish to make: changing the title or description of a field like the title or description.

I can think of some possible solutions; I'll be others can come up with some, too. But, first step, do we agree we've got a problem here?
Steve


On Wed, Nov 5, 2014 at 8:57 AM, Martin Aspeli <[hidden email]> 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.
 - If you personally want to reuse among your types, just use subclassing. Simple, effective.
 - 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.
 - 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).

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.

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 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).

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.
 - 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").
 - 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 myriad ways we can acquire values in Zope 3 land. It seems to add a lot of complexity for very marginal benefit.

Martin

On 5 November 2014 15:44, Jens W. Klein <[hidden email]> 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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers




------------------------------------------------------------------------------


_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Asko Soukka Asko Soukka
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Steve McMahon
Steve McMahon <[hidden email]> kirjoitti 5.11.2014 kello 21.02:

I think I understand why the current plone.app.contenttypes is doing so much via behaviors. It's a way to solve the problem of having the standard content types be relatively customizable. If the fields were frozen in schema or Python-package-base model files, you wouldn't be able to turn fields on and off.

Yet, when it comes to customization, behaviors can only be turned on and off. E.g. their fields cannot be reordered or otherwise customized.

AFAIK, PAC developers tried to do the types with XML schemas at first, but I don't remember why it failed.

-Asko



I'm fearing, though, that it's not the right solution. Consider one of the most common varieties of customization a TTW user might wish to make: changing the title or description of a field like the title or description.

I can think of some possible solutions; I'll be others can come up with some, too. But, first step, do we agree we've got a problem here?

Steve


On Wed, Nov 5, 2014 at 8:57 AM, Martin Aspeli <[hidden email]> 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.
 - If you personally want to reuse among your types, just use subclassing. Simple, effective.
 - 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.
 - 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).

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.

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 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).

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.
 - 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").
 - 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 myriad ways we can acquire values in Zope 3 land. It seems to add a lot of complexity for very marginal benefit.

Martin

On 5 November 2014 15:44, Jens W. Klein <[hidden email]> 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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers


------------------------------------------------------------------------------
_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers

------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
johannes raggam johannes raggam
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Steve McMahon

First time, when I encountered behaviors some years ago, I really
disliked the need to adapt a context to the behavior interface in order
to get or set attributes to it.

However, behaviors give you a lot of power by allowing you to mix-in
different schemata to content types or enrich them with another
behaving.

It was an intentional decision to implement the Dexterity part of
plone.app.event as behaviors instead of content types and schemata. It
was always meant that these event related behaviors would be added to
any other content type.
This concept is so powerful! I still stand behind it, even I see it
gives you a clumsy API.
The change from content type schemata to behaviors in
plone.app.contenttypes followed the same intentions.
bdap.plone.shop is another example of leveraging the power of behaviors
AND archetypes.schemaextenders, by allowing to make any content type a
shop item.

Maybe the behavior-adapter API is not all that bad. You can teach
developers to use and getting an absolute flexible concept in return.
Maybe the content type schemas should be dropped and everything done via
behaviors instead, so that we don't have multiple concurring API
concepts.

Regarding the RFC, I'd favor Option 1 "Explicit behaviors proposal".

Johannes



On Wed, 2014-11-05 at 11:02 -0800, Steve McMahon wrote:

> I've a challenge for those who have looked at the dexterity interface
> with plone.app.contenttypes installed:
>
>
>         Try to see if you can describe -- or document -- the
>         difference between fields and behaviors to Dexterity's
>         principle audience. That's people starting content-type
>         development TTW.
>        
>        
> I fear we are currently in a situation where this is close to
> impossible.
>
>
> The problem with attribute access is a symptom of this. We are
> bringing in a lot of fields via behavior. We have the potential for
> namespace collision if those fields are simple attributes, and the
> problem of API complexity if they aren't.
>
>
> I think I understand why the current plone.app.contenttypes is doing
> so much via behaviors. It's a way to solve the problem of having the
> standard content types be relatively customizable. If the fields were
> frozen in schema or Python-package-base model files, you wouldn't be
> able to turn fields on and off.
>
>
> I'm fearing, though, that it's not the right solution. Consider one of
> the most common varieties of customization a TTW user might wish to
> make: changing the title or description of a field like the title or
> description.
>
>
> I can think of some possible solutions; I'll be others can come up
> with some, too. But, first step, do we agree we've got a problem here?
>
>
> Steve
>
>
>
> On Wed, Nov 5, 2014 at 8:57 AM, Martin Aspeli <optilude
> +[hidden email]> 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.
>          - If you personally want to reuse among your types, just use
>         subclassing. Simple, effective.
>          - 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.
>          - 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).
>        
>        
>         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.
>        
>        
>         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 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).
>        
>        
>         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.
>          - 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").
>          - 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 myriad ways we can acquire values in
>         Zope 3 land. It seems to add a lot of complexity for very
>         marginal benefit.
>        
>        
>         Martin
>        
>         On 5 November 2014 15:44, Jens W. Klein
>         <[hidden email]> 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
>                 [hidden email]
>                 https://lists.sourceforge.net/lists/listinfo/plone-developers
>        
>        
>        
>         ------------------------------------------------------------------------------
>        
>         _______________________________________________
>         Plone-developers mailing list
>         [hidden email]
>         https://lists.sourceforge.net/lists/listinfo/plone-developers
>        
>
>
> ------------------------------------------------------------------------------
> _______________________________________________
> Plone-developers mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/plone-developers
--
programmatic  web development
di(fh) johannes raggam / thet
python plone zope development
plone framework  team  member
mail: [hidden email]
web:  http://programmatic.pro
      http://bluedynamics.com


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers

signature.asc (188 bytes) Download Attachment
Jens W. klein-2 Jens W. klein-2
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Martin Aspeli
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
> <[hidden email]
> <mailto:[hidden email]>> 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
>     [hidden email]
>     <mailto:[hidden email]>
>     https://lists.sourceforge.net/lists/listinfo/plone-developers
>
>
>
>
> ------------------------------------------------------------------------------
>
>
>
> _______________________________________________
> Plone-developers mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/plone-developers
>


--
Klein & Partner KG, member of BlueDynamics Alliance


------------------------------------------------------------------------------
_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Eric BREHAULT Eric BREHAULT
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Robert Niederreiter
I agree TTW development is not the subject here.
The TTW experience must be improved in Plone, and, yes, it is certainly a valid approach to Plone development.

Nevertheless, TTW developers and classical developers haven't the same expectations nor the same programming skills.
And we cannot make a unique content-type API that would fit those two audiences.
The API proposed here will be used by classical developers crteating their own specific add-ons.
Regarding behavior usage, hiding explicit adaptation is probably nice, but hiding completely the behaviors existence would be annoying, as behavior is a concept those developers will have to handle anyhow.

+1 for "Explicit behaviors proposal: expose behaviors explicitly"

Eric

On Wed, Nov 5, 2014 at 9:13 PM, Robert Niederreiter <[hidden email]> wrote:
I think we need to clarify the context of what we are talking about.

Dexterity has been choosen beeing the replacement for archetypes and the content type story. As such i expect all the features at least in a similar way i had with archetypes. From a programmers point of view.

It feels that the TTW aspect gets focused as the most important one here, and in my opinion, it's not. We still are writing our addons, customer implementations, contents types, views in python eggs, with GS integrations, tests and such.

All the TTW stuff is a nice thing to get started with, for small installations and for prototyping, but when it comes to long term maintainable applications, at least i have not seen a big plone project which gets maintainerd TTW only. Especially when it comes to complex data and security schemes.

And i think one of the most important takling points for plone is the reliability on - even if somewhat strage looking - stable and secure model and code.

As developer working on plone projects since 2004, i see behaviors as a replacement to archetypes.schemaextender with the advantage that each behavior typically comes along with an interface set on the content intstance once this behavior is applied. And here is the big strength - now i'm able to integrate into the application in terms of components, with respective data adapters, views, field permissions, event subscribers, indexing, etc.

And i think this is the context in which this API discussion has been started, and in which the advantages and disadvantages should be discussed.

When it comes to to the explanation between TTW fields and behaviors, we need to see the behaviors as what they are; components adding a more or less complex functionality to content objects, including all the surrounding (as described above), and a field is simply a snippet of data, without much application semantics bound to it.

To answer complaints about restricted python and access to a dedicated data holding attribute as mentioned in a prior post, it's possible to explicitely expose attributes to restricted code. see https://pypi.python.org/pypi/RestrictedPython#examples as starting point

Robert

Am 2014-11-05 um 20:02 schrieb Steve McMahon:
I've a challenge for those who have looked at the dexterity interface with plone.app.contenttypes installed:

Try to see if you can describe -- or document -- the difference between fields and behaviors to Dexterity's principle audience. That's people starting content-type development TTW.

I fear we are currently in a situation where this is close to impossible.

The problem with attribute access is a symptom of this. We are bringing in a lot of fields via behavior. We have the potential for namespace collision if those fields are simple attributes, and the problem of API complexity if they aren't.

I think I understand why the current plone.app.contenttypes is doing so much via behaviors. It's a way to solve the problem of having the standard content types be relatively customizable. If the fields were frozen in schema or Python-package-base model files, you wouldn't be able to turn fields on and off.

I'm fearing, though, that it's not the right solution. Consider one of the most common varieties of customization a TTW user might wish to make: changing the title or description of a field like the title or description.

I can think of some possible solutions; I'll be others can come up with some, too. But, first step, do we agree we've got a problem here?
Steve


On Wed, Nov 5, 2014 at 8:57 AM, Martin Aspeli <[hidden email]> 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.
 - If you personally want to reuse among your types, just use subclassing. Simple, effective.
 - 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.
 - 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).

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.

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 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).

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.
 - 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").
 - 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 myriad ways we can acquire values in Zope 3 land. It seems to add a lot of complexity for very marginal benefit.

Martin

On 5 November 2014 15:44, Jens W. Klein <[hidden email]> 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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers




------------------------------------------------------------------------------


_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers



------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Martin Aspeli Martin Aspeli
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Robert Niederreiter
Hi,

On 5 November 2014 20:13, Robert Niederreiter <[hidden email]> wrote:

It feels that the TTW aspect gets focused as the most important one here, and in my opinion, it's not. We still are writing our addons, customer implementations, contents types, views in python eggs, with GS integrations, tests and such.

I didn't say that. What I said was that the original use case for behaviours had evolved from a desire to allow people to build reusable components that could be reused TTW or by less experienced developers. Archetypes had no direct analogy of this. at.schemaextender is obviously the closest thing, but it does work somewhat differently.

I agree that Python development is by far the most important use case.

My overarching hypothesis is that your pain is felt because of the particular way that p.a.contenttypes has chosen to use behaviours and the implications for "good practice". I'd rather fix that than introduce another API for value access, which sounds like the kind of thing we may regret in a few years' time.
 
As developer working on plone projects since 2004, i see behaviors as a replacement to archetypes.schemaextender with the advantage that each behavior typically comes along with an interface set on the content intstance once this behavior is applied. And here is the big strength - now i'm able to integrate into the application in terms of components, with respective data adapters, views, field permissions, event subscribers, indexing, etc.

I kind of agree, but this is a very advanced use case. I think if you are really capable of designing and working in a context where fields can be applied extrinsically to the definition of the type, then having you opt into using adaptation syntax (IMyBehaviour(context)) is really not a very big ask.

If the alternative is a magic dict to access that you access with string keys then I don't think we're gaining anything. Jens' examples in the original mail look very worrying to me:

 - String indexing is typo prone
 - You have to know about the values object
 - The values object isn't a dict, it's something that looks like a dict and behaves kind of like a dict except when it doesn't
 - There's another magic thing called restricted_values which gives you different behaviour

This doesn't feel very Pythonic to me.

I think if you have a use case where this indirection is needed (e.g. you are building some kind of very generic framework) then it'd be easier to build that off a particular base class.

Martin

------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Martin Aspeli Martin Aspeli
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Asko Soukka


On 5 November 2014 20:26, Asko Soukka <[hidden email]> wrote:
Steve McMahon <[hidden email]> kirjoitti 5.11.2014 kello 21.02:

I think I understand why the current plone.app.contenttypes is doing so much via behaviors. It's a way to solve the problem of having the standard content types be relatively customizable. If the fields were frozen in schema or Python-package-base model files, you wouldn't be able to turn fields on and off.

Yet, when it comes to customization, behaviors can only be turned on and off. E.g. their fields cannot be reordered or otherwise customized.


This is true. But the question is, is this a real use case? I'd see a couple of "sensible default"  use cases here:

 - Switch off a group of things, e.g. a tab's worth of fields. That's how the DC behaviours in p.a.dexterity were designed from memory.
 - Switch off everything: my type doesn't need any of the DC stuff
 - I want something unique... switch off the things I don't want and maybe add one or two of them back, or do something more clever in Python

The point is that having lots of declarative customisability (the behaviour-per-field approach) adds a cognitive cost that counters the benefits of having toggleable/re-usable things in the first place. At some point it just becomes easier to do it in code. And we will always have regular composability of interfaces and base classes in Python.

I think behaviours are always going to be an "80%" solution. I hope they'll be a rather good "80%" solution so that people who don't want to write complex code can re-use some complex code ("I want versioning for my type" or "I want audit logging for my type") in a declarative way.

Behaviours are not and were never designed to be a way simply to build reusable fields.
 
AFAIK, PAC developers tried to do the types with XML schemas at first, but I don't remember why it failed.

Not sure I understand this. If there's a problem happy to try to help.

Martin 

------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
David Glick (Plone) David Glick (Plone)
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

On 11/5/14, 2:37 PM, Martin Aspeli wrote:


On 5 November 2014 20:26, Asko Soukka <[hidden email]> wrote:
Steve McMahon <[hidden email]> kirjoitti 5.11.2014 kello 21.02:

I think I understand why the current plone.app.contenttypes is doing so much via behaviors. It's a way to solve the problem of having the standard content types be relatively customizable. If the fields were frozen in schema or Python-package-base model files, you wouldn't be able to turn fields on and off.

Yet, when it comes to customization, behaviors can only be turned on and off. E.g. their fields cannot be reordered or otherwise customized.


This is true. But the question is, is this a real use case? I'd see a couple of "sensible default"  use cases here:

 - Switch off a group of things, e.g. a tab's worth of fields. That's how the DC behaviours in p.a.dexterity were designed from memory.
 - Switch off everything: my type doesn't need any of the DC stuff
 - I want something unique... switch off the things I don't want and maybe add one or two of them back, or do something more clever in Python

The point is that having lots of declarative customisability (the behaviour-per-field approach) adds a cognitive cost that counters the benefits of having toggleable/re-usable things in the first place. At some point it just becomes easier to do it in code. And we will always have regular composability of interfaces and base classes in Python.

I think behaviours are always going to be an "80%" solution. I hope they'll be a rather good "80%" solution so that people who don't want to write complex code can re-use some complex code ("I want versioning for my type" or "I want audit logging for my type") in a declarative way.

Behaviours are not and were never designed to be a way simply to build reusable fields.

Well, we need a better way to do reusable fields then.

This is a real use case: As an integrator, I want to install an add-on which provides some functionality I can enable for my types (for example a geolocation field), but I want to retain control over where it appears on my edit forms, and maybe change the label and help text.

------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Martin Aspeli Martin Aspeli
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by johannes raggam
Hi,

On 5 November 2014 20:56, Johannes Raggam <[hidden email]> wrote:

First time, when I encountered behaviors some years ago, I really
disliked the need to adapt a context to the behavior interface in order
to get or set attributes to it.

You only need to do that if the behaviour is built to make you do that. ;)

Here are two scenarios that are supported (or at least were considered in the design):

 1) The behaviour provides a collection of fields and those are "normal" fields that your type has. It should use the 'provides' registration that means the behaviour interface is directly provided by the content object. Access to the field is via standard attribute access. You can choose to use a IMyBehavior.providedBy(context) check if you wish, or even a null-adapter IMyBehavior(context) adaptation if you so choose, but you have the attribute access semantics you want.

 2) The behaviour provides some kind of complex logic. Versioning. Audit logging. Whatever. It should use a standard registration that means you have to adapt to it. It may include some fields, but it will be responsible for deciding where they're stored. Possibly on the content object, possibly somewhere else. The main consumer of this will be some other code probably written in the same package, e.g. an event handler or a viewlet or a view, and in this special reusable advanced code, you adapt the context to your interface so you can operate on it.

I think the problem here is that we may have accidentally had a use case for scenario 1 that was implemented like scenario 2. That's pretty easy to fix.

I think we may also have just gone a bit overboard on reusability/configurability by having really fine grained behaviours in some places, which adds complexity that probably isn't warranted and would be better in my opinion to turn into fewer more coarse grained behaviours to reduce cognitive load.

Martin

------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Martin Aspeli Martin Aspeli
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by David Glick (Plone)


On 5 November 2014 22:43, David Glick (Plone) <[hidden email]> wrote:

Well, we need a better way to do reusable fields then.

This is a real use case: As an integrator, I want to install an add-on which provides some functionality I can enable for my types (for example a geolocation field), but I want to retain control over where it appears on my edit forms, and maybe change the label and help text.

I agree with this. I'm just not sure you need to make it possible with zero code to say "it has to be exactly between the title and the description" if the cost of that flexibility is a lot of complexity in the UI.

I do agree this part of the TTW story is somewhat under-explored though and probably you could give much more robust hints to the ordering algorithm (you know that beast all too well, David...) with better UI to manage it.

That's not the same as adding another API for accessing field values for all content objects though...

Martin

------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Robert Niederreiter Robert Niederreiter
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Martin Aspeli
Am 2014-11-05 um 23:31 schrieb Martin Aspeli:

My overarching hypothesis is that your pain is felt because of the particular way that p.a.contenttypes has chosen to use behaviours and the implications for "good practice". I'd rather fix that than introduce another API for value access, which sounds like the kind of thing we may regret in a few years' time.
 
After implementing some addons with dexterity my conclusion is that behaviors should be the only way providing and extending functionality on content instances, with usecases in mind, where behaviors might be assignable per content instance in future by default, i.e. having a document and want to add a geolocation to this specific instance. Still fine then with TTW editing and adding of fields on base TTW types.

It's also not really "my pain", i am fine adapting behavior interfaces for gaining it's attributes the right way. The original discussion has been started in a blog post and another thread by andreas jung, and the discussion has evolved further in bristol, so there are real experiences from migration projects and real complaints from the community that "something needs to be done"

If the alternative is a magic dict to access that you access with string keys then I don't think we're gaining anything. Jens' examples in the original mail look very worrying to me:
There have been two proposals in our original mail, first one only hides ZCA a little bit and add some debugging convenience.

 - The values object isn't a dict, it's something that looks like a dict and behaves kind of like a dict except when it doesn't
In the python docs the provided API is not related to dictionaries only. it's just called dict-like here because most people know the syntax immediately, other if it's called what it is -> emulating container types -> https://docs.python.org/2/reference/datamodel.html#emulating-container-types
 - There's another magic thing called restricted_values which gives you different behaviour
I guess this is some kind of mistake here, goal would be to have restricted access by default (checking field permissions and such) and an unrestricted lookup explicitely, like

>>> context.values.unrestricted('title')


I think if you have a use case where this indirection is needed (e.g. you are building some kind of very generic framework) then it'd be easier to build that off a particular base class.
Subclassing pops up more problems than it solves here in my experience.

Robert


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Robert Niederreiter Robert Niederreiter
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by David Glick (Plone)
Am 2014-11-05 um 23:43 schrieb David Glick (Plone):
On 11/5/14, 2:37 PM, Martin Aspeli wrote:

Behaviours are not and were never designed to be a way simply to build reusable fields.

Well, we need a better way to do reusable fields then.
I really think behaviors should become the default way for building reusable fields. What's the option? Introducing a new concept? Subclassing (not reusable TTW then)? Behaviors are already there and working, Providing all the hooks some need to integrate to plone... except an explicit API ;)



------------------------------------------------------------------------------


_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
Asko Soukka Asko Soukka
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Martin Aspeli
Martin Aspeli wrote:

> Here are two scenarios that are supported (or at least were considered
> in the design):
>
>  1) The behaviour provides a collection of fields and those are
> "normal" fields that your type has. It should use the 'provides'
> registration that means the behaviour interface is directly provided
> by the content object. Access to the field is via standard attribute
> access. You can choose to use a IMyBehavior.providedBy(context) check
> if you wish, or even a null-adapter IMyBehavior(context) adaptation if
> you so choose, but you have the attribute access semantics you want.
>
>  2) The behaviour provides some kind of complex logic. Versioning.
> Audit logging. Whatever. It should use a standard registration that
> means you have to adapt to it. It may include some fields, but it will
> be responsible for deciding where they're stored. Possibly on the
> content object, possibly somewhere else. The main consumer of this
> will be some other code probably written in the same package, e.g. an
> event handler or a viewlet or a view, and in this special reusable
> advanced code, you adapt the context to your interface so you can
> operate on it.
>
> I think the problem here is that we may have accidentally had a use
> case for scenario 1 that was implemented like scenario 2. That's
> pretty easy to fix.

+1

AFAIK, only more like 2) is the event behavior with its dates. Johannes
knows its details. It's designed to enforce timezone aware values, but
nobody seem to know, how to do it properly (because values also depend
on "whole day" and "open end" flags).

-Asko

------------------------------------------------------------------------------
_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers
johannes raggam johannes raggam
Reply | Threaded
Open this post in threaded view
|

Re: RFC: Proposal Dexterity API - two variants

In reply to this post by Martin Aspeli
On Wed, 2014-11-05 at 22:46 +0000, Martin Aspeli wrote:

> Hi,
>
> On 5 November 2014 20:56, Johannes Raggam <[hidden email]> wrote:
>        
>         First time, when I encountered behaviors some years ago, I
>         really
>         disliked the need to adapt a context to the behavior interface
>         in order
>         to get or set attributes to it.
>
>
> You only need to do that if the behaviour is built to make you do
> that. ;)
I know... that was only the introduction to my lengthy mail before ;)

>
>
> Here are two scenarios that are supported (or at least were considered
> in the design):
>
>
>  1) The behaviour provides a collection of fields and those are
> "normal" fields that your type has. It should use the 'provides'
> registration that means the behaviour interface is directly provided
> by the content object. Access to the field is via standard attribute
> access. You can choose to use a IMyBehavior.providedBy(context) check
> if you wish, or even a null-adapter IMyBehavior(context) adaptation if
> you so choose, but you have the attribute access semantics you want.
>
>
>  2) The behaviour provides some kind of complex logic. Versioning.
> Audit logging. Whatever. It should use a standard registration that
> means you have to adapt to it. It may include some fields, but it will
> be responsible for deciding where they're stored. Possibly on the
> content object, possibly somewhere else. The main consumer of this
> will be some other code probably written in the same package, e.g. an
> event handler or a viewlet or a view, and in this special reusable
> advanced code, you adapt the context to your interface so you can
> operate on it.
>
>
> I think the problem here is that we may have accidentally had a use
> case for scenario 1 that was implemented like scenario 2. That's
> pretty easy to fix.
>
>
> I think we may also have just gone a bit overboard on
> reusability/configurability by having really fine grained behaviours
> in some places, which adds complexity that probably isn't warranted
> and would be better in my opinion to turn into fewer more coarse
> grained behaviours to reduce cognitive load.
>
>
> Martin
--
programmatic  web development
di(fh) johannes raggam / thet
python plone zope development
plone framework  team  member
mail: [hidden email]
web:  http://programmatic.pro
      http://bluedynamics.com


------------------------------------------------------------------------------

_______________________________________________
Plone-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-developers

signature.asc (188 bytes) Download Attachment
12