Django, Components, and Interfaces

75 views
Skip to first unread message

Joshua 'jag' Ginsberg

unread,
Sep 7, 2007, 12:48:46 PM9/7/07
to django-d...@googlegroups.com
Howdy all --

I've been working with the internals of both Django and Trac lately, and there's a feature of Trac that I have found to be simply outstanding and remarkably consistent with the engineering standards of Django: Trac's component framework.

The code for Components, Interfaces, and the loader is very light -- less than 400 lines of python and it provides for interface definition, interface implementation, and component registration and selection. All-in-all, it's a fantasticly light, elegant implementation.

There are two benefits I could see to moving toward supporting a componentized framework -- not Trac's necessarily but certainly in the same vein.

First, every section of Django becomes customizeable without chopping up the source tree. We already permit drop-in authentication backends, database backends, and caching backends; there's been talk of drop-in session backends and certainly others. This would permit much greater flexibility in allowing more customized installs. For example, I wrote a Trac Component to recognize Django sessions instead of using its own authentication sources in just 50 lines without touching the Trac source tree. That's pretty nice.

Second, Django applications are proliferating. We as a community need to look long term about the environment this is going to create. We already know there are enough blog applications to overflow MAXINT. There are probably half as many blog rolls and contact information databases and so forth. If this continues unabated, there will be tremendous integration problems for administrators who want to reuse other developers' apps unless the community creates a consensus blessing many more apps as part of django.contrib tools which doesn't sound terribly likely. Alternatively, if django were to bless certain interface definitions for applications, leaving each developer to select the components that best implement those interfaces, we could avert this balkanization.

FSM knows we have enough major branches underway, and that newforms-admin is probably everybody's top priority. But I thought all the same I'd solicit comments on whether or not it makes sense to abstract the interfaces for major Django subsystems out to permit more seamless componentization of the platform.

Thanks for your attention.

-jag (aka j00bar)

Malcolm Tredinnick

unread,
Sep 7, 2007, 1:04:05 PM9/7/07
to django-d...@googlegroups.com
On Fri, 2007-09-07 at 12:48 -0400, Joshua 'jag' Ginsberg wrote:
[...]

> First, every section of Django becomes customizeable without chopping
> up the source tree. We already permit drop-in authentication backends,
> database backends, and caching backends; there's been talk of drop-in
> session backends and certainly others. This would permit much greater
> flexibility in allowing more customized installs. For example, I wrote
> a Trac Component to recognize Django sessions instead of using its own
> authentication sources in just 50 lines without touching the Trac
> source tree. That's pretty nice.
>
> Second, Django applications are proliferating. We as a community need
> to look long term about the environment this is going to create. We
> already know there are enough blog applications to overflow MAXINT.
> There are probably half as many blog rolls and contact information
> databases and so forth. If this continues unabated, there will be
> tremendous integration problems for administrators who want to reuse
> other developers' apps unless the community creates a consensus
> blessing many more apps as part of django.contrib tools which doesn't
> sound terribly likely. Alternatively, if django were to bless certain
> interface definitions for applications, leaving each developer to
> select the components that best implement those interfaces, we could
> avert this balkanization.

It's not clear what problem(s) you are actually trying to solve here in
these paragraphs, so your ideas come across as a little abstract.

Firstly, you seem to be conflating core and application, which is a
misunderstanding. django.contrib is just one directory where
applications live. It's only "special" in that it's owned by Django
itself -- i.e. it's where the maintainers might put any apps we ship
with Django. But that's the complete limit of it's specialness. Apps are
just importable Python packages. Stemming the proliferation of
applications sounds like an anti-problem: we want to encourage people to
write apps, not stop them.

Secondly, keep in mind that infinite flexibility is not necessarily a
pragmatic goal. Partly because it means you spend forever tweaking the
interfaces between sections and it actually restricts what you can do
(because any single change has enormous external implications). Django
already allows a lot of replacement of core components. ORM, templates
and URL dispatching can all be done by other means if you like. You can
use whatever web front-end you like and we have plans to fix things like
the slight WSGI incompatibilities we currently have. Besides those
things, there's not much else in core when you break it down. In most
cases, it's not even a lot of code to do these replacements.

Contrib apps can be used or not as you like. You mention a couple of
examples where contrib apps allow some internal customisation. Could you
be more concrete about what is missing.

Remember that Django aims to provide something that is "sufficiently
good" for creating production-capable websites. As a bonus (and by
design), if you want to replace things, you can. However we're not
TurboGears where they are intentionally only building interfaces between
existing components. If somebody wants that type of changeability, then
TurboGears is probably what they want.

So maybe there is a particular thing you are trying to solve here. If
so, have another shot at explaining what it is, with real-world
examples. Which pieces aren't flexible enough? Abstract conversations
aren't particularly productive (and you'll see that they've come up here
before) because there's no path towards any sort of goal that comes out
of them. Django strives to find a reasonable between "batteries
includes" and allowing customisation. Where do you want to tweak that
balance?

Regards,
Malcolm

--
Everything is _not_ based on faith... take my word for it.
http://www.pointy-stick.com/blog/

Joshua 'jag' Ginsberg

unread,
Sep 7, 2007, 2:14:53 PM9/7/07
to django-d...@googlegroups.com
Malcolm --

Thanks for taking the time to read it and write back. I apologize if what I said at first didn't come across clearly -- I often need two or more stabs at explaining something before I get it across with its semantic integrity still in place.


It's not clear what problem(s) you are actually trying to solve here in
these paragraphs, so your ideas come across as a little abstract.

Okay, that seems like a good place to start.

Problems:
1) While there is a good degree of drop-in replacability of parts in the Django stack as I outlined (db backend, authentication backend, etc.) there is not a clean way for programmers to grok what specific contract various components have to comply.

An example: How do I implement a template loader? While I can trace the behavior of the existing template loaders and try to guess what each of the methods do and the data that their arguments and return values should contain, there is not a defined contractual interface for a template loader. I have no way of knowing that the "filepath" returned from load_template_source will then be expected to be used by Template's origin kwarg for reloading the source.  The Django team put so much effort into making these parts componentized without having a component system to delineate and document contracted interfaces.

2) There is not replaceability for every component unless such replaceability is specifically engineered in by the Django team.

An example: I want to replace the session backend with something not database bound. I can't until Django commits an extensibility for that interface. Or I want to have User objects that implement additional methods, but if I subclass it then all of the other apps won't use instances of my subclass and won't have access to my extensions.

3) Without some sort of agreed upon standards to support interaction between apps, we will not be able to harness the wealth of django apps being written right now into complete, integrated sites.

An example: I like Suzy Creamcheese's Blog application but she used django.contrib.comments in it, and I want Joe Schmoe's slashdot style commenting system. I also want people who have blogs to be able to post their own photos, but Suzy Creamcheese's Blog application uses a BlogAuthor model for biographical data and needs it set as the PROFILE model and John Shaft's photo gallery application uses a Profile model for biographical data and also needs it set as the PROFILE model. I can't integrate these without hacking on them. But if Suzy wrote her Blog application to implement IBlog and IBlogManager which contained extension points for IComment and ICommentManager, I could integrate the two systems without having to alter code. And if both the BlogAuthor model and the Profile model implemented the same interface then I could still use them together as User can provide the extension point for that interface.

Or if I'm using Satchmo and I've written an excellent CRM system in Django, I want Satchmo to use the shipping and contact information that I've defined in my CRM system, and if they both implemented IPerson, IPostalAddress, and IPhoneNumber, I could drop in those replacements. Without that, I'm bound to either duplicate my data across the two applications, hack Satchmo to use my CRM, or constrict my CRM system to require Satchmo.

Firstly, you seem to be conflating core and application, which is a
misunderstanding. django.contrib is just one directory where
applications live. It's only "special" in that it's owned by Django
itself -- i.e. it's where the maintainers might put any apps we ship
with Django. But that's the complete limit of it's specialness. Apps are
just importable Python packages. Stemming the proliferation of
applications sounds like an anti-problem: we want to encourage people to
write apps, not stop them.

I don't have any such confusion in my head. I know that django.contrib is for apps that Django has blessed as standard and other than their integration into the default DJango build, there's nothing special.  I'm not wanting to stem the proliferation -- I'm wanting to maximize the integration and utility. Including an application in django.contrib is one way for the community to enforce standardization. If Django Tagging were included in django.contrib, if I were writing an application that needed tagging services, I'd just use django-tagging because everybody who has django has django tagging. It would be foolish of me to require a foreign dependency. But I don't think we necessarily want to as a community try to produce canonical, standard applications and continue expanding contrib for the utility applications that we all reimplement.

Secondly, keep in mind that infinite flexibility is not necessarily a
pragmatic goal. Partly because it means you spend forever tweaking the
interfaces between sections and it actually restricts what you can do
(because any single change has enormous external implications). Django
already allows a lot of replacement of core components. ORM, templates
and URL dispatching can all be done by other means if you like. You can
use whatever web front-end you like and we have plans to fix things like
the slight WSGI incompatibilities we currently have. Besides those
things, there's not much else in core when you break it down. In most
cases, it's not even a lot of code to do these replacements.

I totally agree. Having this sort of interface definition does require much more planning and more difficulty before breaking exposed interfaces. Perhaps at this young age of Django, it's inappropriate to discuss a component framework and just rely on the solid engineering to have fuzzily defined components. But there is not (necessarily) the same sort of discoverability, rigid contractual obligation, or interchangeability of these components. Like I said, we have all of the intention of a componentized framework without any of the actual code to make it work like one should.

So maybe there is a particular thing you are trying to solve here. If
so, have another shot at explaining what it is, with real-world
examples. Which pieces aren't flexible enough? Abstract conversations
aren't particularly productive (and you'll see that they've come up here
before) because there's no path towards any sort of goal that comes out
of them. Django strives to find a reasonable between "batteries
includes" and allowing customisation. Where do you want to tweak that
balance?

Does what I said above provide some more concrete definition as to what I'm thinking? Let me know if I need to explicate further.

Thanks again for taking the time.

-jag (aka j00bar)



Yuri Baburov

unread,
Sep 7, 2007, 2:40:07 PM9/7/07
to django-d...@googlegroups.com
> An example: I like Suzy Creamcheese's Blog application but she used
> django.contrib.comments in it, and I want Joe Schmoe's slashdot style
> commenting system. I also want people who have blogs to be able to post
> their own photos, but Suzy Creamcheese's Blog application uses a BlogAuthor
> model for biographical data and needs it set as the PROFILE model and John
> Shaft's photo gallery application uses a Profile model for biographical data
> and also needs it set as the PROFILE model. I can't integrate these without
> hacking on them. But if Suzy wrote her Blog application to implement IBlog
> and IBlogManager which contained extension points for IComment and
> ICommentManager, I could integrate the two systems without having to alter
> code. And if both the BlogAuthor model and the Profile model implemented the
> same interface then I could still use them together as User can provide the
> extension point for that interface.
This was design error of applications creators.
Let's think what Django could do to prevent such errors.

> Or if I'm using Satchmo and I've written an excellent CRM system in Django,
> I want Satchmo to use the shipping and contact information that I've defined
> in my CRM system, and if they both implemented IPerson, IPostalAddress, and
> IPhoneNumber, I could drop in those replacements. Without that, I'm bound to
> either duplicate my data across the two applications, hack Satchmo to use my
> CRM, or constrict my CRM system to require Satchmo.
I can see abstract idea. But don't see right implementation idea.
1) You can do this all without all javaish interfaces.
Python metamodel is open for changes when program is running.
2) Interfaces are not python way of doing stuff. google: duck typing.
Please take my arguments into account and reconsider your idea with them.

--
Best regards, Yuri V. Baburov, ICQ# 99934676, Skype: yuri.baburov,
MSN: bu...@live.com

Marty Alchin

unread,
Sep 7, 2007, 3:01:11 PM9/7/07
to django-d...@googlegroups.com
I probably shouldn't be putting my hat in this ring, but I've never
been a big fan of components and interfaces, so I'll provide some of
my own thoughts on the subject.

On 9/7/07, Joshua 'jag' Ginsberg <dja...@flowtheory.net> wrote:
> Problems:
> 1) While there is a good degree of drop-in replacability of parts in the
> Django stack as I outlined (db backend, authentication backend, etc.) there
> is not a clean way for programmers to grok what specific contract various
> components have to comply.
>
> An example: How do I implement a template loader? While I can trace the
> behavior of the existing template loaders and try to guess what each of the
> methods do and the data that their arguments and return values should
> contain, there is not a defined contractual interface for a template loader.
> I have no way of knowing that the "filepath" returned from
> load_template_source will then be expected to be used by Template's origin
> kwarg for reloading the source. The Django team put so much effort into
> making these parts componentized without having a component system to
> delineate and document contracted interfaces.

This sounds like a documentation problem, not a code problem. Template
loaders are indeed under-documented, and it seems to me that
documentation alone would solve this problem.

> 2) There is not replaceability for every component unless such
> replaceability is specifically engineered in by the Django team.
>
> An example: I want to replace the session backend with something not
> database bound. I can't until Django commits an extensibility for that
> interface. Or I want to have User objects that implement additional methods,
> but if I subclass it then all of the other apps won't use instances of my
> subclass and won't have access to my extensions.

But the same is true of interfaces too. Unless the Django developers
expected for something to be extended, they wouldn't provide an
interface for it, and thus you'd have to wait for one in order to hook
into it. So, while you have a fair point that this is a slight
problem, interfaces wouldn't make anything better, so it's a wash.

> 3) Without some sort of agreed upon standards to support interaction between
> apps, we will not be able to harness the wealth of django apps being written
> right now into complete, integrated sites.
>
> An example: I like Suzy Creamcheese's Blog application but she used
> django.contrib.comments in it, and I want Joe Schmoe's slashdot style
> commenting system. I also want people who have blogs to be able to post
> their own photos, but Suzy Creamcheese's Blog application uses a BlogAuthor
> model for biographical data and needs it set as the PROFILE model and John
> Shaft's photo gallery application uses a Profile model for biographical data
> and also needs it set as the PROFILE model. I can't integrate these without
> hacking on them. But if Suzy wrote her Blog application to implement IBlog
> and IBlogManager which contained extension points for IComment and
> ICommentManager, I could integrate the two systems without having to alter
> code. And if both the BlogAuthor model and the Profile model implemented the
> same interface then I could still use them together as User can provide the
> extension point for that interface.

Now, this point I might not be understanding correctly. Are you asking
for Django's core to define an interface for each and every potential
use someone might find for it? While I can understand the marginal
benefit such interfaces might provide, I can't imagine it would be
worthwhile to require Django itself to be responsible for all of
these.

After all, what happens when somebody finds something new to do with
Django, or they'd like to add an attribute or method to an existing
interface? Well, then we go back to your second point, where we have
to wait for the Django team to agree on the changes and implement it,
before anybody can do anything.

> But I don't think we necessarily want to as a community try to produce
> canonical, standard applications and continue expanding contrib for the
> utility applications that we all reimplement.

But that seems to be almost exactly what you're asking for, by having
Django core define all those interfaces. Sure, the interfaces aren't
the implementations, so there's nothing to "override", but you're
still asking the framework to keep a registry of potential
applications.


> Perhaps at this young age of Django, it's inappropriate to discuss a
> component framework and just rely on the solid engineering to have fuzzily
> defined components. But there is not (necessarily) the same sort of
> discoverability, rigid contractual obligation, or interchangeability of
> these components. Like I said, we have all of the intention of a
> componentized framework without any of the actual code to make it work like
> one should.

And this is the point I usually get to when explaining why I don't
like interfaces, and it's at the heart of why I'm not a fan of Java.
Essentially, you're asking for the code to make sure that programmers
don't make mistakes. You're asking for developers to not have to read
(or write!) proper documentation. Personally, I absolutely love Duck
Typing, and as long as there's sufficient documentation on what is
considered a "duck", then anybody can make their own and we're all
happy. I see no need to expect code to be responsible for making sure
that programmers are doing their jobs.

Again, I probably shouldn't have gotten into this, so please disregard
my comments if I'm not making any sense.

-Gul

Christopher Lenz

unread,
Sep 7, 2007, 3:07:18 PM9/7/07
to django-d...@googlegroups.com
Am 07.09.2007 um 20:40 schrieb Yuri Baburov:
>> Or if I'm using Satchmo and I've written an excellent CRM system
>> in Django,
>> I want Satchmo to use the shipping and contact information that
>> I've defined
>> in my CRM system, and if they both implemented IPerson,
>> IPostalAddress, and
>> IPhoneNumber, I could drop in those replacements. Without that,
>> I'm bound to
>> either duplicate my data across the two applications, hack Satchmo
>> to use my
>> CRM, or constrict my CRM system to require Satchmo.
> I can see abstract idea. But don't see right implementation idea.
> 1) You can do this all without all javaish interfaces.
> Python metamodel is open for changes when program is running.
> 2) Interfaces are not python way of doing stuff. google: duck typing.
> Please take my arguments into account and reconsider your idea with
> them.

Except that interfaces in Trac's component system (and AFAIK also in
Zope or PyProtocols) aren't about typing *at all*; they're about
protocols for using, extending, or replacing functionality
(components). It might help to actually read up on stuff before
commenting. For your convenience here's a link:

<http://trac.edgewall.org/wiki/TracDev/ComponentArchitecture>

(I'm not really going to weigh in on whether this whole thing would
be a good match for Django, just defending a design against
uninformed comments; I'm also not saying that the design is in anyway
perfect; there's definitely room for improvement).

Cheers,
Chris
--
Christopher Lenz
cmlenz at gmx.de
http://www.cmlenz.net/

Joshua 'jag' Ginsberg

unread,
Sep 7, 2007, 3:09:35 PM9/7/07
to django-d...@googlegroups.com
Hi Yuri --

Thank you also for taking the time to write. 

 

This was design error of applications creators.
Let's think what Django could do to prevent such errors.

The application creators weren't thinking about interoperability of their applications because there are no such guidelines for making interoperable applications. Interfaces and componentization would give Django the opportunity to define some standard interfaces like IUser and give Django developers the opportunity to define interfaces for other things, such as Satchmo having the ability to define IPostalAddress.


I can see abstract idea. But don't see right implementation idea.
1) You can do this all without all javaish interfaces.

Admitted, this is bringing some higher OO language stuff to Python. Trac and (gasp!) Zope both went down this route. If it can be done another way, I'd love to hear a suggestion on how to use soft paternalism to get developers to conform their code to certain interoperable patterns.
 

2) Interfaces are not python way of doing stuff. google: duck typing.
Please take my arguments into account and reconsider your idea with them.

Sure. Walks, quacks, yep. It's a duck. But if I want my own user model, I don't just have to make something that looks and acts like a User from django.contrib.auth -- I have to convince everybody else to use my version instead of the django one. But applications that need a User-like object can query to see what installed components implement IUser instead of just assuming I want to use django.contrib.auth, then it's much easier.

Thank you for your comments. I look forward to hearing more of your thoughts.

-jag (aka j00bar)

Marty Alchin

unread,
Sep 7, 2007, 3:09:44 PM9/7/07
to django-d...@googlegroups.com
On 9/7/07, Marty Alchin <gulo...@gamemusic.org> wrote:
> Now, this point I might not be understanding correctly. Are you asking
> for Django's core to define an interface for each and every potential
> use someone might find for it? While I can understand the marginal
> benefit such interfaces might provide, I can't imagine it would be
> worthwhile to require Django itself to be responsible for all of
> these.
>
> After all, what happens when somebody finds something new to do with
> Django, or they'd like to add an attribute or method to an existing
> interface? Well, then we go back to your second point, where we have
> to wait for the Django team to agree on the changes and implement it,
> before anybody can do anything.

And I should also explain how this benefit could indeed be achieved
without modifying Django core. As strange as this may sound,
community-established standards could work. If we had a central place
to discuss, standardize, document and publish common paradigms,
developers could easily find the information they need when building
their ducks.

This could be as simple as setting up a website, something like
djangostandards.org or something, with tools to discuss and document
these things. Then, as long as the site makes it easy to find existing
standards, developers will easily see what they'll be expected to
provide if they want to be interoperable. Again, it all comes down to
documentation. Using interface explicitly in code is just a band-aid
to allow developers to read and write less documentation.

-Gul

James Bennett

unread,
Sep 7, 2007, 3:13:48 PM9/7/07
to django-d...@googlegroups.com
On 9/7/07, Joshua 'jag' Ginsberg <dja...@flowtheory.net> wrote:
> Problems:
> 1) While there is a good degree of drop-in replacability of parts in the
> Django stack as I outlined (db backend, authentication backend, etc.) there
> is not a clean way for programmers to grok what specific contract various
> components have to comply.

Personally I'd rather solve this with documentation.

> 2) There is not replaceability for every component unless such
> replaceability is specifically engineered in by the Django team.

Sure there is. Want an alternative session component? Import it and
use it according to its documentation.

> 3) Without some sort of agreed upon standards to support interaction between
> apps, we will not be able to harness the wealth of django apps being written
> right now into complete, integrated sites.

I dunno, I've managed it pretty well.

Offhand I'd be -1 on anything that makes Django's codebase more
complex; there are very few things that can be solved by "component
interfaces" that can't also be solved by good documentation, and the
documentation carries a lot of other benefits with it besides that.


--
"Bureaucrat Conrad, you are technically correct -- the best kind of correct."

Jacob Kaplan-Moss

unread,
Sep 7, 2007, 3:19:50 PM9/7/07
to django-d...@googlegroups.com
Hi Joshua --

> [...] if they both implemented IPerson, IPostalAddress, and
> IPhoneNumber, [...]

... and that's the point where my eyes glaze over and smoke starts
coming out of my ears.

I don't know you, but I'll hazard a guess at your background: Java, right?

The thing you have to understand is that Django tries *very* hard to
be "Pythonic", which usually means doing away with things like
interfaces, components, and overwhelming architecture astronauting. Do
a Google search for "duck typing"; that's how we do interfaces (as it
were) around here.

Now, you're right about a *lot* of your criticisms -- e.g. writing a
template loader shouldn't require a spin through the source code --
but the Django way is to view that as a documentation problem, not a
design issue. Database backends are another example -- they are
pluggable, but almost completely undocumented.

Our culture is to fix these bugs in English, not Python; suggestions
that involve things like "IDatabaseComponent" are going to elicit a
gag reflex from most Django programmers. In fact, just writing that
word made me puke a little in my mouth. Don't worry, I swallowed it.

> [...] I don't think we necessarily want to as a community try to produce
> canonical, standard applications and continue expanding contrib [...]

Yeah, I don't know of a nice way to say this... you're wrong; that's
*exactly* what we (or and least I) would like to do. If there's a
piece of code that does Feature X in way that feels consistant with
Django, we very much want it to be part of django.contrib, and we want
to encourage people to use it whenever possible. Django-tagging is a
great ecample here.

The only reason we've not expanded django.contrib more is that we've
not firmly established a good process for getting apps into contrib
and keeping them up-to-date.

I think you're a bit mistaken about our core philosophy, so I'll try
to sum it up: every single piece of code that's part of Django exists
because it solves a very specific, real-world problem. We vehemently
oppose adding code because "someone might need it" -- the only
features that make it in are those that solve *actual* problems.

If you can articulate what problem you're trying to solve (and how
Django's not letting you), we might be a bit more receptive, but large
architecture proposals are most certainly *not* pragmatic, and are
only undertaken when they seem to be big wins (c.f. magic-removal,
unicode, etc.)

Jacob

Marty Alchin

unread,
Sep 7, 2007, 3:20:32 PM9/7/07
to django-d...@googlegroups.com
On 9/7/07, Joshua 'jag' Ginsberg <dja...@flowtheory.net> wrote:
> Sure. Walks, quacks, yep. It's a duck. But if I want my own user model, I
> don't just have to make something that looks and acts like a User from
> django.contrib.auth -- I have to convince everybody else to use my version
> instead of the django one. But applications that need a User-like object can
> query to see what installed components implement IUser instead of just
> assuming I want to use django.contrib.auth, then it's much easier.

But keep in mind, when you start talking about outright replacing
existing implementations, you're going to run into deeper issues.
Remember, there's an underlying database that has to keep track of
relationships among the various tables, so if you change from one User
model to another, you'll likely have to scrap everything that ever
dealt with the User model.

It's one thing to provide a generic interface for something that
probably hasn't already been implemented, but to replace things
already in core, you give developers a big problem: if I want to use
your application, I have to abandon everything I've already done,
because you needed to have another method on the User model.

And I don't expect the schema evolution code would help much with this
problem either, unless it goes in a new direction to explicitly handle
this. Instead, I think we could look into ways of extending existing
models (even to the point of adding new fields!) in a way that schema
evolution would readily understand. Then, we might have a decent way
to deal with things like this.

-Gul

Vsevolod Solovyov

unread,
Sep 7, 2007, 3:40:36 PM9/7/07
to django-d...@googlegroups.com
On 9/7/07, Joshua 'jag' Ginsberg <dja...@flowtheory.net> wrote:

> > I can see abstract idea. But don't see right implementation idea.
> > 1) You can do this all without all javaish interfaces.
>
> Admitted, this is bringing some higher OO language stuff to Python. Trac and
> (gasp!) Zope both went down this route.

One of Zope developers said that he hates Python because of dynamic
features and duck typing, AFAIR. And as Jacob said - Django tries very
hard to be Pythonic. Both ways are just different ways, no one of them
is The Absolute Truth. Django developers like Pythonic way. I also
think so.

--
Vsevolod Solovyov

Christopher Lenz

unread,
Sep 7, 2007, 5:46:15 PM9/7/07
to django-d...@googlegroups.com
Am 07.09.2007 um 21:07 schrieb Christopher Lenz:
> Am 07.09.2007 um 20:40 schrieb Yuri Baburov:
>>> Or if I'm using Satchmo and I've written an excellent CRM system
>>> in Django,
>>> I want Satchmo to use the shipping and contact information that
>>> I've defined
>>> in my CRM system, and if they both implemented IPerson,
>>> IPostalAddress, and
>>> IPhoneNumber, I could drop in those replacements. Without that,
>>> I'm bound to
>>> either duplicate my data across the two applications, hack Satchmo
>>> to use my
>>> CRM, or constrict my CRM system to require Satchmo.
>> I can see abstract idea. But don't see right implementation idea.
>> 1) You can do this all without all javaish interfaces.
>> Python metamodel is open for changes when program is running.
>> 2) Interfaces are not python way of doing stuff. google: duck typing.
>> Please take my arguments into account and reconsider your idea with
>> them.
>
> Except that interfaces in Trac's component system (and AFAIK also in
> Zope or PyProtocols) aren't about typing *at all*; they're about
> protocols for using, extending, or replacing functionality
> (components). It might help to actually read up on stuff before
> commenting.

After writing this I realized that the example described by jag here
was pretty misleading, in particular with respect to the interface
names chosen (sorry jag ;), which definitely don't reflect correctly
on how interfaces are used in "the Trac model". So I apologize if my
reaction here was too harsh.

But as the "we're pythonic, we use duck typing and documentation"
meme has come up a couple times after that on this thread, let me
repeat: that frankly has *nothing* to do with the component
architecture as used in Trac that jag referred to originally.

buriy

unread,
Sep 7, 2007, 7:05:51 PM9/7/07
to Django developers
> The application creators weren't thinking about interoperability of their
> applications because there are no such guidelines for making interoperable
> applications. Interfaces and componentization would give Django the
> opportunity to define some standard interfaces like IUser and give Django
> developers the opportunity to define interfaces for other things, such as
> Satchmo having the ability to define IPostalAddress.
What you called IUser interface must be base class then.
Customizing users model was better discussed in other threads. With
real solutions given.
Not "make all stuff components and interfaces and have fun connecting
them".
You propose just additional abstraction layer with no benefits. Python
is not Java. You can call any object method without subclassing it
from interface allowing such method. User is already IUser. You can
even change used user model with middleware.

> 2) Interfaces are not python way of doing stuff. google: duck typing.
>
> > Please take my arguments into account and reconsider your idea with them.
>
> Sure. Walks, quacks, yep. It's a duck. But if I want my own user model, I
> don't just have to make something that looks and acts like a User from
> django.contrib.auth -- I have to convince everybody else to use my version
> instead of the django one. But applications that need a User-like object can
> query to see what installed components implement IUser instead of just
> assuming I want to use django.contrib.auth, then it's much easier.
Django is a framework, not a library. That means you have to change
framework anyway if it's not flexible enough.
All parts of application can't be flexible at the time, do you agree?
I remember someone told me about Microsoft application, that took data
path in registry then xml-object under that path, then created COM
object from part of that xml data, then calling XML-RPC to another
component of the same computer just for retrieving one boolean
property value. Great flexibility, right? You want to teach Django to
do that trick? You have come too late.
Your django applications are components, middleware and backends are
components. The component structure is present and working already.
What else do you want? When someone will write function
get_user_model_class() for you? I guess, you want to have exactly the
same errors with User model that you had with profiles :)
(some application working with custom-User-model-1 only, another -
working with custom-User-model-2 only).
The only correct solution is to create your own table for additional
user data and store all your information there.
And just install your User model by yourself.

"Class factory for greater flexibility" pattern makes sense in Java
world only.
Ok, last story. Once I copied Java homogeneous class hierarchy of 5
classes (100 lines each) to python and refactored it. Result was 4
functions of 3 lines each. In Java I won't be able to live without
these 5 classes. Factories and class hierarchy disappeared. Because
they were not necessary in Python!

Joshua 'jag' Ginsberg

unread,
Sep 8, 2007, 12:19:08 PM9/8/07
to django-d...@googlegroups.com
Thank you all for taking the time to write your thoughts -- they've been very helpful! I hope you'll forgive me for trying to write a response to them collectively touching on the excellent points they raised.

For the record, I'm not a Java developer. I spend most of my time writing in Python by choice. I would like my life less with Java. And I liked my life less with Zope 2 and Zope 3 -- we like the joke that Zope's slogan should be "It *is* easy to use -- you're just stupid."

James et al. who said that these are documentation problems. That may very well be, and that's fine. I can live with that answer.

I know Python loves duck typing. And duck typing is very powerful for a certain replacement situation: I need to use somebody else's library that expects an object of the class Foo but I want it to work with my class Bar, so I implement the methods and properties in Bar that make it a act like a Foo, and voila! It works. Duck typing is excellent here.

Where the weakness of duck typing lies is when I've got somebody else's code that I need it to return a Bar but it returns a Foo. This is where interfaces/components/extension points do very well. If that other person's code instead of saying "construct an object of type Foo" it asks "give me the installed Component that acts like a Foo" and it constructs a Bar object instead.

So at my work we developed an app to provide object-level permissions. Ideally, we could ask a User object if it has permission on a certain object via a method in that User object, but absent hacking the User object, that's not going to happen. I can subclass User and add the methods I want -- it will walk and quack like a User. But then I also have to rewrite get_user() so that it returns a ObjectPermissionAwareUser instead of a User. I have to rewrite authenticate() as well. And I have to check the middleware to make sure it uses get_user() instead of returning a user itself.

In the end we subclass User and write a method to give us an ObjectPermissionAwareUser when we have a User object.

It may very well be that this componentization is all inappropriate for Django. And that's fine. But let it be on the basis of "the benefits we can reap from having componentization exceed the cost of implementation, code complexity, and interface flexibility" rather than adherence to the dogma "Python is purely duck typed so doing anything else would be un-Pythonic"

To Jacob: obviously I know your work with Django, so I apologize for the gag reflex. :) I'll try to construct some concrete proposals for improvements to the extensibility of Django without architectural changes and some suggestions for administrative/bureaucratic processes to help canonize some common application pieces to improve interoperability and avoid reimplementation of the same apps over and over.

Thanks again, everybody. Have a great weekend!

-jag (aka j00bar)

Vsevolod Solovyov

unread,
Sep 8, 2007, 12:35:41 PM9/8/07
to django-d...@googlegroups.com
On 9/8/07, Joshua 'jag' Ginsberg <dja...@flowtheory.net> wrote:

> So at my work we developed an app to provide object-level permissions.
> Ideally, we could ask a User object if it has permission on a certain object
> via a method in that User object, but absent hacking the User object, that's
> not going to happen. I can subclass User and add the methods I want -- it
> will walk and quack like a User. But then I also have to rewrite get_user()
> so that it returns a ObjectPermissionAwareUser instead of a User. I have to
> rewrite authenticate() as well. And I have to check the middleware to make
> sure it uses get_user() instead of returning a user itself.
>
> In the end we subclass User and write a method to give us an
> ObjectPermissionAwareUser when we have a User object.

You can use monkey patching [1] instead of subclassing. If you're
using nice dynamic language you can use nice dynamic features.

[1] http://en.wikipedia.org/wiki/Monkey_patching

--
Vsevolod Solovyov

Marty Alchin

unread,
Sep 8, 2007, 3:08:05 PM9/8/07
to django-d...@googlegroups.com
On 9/8/07, Joshua 'jag' Ginsberg <dja...@flowtheory.net> wrote:
> So at my work we developed an app to provide object-level permissions.
> Ideally, we could ask a User object if it has permission on a certain object
> via a method in that User object, but absent hacking the User object, that's
> not going to happen. I can subclass User and add the methods I want -- it
> will walk and quack like a User. But then I also have to rewrite get_user()
> so that it returns a ObjectPermissionAwareUser instead of a User. I have to
> rewrite authenticate() as well. And I have to check the middleware to make
> sure it uses get_user() instead of returning a user itself.

For the record, when the developers ask you what *actual problem*
you're trying to solve, this paragraph is what they were asking for.
It generally helps to understand what you're trying to say, if we can
see exactly what you're facing, and how hard it is to get there.

-Gul

Reply all
Reply to author
Forward
0 new messages