Best-Practices For Development
Best-Practices For Development
1
CONTENTS CONTENTS
Contents
1 Best Practices for Plone Development 3
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.1 Handouts and Examples . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.2 Why Do We Need This? . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.3 Safety . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.4 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.5 Re-Usability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.6 Streamlined Development . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Products . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.1 Concept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.2 Products . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.3 Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.4 Framework: config.py . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.5 Framework: content/ . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.6 Framework: skins/ . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.7 Framework: Extensions . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.8 Framework: doc/ . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.9 Framework: VERSION.txt . . . . . . . . . . . . . . . . . . . . . . 8
1.2.10 Framework: __init__.py . . . . . . . . . . . . . . . . . . . . . . . 9
1.2.11 Site Product Overview . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2.12 ArchGenXML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2.13 UML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.2.14 Converting UML . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.2.15 ArchGenXML Tips . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.2.16 Skeletor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.3 Filesystem Skins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.1 Through the Web Editing . . . . . . . . . . . . . . . . . . . . . . 12
1.3.2 More Web Editing Problems . . . . . . . . . . . . . . . . . . . . . 12
1.3.3 File-System Stored Skins . . . . . . . . . . . . . . . . . . . . . . . 13
1.3.4 Filenames Matter . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2
CONTENTS CONTENTS
3
CONTENTS CONTENTS
4
CONTENTS CONTENTS
5
CONTENTS CONTENTS
2 Footnotes 52
6
1 BEST PRACTICES FOR PLONE DEVELOPMENT
7
1.1 Introduction 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.1 Introduction
1.1.3 Safety
• Constancy and Fortitude
1.1.4 Documentation
• Truth and Unity
8
1.1 Introduction 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.1.5 Re-Usability
• Mercy and Clemency
9
1.2 Products 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.2 Products
1.2.1 Concept
• Build products for each major feature
For every feature of the site that might be re-used in another site, build a
product for this. For example, I recently wanted a Plone site that allowed
Plone to use the “sent to friend” feature for any page, based on URL, not just
based on Plone content. This only required changing 3 skins from CMFPlone,
and could have been customized for this site. Instead, I chose to separate it
out to the product SendToURL, allowing me to add this to any site instantly.
And, if I want to customize these skins further for another site, I can do so.
1.2.2 Products
• Each product contains
10
1.2 Products 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.2.3 Framework
• Ordinary setup:
__init__.py
config.py
content/
__init__.py
YourClass.py
skins/
productname/
class_view.pt
class_edit.py
Extensions/
Install.py
YourExternalMethod.py
doc/
YourDocumentation.txt
VERSION.txt
– Usually Archetypes-based
Many existing products use the directory name ’types’ for this, but this has a conflict
with the python built-in types.
11
1.2 Products 1 BEST PRACTICES FOR PLONE DEVELOPMENT
– Detailed later
12
1.2 Products 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.2.12 ArchGenXML
• Turns UML data to AT classes
– Installers
– Initializers
– Classes
13
1.2 Products 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.2.13 UML
• Good open source Java-based UML editors
– http://uml.joelburton.com
– Only accepts XMI files
14
1.2 Products 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.2.16 Skeletor
• Skeletor3: “Product skeleton builder”
15
1.3 Filesystem Skins 1 BEST PRACTICES FOR PLONE DEVELOPMENT
Don’t underestimate the value of this. I use vim, which launches quickly
(so it can be used easily with ExternalEditor TTW), and which practically
every server already has installed (so I can use through ssh). However, even
considering that, I find myself almost twice as productive being able to work
in my exact editing environment, with my macros, scripts, paths, etc., already
set.
– Refactoring extra-painful
16
1.3 Filesystem Skins 1 BEST PRACTICES FOR PLONE DEVELOPMENT
– Security
– Title
– FormController information
These are the accompany files that hold all the “other stuff”, titles, security set-
tings, proxy roles for PythonScripts, and more. These replace the .properties
files in earlier versions of the CMF.
One common mistake is to customize a skin object file (say, ’foo.py’) by
copying it to a new directory, but not copying any ’foo.py.metadata’. Note
that the .metadata file must be in the same directory, so in this case, the
customized foo object is used, and it does not get the settings in its metadata
file. If this contained important things, like security or proxy settings, this
could be disastrous.
In CMFPlone, there are examples of all of the types that can be stored on the
filesystem including feature like proxy settings, titles, security settings. ’grep’
is your friend here: ’grep -r --include=“*.metadata” proxy *’ Will give you an
example of using a proxy setting in .metadafiles.
Inline emphasis start-string without end-string.
Inline emphasis start-string without end-string.
17
1.3 Filesystem Skins 1 BEST PRACTICES FOR PLONE DEVELOPMENT
• PythonScripts: *.py
[default]
title=Register a User
18
1.3 Filesystem Skins 1 BEST PRACTICES FOR PLONE DEVELOPMENT
context.doStuff(new_body, attribA)
return context()
[default]
title=Register a User
proxy=Manager,Anonymous
[validators]
validators = validate_registration
[actions]
action.failure=traverse_to:string:join_form
action.success=traverse_to:string:registered
action.prefs=traverse_to:string:prefs_users_overview
19
1.3 Filesystem Skins 1 BEST PRACTICES FOR PLONE DEVELOPMENT
<dtml-comment>
connection_id: my_conn
arguments: fname lname
</dtml-comment>
– Set in zope.conf
– Leave on for development!
Refreshing products saves the time for Zope to restart, but there can be minor
side-effects that require a restart, anyway, depending on what the product
does.
There’s no harm try this and seeing it works, though. To do so, drop a file
in your product’s top directory called refresh.txt, then you can refresh the
product and see if this works.
Note that if you’re using SpeedPack under debug mode, you’ll see changes
to skin objects, as long as they don’t get copied from one directory to another.
However, if you customize a skin object to a new directory and are running
SpeedPack under debug mode, Zope has already cached the old location of
the skin object, and won’t use the new location version. Restart or use product
refresh to have Zope notice this.
20
1.3 Filesystem Skins 1 BEST PRACTICES FOR PLONE DEVELOPMENT
That is, our end goal is that the only thing in the ZODB will be our actual contentish
objects and configuration settings made by scripts. All of our skins and all of our
scripts will be on the filesystem.
Sometimes, it’s very helpful to have scripts or skins be placeful. For example, you
might have a different logo in different parts of your site, and a common Zope
practice for this would be to have ’logo.jpg’ in the root of your site, and a different
one in ’/about’. However, this leaves a piece of skin in the site, and ruins our ability
to maintain it well. Better is to have the root folder and ’/about’ folder have a
property--say, logo_name, which tells us what logo to use in this area. Then, we
can keep all of these logos on the filesystem, and have achieved our goal of just
keeping the configuration part in the ZODB.
• ’FSExternalMethod’
An example of taking an existing Zope object type and creating a FS-stored
capable version of it. Taken from FileSystemSite.
21
1.3 Filesystem Skins 1 BEST PRACTICES FOR PLONE DEVELOPMENT
allow_module(’zipfile’)
from zipfile import ZipFile
allow_class(ZipFile)
22
1.4 Form Controller 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.4.1 CMFFormController
• New form handling/dispatching system
– Validation
– Dispatching
• Status
23
1.4 Form Controller 1 BEST PRACTICES FOR PLONE DEVELOPMENT
• Button
• Argument
24
1.4 Form Controller 1 BEST PRACTICES FOR PLONE DEVELOPMENT
– TALES expression
– “string:http://www.yahoo.com”
– “string:view”
– or “python:”, or just path, of course
– Template: “friend_edit_form”
– Status: “success”
– Context: “Any” or “Friend”
A subtle difference. It’s possible that our friend_edit_form might be
used for just Friend portal types. It’s also possible that we re-use it for
CoWorker portal types. If we want the behavior to be the same, we can
keep this as “Any”. If we want to have different dispatching for the
two (perhaps coworker-editing needs a special coworker_edit script
that does things differently, we can specify “Friend” here and put in a
different action for “CoWorker”.
– Button: Any (unless you have cancel!)
– Action: “traverse_to”
– Argument: “string:friend_edit”
25
1.4 Form Controller 1 BEST PRACTICES FOR PLONE DEVELOPMENT
try:
context.n = context.REQUEST.n
except:
state.set(new_status=’failure’)
else:
state.set(
portal_status_message=’n=’ + n)
return state
- Template: "foo_edit
– Status: “success”
– Context: “Any” or “Foo”
– Button: Any
– Action: “redirect_to_view”
– Argument: “string:view”
Don’t forget the string:!
26
1.4 Form Controller 1 BEST PRACTICES FOR PLONE DEVELOPMENT
– Excellent
– Examples here borrowed from there
[validators]
validators.[Type].[Button] = val1, val2
validators.Event.Save = validate_event
validators..Save = validate_event
validators = validate_id, validate_event
27
1.4 Form Controller 1 BEST PRACTICES FOR PLONE DEVELOPMENT
• Validators: *.vpy
28
1.5 Skinning Plone 1 BEST PRACTICES FOR PLONE DEVELOPMENT
29
1.5 Skinning Plone 1 BEST PRACTICES FOR PLONE DEVELOPMENT
30
1.5 Skinning Plone 1 BEST PRACTICES FOR PLONE DEVELOPMENT
• #portal-breadcrumbs
• #portal-colophon
• .documentByline
• table.listing
31
1.6 Version Control 1 BEST PRACTICES FOR PLONE DEVELOPMENT
• Branches
Often, you’ll work for a day or two on a new idea, only to figure out that it
isn’t working out, you’ve screwed up, and you can’t remember all the billions
of things you changed while on a tear to try out this new idea. This is exactly
what branches in a version control system are meant to manage.
Learn how to use branches for your VC system. They’re easier that even in
Subversion.
32
1.6 Version Control 1 BEST PRACTICES FOR PLONE DEVELOPMENT
– Checks in changes
– If [files] not given, do all
– Calls up editor to enter comments
33
1.6 Version Control 1 BEST PRACTICES FOR PLONE DEVELOPMENT
At first, the task of having non-developers use your version control system
seems daunting. I’ve found, however, the non-developers can love it when
they realize they can easily work off files on their computer and sync it with the
server, and they understand that they don’t have to “worry” about mistakes.
It’s all in how you sell this idea.
34
1.6 Version Control 1 BEST PRACTICES FOR PLONE DEVELOPMENT
– Or put it on a branch
35
1.7 Documentation 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.7 Documentation
• DCWorkflowDump
• EpyDoc
• ArchGenXML
36
1.8 Setup and Scaffolding 1 BEST PRACTICES FOR PLONE DEVELOPMENT
Everyone that’s worked with Zope for more than a few months has encountered
“ZODB Dread”: that awful, sinking feeling that you’ve sunk a chunk of your very
life into a single, binary-format object database, with no hope you’ll ever be able
to remember all the scripts, skins, properties, and settings you’ve put into it. You
konw that if this puppy ever gets badly corrupted, you’re going to be in a world of
hurt.
This is what we want to avoid.
setup/
__init__.py
CustomSetup.py
37
1.8 Setup and Scaffolding 1 BEST PRACTICES FOR PLONE DEVELOPMENT
from Products.CMFPlone.setup.SetupBase \
import SetupWidget
from zLOG import INFO
from Products.Archetypes.utils \
import OrderedDict
functions = OrderedDict()
functions[’Americanize’] = Americanize
38
1.8 Setup and Scaffolding 1 BEST PRACTICES FOR PLONE DEVELOPMENT
class CustomSetup(SetupWidget):
type = ’MyProduct Setup’
description="Setup for ..."
39
1.8 Setup and Scaffolding 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.8.8 GenericSetup
• (Was CMFSetup)
40
1.9 Debugging 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.9 Debugging
• plone_log(summary, text)
41
1.9 Debugging 1 BEST PRACTICES FOR PLONE DEVELOPMENT
– zopectl fg
import pdb
pdb.set_trace()
• s: step, n: next
• r: return, c: continue
• w: frames
• b: breakpoint:
42
1.9 Debugging 1 BEST PRACTICES FOR PLONE DEVELOPMENT
• Edit $INSTANCE_HOME/etc/zope.conf
43
1.9 Debugging 1 BEST PRACTICES FOR PLONE DEVELOPMENT
app.plone.objectIds()
app.plone.portal_catalog(Title="Hello")
app.plone.Members.joel.doc.attrib=2
• Inspection: dir()
44
1.9 Debugging 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.9.13 Transactions
• Automatically discarded at end of session
• Discard now:
get_transaction().abort()
• Commit now:
get_transaction().commit()
app._p_jar.sync()
import Zope
Zope.debug(’/path/to/object’)
• Returns output
45
1.9 Debugging 1 BEST PRACTICES FOR PLONE DEVELOPMENT
pdb> b MembershipTool.listMembers
pdb> c
> .../MembershipTool.py(247)listMembers()
46
1.9 Debugging 1 BEST PRACTICES FOR PLONE DEVELOPMENT
• Nice editor/IDE
47
1.9 Debugging 1 BEST PRACTICES FOR PLONE DEVELOPMENT
48
1.9 Debugging 1 BEST PRACTICES FOR PLONE DEVELOPMENT
– Outdated by ZEO
– Documented in $SOFTWARE_HOME/docs/DEBUGGING.txt
• ActiveState Komodo
49
1.10 Testing 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.10 Testing
– Even “client-safe”
• Uses JavaScript
• Checks
• Element Locators
• DOM
• XPath
• Link Text
– requires prefix
50
1.10 Testing 1 BEST PRACTICES FOR PLONE DEVELOPMENT
• click
• type
• select
• And more
• verifyLocation
• verifyTitle
• verifyElementPresent
• verifySelected
51
1.10 Testing 1 BEST PRACTICES FOR PLONE DEVELOPMENT
• verifyTextPresent
– Anywhere on page
• verifyTextNotPresent
52
1.11 Developing With Others 1 BEST PRACTICES FOR PLONE DEVELOPMENT
• No wires, no wireless
• Each developer has their own skinpath, with their skinfolder as most cus-
tomized
53
1.11 Developing With Others 1 BEST PRACTICES FOR PLONE DEVELOPMENT
• My Site1 tutorial
• RichDocument tutorial
54
1.11 Developing With Others 1 BEST PRACTICES FOR PLONE DEVELOPMENT
1.11.6 CREDITS.txt
• Kapil Thangavelu
• Rob Miller
• Ben Saller
• Alec Mitchell
55
2 FOOTNOTES
2 Footnotes
1
http://www.neuroinf.de/PloneDevTutorial
2
http://svnbook.red-bean.com/
3
http://plone.org/products/skeletor
4
http://wingware.com/downloads/wingide/2.1.0/zope
56