[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gump
Subject:    [RT] Gump3 design idea: small classes, many functions
From:       Leo Simons <mail () leosimons ! com>
Date:       2005-04-27 19:10:05
Message-ID: BE95B02D.2FBE4%mail () leosimons ! com
[Download RAW message or body]

Hi gang,

In Java, we have objects, and objects have methods and properties. Objects
are instances of classes, and classes have methods and properties too. When
we need to put properties or methods "somewhere else", we build stuff like
J2EE and JNDI.

In python, we have objects, and objects have methods and properties. Objects
are instances of classes, and classes have methods and properties too.
However, methods are also objects, which for example means that the
"flyweight" pattern or the "command" pattern doesn't make much sense in
python: just pass around a function representing the command instead of an
object. In python we also have modules which have methods (called functions)
and properties (called variables). When we would have needed to put
properties or methods "somewhere else", chances are we can put them inside a
module. We don't need J2EE or JNDI.

In java, it is customary to do "full-fledged" OOP which starts with the
basic mantra that "everything is an object". In python, "everything is an
object" already (except stuff like integers, just like with java), so you
don't have to worry about making that happen. In fact, you should explicitly
worry about minimizing the number of "objects" you create yourself, since
they're more expensive.

The trick is to only do Object-oriented design when you need it (ie we have
a Model which consists of ModelObjects like Module and Project, we have a
plugin model which consists of Plugins, we have a Database as an object
because we want to hold on to state (database settings and connection)
that's closely tied to a concise set of methods).

Another way to put it is to do less design. Find yourself writing a bunch of
code? The first place to put it is in a module-level function. Once you find
that you've got a set of functions that keep operating on the same data that
you keep passing around all the time, you have a class.

Yet another way to put it is to not use "utility classes" or static methods.
Use functions. I.e. Instead of

Mailer.py
---------
 class Mailer:
   def __init__(mailserver):
     assert mailserver != None
     self.mailserver = mailserver

   def send_email(from, to, subject, body):
     do_send_mail(self.mailserver, from, to, subject, body)

User.py
-------
 # init
 from Mailer import Mailer
 mailer = Mailer('mail.apache.org')

 # somewhere
 mailer.send_email('me', 'you', 'hi', "blaat")

 # somewhere else
 mailer.send_email('me', 'you', 'hi', "blaat")

Make sure to consider

Mailer.py
---------
 mailserver = None

 def send_email(from, to, subject, body, mailserver=mailserver):
   assert mailserver != None
   do_send_mail(mailserver, from, to, subject, body)

User.py
-------
 # init
 import mailer
 mailer.mailserver = 'mail.apache.org'

 # somewhere
 mailer.send_email('me', 'you', 'hi', "blaat")

 # somewhere else
 mailer.send_email('me', 'you', 'hi', "blaat")

Note that, in this example, one is easily transformed into the other in
userland code. The only bit that changes is the initialization code. Kewl
eh?

It's fun to see that I only figured this out a few weeks into writing Gump3.
Some of the newer stuff I wrote (in fact the code I'm writing now locally is
a nice example, but I'll show that when it works :-) is a nice example of
being closer to "getting it right". For example the executor.py module
doesn't bother with a "complete" OO way to do things. It recognizes we want
to kill some stuff before exit, so just has some module initialization code
that keeps that some stuff around until exit. The dirbuilder plugin uses
several utility functions (defined in gump.model.util, in fact) where in
java I would probably have used a static class method.

OTOH, the code I started with, the gump.engine, is very object-oriented for
no good reason. For example, the Engine class is basic procedural code
that's only ever run once. The same goes for the code in the modeller
module. Surprise surprise, this is also the code that is not well-tested,
hard to test, and hard to read. (To be fair, there's a lot of hard work
being done in the modeller code as well ;)

Heh. This stuff is pretty general. Should probably be writing a blog entry
instead :-). Too late!

Cheers,

Leo



---------------------------------------------------------------------
To unsubscribe, e-mail: general-unsubscribe@gump.apache.org
For additional commands, e-mail: general-help@gump.apache.org

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic