My Stuff
Love
Respect
Admiration
My Amps
Links
Archives


Add this feed to a running copy of BottomFeeder

Linux World 2006 Speaker

Thursday, September 29, 2005

Omaha Ruby User's Group

 
It's time to hold another great meeting of the Omaha Ruby User's Group. We'll be discussing Rails, Ruby, dynamic languages, and anything else we can think of. So bring your favorite pieces of Ruby code and your curiousity. Hope to see a lot of people there! Make sure you sign up on the mailing list. Here's the information of the when and where:

    When:October 3, 2005
    Where:Panera @ Eagle Run Shopping Center
    13410 West Maple Road
    Omaha, NE 68164

Comments

What He Said

 
I couldn't have said it better myself.
From Vincent Foley:
I compared dynamic languages and Java with riding a bike; in dynamic languages, you ride on two wheels and you get where you want pretty quickly. You can fall if the road is slippery, if you hit a rock or something, but with a little experience, these cases rarely occur. On the other hand, riding a Java bike is like having 8 wheels to make sure you don’t fall over, 10 people constantly around you, ready to catch you should you fall. You may be safer, but you’re not getting places faster than the dynamic biker.


Right on! Can I get an amen?

Comments

Monday, September 26, 2005

How not to make money

 
On the first visit to your site, I get this:
Mod_python error: "PythonHandler mod_python.servlet"

Traceback (most recent call last):

File "/usr/local/lib/python2.4/site-packages/mod_python/apache.py", line 299, in HandlerDispatch
result = object(req)

File "/usr/local/lib/python2.4/site-packages/mod_python/servlet.py", line 1464, in handler
servlet.prep()

File "/home/hosting/users/metald/web/index.mps", line 23, in prep
SitePage.prep(self)

File "/home/hosting/users/metald/lib/pages.py", line 42, in prep
HTMLPage.prep(self)

File "/usr/local/lib/python2.4/site-packages/mod_python/servlet.py", line 593, in prep
timeout=self.session_timeout)

File "/usr/local/lib/python2.4/site-packages/mod_python/Session.py", line 389, in Session
timeout=timeout, lock=lock)

File "/usr/local/lib/python2.4/site-packages/mod_python/Session.py", line 294, in __init__
timeout=timeout, lock=lock)

File "/usr/local/lib/python2.4/site-packages/mod_python/Session.py", line 132, in __init__
Cookie.add_cookie(self._req, self.make_cookie())

File "/usr/local/lib/python2.4/site-packages/mod_python/Session.py", line 160, in make_cookie
c.path = dirpath[len(docroot):]

TypeError: unsubscriptable object

Ouch...Talk about bad first impressions. This is what happened when I tried to go to Metal Direct. I guess they don't like customers.

Comments
  • I'm guessing this is why Ruby on Rails has such a strong emphasis on testing ;)

    By Vincent Foley, at 6:43 PM   

  • Must have been another quality job by the A-Kids.

    By Rusty, at 6:45 AM   

Sunday, September 25, 2005

Private: The Enemy of Extensibility

 
I was shocked to find out tonight that junit.runner.ClassPathTestCollector didn't account for tests in jars. OK, easy enough. I look through the class and find a methood called gatherFiles(File,String,result). It takes a file and determines if it is a test class. Well, a simple check to see if the file is a jar, add the class names of the entries which are tests to the result, and we were in business, right? Well, that's what I thought! So, I overrode gatherFiles, added super to let it do its job, and then, added my jar functionality. Simple right?! It didn't compile. It seems gatherFiles is a private method and I didn't have any visibility for the super. OK, I then just copied the original gatherFiles in place of the super and a little gentle refactoring. Everything compiled, but it worked like the old one. It then struck me. You can't override private methods. GRRRRRR! So, I wound up copying the remaining methods that I needed and removed ClassPathTestCollector as my superclass. It shocked me to know what should have been a simple refactoring, turned into a lot more, and it forced me to commit the worst of all sins: Duplicate code. Oh, did you want to see the jar code? Here you go:

protected void gatherFilesInJar(File jarFile, Hashtable result) {
try {
JarFile jar = new JarFile(jarFile);
try {
Enumeration enumeration = jar.entries();
while (enumeration.hasMoreElements()) {
JarEntry next = (JarEntry) enumeration.nextElement();
if (next.getName().endsWith(".class") && next.getName().indexOf('$') == -1) {
addToResultsIfTest(next.getName(), result);
}
}
} finally {
jar.close();
}
} catch (IOException ex) {
//DO NOTHING
}
}

Nothing to it! Anyway, it was a fun bit of functionality to add, so that I can find and add all of my tests in my project now. I ran into these issues with private in Swing as well. I just think as designers we should not close our classes. The reason is because you never know what someone might need to do with your code eventually. Sealing means you know best. Just like I wanted to be able to handle jars in ClassPathTestCollector. If the original designer had thought of that, then he/she would have added that capability. Instead, they sealed off the class and forced me to sin. Don't make the same mistake.

Comments

Thursday, September 22, 2005

Want To See Beautiful Code?

 
Comments
  • Hi Blaine,

    Check out the 3rd Ruby on Rails podcast. http://podcast.rubyonrails.org/

    Tobias Lütke talks about code beauty being very important. I thought it was a good podcast where content is concerned but a little painful to ear where production quality is concerned.

    Adios.

    --Mel

    By Mel, at 10:55 AM   

  • I found the quote "As speed of development approaches infinity, reusability becomes irrelevant." more telling.

    It helps explain why Squeak changes take more time than expected; making sure reusability still works for everyone.

    I've suspected that something like Intentional Programming or Rule-based programming might overtake OOP for speed of understanding, modeling, & creation. Code as text, how quaint.

    By Socinian, at 1:06 PM   

Tuesday, September 20, 2005

Private Testing

 
David Buck and Charles Monteiro have been discussing how to make sure "private" methods in Smalltalk stay "private". Both have great techniques and it of course got me to thinking: "What a great use for unit tests!"

In all Smalltalks, we categorize methods of a class. Why not mark the private methods in some way? For example, use "private" somewhere in the category name (private, private-processing, private-accessing, etc). This way we know what should be private and what shouldn't be. It doesn't matter the convention just pick one. Now, that we know the private methods, create an object proxy that forwards all calls to the real object. This proxy would check if the method coming in is "private" and signal an exception if a method is "private" since only outside objects will call the proxy directly (Everything else will behind the proxy wall). Now, just pass the proxy around in the unit test as if it were the real object. Let the unit tests verify that we are not calling "private" methods and we have no run-time costs. Of course, we could get fancy and use method wrappers and #become:, but I will leave that as an exercise to the reader (or maybe a future blog entry?).

The main point of this post was to give yet another idea of how to make sure private methods stay private. I would love to hear more techniques. This technique that I just described is what I call meta-unit-tests. We are verifying meta-information about our program. I've used meta-unit-tests for making sure deprecated API calls are not sent in my code and that certain methods are implemented (ie don't have super that calls #shouldBeImplemented). We have a lot of information available to us at unit test time. We can take advantage of it!

Comments
  • If you have some kind of pragmas or method annotations support, you could put this information in those.

    By Giovanni Corriga, at 4:00 AM   

  • YES! This is why I suggested categories, but left it open. Since in Smalltalk, you can get to everything, there is a CompiledMethod object. You can ask all kinds of questions. You could even put #private in your method and look for the literal #private. I know there are extensions to various Smalltalks that add annotations. The Tweak framework in Squeak makes extensive use of annotations. No changes to the language. You just change some code and voila you have annotations. It's great having an extensible language!

    By Blaine, at 8:20 PM   

  • could get more fanciful - change the compiler to look whether a method is messaging methods in the "private" category
    i am a little doubtful though at introducing tthe concept of private versus public in a language like Smalltalk. it is a very static concept and IMHO seems to go against a very basic Smalltalk axiom - trust the developer.
    having said that, an external tool (maybe as part of a code critique package ?) which advises on possible inappropriate usage based on category might make sense

    By Anand, at 9:56 AM   

Re: Dolphin's Command Framework

 
I got a comment from Anand that suggested that I change this code:
CommandMessageSend>>queryCommand: query 
| canSelector |
canSelector := ('can' , query command selector capitalized) asSymbol.
^(self receiver respondsTo: canSelector)
ifTrue:
[query
isEnabled: (self receiver perform: canSelector);
receiver: self receiver.
true]
ifFalse: [super queryCommand: query]

to:
CommandMessageSend>>queryCommand: query
| canSelector isEnabled |
canSelector := ('can' , query command selector capitalized) asSymbol.
[isEnabled := self receiver perform: canSelector]
on: MessageNotUnderstood
do: [:ex | ^super queryCommand: query].
query
isEnabled: isEnabled;
receiver: self receiver.
^true

We got rid of the ifTrue:ifFalse: and the code is clearer. But, something bothered me about it. The MessageNotUnderstood could catch any MessageNotUnderstood further down in the stack (it might not be my canCommandSelector). What is a Smalltalker to do? How about this:
Object>>perform: aSelector onNotUnderstoodDo: aBlock
^[self perform: aSelector]
on: MessageNotUnderstood
do: [:ex | (ex receiver == self and: [ex selector == aSelector])
ifTrue: [aBlock value]
ifFalse: [ex pass]]

This message allows us to do the perform, but check to make sure it's the one we care about. Now, our CommandMessageSend code looks like this:
CommandMessageSend>>queryCommand: query
| canSelector isEnabled |
canSelector := ('can' , query command selector capitalized) asSymbol.
isEnabled := self receiver perform: canSelector onNotUnderstoodDo: [^super queryCommand: query].
query
isEnabled: isEnabled;
receiver: self receiver.
^true

The code is about the same, but now we are only catching the MessageNotUnderstood exception that we care about and not any others. The code is still clean and we see another example of the power of Smalltalk exceptions. And I would like to thank Anand for the suggestion!

Comments
  • this looks good and safe.
    small nitpick (my apologies for being so)
    in onNotUnderstoodDo: the ifTrue: part can be just ifTrue: aBlock rather than ifTrue: [aBlock value]
    same result; one less block evaluation. or am I missing something ?
    Regards
    Anand

    By Anand, at 1:13 PM   

  • I actually I thought about it, but decided not to because I've noticed it freaks out some programmers because they're used to seeing that extra block. So, to make it more readable, I optted for the ifTrue: [aBlock value] instead of ifTrue: aBlock instead. You are right though. It is one more block evaluation that is unneeeded. I often err on the side of readability, but it is subjective. Your mileage may vary.

    By Blaine, at 5:55 PM   

  • this got me thinking of cases where
    [[aBlock value]]value would be different from [aBlock] value.
    if i had subclassed Block and if my class had overridden value to say return another block; the above would cause an issue ?

    pretty contrived example i know
    i shud go do a quick check

    By Anonymous, at 10:06 AM   

  • Blaine,

    I tried to get this to work with Menus and ContextMenus in the ViewComposer, without success.

    Could you give us a for dummies description how to do that?

    Thanks,

    Günther, guenni

    By Günther, at 4:11 PM   

Monday, September 19, 2005

Oh Lucky Day

 
I pre-ordered Coheed and Cambria's "Good Apollo, I'm Burning Star IV" and it arrived a day early this morning. I immediately popped it into the player and was just floored. Great rock music from start to finish. I hear bits of The Cars, Led Zeppelin, Iron Maiden, and a whole bunch more. This is the way power pop is supposed to be. Oh yeah, they get the prog punk tag, but this is just wonderfully written music period. I haven't been this excited by a new band in a long time. I love the way they write incredibly catchy music that you never grow tired of hearing.

And then the mail man arrived with two more packages. I received Clutch's "Robot Hive/Exodus" and 3's "Wake Pig". Oh My God! I've never been blessed with this much good music in one day ever! Clutch is a mix of funk and stoner rock that pleases and 3 is like a blender of styles that just simply works. I guess progressive pop punk would be a tag, but you just have to listen to it.

All 3 albums are incredible slab of originality. Did I mention that they were great. Man, my ears are worn out! If anyone thinks that good rock music died in the 90's or you've been having a hard time looking for original great music. Look no further than these bands!

Comments

Great Advice

 
I have to apologize, but I have to pimp "Streamlined Object Modeling" yet again.
Personify Objects
Object model a domain by imagining its entities as active, knowing objects, capable of performing complex actions.
Talk Like an Object
To scope an object's responsibilities, imagine yourself as the object, and adopt the first-person voice when discussing it.
Do It Myself
Objects that are acted upon by others in the real world do the work themselves in the object world.

Live it, be it, model it! Let the design flow!

Comments
  • Ahh, my little friend... the design of the small pieces and their chaotic interactions is essential for the system as a whole to have interesting emergent properties.

    We, as well, are much more modest than we think --- just a cog in the machinery. Fortunately, there's the butterfly effect that sensitive cogs can use to prevent authority from forcing your teeth to some particular shape. Same deal.

    By Andres, at 9:52 PM   

Smalltalk Unreadable? Huh?

 
Spotted this quote in JavaLobby via James Robertson:
Have you ever tried to go back an make significant changes to a large Smalltalk application that you haven't touched the code for in 3-5 years or maybe didn't even a part in writing? Try that some time if you haven't and then tell us what you think of Smalltalk. If a language can't pass that battle test, it sucks. IMO, Java passes that test very well, much better than Smalltalk or C/C++.

OK, I've been there and done that with both Java (revisited old code from 3 years ago) and Smalltalk (revisited old code from 5 years) code bases. Now, both of the code bases were written by me and I didn't have a problem getting back into the code with either one. If you have well-defined names and intention revealing code, then it's NEVER a problem.

But, to get up to speed on existing code that I didn't write is another issue. I find Smalltalk to be easier than any language I've ever dealt with. It generally takes me no time to get up to speed with unknown Smalltalk code. Hell, I've been having a blast going through all of the Dolphin code recently. But, I've had my fair share of problems understanding Java code written by other programmers. And most of the reasons have nothing to do with language. It's mostly a matter of writing intention revealing code. Something that most good coders do unconsciously. I've seen my share of bad code in Perl, C, C++, Java, etc. But, I will say this, I find bad code in Smalltalk is much easier to read and understand. Since there's less rules, there's less to get messed up.

Anyway, it's amazing me that we are still having these discussions. Pick the language you love and write code. Stop whining about everyone else's. Each language has its strengths and weaknesses. I choose Smalltalk because it makes me more productive. If Java or Perl makes you more productive, then go write code in it! I do try to sell Smalltalk, but I don't believe in doing it at the expense of putting down another. I think Ruby, Smalltalk, Lisp, etc attacts a different kind of programmer than Java. And that's cool. There's nothing wrong with it. Now, let the Smalltalk flow!

Comments
  • Some people would learn a lot from reading Kent Beck's "Smalltalk Best Practice Patterns". The emphasis of the book is on communication, which I think is something that people often forget. Everything from using intention revealing names for classes, protocols, methods and variables to using the correct collection class for a given case help make Smalltalk readable and understandable by someone picking up the project. And those patterns are not all specific to Smalltalk: picking good names and extracting components to classes does help in any language.

    By Vincent Foley, at 8:15 AM   

Sunday, September 18, 2005

Dolphin's Command Framework

 
When I first started to play with Dolphin's MVP framework for building GUIs, I thought it was interesting. It forced you to keep all of the controller code in the presenter. The view was only responsible for view things, the presenter was the glue, and the model was where all of the magic occured. But, there was one thing that bothered me and that's how you used the command framework. From the examples, you override the #queryCommand: method in your Shell. Well, you ended up with code like this which I absolutely hate (BTW, this is taken from my first MVP application):
queryCommand: aCommandQuery

| command |
command:=aCommandQuery command.
(#(File Agents Help about) includes: command)
ifTrue: [^aCommandQuery beEnabled].
command == #saveAgentTape
ifTrue: [^aCommandQuery isEnabled: self tape name isEmpty not].
command == #recordPressed
ifTrue: [^aCommandQuery isEnabled: self tape canRecord].
command == #stopPressed
ifTrue: [^aCommandQuery isEnabled: self tape canStop].
command == #playPressed
ifTrue: [^aCommandQuery isEnabled: self tape canPlay].
command == #pausePressed
ifTrue: [^aCommandQuery isEnabled: self tape canPause].
command == #generateJavaScript
ifTrue: [^aCommandQuery isEnabled: self tape canConvertToScript].
^super queryCommand: aCommandQuery.

YUCK! If you go searching through the code, you find CommandPolicy, Command, CommandQuery, etc and I thought to myself, "Why did they create so many objects if the code turns out like the above?" The answer is the framework is smart and has a lot of parts to it. So, I browsed the implementers of #queryCommand: and I found an interesting class that implemented it: AbstractMessageSend! Well, the interesting thing is that normally you add commands as symbols to the CommandDescription for things like Buttons and MenuItems. But, you don't have to. You can put any object that understands #forwardTo:! And if you add #queryCommand: to your object to use as your command, then you can allow the command to decide when to enable/disable itself! So, I whipped up a little CommandMessageSend that disables/enables itself by calling a canCommandName method if it exists to know when to disable/enable the command in the menu.

MessageSend subclass: #CommandMessageSend
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
classInstanceVariableNames: ''

CommandMessageSend>>queryCommand: query
| canSelector |
canSelector := ('can' , query command selector capitalized) asSymbol.
^(self receiver respondsTo: canSelector)
ifTrue:
[query
isEnabled: (self receiver perform: canSelector);
receiver: self receiver.
true]
ifFalse: [super queryCommand: query]
CommandMessageSend>>command

^self

Now, instead of adding a symbol, I add this object. I now no longer override the #queryCommand: method in my Shell class! And the code from above no longer exists! No more case like if statements! It turns out that the Dolphin guys came up with really nice Command framework that works its way from the Command object itself and works it's way asking at each level of Presenters until it reaches the Shell. I can understand doing the simplest possible thing from the examples, but it doesn't show the power that they have given you. There's also a undo/redo framework for your code to take advantage of. Just browse references to the Command class. Fire up those browsers and start looking at that code! Dolphin has a lot of cool frameworks inside (look at DeferredValue for more fun).

Comments
  • how about something along the lines of
    [self reciever perform: canSelector]on: MessageNotUnderStood
    do:[:ex | ^ super queryCommand:query]
    Since you are doing a #respondsTo: anyways, this is not any worse off performance wise. Will help eliminate the ifTrue:ifFalse: block ...

    By Anand, at 9:18 AM   

  • I should have used this. The only issue might be what if you get a MessageNotUnderstood that you were not expecting (like in your canDoSomething method). But, you could easily check the receiver to be yourself and the right selector in another method...Hmmm, that sounds like another blog entry. Thanks for the suggestion! I'm putting it in my code right now!

    By Blaine, at 9:40 AM   

  • reminds me of a challenge someone once threw out. What is the largest body of code you can write without using ifTrue:ifFalse: ? He had a particular disdain for the construct - procedural in his opinion.
    Thoughts ? does "extreme" polymorphism + using exceptions as would result with the elimination of ifTrue:ifFalse : and other such a good thing ? under what circumstances ?.
    this guy was really good. another very good seat of the pants metric he had - if i need to scroll to read your method - you have a problem

    By Anand, at 10:06 AM   

  • I like to be pragmatic. I try not to use ifTrue:ifFalse:, but in a lot of cases you have to. It all depends on the case.

    As for scrolling your method and you have a problem, well, I think that's a great goal to achieve. I agree that if your method is long enough to scroll, then you're probably doing too much in it. And that goes for any language.

    By Blaine, at 12:13 PM   

  • Personally, I've always hated the notion of constructing selectors on the fly. You have to explicitly manage the methods when packaging, or they'll get stripped, and if you happen to refactor the need for them out of existence, there's no easy way to tell that the code isn't being used anymore. Anyone else looking at the code won't easily know where they're being used, either.

    By Tom K, at 7:38 PM   

  • Generally, I would agree with constructing selectors on the fly. But, if it's by convention, then I'm all for it. I could have given a block to the CommandMessageSend to ask isEnabled instead. Both have their merits and drawbacks. I like convention because it makes reflection nice.

    By Blaine, at 8:11 PM   

Wednesday, September 14, 2005

I Got The Power

 
I've been spending an hour here and there on a mp3 file management system for myself in between on working on some of my other projects. It's basically so I can move files from my local file system, iRiver, and iShuffle. I've been writing it in Dolphin and having a great time. It's meant to be simple and I add features as I find things annoying. So, a production system it is not. Well, I decided to add drag/drop capability so I could do all my file operations within it. I've done drag/drop in several languages and environments in the past and I must admit Dolphin was the easiest. I looked at a few examples from the development environment and I had it all working within a couple of hours. WOW. I didn't even read any of the documentation. Most of my time was actually spent in the domain getting everything working just right. Most drag/drop frameworks I've used in the past are just a pain in the butt. I was simply amazed. Yet, another example of how nice Dolphin really is.

Comments

Ruby On Rails

 
Word on the street is that Sam Tesla gave a tasty sermon on Ruby On Rails at the Omaha Smalltalk User's Group last night. I couldn't make it because of work committments so I guess he's going to have to do it over at the next Ruby User's Group....=) He made a pdf available, so there's no reason not to enjoy its brilliance. Why do I always miss the good stuff?

Comments
  • You know. Some of your coworkers showed up for my talk. Why was it that you couldn't make it again ;)

    It was a lot of fun, I'll have to do something like it at the next Ruby meeting for sure.

    By Samuel Tesla, at 10:54 PM   

Monday, September 12, 2005

Squeak Foundation

 
Towards an acting and communicating core for Squeak. I think this is a wonderful new development in the Squeak community. It's been a long time coming. I love the following quote too:
We will follow the chicken and pig Scrum metaphor: Doers or Core will have the power to do something and talkers will be less considered, even if we will listen to them.

It seems process is getting in place to fund and direct energy in the Squeak community. I think this is exciting! I would like to thank everyone involved in this. Let the Squeak flow!

Comments

Saturday, September 10, 2005

Omaha Smalltalk User's Meeting

 
This month we will be doing a two fisted meeting! First up, we will show the brilliant Avi Bryant Seaside demo from the Vancouver Lisp Meeting. Then, Sam Tesla has been kind enough to show us Ruby and Ruby On Rails. So, it's going to be a meeting not to be missed!

Here's all of the details:

When: September 13, 2005, 7pm - 9pm
Where: Offices of Northern Natural Gas
1111 S 103rd Street
Omaha Nebraska 68154

Office is at 103rd & Pacific. Guests can park in the Northern visitors parking area back of building, or across the street at the mall. Enter in front door, we'll greet you at the door at 7:00pm. If you arrive a bit later, just tell the guard at the reception desk you're here for the Smalltalk user meeting in the 1st floor training room.

Comments

SortedCollection, Block, and Polymorphism

 
I was having a discussion with a friend of mine tonight and they were having problems with serializing an object. After a few questions, I learned that they had a SortedCollection with a custom block. He was using Dolphin and I mentioned that there were other avenues to take. One such avenue is that he could use another object in place of the block as long at it understood #value:value: and returned a boolean. This is a common oversight because it's hard breaking "type thinking" and to step into "protocol thinking". The type of an object doesn't matter, it's the protocol it understands. Rubyists call this "duck typing". Call it what you want, it's powerful. As a side note, this is why interfaces make programming in Java nicer. So, I showed a quick example, say we take the following code:
| collection |
collection := Array
with: 'second' -> 'turbine'
with: 'third' -> 'earth'
with: 'fourth' -> 'good apollo'.
collection asSortedCollection: [:a :b | a key <= b key]

And it returns:

a SortedCollection(
'fourth' -> 'good apollo'
'second' -> 'turbine'
'third' -> 'earth')

In Dolphin, I can use Message instead of block since it understands the same protcol:
collection asSortedCollection: (Message selector: #key)

Or even write a method to do the comparison:
compare: anObjectA to: anObjectB
anObjectA key <= anObjectB key

collection asSortedCollection: (MessageSend receiver: someObject selector: #compare:to:)

Or we could implement #value:value: on an object and pass that in as the block into SortedCollection. Just remember, to use the polymorphism, luke. We can use these tricks anywhere we use a block (Depending on the number of arguments needed, you might been #value:, #value:value:value:, or #valueWithArguments:). And all of the above sample solutions are serializable...=)

It's great to work in a language that allows you the freedom to be creative and extend it in ways the creators never thought of (or perhaps they did). Let the Smalltalk FLOW!

Comments
  • Blaine,

    Cool article. I feel like parts of my mind have atrophied after using Java for so long, these articles are helping to stop thinking in Java.

    Btw, in VisualWorks I serialize out my blog to a file and am able to read it back in just fine even though it contains a SortedCollection with a block.

    Can't wait for dolphin 6, it reminds a lot of VSE... VSE was my first love (as far as programming environments go) and when it died I felt almost like a friend had died. VSE + windowbuilder was awesome (never really cared for parts, though).

    Regards,
    Tim

    By T.A. Jones, at 12:01 AM   

  • I don't want to rag on Java *too* much... I think Interfaces are a cool idea and a real step forward. Checked exceptions, however.....

    By T.A. Jones, at 12:04 AM   

  • The SortCriteria is implemented in the above manner using the value:value: protocol of SortedCollection. Give it a try. Oh, a couple of other messages had to be implemented in some Smalltalk's so the protocol is more than just the value:value: message.

    It would be awesome if someone would port it into Dolphin and send me a file with the Dolphin version so I can add it to the web site. Thanks.

    By Peter William Lount, at 9:15 AM   

  • Vincent,
    You're right. Dolphin handles serializing blocks as well. I don't know why I thought this. It must be another one of those old hold backs that I have. Still it was a fun article to write!

    By Blaine, at 11:35 AM   

  • Peter,

    I read about your SortCriteria object, it looks really nice.

    Regards,
    Tim

    By T.A. Jones, at 12:19 PM   

  • Tim,

    Thanks for the appreciation. The SortCriteria, or SortCritter as it's affectionetly known in Squeak, is really cool. What I like about it is the simplicity of extending the Smalltalk SortedCollection capability. It's awesome that this was possible without modifying any of the existing Smalltalk classes, and yet it's such a fundamental addition to those capabilities. It's also tiny with much of the code being the test class.

    When hooked up to a GUI that allows for realtime adjustments of the SortCriteriaColumns via clicks of the GUI table columns it's very powerful indeed!

    The other aspect that blows my mind about it is that it's so damed simple to use as a programmer! Funny enough it was inspired by the ease of sorting in Microsoft Excell! Notably the SortCritter is even easier to use - from a programming point of view - since it can be memorized with SortCritter instances configured for various purposes. If the GUI is constructed right the user can easily switch between them and be in FULL control over this aspect of how the information is presented to them in the GUI.

    The SortCritter was inspired when I had to write yet another block to sort multiple columns. Sigh... the idea of using value:value: polymorphicly came to mind and within a few hours I had a fully working and tested SortCritter, essentially what you see now!

    It seems that it's rare to have such funcationality and power in such a condensed space and yet still be readable and potently reusable.

    While recently working on two very large Smalltalk applications in production - desktop and web - it became clear that most of the classes were, I don't know the best way to describe it, maybe defused is close. The classes capabilities were defused all over the place, not focused in one place, and with so many of them having that characteristic it made the system that much harder to grasp.

    Clear design is essential to not only comprehension but effectiveness of the design of object components as implemented in their classes. In the case of the SortCritter two classes conspire in such a way as to pretend to be what they are not - a block of code. The two classes divide up their responsibilities with a SortCriteria instance taking on the role of the "sort block" and the SortCriteriaColumn instances knowing about their vertical slice of the sorting problem. It's also interesting that the "sorting algorithm extension" for sorting multiple columns indpendently from each other is such a one off algorithm. That is, it's an algorithm that highly ameniable to encoding once and for all! Once encoded and tested it has powerful benefits such as reliablity in that humans can then trust their sorting requirements. In effect it becomes a new reliable and reuable control structure for Smalltalk.

    If you can - when you find yourself spewing out an algorithm over and over and over again manually as you write code - seize the day and evolve that manual spew into a truely generic and reusable component! Then share it the new wealth!

    I'm glad that you like it. How about porting it to your favorite Smalltalk and sending me the ported file out for posting for others?

    All the best,

    Peter William Lount
    peter@smalltalk.org

    By Peter William Lount, at 1:22 AM   

Domain Specific Languages

 
I still see old world flat file specifications like the following:







TypeNameDescription
9(8)Some DateDDMMYYYY
9(6)Some TimeHHMMSS
x(20)Lovely NameA Good Name
x(36)fillerIgnore

I thought I would do something different implement the parser as if I was a Lisper. So, here's what I came up with:

recordLayout
^#(
(9(8) someDate asDDMMYYYY)
(9(6) someTime asHHMMSS)
(x(20) lovelyName)
(x36) filler)
)

And what does the code look like to parse it? It's even simpler than I thought:

parse: aStream
self recordLayout do: [:eachLayout | | typeInfo typeLength fieldName converterSelector rawData data |
typeInfo := eachLayout first.
typeLength := eachLayout second first.
fieldName := eachLayout third.
converterSelector := eachLayout at: 4 ifAbsent: [#yourself].
rawData := aStream next: typeLength.
(typeInfo == 9) ifTrue: [self verifyIsNumeric: rawData].
data := rawData perform: converterSelector.
self perform: (self setterFor: fieldName) with: data]

WOW! I now have a method that shows the record layout that could be parsed for creating test records as well. I could even show it to a non-Smalltalker and they would know what's going on. I love the flexibility of Smalltalk! I love adding new tricks to my bag.

Comments

XML Generation In Smalltalk

 
Tim Jones showed a simple way to generate XML in Smalltalk. And then Michael Lucas-Smith showed an even simpler way which is very close to what Seaside does for HTML generation (using #doesNotUnderstand:). In fact, I wrote one for Squeak a long time ago for myself that does exactly what Michael and Tim did (my DNU code calls the Tim-like code and compiles it on the fly so to make debugging easy and future hits quick). Anyway, I found that I needed something different for attributes so I created the ability to churn out XML from arrays. Here's some code from one on my tests:
xml := BtbXmlRenderer on: writeStream.
xml render: #(first arg1: 'value1' arg2: 'value2'
(second (third '"fun"'))
(fourth)
(fifth #sixth: 56)).

And this generates the following XML:
<?xml version="1.0"?>
<first arg1="value1" arg2="value2">
<second>
<third>&quot;fun&quot;</third>
</second>
<fourth/>
<fifth sixth="56"/>
</first>

I made all objects implement #renderXMLOn: so that I can use Arrays, Blocks, or anything else to make it easier to output XML in the future. It also means I can use all three approaches to generate one XML document. I think this is a perfect example of polymorphism and the power of dynamic languages at its finest. So, we have three ways of generating XML and I found that each has its advantages at different times. My point to this post was to show yet another way to generate XML using Smalltalk. Keep the Smalltalk flowing!

Comments

Monday, September 05, 2005

FTPlets

 
Apparently, Avi Bryant made an interesting challenge to create a dynamic FTP server. I love the idea of using existing protocols in creative ways. What about a dynamic CSS or Subversion server? Or even automatically save code to a version control system based on submissions to the FTP server and tags things on a per session basis. I'm excited to hear more as this develops. Can you imagine using existing tools for your front-end? Then, people can use the tools that they are most comfortable with.

Comments

Good OO Thoughts

 
From Steve Dekorte's blog:
The amount to which the program is object oriented has an inverse relation to:

1. the number of arguments passed in message calls
2. The number of instance variables in the objects

I tend to use "7 +/- 2" rule. If I have 5 or less instance variables in my object, then everything is cool. I'm even OK with 7, but 9 is on the cusp of too many. The reason why is because too many instance variables is not only a code smell, but your object is getting away from having one responsbility and needs to be broken up.

Arguments are little bit more restrictive. I try to keep them below 5. Otherwise, you're writing big methods and well, your methods should do one thing and nothing more.

Of course, the rule above is excellent, as is the "DRY, Shy, and Tell The Other Guy" rule from the Pragmatic Programmers. They are just some things that I strive for when programming.

Comments
  • Ooh, that's a nice one. I never thought about the number of instance variables in a class, but I guess it does make sense. Thanks for the tip Blaine!

    By Vincent, at 2:06 PM   

  • I system I work has many classes way over 7 instance variables -- even unto 7 times 7 instance variables.

    Are there any refactoring patterns documented by to help tackle the situation?

    By Alan Wostenberg, at 10:22 AM   

Sunday, September 04, 2005

Rule #67 in Design

 
NEVER clean up resources you did not create

I hate to pick on Java, but I found a great example of this in the Java API of all places in the javax.swing.text.html.parser.Parser class. I removed a lot of the code from the method to concentrate on the violation:

/**
* Parse an HTML stream, given a DTD.
*/
public synchronized void parse(Reader in) throws IOException {
/* LOTS OF CODE REMOVED */
try {
/* WHACKED */
parseContent();
/* WHACKED */
} finally {
in.close();
}
/* MORE CODE DELETED */
}

Basically, you pass in a Reader object that obviously you have to CREATE. And what do they for you? They free your resource that you passed in. Heaven forbid, you would like to do something else with it. Besides, why would you do that? Well, that's not the point. In design, I NEVER clean up a resource I did not allocate. If it is passed into me, I do what I need to do with it and that's all. On the other hand, if I allocate it, I take pains to make sure I deallocate it. This is what I did in my C/C++ days and it was a great rule of thumb that prevented a lot of problems.

Comments

Friday, September 02, 2005

Is That All?

 
Taken from the comp.lang.smalltalk.dolphin:

> Besides the IdeaSpace, what else is new?

Well, off the top of my head, and in no particular order:
1) New look tools with sliding panes (imaginatively called Slidey Inny
Outey Things, SIOTs) :-)
2) New look Resource Browser with iconic categories and preview pane.
http://www.object-arts.com/dow nloads/6.0/images/d6rb.png
3) New look View Composer with sliding resource toolbox and Inspector
panes.  The View Composer now supports undo.
http://www.object-arts.com/dow nloads/6.0/images/d6vc.png
4) Improved garbage collector giving approximately 20% speed
improvement overall.
5) Compiler now supports true block closures and not just a
Smalltalk-80 block semantics.
6) All code editing is now done using the Scintilla code editor.  This
means we get away from the vagaries of the Windows Rich Text Control
and also we now have auto completion (IntelliSense).
http://www.object-arts.com/dow nloads/6.0/images/d6ac.png
7) New "literal filer" for storing views which opens up the resources
such that their contents can be refactored etc.  Storing resources in
this way also greatly simplifies the image stripping process at
deployment.
8) New Sockets2 package that uses overlapped/blocking calls rather than
asynchronous messages.  The old package is provided for backwards
compatibility.
9) The Refactoring Browser rewrite tool has been included as a plug-in
in the class and system browsers.
http://www.object-arts.com/dow nloads/6.0/images/d6rwt.png
10) The class and system browsers now have a Code Mentor plug-in that
comments on the style of your code.  It runs the analysis in the
background as you work and is based on the SmallLint facility that
comes with the refactoring engine.
http://www.object-arts.com/dow nloads/6.0/images/d6cm.png
11) Views now support background colour inheritance.
12) New TabViewXP view that supports XP-style tab views in all
orientations (unlike the standard Windows control).
13) Dynamic syntax highlighting in all workspaces as you type.
14) Workspaces highlight compilation errors and warnings with squiggly
underlinesand will display help for these when the mouse hovers over
them.
15) Various new view controls such as: SysLink, LinkButton,
MonthCalendarView, SpinButton.
16) Windows XP application manifest is now included as part of the
version resource in deployed executables.
17) Application deployment now creates a complete XML based contents
list of the entire application.  This can be browsed from within
Dolphin using a class browser to see exactly what methods and classes
are present in the application.
http://www.object-arts.com/dow nloads/6.0/images/d6cm.png
18) New Method Explorer which replaces the old Method Browser to
provide a hierarchical trail of browse requests.  The aim, like with
the IdeaSpace, is to reduce the number of open windows while working
with Dolphin.
http://www.object-arts.com/dow nloads/6.0/images/d6mex.png
There are dozens of other minor enhancements and bug fixes and probably
some other fairly major ones that I've forgotten but the above should
give you a flavour of what is coming in Dolphin 6.
Best regards,
--
Andy Bower
Dolphin Support
www.object-arts.com

WOW! That sure is a lot of stuff to pack in for a release. I'm beyond excited. I'm so lusting for Dolphin 6.0. I feel like a kitten that can see the cream, but can't lap it up. Dolphin on!

Comments

Thursday, September 01, 2005

What kind of technology do you want to create?

 
From Donald Norman's "Things That Make Us Smart":
When I speak of the power and virtues of technology, I am referring to soft technology: technology that is flexible, that is under our control. Hard technology remains unheedful of the real needs and desires of the users. It is a technology that, rather than conforming to our needs, forces us to conform to its needs. Hard technology make us subservient; soft technology puts us in charge. Automating tends to be a hard use of technology. Informating tends to be soft.

So, when you are creating your next program or framework, think to yourself, "How would I want to be treated?" I bet you would prefer soft technology over hard. Let's make the user experience better all around. I promise to take the above quote to heart in my future endeavors. Take the oath and let's start delighting our users together.

Comments
  • One man's soft is another man's hard. This is the realm of "power & influence" not technology.

    By Socinian, at 12:59 PM   




Metalheads Against Racism



This page is powered by Blogger. Isn't yours?