Questions about app design - OOP with python classes

A

adriancico

Hi

I am working on a python app, an outliner(a window with a TreeCtrl
on the
left to select a document, and a RichTextBox at the right to edit the
current
doc).

I am familiarized with OOP concepts and terms but I lack practical
experience
, so any comment/tip/pointer to docs will be welcome.

So far, I have created a separated class for each important
element of my app
- the main Frame (cFrmMain)
- the TreeCtrl
- the TextCtrl at the right
- a cDocument class that contains the entire file with all
docs
and manages creation/deletion/saving to disk, etc
- classes for the toolbar, the menubar, etc

With this design, pretty much everything is encapsulated in it
respective
class. However, that means that the main program logic is in the Frame
class.
From there, it instantiates the other classes and is responsable of
the
communication between them.

For example, the user deletes a node on the Tree, this raises an
event
on cFrmMain (the main Frame class). In the event handler, cFrmMain
notifies
cDocument that a node (and the associated text) has been deleted so
the master
file is modified accordingly.

The problem is, I have been implementing some funcionalities to
test this
design, I have less than a dozen operations implemented and cFrmMain
has grown
more than acceptable, starting to get confusing.

This design feels "not quite right" to me, I've been considering
allowing
the different classes to know of the existence of each other and pass
messages
between them. I would lose encapsulation (I think), and I don't know
if that would be
(very) bad... and I'm not sure if with this design I will gain or lose
clarity on the code.

My questions ( at last :) ) are:

¿Should I stick to my first design idea, eventually moving code
from the
main Frame to modules to gain clarity?

¿Is the second idea I present "correct" (I know it'll work, what I
want to
know is the clearest way of organize my code)?

¿Am I doing this wrong from the start and have to use another
design?

Thanks for reading this long post. Any comment, hint or pointer to
docs will
be greatly appreciated.

Regards
Adrián Garrido
 
B

Bruno Desthuilliers

(e-mail address removed) a écrit :
Hi

I am working on a python app, an outliner(a window with a TreeCtrl
on the
left to select a document, and a RichTextBox at the right to edit the
current
doc).

I am familiarized with OOP concepts and terms but I lack practical
experience
, so any comment/tip/pointer to docs will be welcome.

So far, I have created a separated class for each important
element of my app
- the main Frame (cFrmMain)
- the TreeCtrl
- the TextCtrl at the right
- a cDocument class that contains the entire file with all
docs
and manages creation/deletion/saving to disk, etc
- classes for the toolbar, the menubar, etc

As a side note : hungarian notation is usually considered bad form here.
Look here for usual naming conventions:
http://www.python.org/dev/peps/pep-0008/
With this design, pretty much everything is encapsulated in it
respective
class. However, that means that the main program logic is in the Frame
class.

What do you call "main program logic" exactly ?
the
communication between them.
>
For example, the user deletes a node on the Tree, this raises an
event
on cFrmMain (the main Frame class). In the event handler, cFrmMain
notifies
cDocument that a node (and the associated text) has been deleted so
the master
file is modified accordingly.
Ok.

The problem is, I have been implementing some funcionalities to
test this
design, I have less than a dozen operations implemented and cFrmMain
has grown
more than acceptable, starting to get confusing.
Ok.

This design feels "not quite right" to me,

Looks "almost right" to me !-)

Using the main frame as a mediator between the different widgets is a
well-known design pattern, named - suprisingly - mediator. The
motivation is that it avoid each and every widget to know about the
existence of every other widget. You may want to read about this pattern
- but note that most litterature about design patterns is expressed in
terms of statically typed languages (Java, C++ etc), and that dynamic
languages like Python usually don't need that much boilerplate and
complication (IOW : try to understand the pattern itself, not to blindly
apply it).

What's your looking for IMHO is the "controller" part - the one that
glue together the "view" (main frame and all it's widgets) and the
"model" (mostly, your document). Here again, googling for
"model/view/controller" (MVC) may be a good idea.
I've been considering
allowing
the different classes to know of the existence of each other and pass
messages
between them. I would lose encapsulation (I think),

At least this would introduce too much coupling between these classes.

Note that there's nothing Python-specific in your question. But since
comp.object is one of the worst places on earth to ask questions about OO...
 
A

adriancico

As a side note : hungarian notation is usually considered bad form here.
Look here for usual naming conventions:http://www.python.org/dev/peps/pep-0008/

Thanks for the tip. It's been too many years of VB6, and its difficult
to leave old habits
behind :)
What do you call "main program logic" exactly ?

What I mean is that in the frame code is where all decisions are
taken. The frame handles the
other controls events, decides what needs to be done, calls the
necesary methods of the other controls, etc. The other widgets just
"do the work" when called from the Frame. But this is not
necesarily bad, as you point out below.
Using the main frame as a mediator between the different widgets is a
well-known design pattern, named - suprisingly - mediator. The
motivation is that it avoid each and every widget to know about the
existence of every other widget. You may want to read about this pattern
- but note that most litterature about design patterns is expressed in
terms of statically typed languages (Java, C++ etc), and that dynamic
languages like Python usually don't need that much boilerplate and
complication (IOW : try to understand the pattern itself, not to blindly
apply it).

What's your looking for IMHO is the "controller" part - the one that
glue together the "view" (main frame and all it's widgets) and the
"model" (mostly, your document). Here again, googling for
"model/view/controller" (MVC) may be a good idea.

I understand (I've been in wikipedia :) ). Right now the Frame is the
controller as well
as the view. Moving out the "controller" code to another module seems
to me the
path to follow. I'll start to look out for MVC related material.

My problem was that, altough I knew OOP basics, I didn't know how to
apply them exactly. Thanks
for your answer, it has cleared many things.
Note that there's nothing Python-specific in your question. But since
comp.object is one of the worst places on earth to ask questions about OO....

I am developing in Python, so it made sense to me to post here. But
you are right, the question
is off-topic. Sorry for that.

Thanks again and regards
Adrián Garrido
 
B

Bruno Desthuilliers

(e-mail address removed) a écrit :
On Mar 1, 9:45 pm, Bruno Desthuilliers


I understand (I've been in wikipedia :) ). Right now the Frame is the
controller as well
as the view.

Yeps. Note that this is a common "simplification" of the MVC - Microsoft
labelled it "Document/View".

(snip)
My problem was that, altough I knew OOP basics, I didn't know how to
apply them exactly.

It mostly comes out of experience IMHO. But reading the GOF (I let you
google for what this TLA refers to !-) may not be a bad idea - it's
probably the best book about OO design I've read so far, even if lot of
the described patterns make less sens in an highly dynamic language like
Python.
I am developing in Python, so it made sense to me to post here. But
you are right, the question
is off-topic. Sorry for that.

Alas, the appropriate newsgroup (comp.object) has turned into one of the
most unfriendly and sterile places I know on the net.
 
S

Steven D'Aprano

As a side note : hungarian notation is usually considered bad form here.
Look here for usual naming conventions:
http://www.python.org/dev/peps/pep-0008/

Which Hungarian notation do you mean?

If you mean the Windows "Systems Hungarian", where the prefixes on
variable names is just an underpowered, manual and redundant type system,
then you're right.

But if you mean the original "Apps Hungarian", where prefixes are used to
indicate semantic KINDS of data (e.g. distances in inches versus distances
in millimetres) then I think Joel Spolsky makes a good defence of Apps
Hungarian.

http://www.joelonsoftware.com/articles/Wrong.html

Some years ago, an expensive Mars lander crashed into the planet because
somebody mistakenly compared inches to millimetres. They had done
something conceptually like this:


# we use Systems Hungarian, or a type system that knows about floats
# get the distance to the surface of the planet in millimeters
fpCurrentHeight = radar_unit.get_height_above_planet() # a float
#
# ... many lines of code ...
#
# get the critical height in inches at which we need to engage
# the retro-rockets
fpCriticalHeight = calculate_height(speed, fuel, mass) # also a float
#
# ... many more lines of code ...
#
if fpCurrentHeight <= fpCriticalHeight:
# safe because both objects are floats
engage_the_retro_rockets()


A type system doesn't help. So what if they're both floats? The test
is still bogus, your code will still wait too long to engage the
retro-rockets, and the billion dollar space craft will still be travelling
at hundreds of miles an hour when it reaches the surface of Mars.

Oops.

But if you used Apps Hungarian, and saw this line of code:

if hmmCurrentHeight <= hinCriticalHeight:

then you should instantly recognise that there's a problem. Comparing
a height in millimetres to a height in inches is not a good thing to do,
no matter that they're both floats.
 
P

Paul Rubin

Steven D'Aprano said:
But if you used Apps Hungarian, and saw this line of code:

if hmmCurrentHeight <= hinCriticalHeight:

then you should instantly recognise that there's a problem. Comparing
a height in millimetres to a height in inches is not a good thing to do,
no matter that they're both floats.

That still sounds like an unreliable manual type system, instead of an
automatic type system that includes dimension analysis. You might
like this:

http://futureboy.homeip.net/frinkdocs/

There are many Python implementations of dimensioned units as well. I
posted one here a few weeks ago.
 
S

Steven D'Aprano

That still sounds like an unreliable manual type system,

It's unreliable in the sense that the coder has to follow the naming
convention, and must have some bare minimum of sense. If your coders are
morons, no naming convention will save you. (For that matter, nothing will
save you.)

instead of an
automatic type system that includes dimension analysis. You might
like this:

http://futureboy.homeip.net/frinkdocs/

There are many Python implementations of dimensioned units as well. I
posted one here a few weeks ago.

Sure, and I love the Unix utility "units", and my HP calculator.
Dimensioned units are useful.

But dimensioned units are still only part of the story. Joel describes the
situation the early Word developers found: when you're writing a word
processor, you are doing a LOT of conversions between screen coordinates
and window pane coordinates. Both have the same type (a pair of ints),
both have the same dimensional units (length/pixels) but they are
semantically different. If you place the character "N" at coordinates 0,0,
it makes a big difference if the coordinates are relative to the current
window or relative to the screen.

Apps Hungarian is a heuristic for dealing with semantic differences, not
data types. It deals with more than just dimensional analysis.
 
E

Erik Max Francis

Steven said:
A type system doesn't help. So what if they're both floats? The test
is still bogus, your code will still wait too long to engage the
retro-rockets, and the billion dollar space craft will still be travelling
at hundreds of miles an hour when it reaches the surface of Mars.

It was units of momentum that were inappropriately compared, actually.
(And it broke up before hitting the ground, but that's a minor quibble.)
 
P

Paul Rubin

Steven D'Aprano said:
It's unreliable in the sense that the coder has to follow the naming
convention, and must have some bare minimum of sense. If your coders are
morons, no naming convention will save you. (For that matter, nothing will
save you.)

Well, type systems in programming languages have generally proven more
reliable and easier to deal with than having programmers track it all
manually-- that's why we don't all write in Forth ;-).
But dimensioned units are still only part of the story. Joel describes the
situation the early Word developers found: when you're writing a word
processor, you are doing a LOT of conversions between screen coordinates
and window pane coordinates. Both have the same type (a pair of ints),
both have the same dimensional units (length/pixels) but they are
semantically different. If you place the character "N" at coordinates 0,0,
it makes a big difference if the coordinates are relative to the current
window or relative to the screen.

You're right that this is not exactly dimensional analysis, but it
still seems to call for types and conversion functions, rather than
naming conventions. I guess they were writing that stuff in C++, so
I'd have expected the compiler to handle the conversions through casts
with no runtime cost except when an actual conversion was needed. In
Haskell I believe it would be similar.
 
D

Dennis Lee Bieber

I understand (I've been in wikipedia :) ). Right now the Frame is the
controller as well
as the view. Moving out the "controller" code to another module seems
to me the
path to follow. I'll start to look out for MVC related material.
Maybe take a look at Dabo -- even if not for your application, a
quick & dirty form generation using it should show how /it/ splits the
MVC logic...
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
D

Diez B. Roggisch

A type system doesn't help. So what if they're both floats? The test
is still bogus, your code will still wait too long to engage the
retro-rockets, and the billion dollar space craft will still be travelling
at hundreds of miles an hour when it reaches the surface of Mars.

A type system _could_ help. Multi-Level-Specification allows you to
express physical quantities with their respective unit, and operations
on them to yield the combined unit at compile-time. There are some
rather complicated cases where simple unification won't solve the
type-equations, but then you might annotate things explicitly.

Diez
 
B

bruno.desthuilliers

Which Hungarian notation do you mean?

If you mean the Windows "Systems Hungarian",

Yes. And don't tell, I know it's a totally braindead application of a
somewhat less braindead idea.
 
G

GHUM

if hmmCurrentHeight <= hinCriticalHeight:
then you should instantly recognise that there's a problem.

all civilized nations but one use metric systems. Of course there is a
problem if you spot inches somewhere.

Harald
 
M

MRAB

It's unreliable in the sense that the coder has to follow the naming
convention, and must have some bare minimum of sense. If your coders are
morons, no naming convention will save you. (For that matter, nothing will
save you.)


Sure, and I love the Unix utility "units", and my HP calculator.
Dimensioned units are useful.

But dimensioned units are still only part of the story. Joel describes the
situation the early Word developers found: when you're writing a word
processor, you are doing a LOT of conversions between screen coordinates
and window pane coordinates. Both have the same type (a pair of ints),
both have the same dimensional units (length/pixels) but they are
semantically different. If you place the character "N" at coordinates 0,0,
it makes a big difference if the coordinates are relative to the current
window or relative to the screen.

Apps Hungarian is a heuristic for dealing with semantic differences, not
data types. It deals with more than just dimensional analysis.
Basically what you want are dimensions such as "screen coordinate" and
"window coordinate" as well as "pixel", and also other kinds of
dimensions which combine differently. For example:

The dimension "pixel" works one way and the dimensions "relative to
screen" and "relative to window" work a differnt way.

If:

p is a point relative to the screen: integer, <pixel>,
+<relative to screen>

q is a point relative to the window: integer, <pixel>,
+<relative to window>

r is the window relative to the screen: integer, <pixel>,
+<relative to screen>, -<relative to window>

then:

p = q + r

<pixels> = <pixels> + <pixels>

<relative to screen> = <relative to window> + (<relative to
screen> - <relative to window>)
 
S

Steven D'Aprano

A type system _could_ help.

It's easy to wave your hands and say that Microsoft could have done
something different, but they had to work with what they had, not some
hypothetical alternative language with a hypothetical type system that
didn't exist then (if it even exists now).

Multi-Level-Specification allows you to
express physical quantities with their respective unit, and operations
on them to yield the combined unit at compile-time. There are some
rather complicated cases where simple unification won't solve the
type-equations, but then you might annotate things explicitly.

Which is what Apps Hungarian _is_.
 
P

Paul Rubin

Steven D'Aprano said:
Which is what Apps Hungarian _is_.

I think the idea is that the compiler can still check that your
annotations are correct, or at least consistent, even if it can't
solve the equations itself. Hungarian notation is a variable naming
convention which can be followed manually but which the compiler makes
no attempt to enforce.

Diez, can you suggest any online references about MLS?
 
S

Steven D'Aprano

Well, type systems in programming languages have generally proven more
reliable and easier to deal with than having programmers track it all
manually-- that's why we don't all write in Forth ;-).

Apps Hungarian is NOT a type system.

Systems Hungarian is. It is pointless: an inefficient, manual nuisance
that redundantly does what the type system already does. Even Microsoft
agrees with that now.

Unless there is a type system that can automatically deal with the
semantic difference between (say) screen coordinates and window
coordinates, or between height and width, or safe and unsafe strings, the
coder still has to deal with it themselves.

And even if there is such a type system, Python isn't it.

[snip]
You're right that this is not exactly dimensional analysis, but it still
seems to call for types and conversion functions, rather than naming
conventions.

The problem with types is that as far as the compiler is concerned, the
objects are the same type. Of course it needs conversion functions.

Now maybe you could argue that what Microsoft needed was a different
language instead of C. Maybe so, but they were working with what they
had. Just as we're working with Python.

The point I'm trying to get across isn't that Apps Hungarian is the best
imaginable solution to the problem of dealing with semantically different
kinds of data. But it is an easy solution that works quite well (not
perfectly) and (unlike relying on Haskell's type system) it can be
applied to Python quite easily.
 
P

Paul Rubin

Steven D'Aprano said:
Unless there is a type system that can automatically deal with the
semantic difference between (say) screen coordinates and window
coordinates, or between height and width, or safe and unsafe strings, the
coder still has to deal with it themselves.

And even if there is such a type system, Python isn't it.

Python uses runtime typing, so you'd define classes for screen and
window coordinates, and have them do appropriate conversions or raise
exceptions when you do mixed operations. The compiler wouldn't notice
this happening at compile time, but that's just like the rest of
Python.
The point I'm trying to get across isn't that Apps Hungarian is the best
imaginable solution to the problem of dealing with semantically different
kinds of data. But it is an easy solution that works quite well (not
perfectly) and (unlike relying on Haskell's type system) it can be
applied to Python quite easily.

I think the notion above fits ok into Python's dynamic typing scheme.
Yeah, you may get runtime exceptions at unexpected times due to type
conflicts that you overlooked in testing, but again, the Pythonic
prescription for these and other errors seems to be "write more tests".

Maybe we can concoct a cross between Python and Haskell, and call it
"Paskell" after the philosopher Blaise ;-).
 
D

Dennis Lee Bieber

Unless there is a type system that can automatically deal with the
semantic difference between (say) screen coordinates and window
coordinates, or between height and width, or safe and unsafe strings, the
coder still has to deal with it themselves.

And even if there is such a type system, Python isn't it.
Though a full typing in Ada could support it (and someone would have
to code all the valid combinations... Like height*width=>area?
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
J

John Nagle

Steven said:
It's easy to wave your hands and say that Microsoft could have done
something different, but they had to work with what they had, not some
hypothetical alternative language with a hypothetical type system that
didn't exist then (if it even exists now).

The Pascal/Ada/Modula family of languages all had type systems
with restrictions on conversion. Unlike C, types in Pascal
are not simply abbreviations of the type; they're unique types.

This turns out to be too restrictive, but it's certainly been
tried.

There are C++ class libraries that understand units. And
the conversion factors can be dealt with at compile time, so
the overhead goes away.

John Nagle
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top