A pinch of indirection, and dont cut yourself chopping onions...

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

Transcript of A pinch of indirection, and dont cut yourself chopping onions...

Page 1: A pinch of indirection, and dont cut yourself chopping onions...

A Pinch of IndirectionAnd don’t cut yourself chopping onions…

... practical tips for using component architecture(s).

SeanUptonUniversityofUtahDepartmentofPediatrics/UPIQ.org

#ploneconf2016|@sdupton

Photocredit:https://www.flickr.com/photos/ampersandyslexia (CC:by-sa)

Page 2: A pinch of indirection, and dont cut yourself chopping onions...

Hello Boston!

This talk is about (pick one):

(a) Plone(b) Food(c) Components(d) APIs(e) Some, none, or all of the above.

#ploneconf2016|@sdupton

All uncredited photos in this slide deck:© 2013-2016 Sean Upton, free for your re-use via CC-by-3.0

Page 3: A pinch of indirection, and dont cut yourself chopping onions...

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

Photocredit:https://en.wikipedia.org/wiki/Penrose_stairs

Page 4: A pinch of indirection, and dont cut yourself chopping onions...

This Old Hat

Theoldhatsurelybeats… …thenewhat?

#ploneconf2016|@sdupton

Photocredit:©HBO(usedhereunderfairuse)Photocredit:GarySteward(CC-by-3.0)

https://commons.wikimedia.org/wiki/File:Bullwhip_and_IJ_hat.jpg

Page 5: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 6: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 7: A pinch of indirection, and dont cut yourself chopping onions...

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:JamesBeardFoundation (usedhereunderfairuse)

Page 8: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 9: A pinch of indirection, and dont cut yourself chopping onions...

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

Photocredit:https://commons.wikimedia.org/wiki/File:Inside_a_corn_maze_near_Christchurch,_New_Zealand.JPG(publicdomain)

Page 10: A pinch of indirection, and dont cut yourself chopping onions...

Now ZCA + ZTK

• Frombiggerstacktosmallerparts– Mirepoix,notthewholesouppot.

– Buffet,nottabled'hôte/prixfixe

– Eatwhatyouwant.• e.g.Twistedusesonly

zope.interface

#ploneconf2016|@sdupton

Photo credits: via WikiMedia Commonshttps://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)

Page 11: A pinch of indirection, and dont cut yourself chopping onions...

The “holy trinity” of componentsAdapters

ü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

🌶

Page 12: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 13: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 14: A pinch of indirection, and dont cut yourself chopping onions...

Principles and patterns

#ploneconf2016|@sdupton

Page 15: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 16: A pinch of indirection, and dont cut yourself chopping onions...

“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

Page 17: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 18: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 19: A pinch of indirection, and dont cut yourself chopping onions...

Now, I’m just being contrary…

#ploneconf2016|@sdupton

Page 20: A pinch of indirection, and dont cut yourself chopping onions...

Simplified API Love/hate

THIS: NOTTHIS:

#ploneconf2016|@sdupton

Page 21: A pinch of indirection, and dont cut yourself chopping onions...

APIs

Procedural• Benefit:simplifytosingle

resource:thesite.– Butnow,thesiteismega-

controller.• Costs:

– Doesnotalwaysrepresentwhatweareworkingwith.

– Leakyabstractions(e.g.IPropertiedUser).

– Lostopportunityatsimplifiedresource/noun/stateidioms.

State-driven• Benefits:

– Componentsobeyidioms– Componentslooklikestatethey

directlyrepresent.• Cost:youmusttraversetothe

resourceyouwanttoworkwith.– Isthatsuchabadthing?– Sometimesthisistraversaltoa

folder,insteadofusingthesiteasacontroller.MoreOO.

– Sometimescomponentlookup.

#ploneconf2016|@sdupton

Page 22: A pinch of indirection, and dont cut yourself chopping onions...

…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

Page 23: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 24: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 25: A pinch of indirection, and dont cut yourself chopping onions...

“Just enough”Zope Component Architecture

…andwhattodowhenitwon’tcooperate.

#ploneconf2016|@sdupton

Page 26: A pinch of indirection, and dont cut yourself chopping onions...

zope.interfaceComponents 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

Page 27: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 28: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 29: A pinch of indirection, and dont cut yourself chopping onions...

Methods in interfaces

#ploneconf2016|@sdupton

Debatable merit?

Page 30: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 31: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 32: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 33: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 34: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 35: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 36: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 37: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 38: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 39: A pinch of indirection, and dont cut yourself chopping onions...

Related technologies

#ploneconf2016|@sdupton

Page 40: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 41: A pinch of indirection, and dont cut yourself chopping onions...

Outside the (server) box

TransplantingcomponentideologyintoaJavaScriptenvironment.

#ploneconf2016|@sdupton

Page 42: A pinch of indirection, and dont cut yourself chopping onions...

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

Page 43: A pinch of indirection, and dont cut yourself chopping onions...

“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

Page 44: A pinch of indirection, and dont cut yourself chopping onions...

#ploneconf2016|@sdupton

In food and in software, there is always room for good cooking.