Z3 ECM Enterprise Content Management for Zope3

10/10/2006

The Zope3 presentation layer (adaptation revisited)


    Views in Zope3 are implemented as multi-adapters.

This is pretty much a summary of the Zope3 presentation stack, so let us dig into it.

History: Views as in M-V-C

First of all, the term View is borrowed from the Model-View-Controller design terminology (a.k.a MVC).

From http://www.enode.com/x/markup/tutorial/mvc.html:
Model-View-Controller (MVC) is a classic design pattern often used by applications that need the ability to maintain multiple views of the same data. The MVC pattern hinges on a clean separation of objects into one of three categories — models for maintaining data, views for displaying all or a portion of the data, and controllers for handling events that affect the model or view(s).

The pattern is 25 years old (cf Applications Programming in Smalltalk-80(TM): How to use Model-View-Controller).

Simplified MVC (the UI-delegate)

In Zope3 however, View and Controller are combined inside a same element called ... a view, this is a simplified model of MVC, as implemented in the Swing framework. In Swing however to avoid a confusion with the MVC term "View", this element is called the UI-delegate (see ).

The UI-delegate (i.e. the Zope3 view) manages both interaction and presentation, so that in the end we only have two elements:
  1. a model
  2. a view (UI-delegate)

In the case of a browser view for instance, the View (as in MVC) would correspond to the HTML and javascript code of a web page and the Controller (as in MVC) would be all the methods (Form POST, GET, and other RESTful URLs) associated to the View that allow user interaction with the page.

For instance when some form data gets posted to the "/folder/addItems" URL, the 'addItems' method will be called on the server.

Hence a Zope3 view needs to implement:

  • controller methods (e.g. 'addItems(...)')
  • the actually rendering of the view (this is done with the __call__() method). Usually the __call__ method delegates the rendering to the Page Template engine (ZPT), but it could as well be implemented as:
def __call__(self):
return "hello world."
The pattern is classic in web application frameworks since the view and the controller are usually tightly coupled. In an application server environment the Controller is usually tied to the publisher's REQUEST - RESPONSE lifecycle since user actions initiate a new request. Also at the end of the request, either the same page is refreshed or a new page is displayed after a redirection has occured. Hence the view (as in MVC) is very much tied to the response phase.

Why using multi-adapters?

A view in Zope3 is a multi-adapter. It adapts the contextual object (a.k.a the context) AND the request. The reason why an adapter is used is because the publisher needs to find a "suitable view" for the object depending on the type of request (HTTP, FTP, XMLRPC, ..), and this is done in Zope3 by looking up the view in the adapter registry based on the "context + request" signature.

In fact both the contextual object and the request implement interfaces, hence there is a unique type signature for each combination of object types (e.g. IFolder, ICalenderItem, ICatalog, ...) and request types (IHTTPRequest, IXMLRPCRequest, ... see zope.publisher.interfaces for the list of available request types).

Hence the Zope3 view has access to:

  • the contextual object (the model as one part of the adaptee)
  • the request (as the other part of the adaptee)
  • the session (bound to the request)
  • the application's context

This is pretty neat.

However it only solves the "lookup" part of the problem. Indeed this guarantees that the right view will be used in a given context.

Ian Bicking in its recent "Zope3 critique" article remarks that this it feels too much like a model-driven approach, and the presentation layer is not the one that drives the data.

In fact I recently asked myself this question, so let us see why this is really happening ...

"pull"-style vs. "push"-style MVC

It is clear that the question is:

  • is it the presentation layer that should pull the data that it needs or
  • is it the model that should push what data will be presented?
  • or both?

In one case we have a "model-driven" approach (push-style MVC) as in Zope3 (or I would say an object-driven approach).

In the other case we have a "template-driven" or "presentation-driven" approach (pull-style MVC).

Seam implements both, but mostly uses the "pull"-style approach. The reason is that you often don't know for sure what model(s) you will need to pull data from until the page has actually been displayed.

Basically Seam will see that the presentation needs a given component and it will pull it for you automatically and manage its entire lifecyle. So eventually a view may pull 5 or 10 different models.

In the case of Zope3 views however there is place for only one adapted object, so practically you have to choose one contextual object before you start creating the view and the template.

Often you end up with a view class that needs to pull data from other models. This is done by storing model keys in the request (session, cookies, ...) and the view implementation soon becomes spaghetti code, because it needs to manage session objects, cookies, request parameters and do component lookups.

Of course one may consider that this is a problem that exists with all object-oriented approaches (i.e. the view is derived from the object), and in fact if you look at Zope CMF you will see that the only really contextual object is the folder or the document that is being displayed.

However in reality the presentation stack must be able to accommodate many contextual objects and the adaptation from object to view does not allow that.

Posted by Jean-Marc Orliaguet @ 10/10/2006 04:32 PM. - Categories: user interface, web design8 comments

10/02/2006

The Zope Component Architecture: the Tetris Effect

Note: regarding the previous post, the point that I was making is that in its philosophy the Component Architecture encourages design and code patterns, such as the ones that I listed. I did not invent those patterns myself. Actually the patterns can be found in the zope3 source code itself, in the doctest files, in Phillip's book, in the zope3 mailing list, in zope3 training courses, on IRC. Hence the argument -- otherwise perfectly valid -- that consists in saying that pure python code could have been used instead is not really valid in that case.

Concerning "pure python code", it is interesting to note that the concept of POJO (Plain Old Java Object) is now used to describe regular objects not tied to any particular framework (citing the wiki entry: "A large part of the usefulness of the term is it encourages developers to consider whether the benefits of using some framework are sufficient to justify its complexity.").

In comparison it could be that the Zope Component Architecture will contribute to the concept of POPO ("Plain Old Python Object"), depending on whether zope3 developers at some point realize that the problems to solve are not necessarily made simpler thanks to the framework.

Also Martin commented on my example by writing that using hardcoded registries would be bad design, since the application could not be extended (i.e. new registries be added, ..). Actually it depends on how the application defines its extension mechanisms. If the application is designed to allow new registries to be added, there is no difficulty in implementing that functionality in any language (python, javascript, Java, ...) as I've done here (see 'addRegistry', 'getRegistry').

My point is that defining extension mechanism (or not) should be done in the design of the application, not simply on the assumption that everything in the application may need to be extended.

Also I have been accused of critizing Zope3 for justifying the move to Java, however the reality is that I need to learn more about J2EE before being able to provide good arguments for criticism.

Back to the subject: the Tetris Effect.

You are certainly familiar with the Tetris game.

The object of the game is to manipulate tetrominoes to make them fit on an horizontal line. The shapes can fit well together as long as they are oriented correctly. As the game goes on, an entire stack is created from the blocks.

I believe that this a good metaphor for the Zope Component Architecture: one defines components by using interfaces, one defines rules for connecting components (adapters) and one combines the various components to create an entire architecture (application, framework, ...).

The components have to fit well otherwise the architecture will have "gaps".

Some developers can focus on the low-level stack, others can focus on the intermediate stack and others on the top layers

I would claim that, as of today, only the lower stack exists in Zope3, with the exception of some "vertical blocks" that span from the bottom to the top. Hence the game has just begun. We still need to see how the players will create and arrange the blocks.

Replacing blocks

The Zope Component Architecture promises that all components can be replaced. As long as the new component implements the interfaces specified by the components "surrounding" it, it will fit like a glove in the structure.

This is true technically, however practically components can be replaced only once, i.e. the mechanism defined for that (called "overriding") will fail if two different component providers override the same component.

Hence the question: in which way is the mechanism designed for replacing existing components conceptually differs from monkey-patching? If two developers replace the same component, a configuration conflict will occur. The difference is that the ZCML setup will detect the conflict and the server will not start, but in which way does the CA solve the problem?

It can be argued that new components can be registered under a different name, for instance there are such things as named adapters and named utilities that makes it possible to register several components providing the same interfaces but under different names. However the problem is that other components in the rest of the architecture will not necessarily do a lookup by name, hence components registered by name will simply be ignored.

I can also be argued that local components (e.g. local utilities) can be used for customizing existing components by overriding them locally, however this is done through containment by looking for the nearest site, but if other components do a global lookup as it is often the case, the local components will never be used.

Creating a high-level stack

This is a thorny issue: casual developers want simple APIs, that lead to produce code that can be read and understood like prose. But the CA does not encourage to write prose really (see my previous post). It is clear that there is a conflict of interest. One solution would be to create an intermediate stack above the low-level stack, i.e. a simpler API for developers that are not interested in knowing about the internals of Zope3.

The problem is that creating such a "simplified" stack basically means to not leverage the components architecture by avoiding such arcane idioms as "queryUtility", "getMultiAdapter", "isProvidedBy", ... (which for a casual developer mean nothing).

But the need for a simpler API may be needed in any case but for another simple reason: such idioms as "interfaces", "utilities", "adapters" expose in many cases the implementation details of concepts, but the implementation is not equal to the concept.

There is a confusion for instance between interfaces and types: interfaces can be used to implement typing, but typing can be implemented in many other ways (as in Zope2, using class attributes). Views are implemented using multi-adapters, but they could be implemented in many other ways, also registries are implemented using utilities, ...

TO BE CONTINUED

Posted by Jean-Marc Orliaguet @ 10/02/2006 12:12 AM. -  14 comments

09/29/2006

The Zope Component Architecture: To a hammer, everything looks like a nail.

I have experienced issues with the Zope Component Architecture. This is the first part of a series.

Complexity

The feeling of complexity comes from the fact that some few very abstract concepts such as interfaces, adapters, and utilities are used all over the place to represent all sorts of more familiar concepts.

The Zope3 code leaves the programmer in the situation of a researcher attempting to decode a DNA sequence, i.e. when one is looking too close it is difficult to see.

An example

To find a book by its name, intuitively one would write something like:

>>> from my.app import registries
>>> print registries.getBookRegistry().getBookByName("The book on Zope")

once the 'registries' have been imported, the code completion comes for free (CTRL+space when using an IDE like Eclipse):

  - registries => getCarRegistry() => getListOfCars() ...
  
  - registries => getTypeManager() => getTypeByName() ...

... which means that the API is made available by simply typing the words in English.

One expresses the same idea in Zope3 as:

>>> from my.app.interfaces import IBook
>>> print queryUtility(IBook, name="Book on Zope")

... which amounts to the same quantity of code, but with reduced understandability because that begs the question:

  • what is an interface?
  • what is a utility?
  • what does queryUtility() actually return?

(in fact it returns a book, not a utility)

This forces the brain to handle two foreign concepts (interface, utility) in the place of two otherwise familiar concepts (book registry, book)

Of course there is no such equivalent 'code completion' feature possible in Zope3 since utilities are registered at runtime (in ZCML).

Also to find books one needs to know that they implement the IBook interface and that they are registered as utilities under a name.

Another example

To get the type of the book, one would write in English:

>>> book = Book(type=PAPERBACK)
>>> print book.getType()

but in the spirit of the Component Architecture one would use "interface types", instead:

first by registering book types:

>>> class IBookType(IInterface):
>>>     """The book type""

>>> class Book(object):
>>>     implements(IPaperBack)
>>> alsoProvides(IPaperBack, IBookType)

or even in ZCML:

  <interface interface="IPaperBack" type="IBookType" />

and then by querying the interface type on the book instance:

>>> book = Book()
>>> print queryType(book, IBookType)

It always take me a few minutes to figure out what is actually happening, hence I am not 100% sure that the code is right this time.

more and more complexity

It should also be noted that the recent refactoring of ZCML directives which aimed at removing "redundant" directives because they could be expressed in "simpler" terms as adapters or utilities does not really simplify the task.

Now a factory is a utility providing zope.component.interfaces.IFactory.

We are getting closer and closer to a complete ternary representation (interface, adapter, utility) of the world, which I am sure is an elegant concept, but for the abstract thinker only.

Conclusion: To a hammer, everything looks like a nail.
Posted by Jean-Marc Orliaguet @ 09/29/2006 12:18 AM. -  7 comments

09/25/2006

Slow Trains Coming

There has been some (over)reactions to a post that I made on Zope's need to take a self-critical look.

I would be making "implications" --- which is such an unfair way of leading a discussion.

The only implications -- if there are implications to be make -- is from the news that

If you think that no one in the Java world welcomes the move, think twice.

Indeed, it would be wiser to make implications from that piece of information first, instead of focussing on "my implications", which to be honest I doubt many people care much about..

But to dispel some doubts about some points that obviously got misunderstood:

  • Zope3 needs an IDE, in my opinion. Zope2 had one (the ZMI) which allowed you to create an application and which most non-expert users still use as a way to customize their site. So why does this simple assertion has to be tackled from a binary perspective on "the IDE vs the language"? that's not the point really.
  • Zope3 needs a stable API, in the sense that it needs to stabilize some time.
  • Java hint: How and When To Deprecate APIs

    Valid reasons for wishing one's users to migrate to the new API include:
    • the old API is insecure, buggy, or highly inefficient
    • the old API is going away in a future release
    • the old API encourages very bad coding practices

    in other terms there should be real reasons for deprecating, not simply because the code needs to be restructured or refactored, or packages be moved from zope.app to zope, otherwise it really gives the impression that the code isn't ready.

  • [update 2006-09-25 23:00: another pointer on stable APIs: How To Design a (module) API - "Stable contracts should preserve the investments of those entering into them (users of an API)."]

  • ZCML is not XML. Because in an XML configuration file it is possible to put several levels of nested elements. In ZCML there is place for directives and for subdirectives (2 levels). That forces you to add indirections in the ZCML file itself to fit 2 or more levels in your file.
  • ...
  • self-cricitism, well, I am sure that you know what I meant already, I probably don't need to be more explicit :-)
Posted by Jean-Marc Orliaguet @ 09/25/2006 10:05 PM. - Categories: Java1 comments

09/23/2006

The Times They Are A-Changin'

You probably read the news the other day. There have been very few reactions so far apart from Phillip reporting the news and Paul making an allusion to it (It's Alright, Ma)

There would have been reasons to take a perspective on Nuxeo's technology switch instead and ask oneself the question:

For Zope, what can be learned from the Java technologies?

Admittedly it sounds as a provocative question, knowing that Zope pioneered great innovations at a time when Java-based solutions were still in their infancy.

So here is my take on it, not about comparing Python and Java (the languages), but about the rest, which is what really matters, isn't it?

1) The importance of the IDE

This is a crucial point that some commentators of the web framework comparison video mentionned, saying in substance "But wait ... people use an IDE when developing with JEE".

I have personally always used 'vi' when developing with Zope2 and Zope3. I have tried different IDEs for python (Wing IDE, Eclipse pydev with extensions, BOA constructor) but always went back to vi, because I noticed that what I wanted was not really another editor but an integrated development environment and there is no such thing as 'half-integrated' environment. Julien mentionned this in his blog.

Shane also posted about Zope 3 IDE Considerations about a year ago.

It true that developing in Java without an IDE takes more time than it would have taken in Python, but that's not what people do anyway.

The Eclipse IDE in its most basic form provides:

  • integrated unit tests
  • automatic Java style formatting using templates (just hit CTRL+SHIFT+F)
  • the automatic import of Java packages with one click (and hit CTRL+SHIFT+O to clean up and sort imports in alphabetic order).
  • advanced support for refactoring: renaming files, packages, or moving files between packages updates all references automatically
  • non initialized and unused local variables are highlighted
  • the deprecated classes of a package are marked as such
  • syntax errors are highlighted, but also programming errors such as
    • "not all methods have been implemented, click here to add unimplemented methods or declare this class as abstract"
    • "cannot reduce the scope of this method from public to private"
    • "this class needs a constructor, click here to add the constructor"

Basically this means that when the code is getting compiled, 99% of the basic errors have been removed. The rest are real design errors (null references, ...)

This makes development four to five times faster, indeed. One also learns language features by simply following the IDE's suggestions.

But most of all, it makes development fun.

2) The importance of stable APIs

One important aspect when using external libraries in your own code is to know about the API's contract:

  • how stable is the API? will half of the classes be deprecated or the packages be moved to another location in the next release? Basically: what is the upgrade path?
  • how is the API supposed to be used or extended, what it public what it private?

I have felt some frustration at some Java packages that just would not let me subclass because the class was declare as final, or that would not let me use a method because it was private. But thinking about it afterwards, it simply means that:

"this is not the way the API should be used"

In Python I would have just subclassed or used the private method anyway.

The bottom-line is that there is only one chance for a developer to get the API right, because other developers expect it to be stable and easy to extend.

And no, the deprecation feature is not a tool available to developers for doing cosmetic refactoring or for renaming packages.

3) The importance of standards

What is involved in "getting the API right"?

My conviction is that it is better to get developers to agree on a specification than having the code implemented.

It involves agreeing on a specification, i.e. selecting the list of features and use cases needed by anyone interested in using the API, creating the specification either on paper or by declaring interfaces, and letting anyone interested implement the API, or to provide a default implementation.

Lots of packages are being added in the Zope3 repository without proper reviewing, implying: "we find this useful, hence someone else may find it useful too". This is relatively harmless for utility packages that have a limited scope, but for framework foundation modules this is a problem.

It is perfectly fine to have 3 or 4 different implementations of the same specification that provides a given feature. But having 3 or 4 different specifications of a same basic feature because they were hurried in simply means a lack of concertation.

package naming conventions

Concerning package naming, the standard way in Java is to use namespaces like 'java' or 'javax' for packages that implement standards, and to use fully qualified namespaces for packages with proprietary features.

For instance, in Zope3 there would be:

  • zope.component
  • zope.util
  • ...

for the standard components and:

  • org.zope... for Zope community packages
  • com.zope.... for Zope Corporation packages
  • org.plone...
  • org.nuxeo...
  • com.infrae...

In this way, it would make it clear what packages can be considered as standard, foundation packages and which are vendor-specific.

Otherwise as a developer I may well start using a zope.abc package to learn 3 months later that the package was just the result of an experiment, and that it will be replaced by a "better" implementation.

4) The Design Patterns

This is an interesting topic.

There are no such things as adapters, factories, utilities, events in the Java language, these are just design patterns.

Quoting the "design pattern" definition from the link cited above:

"A design pattern systematically names, motivates, and explains a general design that addresses a recurring design problem in object-oriented systems. It describes the problem, the solution, when to apply the solution, and its consequences. It also gives implementation hints and examples. The solution is a general arrangement of objects and classes that solve the problem. The solution is customized and implemented to solve the problem in a particular context."

The most important part of the definition I think is the last sentence:

"The solution is customized and implemented to solve the problem in a particular context"
In other words, in some cases using the Adapter pattern may be a good idea while in other cases, it may be a bad idea. One cannot know the solution until the problem to be solved has been described.

My impression is that the 4 basic patterns promoted in the zope3 architecture as the "new religion" are predefined solutions to problems that are yet to be identified.

I started questionning the need for adapters when trying to use to equivalent in Java, for example:

If I have an object and I want to know its size, I would in Zope3 do something like:

>>> a = MyObject()
>>> size = ISize(a).getSize()  

in Java that would become:

First the object adapter:

public class SizeAdapter {

    Object object;

    public Size(Object object) {
        this.object = object;
    }

    Integer getSize() {
        Integer size = null;
        // compute the size from the object
        return size;
    }
}

then the adapter would be used as:

   Object a = new SomeObject();
   Integer size = new SizeAdapter(a).getSize()

the difference is that

ISize(a)
in zope3 does an adapter lookup based on adaptee's type. But otherwise the idea is the same: the adapted object is passed as a context parameter to the adapter's constructor and gets stored in the adapter's created instance.

In fact, one probably would not do it that way in Java (that is, using the Object Adapter pattern), because during every use of the adapter a new object is instantiated, that needs to be garbage collected.

Probably one would use a static method instead:

public class SizeCalculator {
    public static Integer getSizeOf(Object object) {
        Integer size = null;
        // compute the size
        return size;
    }
}

and one would use the "size calculator":

   Integer size = sizeCalculator.getSizeOf(a);

which is to say that only one instance of the "SizeCalculator" will be created.

One may also register different "SizeCalculator" factories for different types of objects, or alternatively one could put the entire logic inside the getSize() method. But again it all depends on the nature of the problem to be solved:

For instance, if the "SizeCalculator" is used inside an internal API only, there is no need to make it pluggable to make it support calculating the size of any type of object, because that part of the code is not supposed to be exposed or be extended.

One could also use the Class Adapter pattern or another pattern, or use no specific pattern at all.

Conclusion: the Component Architecture is not a universal solution for particular problems.

5) The Component Architecture

The main question is: what problem does the Component Architecture solve?

But first let us ask: in a platform or in an application, do we want components?

Yes, we want separation of concerns, we want different logical layers that separate storage, business logic, presentation, we want core components for the core functionality. We want to be able to extend the platform without modifying the existing code. we want extension points, etc.
But how "big" do we want these components to be, do we want micro-components?

No, because it takes extra configuration to connect components together, and if the separation occured on a "micro level" this would add complexity only to the application. And it is not necessarily the place where the application or the platform is supposed to be extended.

What is needed in a platform is a "Plugin Architecture" at a high abstraction level, i.e. the ability to define "extension points" at some strategic places of the platform (not everywhere) and give to developers the ability to register their own plugins by using a high-level API.

Conclusion: the Component Architecture does not replace high-level API design (directory service, storage abstraction, presentation layer, document model, ...) The fact that there are lots of components does not imply that the platform is easy to plug anything into.

6) ZCML is not XML

The idea with ZCML is to move the configuration part of the application away from the Python code. So in order to reconfigure a component one would not change the existing application.

Technically this is true. Practically however, one is required to understand how the code works in order to modify a ZCML configuration file, so this only adds an extra indirection compared to modifying the existing Python code directly.

The same level of complexity appeared in J2EE before Annotations where introduced into the Java language. Before that XML configuration files were used to configure all components. This is what comes out clearlyv in the web framework comparison video cited ealier.

With Java5, annotations where introduced that make it possible to configure components entirely in the code:

@Name("My widget")
@Type(SOME_WIDGET_TYPE)
class MyWidget implements Widget {
...
}

Hibernate, EJB3, JBOSS Seam use annotations a lot, and there aren't hundreds of XML files anymore.

There are cases however where XML-based configuration makes sense:

1) when the configuration features are not about configuring individual components, but about configuring the entire application or an entire module instead, for instance to switch to "debug mode", or to configure a presentation framework, or to configure the deployment of an application.

Basically the idea is that actions that are done often should require little registration code in XML, while actions that are performed only once may well require a lot of XML configuration.

2) or when the XML configuration does not refer to any specific Java component, for instance when describing a series of rules, or a workflow definition, or a page layout, or page navigation rules, etc...

Unfortunately ZCML only allows one level of XML nested structures which makes that type of configuration cumbersome, because even more indirections need to be created, instead of simply writing:

<directive1>
  <directive2>
    <directive3 ... />
  </directive2>
</directive1>

7) The Presentation Layer

Well, presentation is not only about presenting data, it mainly about managing the data that is to be presented. That's called "context management".

There are different types of contexts (application, session, request, ...) that can contain data. Each context has a different scope and a specific lifecycle.

For instance, the application's data is present as long as the application runs, the session data exists until the user closes the session or when the session expires, and the request's lifespan ends when the response has been served.

In any case a same presentation template will probably need to get access to many different pieces of data, for instance in this template:

<h1>Documents of #{currentUser}</h1>

<h2>All the documents viewed previously:</h2>
<ui:repeat="#{documentHistory}" var="item">
  <span>#{item/title}</span>,
</ui:repeat>

<h2>Current document</h2>
<p>#{currentDocument.content}</p>

.. a lot of data from different sources needs to be collected before anything can be displayed.

In Zope3 this is what a "view" does. A view adapts the context and the request to create a transient object that the presentation template will be able to use to get access to the presentation data. So the view's function is really to collect data in the first place.

I have had trouble sometimes in Zope3 to decide which object is the "context" object. This is when the presentation is not concerned with presenting a single object but it involves presenting several different objects. In that case there is no obvious one and single context.

In any way, the point is that you don't need view objects really. All that is needed is a simple way to get access to contextual data from inside a presentation template.

This can be done by letting the presentation framework find out which components are used in a template and let it create or look up the components for you.

This is what JSF and JBoss Seam do.

The result is that there is no need to collect data, because the framework does it for you and manages the lifecycle of these objects automatically depending on there scope. Instead it is possible to refer to the components directly from inside the template.

Seam also introduces two new context scopes called "conversation context" and "page context".

A "conversation context" is associated to a page flow, it exists as long as the user has not performed a given final action. This is useful when booking flight tickets, or when shopping items. Sometimes several conversation contexts need to be created in parallel, and the framework does it for you.

The "page context" exists for a given page. When the user navigate back to a same page you the context becomes available again.

There is also "Seam remoting" that makes Ajax remote call completely transparent from javascript, as if all Java methods where directly usable in Javascript.

Some of this is in fact inspired from Ruby-on-Rails.

8) The "pythonic" trip

What is "pythonic" what is not? but who cares basically as long as you have a good API and a great framework?

Really, it is better to spend energy on more important things.

9) Balkanization

The balkanization of the Python community is a real issue I think. Maybe this is due to too much focus on the language itself (the language for the sake of the language) and not enough focus on existing standards.

10) Self-criticism

Self-criticism is about being able to see what others did and admit when it is the case that they did some things better; especially taking a look at JEE, JBoss, Eclipse, or Ruby-On-Rails, Turbogears, Django, etc.

JBoss Seam for instance was created as a Java response to the Ruby-on-Rails' success.

What has the Zope Community's response been to RoR?

  • "that's just because they have a better web site"
  • "that's just hot air and marketing, all that we need is a better web site"

Maybe it is time for constructive self-criticism?

Posted by Jean-Marc Orliaguet @ 09/23/2006 10:39 PM. - Categories: Java -  0 comments

04/23/2006

CPS4/Z3ECM Paris sprint report, CPSSkins4Five

I spent the week during the CPS4/Z3ECM Paris sprint trying to make cpsskins v3 (written entirely with zope3) run on zope2.

Here is a summary, but first see the preview animation

For some background information:

cpsskins v3 provides a theme engine and a portlet manager for zope3.  However it did not until now run on anything but zope3, which provides better technology to develop with but which also still has a limited amount of end-user applications.

The Five approach which consists in using Zope3 technology in Zope2 would have been interesting to consider at the start of the cpsskins project, but the goal was instead to develop entirely with zope3 first and to consider backward compatibility issues with zope2 later on, i.e. now.

Strategy

The strategy is still to keep on developing cpsskins in zope3 without worrying about zope2, which means that cpsskins v3 contains no references to zope2.

However, there is now a Zope2/Five product called CPSSkins4Five which acts as a bridge between zope3 and zope2. In CPSSkins4Five, cpsskins v3 is considered as a python library that does theme rendering.

CPSSkins4Five currently runs on the philikon-local-components branch of zope2 which integrates the jim-adapter branch of zope3, and contains changes in Five for using the new local utility and adapter registration API.

All these branches will be merged into the upcoming zope 2.10 (scheduled in June).

CPSSkins v3 heavily uses local utilities for registering resources and having a clean and a unique API in zope2 and zope3 was sufficiently important to justify developing against Phillip's and Jim's branches.

First phase

The first phase was to port cpsskins v3 to the new local utility and adapter API. This was done in a branch of cpsskins called paris-sprint-2006.

A simple doctest was added to make sure that the part of the utility registration API used by cpsskins worked as expected.

Second phase

The second phase consisted in getting the philikon-local-components branch of zope to start, which required adjusting some module import paths.

Third phase

Then cpsskins v3 was added into the lib/python directory of the zope2 instance. The CPSSkins4Five product was created to load cpsskins' zcml configuration files, do some minor patches and load zope3 packages required by cpsskins.

Also an simple installer was created to make it possible to create a CPSSkins site inside the ZMI.

A "CPSSkins site" can be any folder in Zope2 (CMF, CPS, Plone, Silva ... site) that can be turned into a zope3 site with a local site manager. Of course CPSSkins4Five does not provide compatibility with CMF or CPS or Plone sites, but it shows how a simple zope folder can become a CPSSkins v3 site.

Zope2/Five issues

There have been and there still are a couple of issues:

Use of resources

In zope3, I am used to referring to resources with /++skin+cpsskins/@@/++resource++myfile.css to provide a fixed path to objects. In Five/Zope2 this apparently does not work.

path adapters

I did not manage to get path adapters to work in Five, which is why the theme editorstill displays the "KeyError: formattable" message ('formattable' is a named adapter with support for path traversal).

docstrings on publishable objects

Zope2 does not publish objects without docstrings. The solution is to add docstrings to these classes, however it often takes time to find out what is missing.

page templates / zope2 requests

When passing a zope2 request to zope.app.pagetemplate.ViewPageTemplateFile or to a BrowserView a 'debug' attribute is missing in the request which make it impossible to debug errors unless the attribute is manually added to the request object before calling the template.

icon directive / Five

The <browser:icon> directive is missing in Five.

zope3 packages not configured in Five

A lot of zope3 packages are by default not enabled in Five, although they are distributed in zope2 and are available as python packages. This is not really an issue since the CPSSkins4Five product will load them, but it can take some time to identify the real problems, as one is expecting a bug in the application. Such packages are: zope.app.keyreference and zope.location.

Positive points

The result is very positive: apart from the remaining issues described above, this experiment has shown that it is possible to develop entirely in zope3 for months and port to zope2 afterwards. This however requires that the application be developed without creating too many points of entries with the ZODB. In cpsskins v3 there is only one point: i.e. the "theme management" local utility which contains all persistent information used by the application.

Future plans

  • make it possible for Zope2 applications to register specific portlets. Fortunately the application will only need to provide data structures (not presentation which is taken care of by cpsskins)
  • try and use complex schemas definitions using another language than zope3 schemas for describing portlet data structures that are typically non-flat data structures.


Posted by Jean-Marc Orliaguet @ 04/23/2006 09:29 PM. - Categories: Five, cpsskins -  0 comments

02/18/2006

Treeview widget in AJAX


Here is a treeview widget in about 200 lines of code:

see the animation
http://www.z3lab.org/sections/front-page/design-features/treeview-widget-in-ajax

the tree state is persisted on the client, i.e. the page can be reloaded and the tree will be displayed again as the user left it.

the tree data is fetched from the remote server in JSON.

here is the code


Posted by Jean-Marc Orliaguet @ 02/18/2006 08:42 PM. - Categories: AJAX, JSON, cpsskins -  0 comments

02/15/2006

Controlling network latency in AJAX

I have checked-in some code that make it possible to get some control over network or server latency when doing asynchronous requests in AJAX.

But first SEE THE FLASH DEMO
(the AJAX proxy was used to simulate network latency)

The problem is well known and documented as you can see:
http://richui.blogspot.com/2005/09/ajax-latency-problems-myth-or-reality.html

or even see this demo to the what happens when Ajax.Request gets direct control over a widget:
http://www.phppatterns.com/stuff/latency.html

one solution to reduce latency is to preload data:
http://www.jonathanboutelle.com/mt/archives/2004/08/latency_must_di.html

but this is not always feasible.

So here is a solution: a transaction manager must be inserted between the model's data accessors (getData() setData()) and the storage adapters

This is especially important for a remote storage since the data will have to be
  1. transfered from the client to the server over the network,
  2. handled on the server (the server may get data from another server, e.g. LDAP) and
  3. be sent back to the client over the network.

There are a lot of steps between the instant the user presses a key and when the results are displayed on the screen.

Basically there are two approaches:

- the queue sequence (aka. "first-in first-out" or FIFO).
 The requests are handled in the same order as they are initiated. This is important when a series of actions are to be performed in a given order.

- the stack sequence (aka "last-in first-out" or LIFO).
  The latest requests are treated first. This would have been useful in auto-completion example shown above.

When defining a model, it is now possible to specify the type of access:

<ins class="model">
  {"id": "stack-sequence",
     "data": {
       "position": 0,
       "s": 0
     },
     "storage": {
     "type": "remote",
       "access": {
       "type": "stack",
       "signature": "s"
     },
     "accessors": {
       "set": "@@setDataWithLatency.html"
     }
   }}
</ins>


A signature (e.g. a timestamp) is also sent along to be able to identify the which response corresponds to which request. This information could also be used by the server to handle the requests in a given order.

There is no maximum stack / queue size yet, but this is going to be implemented too.
Posted by Jean-Marc Orliaguet @ 02/15/2006 03:43 PM. - Categories: AJAX, cpsskins -  0 comments

02/13/2006

AJAX chat application with 0 lines of javascript


Here is a demo of a simple chat application:

http://www.z3lab.org/sections/front-page/design-features/ajax-chat-demo

The messages are stored on a remote server (zope3), the message box is refreshed every 5 seconds, the user's name is stored in a cookie, the status message is stored in RAM.

The application's code uses exactly 0 lines of javascript.

see the source code
Posted by Jean-Marc Orliaguet @ 02/13/2006 01:19 AM. - Categories: AJAX, JSON, cpsskins -  0 comments

02/09/2006

Graceful degradation vs progressive enhancement in Ajax

Here is a simple pattern for enhancing existing applications with "Ajax"-enabled widgets:

One known approach (used by for instance by script.aculo.us) is called "graceful degradation". It puts some restrictions on the design of the widgets since there is a constraint between the "enhanced" and the "degraded" versions: the enhanced widget must "naturally" degrade into standard and functional HTML..

The approach taken here is the opposite: existing page elements are replaced by Ajax-enhanced widgets when the page is loaded and the widget definitions are being parsed.

If the browser is not supported by the library, or if javascript is disabled, the original HTML widgets will be used instead.

Here is some sample code:

<div id="htmlwidget" class="standard">
   Standard HTML widget
</div>

<ins class="view">
{"widget": {
"type": "ajaxwidget",
"replace": "htmlwidget"
}}
</ins>


This is trivially implemented in the CPSSkins Ajax toolkit since the widgets are by design already inserted into the page on-the-fly, in that case they are told to simply replace existing elements.


Posted by Jean-Marc Orliaguet @ 02/09/2006 12:29 AM. - Categories: AJAX, cpsskins, web design -  0 comments | Trackbacks (9097)
Last modified: 08/14/2005 07:50 PM