Practical tips for using component architecture(s). Provides idea, opinions, idioms, tricks for using Zope Component Architecture (ZCA), and some notes about application of component-based design and development outside the Zope and Plone context (e.g. Python, generally; JavaScript).
A healthy diet for your Java application Devoxx France.pdf
A pinch of indirection, and don't cut yourself chopping onions...
1. A Pinch of Indirection
And don’t cut yourself chopping onions…
... practical tips for using component architecture(s).
Sean Upton
University of Utah Department of Pediatrics / UPIQ.org
#ploneconf2016 | @sdupton
Photo credit: https://www.flickr.com/photos/ampersandyslexia (CC:by-sa)
3. The topic…
• Let’s talk about components
• Idioms and helpful ideas
• Cooking analogies
• Round and round we go: how many #ploneconf ZCA
talks have there been over the years? Why this, why
now?
• I have opinions.
– There might even be JavaScript involved.
– Run while you still can!
#ploneconf2016 | @sdupton
Photo credit: https://en.wikipedia.org/wiki/Penrose_stairs
5. Components are our craft!
• Our “old hat” dates 1.5 decades. It is
weathered, sturdy -- not rotting in the fridge.
• Anyway, we are in Boston, home to public
television show “This Old House”…
– And some of the best American food media have
roots here too.
– Plan for kitchen metaphors "peppered" throughout
the discussion...
• Components are relevant part of our craft.
#ploneconf2016 | @sdupton
6. Goals
• Talk about components;
– ...in the kitchen of Python;
– ...in the fine dining experience of Plone;
– ...in "foreign cuisine" (e.g. JavaScript).
• Explore idioms and ideas
• Motives: why does this approach matter?
• Hacks, workarounds, surviving a bit of
pdb.set_trace()
#ploneconf2016 | @sdupton
7. No fear!
• Complexity is okay, if essential.
• Components solve problems.
• I am probably more contrarian than necessary about
simplified "public" APIs (though I use them).
#ploneconf2016 | @sdupton
"If you're convinced that
cooking is drudgery, you're
never going to be good at it,
and you might as well warm
up something frozen."
-- James Beard
Photo: James Beard Foundation (used here under fair use)
8. Disclaimers
• I am not sure if this talk is about software
architecture, development practice, or
cooking.
• All truths are contingent on your own practical
realities.
• I hope to impart three things:
– Why and how I think ZCA matters to all kinds of
developers on this platform.
– A few scattered ideas on making use easier.
– Applications outside the box (e.g. JavaScript).
#ploneconf2016 | @sdupton
9. A brief history…
• "Zope 3"
– Motivations spurred from
anxiety over mixin mazes
• Trying to solve the Z-shaped
learning curve?
• We still have these mazes today
(e.g. read Zope 2 OFS.* source).
– Community absorbed the complexity
that works, ignored what didn’t?
#ploneconf2016 | @sdupton
• IIRC, my earliest recollection is 2002 BOF at
OSCON with Jim Fulton
Photo credit: https://commons.wikimedia.org/wiki/File:Inside_a_corn_maze_near_Christchurch,_New_Zealand.JPG
(public domain)
10. Now ZCA + ZTK
• From bigger stack to
smaller parts
– Mirepoix, not the
whole soup pot.
– Buffet, not table
d'hôte / prix fixe
– Eat what you want.
• e.g. Twisted uses only
zope.interface
#ploneconf2016 | @sdupton
Photo credits: via WikiMedia Commons
https://commons.wikimedia.org/wiki/File:Onion_on_White.JPG (CC-by-sa)
https://commons.wikimedia.org/wiki/File:C%C3%A9leri.jpg (CC-by-sa)
https://commons.wikimedia.org/wiki/File:Baby_Carrots_2.jpg (CC-by-2.0)
https://upload.wikimedia.org/wikipedia/commons/4/44/Mirepoix_on_cutting_board.jpg
(CC:by-sa)
11. The “holy trinity” of components
Adapters
ü Single context
ü Views and multiple context
ü Subscribers (event notification)
Resources
ü Content
ü Utilities
ü Request/response
Schema
…because resources are nouns, why think in verbs?
#ploneconf2016 | @sdupton
🌶
12. Categorizing objects
• There are two broad categories of objects
– Those you look up
• By path (content traversal)
• By component registry
• By both (views)
– Those you don't
• But many of these are in the service of some kind of lookup:
– Request objects (object publishing)
• Site-global state
– But plone.app.registry makes even this less likely.
• We have indirection everywhere; that’s okay.
#ploneconf2016 | @sdupton
13. Indirection
• Scary departure from imperative
programming?
• You still will eventually end up in the debugger.
• We get a lot of flexibility, and very consistent
idioms doing this.
• Components are the mirepoix of good
software, registries are our larder.
• Using adapters does not require a registry, but
it does help keep the kitchen tidy.
#ploneconf2016 | @sdupton
15. Recipe-driven development
1. Write interfaces first;
2. then tests, often doctests;
3. write your implementation(s);
4. refine and adjust.
5. Break the build (hey, it happens sometimes!)
#ploneconf2016 | @sdupton
16. “Design by contract”
• Who on Earth thinks this is a trademark-
worthy phrase?
• Interfaces are contracts.
• We can use multiple implementations to fulfill
contracts.
• This is a good thing
– Form widgets
– Separation of concerns
– Test to the interface, not to the implementation.
#ploneconf2016 | @sdupton
17. Component Corollary #1: Language Idioms
• Make components that look like native Python
data structures!
– Mappings
– Sequences
– Sets
• If you do this, chances are you will represent
things as nouns, not verbs.
• Resource-centric development
#ploneconf2016 | @sdupton
18. Resource-centric Development
• Driven by state, not by action
• Placeful, often.
• M in MVC matters more than V, C.
• Our community and our platform has unique
talents:
– Traversal, Traversal, Traversal!
– Persistent objects: objects are first class, they are the
things we want, not mere proxies.
• Components should be more noun than verb,
suiting both platform and language idioms.
#ploneconf2016 | @sdupton
19. Now, I’m just being contrary…
#ploneconf2016 | @sdupton
21. APIs
Procedural
• Benefit: simplify to single
resource: the site.
– But now, the site is mega-
controller.
• Costs:
– Does not always represent what
we are working with.
– Leaky abstractions (e.g.
IPropertiedUser).
– Lost opportunity at simplified
resource/noun/state idioms.
State-driven
• Benefits:
– Components obey idioms
– Components look like state they
directly represent.
• Cost: you must traverse to the
resource you want to work with.
– Is that such a bad thing?
– Sometimes this is traversal to a
folder, instead of using the site as
a controller. More OO.
– Sometimes component lookup.
#ploneconf2016 | @sdupton
22. …at it’s most hyperbolic:
• Are procedural APIs the "frozen microwave
meal" of software design?
– They have utility;
– Some can be quite good;
– Not always as satisfying or complete as the heart
of component-driven software.
• Placeful interfaces (e.g. traversal) made clean
URLs before the cool kids in the other
frameworks thought about routes, mappings,
and slugs.
#ploneconf2016 | @sdupton
23. These approaches are not mutually exclusive.
• I can and do use parts of plone.api I like or
that save me time.
• I can use components that have state, place --
and don’t act procedurally.
• I can mix these.
• I’m okay with that.
• Use procedural APIs when they save time or
help learning curve – however, imperative,
action-driven code is not always appropriate.
#ploneconf2016 | @sdupton
24. My point
• Components, ZCA are not just for ninjas.
• Keep your kitchen appliances, but know how to
handle a knife without cutting yourself!
• You should not be afraid to get a knick or two. Even
pro chefs have scars. Scars teach.
• Sometimes it’s okay to buy pre-cut Mirepoix from
Whole Foods. I won’t tell, or judge.
• I even bought a frozen Chicken Tikka meal from Trader
Joes last week.
• I do make my own stock, but don’t grind my own
sausage. Make choices you are comfortable with.
#ploneconf2016 | @sdupton
26. zope.interface
Components are “objects connected by interfaces”
• Fundamental to all of this.
• Should infuse how you think and write code.
• Interface is a contract for behavior and state.
#ploneconf2016 | @sdupton
“What's important about components is that
you can put them together. Interfaces are the
mechanism for connecting things. “
-- Jim Fulton in 2004 [1]
[1]:http://ftp.ntua.gr/mirror/python/pycon/dc2004/papers/3/PyCon2004ZopeRoadmap.pdf
27. Separation of concerns
• Content type implementations should not do
much. Separate concerns, and…
• ...write adapters that do heavy lifting (actions)
and transformation.
• Resources work much better with pluggable
components, whether widgets, behaviors, etc.
• Make global functionality site-independent.
• OO by composition, not inheritance.
#ploneconf2016 | @sdupton
28. Schema
• Let’s suppose we have
a recipe system.
• Where each ingredient
is stored with
structured data, in a
grid.
• The recipe is just
about state, as is its
ingredients.
– Describe state (schema)
– Store state (content)
#ploneconf2016 | @sdupton
30. Adapters
• Fetch density (utility, or adapter of site)
• Give me metric
• Give me fractions! Or decimals!
• Give me volume to weight! Or vice-versa.
• Each with specific concern, purposeful, pluggable.
#ploneconf2016 | @sdupton
31. Adapters usually registered
• Adapter declares it implements an interface.
• Python or ZCML declares what adapter
adapts.
• ZCML registers adapter in (usually global)
component registry.
• Lookup is by calling interface:
adapter = IIngredientFormatter(my_ingredient)
title = adapter()
#ploneconf2016 | @sdupton
32. When registrations attack
• Pdb needs a bit of help from you before you dive into
debugging adapter, widget, and event subscriber
registration problems.
– Move _zope_interface_coptimizations.so out of your
zope.interface distribution;
– Restart, coffee, debug;
– Fix it, coffee, really fix it;
– Move the optimizations back into place.
• Specificity helps, sometimes you need to resort to
interface subclassing to make your registrations more
specific.
#ploneconf2016 | @sdupton
33. Browser Views
• Other frameworks see views as endpoints to
URLs.
• We see views as all about context.
• Multi-adapter: a view is a component that
takes a resource (e.g. content) and a request,
and makes a response.
– Placeful
– Graceful
– All about the content!
#ploneconf2016 | @sdupton
34. Global utilities
• Useful for site-agnostic things like:
– Vocabulary lookups
– Integration with other services (e.g. message or job
queues)
– Quick static transformation of content that needs no
configuration.
– Object serialization or cryptographic signing
– Custom field types for plone.schemaeditor
#ploneconf2016 | @sdupton
35. Vocabularies
• When we write schema for ”Choice” type
fields, we need choices.
• Sometimes this is static (in your Python or
your supermodel XML for a TTW type).
• Sometimes, you want a dynamic source.
– Stock global: e.g. timezone
– Site or context-local: e.g. show only items in navroot.
• Used for enumeration and/or validation.
– Sometimes, just one or the other.
#ploneconf2016 | @sdupton
36. Site-global functionality
• Four approaches
– Persistent component (utility)
– Adapter-of-site
– plone.api functions, where applicable.
– CMF tools (deprecated)
• If you need to store state in the site, you likely
need to choose between the first two.
#ploneconf2016 | @sdupton
37. Persistent utilities
• Can store state in ZODB: good.
• Uninstalling can be a hard problem: bad.
• Cache data in _v_ attrs across requests: good.
• No need for proxies – data, methods in one
place: good.
• Requires use of
zope.component.hooks.setSite.
• Might be responsible for the 2008 global
recession? ;-)
#ploneconf2016 | @sdupton
38. Adapter of site
• Needs to be cheap to construct, because you
will do this more than once, though you can
avoid doing more than once per request if
clever.
• No need for setSite() in scripts.
• No uninstallation nightmares.
• Forces you to think about how to use OOTB
data structures in Annotations: good or bad,
depending on need.
#ploneconf2016 | @sdupton
40. Related, worth mention
• Martijn Faassen’s Reg (and Morepath)
• Python ABCs
– Pauper’s interface
– IMHO, problem:
• “Is a” is possible relationship
• “As a” is not
• No per-instance markers, no per-instance behavior based on
such.
– E.g. https://github.com/seanupton/experimental.flavors
» Disclaimer: may suffer some bit rot.
– Better critique:
• https://glyph.twistedmatrix.com/2009/02/explaining-why-interfaces-are-great.html
#ploneconf2016 | @sdupton
41. Outside the (server) box
Transplanting component ideology
into a JavaScript environment.
#ploneconf2016 | @sdupton
42. Some examples
• For UPIQ, I recently wrote:
– A mockup widget that extends PickADate, using an
adapter pattern (but not any kind of component
presumptions otherwise).
– Several incarnations of JavaScript zope.schema
look-alikes. I will briefly show you what one of these
looks like; I see much promise in the idea.
– https://github.com/upiq/plotqi/blob/master/spec/modelref/dataviz.js#L357
• We plan to write a 100% JavaScript forms
library based on client-side schema, that
groks plone.supermodel XML.
#ploneconf2016 | @sdupton
43. “Components” vs “Web Components”
• My use of “component architecture” in
JavaScript is distinct from “web components”:
– We can have schema in JavaScript.
• And resource-centric development, validation, etc.
• And design by contract for applications where JSON is an
interchange format. JSON Schema is very limited.
– We could have component registries in JavaScript, if
we wanted.
– We can use adapters, we could try using
synchronous event notification as adjunct to
asynchronous callback ideology.
– Form applications are an opportunity.
#ploneconf2016 | @sdupton