"Linux Gazette...making Linux just a little more fun!"
Abstract
For those who haven't read the previous articles,
be sure to read the
statement of purpose first. This month, we're going to
discuss OO thinking. For those looking to read the whole series locally
or information about upcoming articles, you can check
the MST page. For those looking for further information
on learning Squeak, here are some
good resources.
This is the last planned article for this series.
The reader interest has been high enough for me to continue with the next
series, but unfortunately my available writing time has quickly dwindled
:-( as my wife nears her due date :-) So this will be the last regular
article at least for a while.
Quote of the day
Reason never changed a man's opinion which by reason he never acquired.
-- Mark Twain
OO Thinking
If you're just getting into OO from another programming
background, you'll soon realize that it requires a change in the way that
you think, the way you approach problems, and (IMHO) how much fun you're
having. This month, we go over some things to keep in mind when doing
OO programming.
Breaking Linear Thinking
This is the first hurdle I've seen many people trip
over. They're so used to programs with a main() routine of some sort,
that when they first dip their toes into the Smalltalk pool they're frightened
off by not being able to find a linear beginning, middle, and end of something.
Realize that Smalltalk is about working with a group of collaborating objects.
To be sure, you will need some entry point to your code/application, however
it likely be in the form of opening your starting window, then saving/stripping
your image.
Thinking of problems in terms of nouns and verbs
(objects and responsibilities) is a more natural way of thinking, and often
leads to a much different decomposition of the problem than functional
decomposition. Try to identify which objects are inherit to the problem,
which objects need to involved to help out, then think of the most basic
responsibilities and distribute them appropriately across the objects.
This leads us to our next item: OO programming
lends itself well to iterative development. It's a natural activity
to define the basic objects, then start adding basic relationships and
responsibilities. If you find something doesn't fit right, then shift
the responsibility elsewhere. Flesh out your objects and responsibilities
over time.
Try to use short methods to help maximize reuse
and maintainabilty. If you find yourself writing 100 line methods,
then you're still thinking linearly. The average method length varies
depending on whom you ask, but it should be short - somewhere around 8
statements or so. Of course, there's always exceptions to any rule
- this is just a rule of thumb.
Decision Making vs Commanding
This is what I often think is the most fundamental difference
between OO programming and procedural programming. In procedural
programming it's common to do things in terms of decision making.
You do things like:
-
if this, then that, else that
-
For example, if data is an integer and user input is a float, then convert
the float to an integer to add
-
for i = 1 to i = maxRange do this unless i > maxBounds, and if early
break condition is met then break out of loop
-
1 + 2 * 3 = ?
-
This example uses operator precedence, which is something that most languages
have. The statement is evaluated as: (1 + (2 * 3)) = 7. But
to determine precedence the language needs to make a decision which
operator to precede.
A common problem that arises from decision making programming
is that you have similar decision making being done in several parts of
a program. Then when requirements or needs inevitably change, there
are many different spots that you need to update/modify your program to
update all the decision making spots.
In OO programming, it's more common to do things
in terms of commanding. You command (or ask if you're polite) objects
to do things. If the object shouldn't do something, or should do
something differently, then it should know that. Since you ask different
objects the same thing, and they respond as each of them should, there's
no decision making. You do things like:
-
object doSomething
-
For example, it doesn't matter that you're adding a float to an int, the
float object knows how to add floats to itself, how to add ints to itself,
how to add fractions to itself.
-
aCollection do: [:eachElement | eachElement doSomething]
-
Notice how there are no bounds checking - a collection object already knows
how to do that and does it for you.
-
1 + 2 * 3 = ?
-
In this example, remember integers are objects too in Smalltalk (part of
the pure OO nature of Smalltalk). So we're asking the object 1 to
add itself to 2, then the resulting object to multiply itself by 3.
Hence, the statement is evaluated as: ((1 + 2) * 3) = 9.
-
As a side note, it's funny how often I've seen some of my C++ or Java coworkers
flee from Smalltalk because this doesn't make sense to them. They
still haven't entirely made the shift to OO thinking.
Don't Sweat the Details
I once heard Alan Knight remark that you know somebody
is starting to get Smalltalk if they answer the question: "How does
Transcript show: 'HELLO WORLD' work?" with: "I don't care".
A common theme among Smalltalk newbies is a need to know exactly how everything
works, and step through all the methods of the objects from the library
that they use. This is related to linear thinking, in that you need
to understand how a linear path flows to determine how it broke down the
road. If you find yourself sweating the details of the class library,
then you're probably still in linear thinking mode.
A related theme is that Smalltalk lends itself to
top-down coding. Put off work as long as possible and put off decisions
as long as possible - abstract and stub out reponsibilities if you can.
It's a powerful feeling to define even a trivial system that works, then
keep it working as you add real meat to it. You're most often in
a state of things working.
Simplification by Encapsulation
Try and group data together with appropriate operations
in an object. If you're acting directly on an object's data in some
manner, then you're breaking encapsulation. If you're doing something
like: anObject aDataAttribute aPartOfAttribute doSomething, then
you're breaking encapsulation.
A nice example of encapsulation is the looping noted
above. The collection class knows how many elements it has, and how
to loop over its elements, and you're not concerned with bounds checking
nor should you be.
Reuse
Opportunities for reuse abound, and not just from the usual place of inheritence
...through the class library
Before coding something, browse the class library to
see if it's already been done for you. Reinventing the wheel is definately
non-OO and wastes time.
Another rule of thumb for knowing when you're getting
Smalltalk is the proportion of time you spend browsing the class library
to the proportion of time you spend coding. As you gain experience
and familiarity with the library, your proportion of time will go down,
but for a beginner you should expect to spend the majority of your time
browsing the library and the minority of your time coding.
An appropriate remark I once heard (sorry, don't
remember the source), during a LOC metrics flame war is that Smalltalkers
should be measured by the LOC they don't write, as they're saving
time and maintentance costs by reusing the class library.
...through goodies
Smalltalk has a rich history and a great user community.
There may be a freeware or opensource goodie out there that will satisfy
your needs. Have a look at the UIUC
repository, or search the web or ask the newsgroups for goodies.
...by approrpiate responsibilities
If it isn't your reponsibility, then don't do it (or
redo it). Conversely, avoid responsibilities as much as possible
(only take the appropriate responsibilities). By trying to stick
to only appropriate responsibilities, then you're more likely to reuse
responsibilities elsewhere in the system.
For example, don't have the responsibility to login
to your application in your client's login GUI (a bad practice in general),
if you later have a web GUI, then you need to either copy the login logic
to your web GUI, or factor out the login code to a reusable object.
...through inheritence
Now we finally get to reuse through inheritence.
I leave this for last, as reuse through inheritence has been (IMHO) overhyped
and often overabused with needlessly deep class hierarchies that complicate
maintenance.
For example, if you're writing a hospital system
you'd probably want to reuse a Person's characteristics of firstName,
lastName,
and socialSecurityNumber by making subclasses of
Doctor and
Patient.
Distributing responsibilities
Watch out for bloated parts of system - you can see
this if you're drawing your system out and your diagram looks like an octopus.
This is a sign that there are too many responsibilities on one object,
and that object is going to get harder to maintain as it bloats.
You should try and have groups of peer objects collaborating.
Another warning sign is using a 'manager' object.
Again, there are perfectly good times and uses for a manager object, and
it can be difficult to determine if you're abusing a manager object.
I like to use a rule of thumb I heard from Alan Knight: object managers
should be like real world managers: they should not do any real work
- they should facilitate or manage interactions between other objects.
A Sweet Squeak
This month's sweet squeak is the release of Squeak 3.0! :-) To be
generic as possible, this description covers the scenario where you want
to run Squeak in Windoze or Linux. For this simple path install,
on Linux you will need root priviledges. (Note: you can install
without root privilidges if you're familiar with updating your paths, I'm
not going to cover that topic in this simple guide)
Step 1: Downloading Squeak 3.0
Go to the FTP site: ftp://st.cs.uiuc.edu/pub/Smalltalk/Squeak/3.0
and download:
-
Squeak3.0-win.zip, includes:
-
Squeak.exe, the virtual machine (only good for Windoze, we'll need
to compile a VM for linux)
-
Squeak3.0.image, (can use this on linux or Windoze)
-
SqueakV3.sources, (can use this on linux or Windoze)
-
Squeak-3.0pre2.tar.gz
-
Source files for compiling the linux VM
Step 2: Set a base directory to run squeak from
Assumes your Windoze mount point is /windoze, change for your system.
Note: if you don't have/want to run dual boot, just change
your install location to be whatever you desire, for example: ~myuserid/squeak3,
and delete the unnecessary files: NPSqueak.dll, Squeak.exe, SqueakFFIPrims.dll.
Make a /windoze/squeak3 directory
Unzip the Squeak3.1-win.zip file into a /windoze/squeak3
directory.
Step 3: Installing VM for linux
This is a very easy thing to do - even if you've never programmed
or compiled anything in your life before. Here are the steps:
-
Unzip Squeak-3.0pre2.tar.gz to wherever (be sure to unzip with directories,
this unzips into a Squeak-3.0 directory)
-
cd to where you unzipped the sources. (The BUILD.UnixSqueak
is a quick-n-easy guide from which these steps were condensed from)
-
mkdir build
-
cd build
-
../src/unix/configure --bindir="/windoze/squeak3"
-
make
-
make install (NOTE: here is where you'll need root privilidges
with the default install, as stuff is copied to /usr/lib, /usr/man, etc)
-
Here, you're going to get a couple of errors (unless you're installing
to a Linux location), as you can't make links on a Windoze file system
-
Copy the referenced files to your /windoze/squeak3 directory:
-
cp /usr/lib/squeak/3.0/squeak /windoze/squeak3
-
cp /usr/lib/squeak/3.0/inisqueak /windoze/squeak3
Step 4: Start Squeak :-)
-
cd /windoze/squeak3
-
squeak Squeak3.0final.image
...I'll leave starting up Squeak in Windoze as an exercise for the reader
;-)
Quick tour
When I started up the image for the first time, I was
pleasently surprised that the default GUI to come up is the newer morphic
GUI (as opposed to the older MVC GUI that was mentioned in Article 1).
For the read-along folks, you'll see (click on the below half size images
for full size images):
The entry screen. The Squeak logo in the top right is an xeyes
type of app, where the eyes follow the mouse.
If you put the mouse curor over the logo, you'll notice the pop-up balloon
help is enabled.
If you click on the project at the bottom right of the screen, it'll
zoom to full screen size as you enter it.
And finally, lets click on the music project to have a look.
Looking forward
Alas, there will be no immediate looking forward due
to my time constraints. The next series I was planning covers
some basic programming basics like: unit testing (SUnit), source
code management (change sets and SCAN), an object tour of commonly used
objects, control structures, and Squeaklets.
In the meantime though, I highly recommend
downloading v3.0 of Squeak (noted below) and trying out the STP goodies
as your first goodie exploration. They're available from: http://www.create.ucsb.edu/squeak/STP12.html
I've enjoyed learning about Squeak over the past
few months, and I hope you've enjoyed the series.
Smalltalk Code
Somebody pointed out to me that the ScopedBrowser used in Article 4 doesn't
work properly in Squeak v3.0, so here's an updated
version.
Note: I noticed that SUnit is now included as part of the base
image now, so I've included some programmatic unit tests. After loading
the code, if you wish to run the unit tests, do: TestModel openAsMorph,
then click the Run button. You'll notice 8 windows pop up
and close, and there shouldn't be any errors listed in the error pane.
Copyright © 2001, Jason Steffler.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 65 of Linux Gazette, April 2001