cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Daniel Fagerstrom <dani...@nada.kth.se>
Subject Re: [RT] composition vs. inheritance in blocks
Date Wed, 30 Mar 2005 10:51:35 GMT
Stefano Mazzocchi wrote:

> Daniel Fagerstrom wrote:
>
>> Stefano Mazzocchi wrote:
>>
>>> Daniel Fagerstrom wrote:
>>
>> <snip/>
>>
>>> I don't like multiple inheritance and this is not just because I 
>>> learned OOP thru java, but because every single time I wish I had 
>>> multiple implementation inheritance in java I found a way to go 
>>> around the problem with single implementation inheritance that was 
>>> more elegant.
>>
>> I learned OOP thru C++, so I even have had the possibility of using 
>> multiple implementation inheritance, not just the work arounds ;) And 
>> in most cases composition is better than multiple implementation 
>> inheritance, but in the cases where you merge two different concern 
>> areas it is useful and natural according to my experience. While I 
>> don't find the "extend the largest abstract base class and repeat the 
>> interface and delgate to the other" ideom used in Java particulary 
>> elegant.
>>
>> But, although I believe that we should use well known concepts from 
>> OO as much as possible in the design of blocks, as we know some of 
>> the consequnces of them and as they are familiar to the users, we 
>> must be aware about that blocks and typical objects have quite 
>> different levels of granularity and are not completely analogous.
>>
>>                                    --- o0o ---
>>
>> So what I propose is that "extend and override" is a convenient and 
>> productive way to build webapps. You start from a working default 
>> application and add your own data and modify the behaviours that you 
>> need to modify. If you have used Forrest, you know what I'm talking 
>> about. But the difference between Forrest and what I propose is that 
>> you don't need any complicated sitemap tricks and global 
>> configurations with search paths, if we makes the block polymorphic.
>>
>>                                    --- o0o ---
>>
>> This is not just armchair speculations from me. We have built a 
>> number of webapps during the last year based on sitemap polymorphism. 
>> The mechanism is rather simple, in the sitemap of the base 
>> application we use a variant of the cocoon protocol:
>>
>> cocoon:polymorph:/foo.xml
>>
>> that basically calls
>>
>> cocoon://<sitemap-path>/foo.xml
>>
>> by mounting the base application in the end of the "extending" 
>> sitemap, the polymorph sitemap rules can be overrided just by 
>> defining the uri in the before the mount.
>>
>> Its easy and works well. Of course one have to do some thinking to 
>> build a reusable base application, but that goes generally for 
>> reusability.
>>
>> We started to use this pattern because we had a webapp, that a number 
>> of customers wanted slight variations of. In the beging we just made 
>> the new webapps extend a slight abstraction of the original webapp. 
>> Not because I thought it was a good idea, but more because of time 
>> constraints. Our experience is, hardly supprising, that it is more 
>> flexible to base your webapp on a number of orthogonal vertical 
>> frameworks. So we have factored out some such from the original webapp.
>>
>>                                    --- o0o ---
>>
>> So our experience is:
>> * extend and override is productive
>> * vertical frameworks are easier to reuse
>
>
> If you are talking about
>
>  block A extends block B
>
> then the functionality that you describe above is already included in 
> the original real block design and you don't even need the (ugly!) 
> polymorphic protocol flavor, since the block protocol should takes 
> care of all this transparently (thru the block dependency map of the 
> block manager).

Citing from 
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=111209768003970&w=2

>In your example block A extends block B, then in block B we can have a 
>sitemap rule like:
>
><map:match pattern="**.html">
>  <map:generate src="{1}.xml"/>
>  <map:transform src="block:polymorph:/stylesheets/document2html.xslt"/>
>  <map:serialize/>
></map:match>
>
>The block:polymorphism makes that stylesheets/document2html.xslt is 
>taken from A rather than B. Say that you use that stylesheet in several 
>rules, then you change multiple behaviours by overriding it.
>  
>
I described why I think its safer to be explicit about when an 
(extended) block should find a service by polymorphic rather than local 
lookup in 
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=111183895029727&w=2:

>Ok, allready discussed that above. I think we need to be more explicit 
>about what behaviour we want. If we just write:
>
><map:transform src="stylesheets/document2html.xslt"/>
>
>that means normally the same as:
>
><map:transform src="context:/stylesheets/document2html.xslt"/>
>
>and I don't think it is a good idea for isolation between block to be 
>able to overide what is in the current context, only things that are 
>exposed through the sitemap should IMO be overidable:
>
><map:transform src="block:polymorph:/stylesheets/document2html.xslt"/>.
>  
>
So I talk about polymorphic access *whithin* a possibly extended block. 
I'm fully aware that you described how A can override B by exposing an 
uri that is exposed in B, and I agree with the proposed mechanism. 
Question is how to handle the use of a service within the extended block 
(B) if this service is overriden i the extending block (A).

> But (as usual), you jumped directly from that to
>
>  block A extends block b *and* c

I wrote:

> Our experience is, hardly supprising, that it is more flexible to base 
> your webapp on a number of orthogonal vertical frameworks. So we have 
> factored out some such from the original webapp. 

on the line before my conclusion, and also described why I wanted it 
earlier in the thread, but (as usual) you jumped in and started 
screaming without bothering to read the whole thread.

> which, to me, is not the painless jump that you (and Peter) seem to 
> suggest.

As already said, I have practical experience of using multiple 
inheritance in C++ and poymorphic extensions of sitemaps in Cocoon. And, 
like any other powerful construct, you have to learn how to use it and 
it can be missused, but in my experience, it simplifies life if you use 
it in the right way.

A coleauge of mine was involved in building some rather large systems in 
Common Lisp long time ago, and used multiple (implementation) 
inheritance as one of the major ways to compose the systems. Hi find the 
single inheriatnce idea in Java ridiculous, and claims that he was about 
a magnitude more productive when he programmed in Common Lisp rather 
than in Java. Now comparing langauges is rather unproductive, I just 
wanted to point out that multiple inheritance not is bad per se, it all 
depends on what you use it for and how it is implemented in the 
particular language.

>> This implies AFAICS multiple inheritance
>
> not at all. you can have block 'cascading'/'wrapping' (you name it) 
> without multiple inheritance.

Sure, but if you want to base your webapp on several blocks that takes 
care of different concerns you have to chose which of them you want to 
be able to extend if you have single inheritance.

                                              --- o0o ---

But let's take a look at an example instead. We have built a number of 
webapps for administring sells campaigns for a number of companies 
within the same concern that are based on the polymorphic sitemap 
inheritance scheme that I described above. The webapps have 
functionality for administring the campaigns (of course), functionality 
for selecting and optimizing what customers to communicate with, 
documentation of how it works and about data models, visualization of 
the results of the campaigns, it communicates with some other systems, 
database administration functionality that we use internally etc.

Ok, when building a new system like this I start with a sitemap like:

...
<pipeline>
  <match pattern="sysadm/**">
    <mount uri-prefix="sysadm" src="context://block/sysadm"/>
  </match>
  <match pattern="campaign/**">
    <mount uri-prefix="campaign" src="context://block/campaign"/>
  </match>
  <match pattern="doc/**">
    <mount uri-prefix="doc" src="context://block/doc"/>
  </match>

  <!- other "blocks" -->

  <match pattern="**">
    <mount uri-prefix="" src="context://block/skin"/>
  </match>
</pipeline>
...

By typing "index.html" in my browser I get the default start page from 
"/block/skin", its a little bit like the default start page from 
Forrest: menu, menubar, bread crumb, short description about how to 
continue the development in the main page, etc.

First step is puting the other functionality in the menu, so I write an 
own "site.xml" that overides the polymorphically used in skin:

<pipeline>
  <match pattern="site.xml">
    ...
  </match>
  <!-- as before -->


whithin skin "site.xml" is used through "block:polymorph:/site.xml" and 
the overriding version will be used instead. Now my application have 
menu links to the default implementation of the other blocks (that may 
contain own manu definitions). I continue by overiding the uris to some 
of the icons, the start page, some css rules and maybe a "setting.xml" 
that describe some of the texts etc in the skin. Now I have customized 
how the application looks, start page an the top menu structure.

Next, probably after having created sub sitemaps for campaign, doc etc, 
I start to customize the parts of my webapp, by overriding some default 
behaviour in campaign, doc etc. I override the default (example) db meta 
description for my particular campaign database, change some of the adm 
forms etc. I use the same db meta description to my doc "block" as well 
for geting various data views: table overview and a connection diagram. 
For more general use we should of course factor out the db documentation 
to a separate dbdoc block, but all our webapps are db based so we 
haven't found it worthwhile yet.

                                              --- o0o ---

The important thing here is that my "blocks" are useable as is with 
example or default data, so that you just can mount them and test them. 
Then the things that are designed to be overidden is used through the 
"block:polymorph" protocol and can be overiding by puting a rule before 
the mount in the mounting sitemap.

To make this way of building webapps as simple and convenient as 
possible it is of course important to have common formats and design 
conventions between the block. And to focus the blocks so that they do 
one thing good instead of doing a little bit of everything. Also most of 
the blocks: systemadm, campaign and doc above should be "content" blocks 
and let the skin take care of view aspects.

If the blocks doesn't use the same formats things get more complicated, 
but it is still possible to handle. Say that "campaign" and "doc" uses 
different db description formats. Then you could write something like:

<match pattern="campaign/db.xml"/>
  <read src="db.xml"/>
</match>

<match pattern="doc/db.meta"/>
  <generate src="db.xml"/>
  <transform src="myDMMeta2TheirDBMeta.xsl"/>
  <serialize/>
</match>

<!-- mount the campaign and doc blocks -->

                                              --- o0o ---

So what I want to have in blocks, is this possiblity to extend and 
override functionality in several blocks. But I don't see any need for 
leting my "application level" blocks export all the services from the 
blocks it extend the functionality from. For sitemap services I prefer 
to explicitly export things with "mount" and for components we could 
have some similar mechanism as I described in my comment to Peter's mail.

>> as you have to implement polymorphism by hand if you use composition. 
>
>
> No. Absolutely not. Go back and read all my emails about the block 
> protocol: the functionality you describe is already there and doesn't 
> require MI at all.

I have read the ones that have links from 
http://wiki.apache.org/cocoon/Blocks and serched the archives for block 
discussions numerous times, and haven't found anything that adresses the 
usage scenario that I described above. If there are other relevant mails 
that adresses this, please do us all a service and add the links to the 
Wiki.

<snip/>

Can you describe how you would prefer to adress the "building a webapp 
from several blocks" scenario that I described above.

/Daniel


Mime
View raw message