<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>On Smalltalk</title>
	<atom:link href="http://onsmalltalk.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://onsmalltalk.com</link>
	<description>thoughts on Smalltalk and programming in general...</description>
	<pubDate>Tue, 13 May 2008 05:02:09 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>Small Scriptaculous API Change for Seaside 2.8</title>
		<link>http://onsmalltalk.com/programming/smalltalk/small-scriptaculous-api-change-for-seaside-28/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/small-scriptaculous-api-change-for-seaside-28/#comments</comments>
		<pubDate>Wed, 16 Apr 2008 16:04:54 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Squeak]]></category>

		<category><![CDATA[Updates]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/?p=125</guid>
		<description><![CDATA[Yesterday I was upgrading one of my applications to the latest version of Scriptaculous and Seaside 2.8, at first everything seemed to go OK but shortly thereafter I noticed that some of the Ajax in the application had stopped working.  After a bit of testing I traced the problem to multi element Ajax updates [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday I was upgrading one of my applications to the latest version of Scriptaculous and Seaside 2.8, at first everything seemed to go OK but shortly thereafter I noticed that some of the Ajax in the application had stopped working.  After a bit of testing I traced the problem to multi element Ajax updates where I&#8217;m using the evaluator.  Stuff like this occasionally happens so it was time for some investigation.  </p>
<p>I cracked open an older image and checked the version I&#8217;d been using and started reading the commit comments for each version looking for clues.  You can do this from <a href="http://squeaksource.com">SqueakSource</a> but I usually just do it in Monticello directly.  After a bit of digging I find in Scriptaculous-lr.232.mcz the information I&#8217;m looking for, namely&#8230;</p>
<p>- NOTE: SUElement>>#render: does not call #update: anymore, directly use #update:, #replace:, #insert:, and #wrap: now. These methods finally accept any renderable object (string, block, &#8230;) and also encode the contents correctly.</p>
<p>Seems Lukas changed the API to make things more intention revealing.  A quick trip through the app looking for evaluators and changing #render: to #update: and everything started working again.  Having made the necessary changes, and looking at the new code for a few minutes, I liked it and agree with API change.</p>
<p>What I want to point out is the importance of good commit comments (thanks Lukas) that allow those who use your frameworks to work out their problems.  Commit comments are the best place to share your thoughts about why you changed something or decided to go in a particular direction because they are, or should be, the first thing a developer reads before loading a new version of that code.  </p>
<p>I also what to point out the process itself.  Being open source code, when things go wrong it&#8217;s often up to you to solve your own problems.  Had I not found what I needed in the comments, I&#8217;d have started Googling and searching the archives of the Seaside-Dev list to see if anyone else had run into this issue.  If that fails, then I&#8217;d post to Seaside-Dev asking for help.  </p>
<p>There&#8217;s not a lot of documentation on Seaside and Scriptaculous in comparison to some other frameworks, but there&#8217;s plenty of help to be found with just a little bit of effort on your part to do your homework and a great community ready and willing to help you out when you need it.  But always do your homework first, in case your question has been answered many times over.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/small-scriptaculous-api-change-for-seaside-28/feed/</wfw:commentRss>
		</item>
		<item>
		<title>13 April 2008 &gt; Squeak Image Updated</title>
		<link>http://onsmalltalk.com/programming/smalltalk/13-april-2008-squeak-image-updated/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/13-april-2008-squeak-image-updated/#comments</comments>
		<pubDate>Sun, 13 Apr 2008 19:51:50 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Updates]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/?p=124</guid>
		<description><![CDATA[Just a quick notification that I updated my squeak image.
It&#8217;s based on Damien Cassou&#8217;s latest Squeak Dev Image (Squeak 3.9.1), an awesome base image with all the necessary goodies a developer needs.  This image is a bit smaller than previous ones because I&#8217;ve taken Glorp out since I&#8217;m not currently using it anymore.  [...]]]></description>
			<content:encoded><![CDATA[<p>Just a quick notification that I updated <a href="http://onsmalltalk.com/my-squeak-image/">my squeak image</a>.</p>
<p>It&#8217;s based on Damien Cassou&#8217;s latest <a href="http://damien.cassou.free.fr/">Squeak Dev Image</a> (Squeak 3.9.1), an awesome base image with all the necessary goodies a developer needs.  This image is a bit smaller than previous ones because I&#8217;ve taken Glorp out since I&#8217;m not currently using it anymore.   I&#8217;ve also dumped the windows native fonts and use different default fonts due to my working from both Windows and Linux these days.  </p>
<p>rST (Remote Smalltalk) is now loaded because I plan on experimenting with it a bit.  OSProcess is part of my default setup as well, on the Linux side, it&#8217;s quite useful.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/13-april-2008-squeak-image-updated/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Simple File Based Application Configuration</title>
		<link>http://onsmalltalk.com/programming/smalltalk/simple-file-based-application-configuration/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/simple-file-based-application-configuration/#comments</comments>
		<pubDate>Sat, 01 Mar 2008 20:19:10 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[General]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/simple-file-based-application-configuration/</guid>
		<description><![CDATA[I thought this was too simple to bother posting about, but someone requested it, so here it is.  Having made my journey to Linux about a year ago, I&#8217;ve found a new appreciation for the simplicity of plain old text files and the file system in general.  
Some of the tools I&#8217;ve come [...]]]></description>
			<content:encoded><![CDATA[<p>I thought this was too simple to bother posting about, but someone requested it, so here it is.  Having made <a href="http://onsmalltalk.com/programming/smalltalk/seaside/my-journey-to-linux/">my journey to Linux</a> about a year ago, I&#8217;ve found a new appreciation for the simplicity of plain old text files and the file system in general.  </p>
<p>Some of the tools I&#8217;ve come to rely on like Daemontools from <a href="http://www.thedjbway.org/djbwhy.html">Daniel Bernstein</a> also show this appreciation of the Unix way, small simple reliable tools that just work and are configured easily with plain text files.  The most recent versions of Apache have also broken up the monolithic httpd.config into much smaller simpler individual files spread out over various directories that greatly ease automation by keeping individual site settings in separate files and using simple symbolic links to enable or disable individual sites.</p>
<p>Inspired by the simplicity and ease of managing these tools, I decided my Smalltalk programs, while ungodly easy to write, were much too hard to configure and deploy because configuration was based either on code in the image or in the case of Seaside, its custom configuration system, neither of which are simple or easy to move around between images and servers.  I also like how Ruby on Rails configuration system allows multiple configurations that you can easily switch between to run your code in your various environments.</p>
<p>Rather than trying to design some ultimate configuration system, I just looked at how I write and deploy *my* applications, which is always one image per application in its own directory (possibly launched multiple times on various ports) and decided the simplest thing that could possibly work for me was just a directory named config, in my image directory, with three subdirectories named prod, dev, and test, and a single file named config which tells me which config subdirectory is active.</p>
<p>So I&#8217;ll declare a configuration class&#8230;</p>
<pre>
Object subclass: #SSConfig
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'SentorsaSeaside-Configuration'
</pre>
<p>and a class side #create method to setup this structure on the filesystem&#8230;</p>
<pre>
create
    | configDir |
    configDir := (FileDirectory default directoryNamed: #config) assureExistence.
    FileStream
        forceNewFileNamed: (configDir fullNameFor: #config)
        do: [ : f | f nextPutAll: 'dev' ].
    (configDir directoryNamed: #prod) assureExistence.
    (configDir directoryNamed: #dev) assureExistence.
    (configDir directoryNamed: #test) assureExistence
</pre>
<p>Next, I want a simple dictionary style API, &#8220;SSConfig at: #someSetting&#8221;, so I&#8217;ll need the core class side method #at: which grabs the current configuration and uses the key you hand it to looks for the file name that matches, opening it in read only mode if it exists or simply creating it if it doesn&#8217;t.</p>
<pre>
at: aKey
	| currentConfig configDir value |
	currentConfig := FileStream
		readOnlyFileNamed: ((FileDirectory default directoryNamed: #config) fullNameFor: #config)
		do: [ : f | f contentsOfEntireFile ].
	configDir := (FileDirectory default directoryNamed: #config) directoryNamed: currentConfig.
	value := (configDir fileExists: aKey)
		ifTrue:
			[ FileStream
				readOnlyFileNamed: (configDir fullNameFor: aKey)
				do: [ : f | f contentsOfEntireFile ] ]
		ifFalse:
			[ FileStream
				forceNewFileNamed: (configDir fullNameFor: aKey)
				do: [ : f | f contentsOfEntireFile ] ].
	^ (value endsWith: Character lf asString)
		ifTrue: [ value allButLast ]
		ifFalse: [ value ]
</pre>
<p>Next I want to be able to ask for a value and provide a default in case there is no configured value, built simply upon the previous method&#8230;</p>
<pre>
at: aKey default: aValue
    ^(self at: aKey)
        ifEmpty: [ aValue ]
        ifNotEmptyDo: [ : it | it ]
</pre>
<p>I also want to be able to ask for a config value typed to a boolean (SSConfig can: #useBlaBla) for the common case of true/false settings, another simple method built upon #at:&#8230;</p>
<pre>
can: aKey
    ^(self at: aKey) = 'true'
</pre>
<p>And of course, having strings and booleans, I now want a couple of simple methods for asking for integers from config&#8230;</p>
<pre>
numAt: aKey
    ^(self at: aKey)
        ifEmpty: [ 0 ]
        ifNotEmptyDo: [ : it | it asInteger ]

numAt: aKey default: aValue
    ^(self at: aKey)
        ifEmpty: [ aValue ]
        ifNotEmptyDo: [ : it | it asInteger ]
</pre>
<p>These are all class side methods, and so far I&#8217;ve not found the need for anything more than strings, bools, and integers.  If I do, I&#8217;ll extend it more, however, this seems to be all I need for all of my configuration needs thus far.  It&#8217;s simple, every setting is its own file, and it allows me to easily switch between various configs and easily share configurations between various images with nothing more than a simple file copy.  I can also easily edit the configuration from the shell, where I do most of my administration tasks.</p>
<p>NOTE: This method is not application aware, so it won&#8217;t work well if you run multiple applications within a single image, but I&#8217;m not writing code for use cases I don&#8217;t have and it works well for how I deploy my applications.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/simple-file-based-application-configuration/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Upgrading a Running Squeak Image</title>
		<link>http://onsmalltalk.com/programming/smalltalk/upgrading-a-running-squeak-image/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/upgrading-a-running-squeak-image/#comments</comments>
		<pubDate>Tue, 26 Feb 2008 04:05:17 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/upgrading-a-running-squeak-image/</guid>
		<description><![CDATA[One of the challenges you&#8217;ll face when deploying an application in Seaside, especially if you&#8217;re running headless on a Linux box somewhere, is how to upgrade your production application to the latest version of your code.  For the longest time, I&#8217;ve done this the easy way, upgrade the production image off-line, upload it, and [...]]]></description>
			<content:encoded><![CDATA[<p>One of the challenges you&#8217;ll face when deploying an application in Seaside, especially if you&#8217;re running headless on a Linux box somewhere, is how to upgrade your production application to the latest version of your code.  For the longest time, I&#8217;ve done this the easy way, upgrade the production image off-line, upload it, and restart the services.  It&#8217;s simple and straight forward, but it blows away all active sessions and kicks off any users currently online.  There are other more interesting ways.</p>
<p>Some people use VNC to connect to their production image, fire up Monticello, and hot upgrade the code.  Personally, I&#8217;ve never been able to get a stable version of VNC going, there are always issues, the latest being that the client is messed up by the nice Squeak UI Enhancements hiding the menus.  Too much hassle, I gave up, I don&#8217;t trust VNC at all.</p>
<p>There&#8217;s a simple web based method within Seaside under /tools/versionuploader, you can use the web version of Monticello to load packages into the running image and then save the image from there.  It&#8217;s simple and effective, if not a bit clunky, but it works great if you&#8217;re willing to expose that to the internet wrapped with just basic http authentication.  I&#8217;ve been using this, but I thought I could have a little fun hacking up something a little more interesting.</p>
<p>So what are we talking about here, just loading a few Monticello packages and saving the image, how hard could that be to automate?  Turns out, not so hard if I use the Installer that comes in Damien&#8217;s dev image (that my image is based upon).  I decide to make my images upgrade themselves from a staging directory where I can just secure copy or ftp up the new versions plus an empty trigger file named &#8220;load&#8221; to kick the process off.  I&#8217;ve been playing with it a few days now, seems to work pretty well.  Here&#8217;s what it takes to make a self upgrading image (assuming you use Monticello to package all your code, as I do).  </p>
<p>It&#8217;s just two methods really, one to load all the packages deleting them after each one is installed, assuming the load file exists&#8230;</p>
<pre>
loadChanges
    | dir |
    dir := (FileDirectory default directoryNamed: 'load-package') assureExistence.
    dir fileNames
        select: [ : ea | ea endsWith: '.mcz' ]
        thenDo:
            [ : fileName |
            ((dir fileExists: fileName) and: [ dir fileExists: #load ]) ifTrue:
                [Transcript show: (fileName , ': ').
                Installer installFile: (dir fullNameFor: fileName).
                Transcript cr.
                dir deleteFileNamed: fileName ] ].
    (dir fileExists: #load) ifTrue:
        [ dir deleteFileNamed: #load.
        SmalltalkImage current saveSession]
</pre>
<p>And a second to kick off a background process that runs continually, say every few seconds, that kicks off #loadChanges.</p>
<pre>
watchForChanges
    [[ (Delay forSeconds: 5) wait.
    [ self loadChanges ]
        on: Error
        do: [ : error | Transcript show: error ] ] repeat ]
        forkAt: Processor userBackgroundPriority + 1
        named: &#8216;code loader&#8217;
</pre>
<p>Then I call watchForChanges in a class side #initialize somewhere on a utility class so the background process is kicked off automatically in any image I load my code into.  Seems pretty slick so far, just upload the new packages, upload an empty file named load, the image upgrades itself, deletes all the files in the staging directory, saves itself, and chugs along like nothing happened at all.  No session are lost, no users booted, if anything they might notice a slight pause for a bigger package loading.  </p>
<p>This all of course assumes your production image is basically read only, i.e. has no code changes in it, as mine are.  Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/upgrading-a-running-squeak-image/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Simple Image Based Persistence in Squeak</title>
		<link>http://onsmalltalk.com/programming/smalltalk/simple-image-based-persistence-in-squeak/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/simple-image-based-persistence-in-squeak/#comments</comments>
		<pubDate>Tue, 15 Jan 2008 04:45:36 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Databases]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Sql]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/simple-image-based-persistence-in-squeak/</guid>
		<description><![CDATA[One of the nicest things about prototyping in Smalltalk is that you can delay the need to hook up a database during much of your development, and if you&#8217;re lucky, possibly even forever.  
It&#8217;s a mistake to assume every application needs a relational database, or even a proper database at all.  It&#8217;s all [...]]]></description>
			<content:encoded><![CDATA[<p>One of the nicest things about prototyping in Smalltalk is that you can delay the need to hook up a database during much of your development, and if you&#8217;re lucky, possibly even forever.  </p>
<p>It&#8217;s a mistake to assume every application needs a relational database, or even a proper database at all.  It&#8217;s all too common for developers to wield a relational database as a golden hammer that solves all problems, but for many applications they introduce a level of complexity that can making development feel like wading through a pond full of molasses where you spend much of your time trying to keep the database schema and the object schema in sync.  It kills both productivity and fun, and god dammit, programming should be fun!</p>
<p>This is sometimes justified, but many times it&#8217;s not.  Many business applications and prototypes are built to replace manual processes using Email, Word, and Excel.  Word and Excel by the way, aren&#8217;t ACID compliant, don&#8217;t support transactions, and manage to successfully run most small businesses.  MySql became wildly popular long before it supported transactions, so it&#8217;s pretty clear a wide range of apps just don&#8217;t need that, no matter how much relational weenies say it&#8217;s required.</p>
<p>It shouldn&#8217;t come as a surprise that one can take a single step up the complexity ladder, and build simple applications that aren&#8217;t ACID compliant, don&#8217;t support transactions, and manage to successfully run most small businesses BETTER than Word and Excel while purposely not taking a further step and moving up to a real database which would introduce a level of complexity that might blow the budget and make the app infeasible.</p>
<p>No object relational mapping layer (not even Rails and ActiveRecord) can match the simplicity, performance, and speed of development one can get just using plain old objects that are kept in memory all the time.  Most small office apps with no more than a handful of users can easily fit everything into memory, this is the idea behind <a href="http://www.prevayler.org/wiki/">Prevayler</a>.</p>
<p>The basic idea is to use a command pattern to apply changes to your model, you can then log the commands, snapshot the model, and replay the log in case of a crash to bring the last snapshot up to date.  Nice idea, if you&#8217;re OK creating commands for every state changing action in you&#8217;re application and being careful with how you use timestamps so replaying the logs works properly.  I&#8217;m not OK with that, it introduces a level of complexity that is overkill for many apps and is likely the reason more people don&#8217;t use a Prevayler like approach.</p>
<p>One might attempt to use the Smalltalk image itself as a database (and many try), but this is ripe with problems.  My average image is well over 30 megs, saving it takes a bit of time, and saving it while processing http requests risks all kinds of things going wrong as the image prepares for what is essentially a shutdown/restart cycle.</p>
<p>Using a ReferenceStream to serialize objects to disk Prevayler style, but ignoring the command pattern part and just treating it more like crash proof image persistence is a viable option if your app won&#8217;t ever have that much data. Rather than trying to minimize writes with commands, you just snapshot the entire model on every change.  This isn&#8217;t as crazy as it might sound, most apps just don&#8217;t have that much data.  This blog for example, a year and a half old, around 100 posts, 1500 comments, has a 2.1 megabyte MySql database, which would be much smaller as serialized objects.  </p>
<p>If you&#8217;re going to have a lot of data, clearly this is a bad approach, but if you&#8217;re already thinking about how to use the image for simple persistence because you know your data will fit in ram, here&#8217;s how I do it.</p>
<p>It only takes a few lines of code in a single abstract class that you can subclass for each project to make a Squeak image fairly robust and crash proof and more than capable enough to allow you just use the image, no database necessary.  We&#8217;ll start with a class&#8230;</p>
<pre>
Object subclass: #SMFileDatabase
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'SimpleFileDb'

SMFileDatabase class
	instanceVariableNames: 'lock'
</pre>
<p>All the methods that follow are class side methods.  First, we&#8217;ll need a method to fetch the directory where rolling snapshots are kept.  </p>
<pre>
backupDirectory
	^ (FileDirectory default directoryNamed: self name) assureExistence.
</pre>
<p>The approach I&#8217;m going to take is simple, a subclass will implement #repositories to return the root object that needs serialized, I just return an array containing the root collection of each domain class.</p>
<pre>
repositories
	self subclassResponsibility
</pre>
<p>The subclass will also implement #restoreRepositories: which will restore those repositories back to wherever they belong in the image for the application to use them.  </p>
<pre>
restoreRepositories: someRepositories
	self subclassResponsibility
</pre>
<p>Should the image crash for any reason, I want the last backup will be fetched from disk and restored.  So I need a method to detect the latest version of the backup file, which I&#8217;ll stick a version number in when saving.</p>
<pre>
lastBackupFile
	^ self backupDirectory fileNames
		detectMax: [:each | each name asInteger]
</pre>
<p>Once I have the file name, I&#8217;ll deserialize it with a read only reference stream (don&#8217;t want to lock the file if I don&#8217;t plan on editing it)</p>
<pre>
lastBackup
	| lastBackup |
	lastBackup := self lastBackupFile.
	lastBackup ifNil: [ ^ nil ].
	^ ReferenceStream
		readOnlyFileNamed: (self backupDirectory fullNameFor: lastBackup)
		do: [ : f | f next ]
</pre>
<p>This requires you extend ReferenceStream with #readOnlyFileNamed:do:, just steal the code from FileStream so nicely provided by Avi Bryant that encapsulates the #close of the streams behind #do:.  Much nicer than having to remember to close your streams.</p>
<p>Now I can provide a method to actually restore the latest backup. Later, I&#8217;ll make sure this happens automatically.</p>
<pre>
restoreLastBackup
	self lastBackup ifNotNilDo: [ : backup | self restoreRepositories: backup ]
</pre>
<p>I like to keep around the last x number of snapshots to give me a warm fuzzy feeling that I can get old versions should something crazy happen.  I&#8217;ll provide a hook for an overridable default value in case I want to adjust this for different projects.</p>
<pre>
defaultHistoryCount
	^ 15
</pre>
<p>Now, a quick method to trim the older versions so I&#8217;m not filling up the disk with data I don&#8217;t need.</p>
<pre>
trimBackups
	| entries versionsToKeep |
	versionsToKeep := self defaultHistoryCount.
	entries := self backupDirectory entries.
	entries size < versionsToKeep ifTrue: [ ^ self ].
	((entries sortBy: [ : a : b | a first asInteger < b first asInteger ])
		allButLast: versionsToKeep)
			do: [ : entry | self backupDirectory deleteFileNamed: entry first ]
</pre>
<p>OK, I&#8217;m ready to actually serialize the data.  I don&#8217;t want multiple processes all trying to do this at the same time, so I&#8217;ll wrap the save in a critical section, #trimBackups, figure out the next version number, and serialize the data (#newFileNamed:do: another stolen FileStream method), ensuring to #flush it to disk before continuing (don&#8217;t want the OS doing any write caching).  </p>
<pre>
saveRepository
	| version |
	lock critical:
		[ self trimBackups.
		version := self lastBackupFile
			ifNil: [ 1 ]
			ifNotNil: [ self lastBackupFile name asInteger + 1 ].
		ReferenceStream
			newFileNamed: (self backupDirectory fullPathFor: self name) , &#8216;.&#8217; , version asString
			do: [ : f | f nextPut: self repositories ; flush ] ]
</pre>
<p>So far so good, let&#8217;s automate it.  I&#8217;ll add a method to schedule the subclass to be added to the start up and shutdown sequence.  You must call this for each subclass, not for this class itself.  </p>
<p>UPDATE: This method also initializes the lock and must be called prior to using #saveRepository, this seems cleaner.</p>
<pre>
enablePersistence
	lock := Semaphore forMutualExclusion.
	Smalltalk addToStartUpList: self.
	Smalltalk addToShutDownList: self
</pre>
<p>So on shutdown, if the image is actually going down, just save the current data to disk.</p>
<pre>
shutDown: isGoingDown
	isGoingDown ifTrue: [ self saveRepository ]
</pre>
<p>And on startup we can #restoreLastBackup.</p>
<pre>
startUp: isComingUp
	isComingUp ifTrue: [ self restoreLastBackup ]
</pre>
<p>Now, if you want a little extra snappiness and you&#8217;re not worried about making the user wait for the flush to disk, I&#8217;ll add little convience method for saving the repository on a background thread.</p>
<pre>
takeSnapshot
	[self saveRepository] forkAt: Processor systemBackgroundPriority
		named: &#8217;snapshot: &#8216; , self class name
</pre>
<p>And that&#8217;s it, half a Prevayler and a more robust easy to use method that&#8217;s a bit better than trying to shoehorn the image into being your database for those small projects where you really really don&#8217;t want to bother with a real database (blogs, wikis, small apps, etc).  Just sprinkle a few MyFileDbSubclass saveRepository or MyFileDbSubclass takeSnapshot&#8217;s around your application whenever you feel it important, and you&#8217;re done.</p>
<p>Here&#8217;s a file out if you just want the code fast, <a href='http://onsmalltalk.com/wp-content/uploads/2008/01/smfiledatabase.st' title='SMFileDatabase.st'>SMFileDatabase.st</a></p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/simple-image-based-persistence-in-squeak/feed/</wfw:commentRss>
		</item>
		<item>
		<title>07 December 2007 &gt; Squeak Image Updated</title>
		<link>http://onsmalltalk.com/programming/smalltalk/07-december-2007-squeak-image-updated/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/07-december-2007-squeak-image-updated/#comments</comments>
		<pubDate>Fri, 07 Dec 2007 19:30:39 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Updates]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/07-december-2007-squeak-image-updated/</guid>
		<description><![CDATA[Just a quick notification that I updated my squeak image (several of you have asked).
It&#8217;s based on Damien Cassou&#8217;s latest Squeak Dev Image (Squeak 3.9), an awesome base image with all the necessary goodies a developer needs.  Of course I&#8217;ve loaded up my window customizations and preferences, nicer looking fonts, and have all the [...]]]></description>
			<content:encoded><![CDATA[<p>Just a quick notification that I updated <a href="http://onsmalltalk.com/my-squeak-image/">my squeak image</a> (several of you have asked).</p>
<p>It&#8217;s based on Damien Cassou&#8217;s latest <a href="http://damien.cassou.free.fr/">Squeak Dev Image</a> (Squeak 3.9), an awesome base image with all the necessary goodies a developer needs.  Of course I&#8217;ve loaded up my window customizations and preferences, nicer looking fonts, and have all the preferences set the way I like.  </p>
<p>Nothing major in this update other than keeping up with the latest versions of everything I use.  I have removed the SentorsaBrowser and TrickRefractoringBrowser because the new OmniBrowser is just getting too good to use anything else.  Enjoy.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/07-december-2007-squeak-image-updated/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Seaside 2.8 Released</title>
		<link>http://onsmalltalk.com/programming/smalltalk/seaside-28-released/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/seaside-28-released/#comments</comments>
		<pubDate>Sun, 28 Oct 2007 18:57:49 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/general/seaside-28-released/</guid>
		<description><![CDATA[Quoted from the Seaside mailing list&#8230;
After a beta phase of two months we release the final version of Seaside 2.8. Most bugs fixed during this period were either long standing (already in 2.7), minor or portability related, Together with the dozens of Seaside 2.8 applications already in production today this gives a pretty good feeling [...]]]></description>
			<content:encoded><![CDATA[<p>Quoted from the Seaside mailing list&#8230;</p>
<p>After a beta phase of two months we release the final version of Seaside 2.8. Most bugs fixed during this period were either long standing (already in 2.7), minor or portability related, Together with the dozens of Seaside 2.8 applications already in production today this gives a pretty good feeling about this version. A special mention deserves Roger Whitney, thanks to him we went from 99 commented classes to 144.</p>
<p>We have a list of new features [1] and a migration guide [2] on our homepage.</p>
<p>Squeak users can get it either from SqueakMap, Universes or directly via Monticello (Seaside2.8a1-lr.518). A special note for Squeak users, do not load Seaside 2.8 into an image that has already Seaside 2.7 in it. If you use Squeak 3.7 you will have to load SeasideSqueak37 as well.</p>
<p>VisualWorks users can get it form Store (2.8a1-lr.518,tkogan).</p>
<p>GemStone/S users can load Seaside2.8g1-dkh.522.</p>
<p>[1] <a href="http://www.seaside.st/community/development/seaside28a1">http://www.seaside.st/community/development/seaside28a1</a><br />
[2] <a href="http://www.seaside.st/documentation/migration">http://www.seaside.st/documentation/migration</a></p>
<p>Cheers<br />
The Seaside Team</p>
<p>I&#8217;ve been using 2.8 for a while now in development and for several weeks in production, it&#8217;s solid and very easy to port to for 2.7 users.  Upgrade as soon as you can, it&#8217;s quite a bit snappier and uses much less memory.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/seaside-28-released/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Smalltalk Concurrency, Playing With Futures</title>
		<link>http://onsmalltalk.com/programming/smalltalk/smalltalk-concurrency-playing-with-futures/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/smalltalk-concurrency-playing-with-futures/#comments</comments>
		<pubDate>Sat, 27 Oct 2007 04:20:02 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/smalltalk-concurrency-playing-with-futures/</guid>
		<description><![CDATA[Concurrency is always a source of problems in complex systems and one of the coolest patterns I&#8217;ve seen for simplifying it is Futures.  I thought I&#8217;d explore the idea today and hack up a quick implementation of a dynamic Future proxy.  
The basic idea is to take a block of code, schedule it [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/Concurrency_(computer_science)">Concurrency</a> is always a source of problems in complex systems and one of the coolest patterns I&#8217;ve seen for simplifying it is <a href="http://en.wikipedia.org/wiki/Futures_and_promises">Futures</a>.  I thought I&#8217;d explore the idea today and hack up a quick implementation of a dynamic Future proxy.  </p>
<p>The basic idea is to take a block of code, schedule it on another thread and return a dynamic proxy that if accessed, blocks until the value returns.  This lets useful work continue on the main thread until you access the value. </p>
<p>A nice way to break up a big task concurrently might be to #collect: all the futures for a bunch of work processes you have, say fetching rates for a bunch of hotels that require calls to outside systems that may or may not return quickly, and then aggregate the results at the end.</p>
<p>Here&#8217;s the complete implementation, it&#8217;s quite simple but seems to work pretty well while playing around in a workspace and makes concurrency seem less of a beast.</p>
<p>First the class, a subclass of ProtoObject since we&#8217;re building a proxy&#8230;</p>
<pre>
ProtoObject subclass: #SFuture
	instanceVariableNames: 'futureValue error lock'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'OnSmalltalk'
</pre>
<p>Then a #value: write accessor which eagerly kicks off the process, sets up, and clears the lock after fetching the future value.</p>
<pre>
value: aBlock
    lock := Semaphore new.
    [futureValue := [aBlock on: Error do: [:err | error := err]]
                ensure:
                    [lock signal.
                    lock := nil]] fork
</pre>
<p>Now a #value read accessor that blocks if the lock still exists, re-throws any error that may have happened on the worker thread in the context of the main thread, and finally returns the future value.</p>
<pre>
value
	lock ifNotNil: [lock wait].
	error ifNotNil:
			[error
				privHandlerContext: thisContext;
				signal].
	^ futureValue
</pre>
<p>A quick testing method for checking if the future has finished executing (useful for doing what work you can with the results that have returned).</p>
<pre>
hasValue
	^lock isNil
</pre>
<p>And the all important #doesNotUnderstand: override that intercepts any message sent to the proxy and sends it to the future value, causing the thread to block until the result is finished computing.</p>
<pre>
doesNotUnderstand: aMessage
    ^ self value
		perform: aMessage selector
		withArguments: aMessage arguments
</pre>
<p>Finally, a single extension method to BlockContext to make using the future more natural and ensuring to call fixTemps so I can collect future values in a loop with the assumption that the block will act like a proper closure.</p>
<pre>
BlockContext>>future
	^ SFuture new value: self fixTemps
</pre>
<p>Now we can ask any block for its future value and just pretend we have it.  Executing some test code in a workspace&#8230;</p>
<pre>
value1 := [200 timesRepeat:[Transcript show: '.']. 6] future.
value2 := [200 timesRepeat:[Transcript show: '+']. 6] future.
Transcript show: &#8216;other work&#8217;.
Transcript show: (value1 + value2).
</pre>
<p>Reveals the string &#8216;other work&#8217;, a long string of interspersed periods and pluses, and finally 12, the result of adding the value returned by each future.  In all, a pretty nice way to handle concurrency, I&#8217;ll have to see where I can simplify some code with the use of Futures, I can already think of a few.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/smalltalk-concurrency-playing-with-futures/feed/</wfw:commentRss>
		</item>
		<item>
		<title>20 October 2007 &gt; Squeak Image Updated</title>
		<link>http://onsmalltalk.com/programming/smalltalk/20-october-2007-squeak-image-updated/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/20-october-2007-squeak-image-updated/#comments</comments>
		<pubDate>Sat, 20 Oct 2007 17:39:32 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Updates]]></category>

		<category><![CDATA[Seaside]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/20-october-2007-squeak-image-updated/</guid>
		<description><![CDATA[Just a quick notification that I updated my squeak image a few days ago, I&#8217;m just getting around to posting about it.
It&#8217;s based on Damien Cassou&#8217;s Squeak Dev Image (Squeak 3.9), an awesome base image with all the necessary goodies a developer needs.  Of course I&#8217;ve loaded up my window customizations and preferences, nicer [...]]]></description>
			<content:encoded><![CDATA[<p>Just a quick notification that I updated <a href="http://onsmalltalk.com/my-squeak-image/">my squeak image</a> a few days ago, I&#8217;m just getting around to posting about it.</p>
<p>It&#8217;s based on Damien Cassou&#8217;s <a href="http://damien.cassou.free.fr/">Squeak Dev Image</a> (Squeak 3.9), an awesome base image with all the necessary goodies a developer needs.  Of course I&#8217;ve loaded up my window customizations and preferences, nicer looking fonts, and have all the preferences set the way I like.  The main update here is <a href="http://www.squeaksource.com/UIEnhancements.html">Squeaks great new UI enhancements</a> from Gary Chambers and Seaside 2.8.  Squeak has never looked better, I hope to see the UI enhancements continue to make Squeak a tool for grown ups.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/20-october-2007-squeak-image-updated/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Seaside Tutorial By Software Architecture Group</title>
		<link>http://onsmalltalk.com/programming/smalltalk/seaside-tutorial-by-software-architecture-group/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/seaside-tutorial-by-software-architecture-group/#comments</comments>
		<pubDate>Fri, 19 Oct 2007 17:06:38 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/seaside-tutorial-by-software-architecture-group/</guid>
		<description><![CDATA[A new Seaside tutorial has been released by the Software Architecture Group at the Hasso-Plattner-Institut (University of Potsdam).  They walk you through the setup of your image and the building of a ToDo list application including such things as encryption, external resources, various persistence options, and Ajax.  It&#8217;s a good tutorial and more [...]]]></description>
			<content:encoded><![CDATA[<p>A new <a href="http://www.swa.hpi.uni-potsdam.de/seaside/tutorial">Seaside tutorial</a> has been released by the Software Architecture Group at the Hasso-Plattner-Institut (University of Potsdam).  They walk you through the setup of your image and the building of a ToDo list application including such things as encryption, external resources, various persistence options, and Ajax.  It&#8217;s a good tutorial and more importantly an up to date tutorial using the latest versions of Seaside and Squeak.  It should prove to be a good resource for beginners looking to attempt their first Seaside applications, go check it out!</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/seaside-tutorial-by-software-architecture-group/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A Simple File Based Wiki in Seaside</title>
		<link>http://onsmalltalk.com/programming/smalltalk/a-simple-file-based-wiki-in-seaside/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/a-simple-file-based-wiki-in-seaside/#comments</comments>
		<pubDate>Wed, 26 Sep 2007 03:50:17 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Magritte]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/a-simple-file-based-wiki-in-seaside/</guid>
		<description><![CDATA[There can never be enough simple sample apps to help beginners learn Seaside.  In that spirit, here&#8217;s a simple file based Wiki written in pure Seaside (i.e. no Magritte and not overly abstracted to the point you can&#8217;t figure out what&#8217;s going on).  
It has bookmarkable URLs, uses regex (regex package found on [...]]]></description>
			<content:encoded><![CDATA[<p>There can never be enough simple sample apps to help beginners learn Seaside.  In that spirit, here&#8217;s a simple file based Wiki written in pure Seaside (i.e. no Magritte and not overly abstracted to the point you can&#8217;t figure out what&#8217;s going on).  </p>
<p>It has bookmarkable URLs, uses regex (<a href="http://www.squeaksource.com/Regex">regex package found on SqueakSource</a>) to make <a href="http://c2.com/cgi/wiki?WikiWord">WikiWords</a> into links, keeps line breaks, and accepts raw HTML.  Pages are stored on the file system under your image directory based upon the app name.</p>
<p>For a production quality Wiki, use <a href="http://www.lukas-renggli.ch/smalltalk/pier">Pier</a>, this one is super simple and only intended for learning.  It was written in about two hours (not counting some changes made during the writing of this article) as a single Seaside component.</p>
<p>OK, here we go, broken up into code sections by method category, first declare the class&#8230;</p>
<pre>
WAComponent subclass: #WikiPage
    instanceVariableNames: 'isEditing currentContent currentPage'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'SimpleFileWiki'
</pre>
<p>Setup the app on the class side&#8230;</p>
<pre>
canBeRoot
    ^ true  

initialize
    self registerAsApplication: #wiki
</pre>
<p>Initialize instances of the class&#8230;</p>
<pre>
initialize
    super initialize.
    currentPage := ''.
    isEditing := false
</pre>
<p>Create some accessing methods we&#8217;ll need&#8230;</p>
<pre>
currentContent
    ^ currentContent ifNil: [currentContent := '']

currentContent: aString
    currentContent := aString   

style
    ^ &#8216; textarea {width:90%;height:500px;}&#8217;
</pre>
<p>Then some fancier accessors that ensure our file system is setup and reads pages from it&#8230;</p>
<pre>
pageDirectory
    ^ (FileDirectory default
        directoryNamed: self session application name , #Pages) assureExistence 

pageAt: aPage
	isEditing := (self pageExists: aPage) not.
	isEditing ifTrue: [^ ''].
	^ FileStream readOnlyFileNamed: (self pageDirectory fullNameFor: aPage)
		do: [:file | file contentsOfEntireFile]
</pre>
<p>If a page doesn&#8217;t exist, the Wiki kicks into editing mode to create it.  A testing method use by the above&#8230;</p>
<pre>
pageExists: match
    ^ self pageDirectory fileExists: match
</pre>
<p>A couple of actions (our controller methods)&#8230;</p>
<pre>
loadPage: aPage
    isEditing := false.
    currentPage := aPage.
    self currentContent: (self pageAt: aPage)   

savePage
	self currentContent
		ifEmpty:
			[ (self pageExists: currentPage) ifTrue:
				[ self pageDirectory deleteFileNamed: currentPage.
				self loadPage: #FrontPage ] ]
		ifNotEmpty:
			[ FileStream
				forceNewFileNamed: (self pageDirectory fullNameFor: currentPage)
				do: [ :file | file nextPutAll: self currentContent ].
			isEditing := false ]    

cancel
	isEditing := false
</pre>
<p>Deleting the contents of a page, deletes the page as well.  </p>
<p>Now we&#8217;re ready for rendering.  Let&#8217;s start with page title in the head&#8230;</p>
<pre>
updateRoot: aRoot
    super updateRoot: aRoot.
    aRoot title: currentPage
</pre>
<p>And setting up the url&#8230;</p>
<pre>
updateUrl: aUrl
    super updateUrl: aUrl.
    aUrl addToPath: currentPage withFirstCharacterDownshifted
</pre>
<p>Now that the URL looks valid, lets make it work by parsing new requests, those that don&#8217;t include the session key (_s) or includes an expired session key.  Once the session key and the continuation key (_k) are present, the URL is no longer necessary and will be ignored.  Should this URL be bookmarked and returned to later, after the session has expired, #initialRequest: will be invoked, a new session started, and the correct page served&#8230;</p>
<pre>
initialRequest: aRequest
	| page url |
	url := aRequest url stringAfter: self application basePath.
	page := (url beginsWith: '/')
		ifTrue: [ url allButFirst copyAfterLast: $/ ]
		ifFalse: [ url copyAfterLast: $/ ].
	self loadPage: (page ifEmpty: [ 'FrontPage' ] ifNotEmpty: [ page ])
</pre>
<p>This uses an extension method #stringAfter that I have loaded in all my images, and it relies on another #split that is also in my images.  Here they are&#8230;</p>
<pre>
String>>stringAfter: aDelim
    | list |
    list := self split: aDelim.
    ^ list isEmpty ifTrue: [self] ifFalse: [list last withBlanksTrimmed]

String>>split: aString
    | index lastIndex |
    index := lastIndex := 1.
    ^ Array streamContents:
            [:stream |
            [index <= self size] whileTrue:
                    [index := self findString: aString startingAt: lastIndex.
                    index = 0 ifTrue: [index := self size + 1].
                    stream nextPut: (self copyFrom: lastIndex to: index - 1).
                    lastIndex := index + aString size]]
</pre>
<p>Now our main render method which decides which mode the Wiki is in&#8230;</p>
<pre>
renderContentOn: html
    isEditing
        ifTrue: [self renderEditorOn: html]
        ifFalse: [self renderViewerOn: html]
</pre>
<p>And either edits the Wiki page&#8230;</p>
<pre>
renderEditorOn: html
	(html heading)
		level1;
		with: ((self pageExists: currentPage)
					ifFalse: ['Page ' , currentPage , ' hasn''t been created yet, go for it!']
					ifTrue: ['Editing ' , currentPage]).
	html form:
			[html textArea on: #currentContent of: self.
			html break.
			html submitButton on: #savePage of: self.
			html text: ' or '.
			html anchor on: #cancel of: self]
</pre>
<p>Or renders the viewer which also parses the text for <a href="http://c2.com/cgi/wiki?WikiWord">WikiWords</a> and line breaks&#8230;</p>
<pre>
renderViewerOn: html
    self withLineBreaks: (self currentContent
                copyWithRegex: '[A-Z][a-z]+([A-Z][a-z]+)+&#8217;
                matchesTranslatedUsing:
                    [:match |
                    (self pageExists: match)
                        ifTrue: ['&lt;a href="' , (html urlForAction: [self loadPage: match]) displayString, &#8216;&#8221;&gt;&#8217;, match , &#8216;&lt;/a&gt;&#8217;]
                        ifFalse: [match , '&lt;a href="' , (html urlForAction: [self loadPage: match]) displayString, &#8216;&#8221;&gt;?&lt;/a&gt;&#8217;]])
        on: html.
    html paragraph:
            [(html anchor)
                callback: [isEditing := true];
                text: &#8216;Edit&#8217;.
            html space.
            (html anchor)
                callback: [self loadPage: #FrontPage];
                text: &#8216;FrontPage&#8217;]
</pre>
<p>The editor and viewer could have been separate components, but I&#8217;m going for simple here, one class.  And finally, the method for breaking lines&#8230;</p>
<pre>
withLineBreaks: aString on: html
    | stream |
    stream := aString readStream.
    [stream atEnd] whileFalse:
            [html html: stream nextLine.
            stream atEnd ifFalse: [html break]]
</pre>
<p>And there we have it, a simple file based Wiki that covers quite a few things you&#8217;d want to do in a web app and should be easily digestible for the Seaside beginner.  There are probably bugs, I didn&#8217;t do a ton of testing and its only intended use is this blog post.  </p>
<p>According to the message &#8220;WikiPage linesOfCode&#8221;, that&#8217;s 90 lines of code total (and that&#8217;s including the HTML and CSS).  Here&#8217;s <a href="http://onsmalltalk.com/downloads/WikiPage.st">a file out of the code</a> for anyone interested.   Make sure to manually add the two extension methods to String for this to work.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/a-simple-file-based-wiki-in-seaside/feed/</wfw:commentRss>
		</item>
		<item>
		<title>An Excellent Smalltalk Primer By Alan Lovejoy</title>
		<link>http://onsmalltalk.com/programming/smalltalk/an-excellent-smalltalk-tutorial-by-alan-lovejoy/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/an-excellent-smalltalk-tutorial-by-alan-lovejoy/#comments</comments>
		<pubDate>Mon, 24 Sep 2007 18:20:48 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/an-excellent-smalltalk-tutorial-by-alan-lovejoy/</guid>
		<description><![CDATA[Alan Lovejoy has released an excellent primer on Smalltalk that seems to really focus on what&#8217;s important, message passing, and why OOP in Smalltalk isn&#8217;t like OOP in other languages.  For those who don&#8217;t know, OOP isn&#8217;t about objects and classes, it&#8217;s about message passing between objects.  Bad OO code is the result [...]]]></description>
			<content:encoded><![CDATA[<p>Alan Lovejoy has released an <a href="http://www.chronos-st.org/Smalltalk-Getting-the-Message.html">excellent primer on Smalltalk</a> that seems to really focus on what&#8217;s important, message passing, and why OOP in Smalltalk isn&#8217;t like OOP in other languages.  For those who don&#8217;t know, OOP isn&#8217;t about objects and classes, it&#8217;s about message passing between objects.  Bad OO code is the result of not grasping this vital distinction and the source of much FUD about OO.  It&#8217;s also full of references for those looking to dig deeper into particular concepts, or find other resources in the Smalltalk world.  I highly recommend it.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/an-excellent-smalltalk-tutorial-by-alan-lovejoy/feed/</wfw:commentRss>
		</item>
		<item>
		<title>New GNU Smalltalk Site Launched</title>
		<link>http://onsmalltalk.com/programming/smalltalk/new-gnu-smalltalk-site-launched/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/new-gnu-smalltalk-site-launched/#comments</comments>
		<pubDate>Sat, 22 Sep 2007 22:56:55 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/new-gnu-smalltalk-site-launched/</guid>
		<description><![CDATA[GNU Smalltalk has launched a new site.  I thought it was about time to give it a try so I can write my shell scripts in Smalltalk.  I work in Windows but I use Cygwin so I can have a real shell handy, fortunately GNU Smalltalk runs under Cygwin.  So I fire [...]]]></description>
			<content:encoded><![CDATA[<p>GNU Smalltalk has launched a <a href="http://smalltalk.gnu.org/">new site</a>.  I thought it was about time to give it a try so I can write my shell scripts in Smalltalk.  I work in Windows but I use Cygwin so I can have a real shell handy, fortunately GNU Smalltalk runs under Cygwin.  So I fire up a shell and grab the latest version, unzip and untar it&#8230;</p>
<pre>
wget ftp://ftp.gnu.org/gnu/smalltalk/smalltalk-2.3.6.tar.gz
gunzip smalltalk-2.3.6.tar.gz
tar -xf smalltalk-2.3.6.tar
</pre>
<p>So far so good.  The instructions say I need autoreconfig, so I fire up Cygwin setup and hit the Devel category and install it, just to be safe I install gcc compilers for C and C++ as well.  Time to build Smalltalk (that sounds weird to me).</p>
<pre>
autoreconf -fvi
./configure
make
</pre>
<p>Takes a minute, checks a gazillion things, but all is well, build seems to work fine.  Time to run the unit tests&#8230;</p>
<pre>
make check
</pre>
<p>Good to go, so lets install&#8230;</p>
<pre>
make install
</pre>
<p>OK, now just type &#8220;gst&#8221; to get a REPL, play around for a bit, and write my first simple shell script, a quick loop printing 1 to 10000 on stdout&#8230;</p>
<pre>
#!/usr/local/bin/gst -f
(1 to: 10000) do:[:it | it printOn: stdout].
!
</pre>
<p>Sweet, works like a charm.  I can now fall back on Smalltalk for shell scripting instead of ruby or pearl when I need more power than simple bash scripts.</p>
<p>Stealing a sample from the Wiki shows a nice scripting syntax making use of blocks for declaring class and method bodies&#8230;</p>
<pre>
Object subclass: Person [
    | name age |
    Person class >> name: aString age: anInteger [
        ^(self new)
            name: aString;
            age: anInteger;
            yourself
    ]

    name [ ^name ]
    name: aString [ name := aString ]
    age [ ^age ]
    age: anInteger [ age := anInteger ]

    printOn: aStream [
        aStream << ('%1 (%2)' % {name. age})
    ]
]
</pre>
<p>I think I like it!  Only time will tell, but I think this will be my new scripting language of choice.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/new-gnu-smalltalk-site-launched/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Using Magritte With Seaside</title>
		<link>http://onsmalltalk.com/programming/smalltalk/using-magritte-with-seaside/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/using-magritte-with-seaside/#comments</comments>
		<pubDate>Tue, 11 Sep 2007 05:41:48 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Magritte]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[General]]></category>

		<category><![CDATA[Seaside]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/using-magritte-with-seaside/</guid>
		<description><![CDATA[One of the more tedious things one is faced with while writing web applications is input forms.  Forms suck because they&#8217;re boring and repetitive.  Building them manually is the same thing over and over, but they&#8217;re often just different enough that fully automating them is rather difficult.  I can&#8217;t say I&#8217;ve ever [...]]]></description>
			<content:encoded><![CDATA[<p>One of the more tedious things one is faced with while writing web applications is input forms.  Forms suck because they&#8217;re boring and repetitive.  Building them manually is the same thing over and over, but they&#8217;re often just different enough that fully automating them is rather difficult.  I can&#8217;t say I&#8217;ve ever seen a perfect solution, but I&#8217;ve come to consider Magritte the best solution I&#8217;ve used thus far.  </p>
<p>For an in depth look at the design of Magritte you should read <a href="http://www.iam.unibe.ch/~scg/Archive/Diploma/Reng06a.pdf">Lukas&#8217; Master&#8217;s thesis</a>, however, it&#8217;s a bit much if you&#8217;re just trying to get something done and just want to understand how to get going with the basics.  Magritte&#8217;s capable of more than you&#8217;ll likely use if you&#8217;re just wanting to build forms with Seaside.  I&#8217;m going to ignore those other abilities because frankly, I don&#8217;t use them and don&#8217;t plan to.</p>
<p>The basic design of Magritte involves a few classes that you&#8217;ll need to be familiar with and often subclass to extend and customize. </p>
<h3>MADescription</h3>
<p>With Magritte you describe your objects with subclasses of MADescription, this is where you&#8217;ll always start, just describing the fields of your domain objects that you&#8217;ll want generated forms for.  Descriptions contain the extra metadata necessary to create user interfaces, and which component will be used to render it.  A simple description looks like this&#8230;</p>
<pre>
descriptionIsClosed
    ^ (MABooleanDescription new)
          selectorAccessor: #isClosed;
          label: 'Is Closed';
          priority: 1000;
          yourself
</pre>
<p>Generally speaking you&#8217;ll keep these descriptions on the class side of your domain object.  On occasion, you&#8217;ll want some property of the description to be dynamic and depend on the actual value of an instance side value, so you&#8217;ll move the description to the instance side.  Strictly speaking, it doesn&#8217;t matter where you put them, sometimes you&#8217;ll use them to build forms when you don&#8217;t even have a domain object, but this isn&#8217;t the normal case.</p>
<p>There are two basic ways to create a form dynamically, one is simple and includes all descriptions found on an object&#8230;</p>
<pre>
buildComponentFor: aModel
    ^aModel asComponent addValidatedForm
</pre>
<p>The other, a little more complex, but much more useful because you&#8217;ll find that rarely do you want &#8220;every&#8221; described field in a form.  Often you&#8217;ll have multiple UI representations of a domain object within an app.  Descriptions are composable using a comma so you can build a form any subset of the fields&#8230;</p>
<pre>
buildComponentFor: aModel
    ^((ModelClass descriptionFieldOne, ModelClass descriptionFieldTwo, ModelClass descriptionFieldThree)
            asComponentOn: aModel)
        addValidatedForm;
        yourself
</pre>
<p>A Magritte form is generally wrapped with a form decoration via #addValidateForm, which by default gives you a #save and #cancel button.  Magritte forms don&#8217;t directly work on your domain objects.  They work on a memento of the values pulled from your object using the descriptions.  When you call #save, the values are validated using the descriptions, and only after passing all validation rules are the values committed to your domain object by the momentos via the accessors, which I&#8217;ll describe shortly.  For those interested, this is a good place to plug in a custom container component and integrate the #commit with Glorp, but that&#8217;s another post.</p>
<h3>Conditions</h3>
<p>Descriptions can have predicates associated with them to validate the input data which it calls conditions.  There are two basic kinds of conditions (there are actually more, but the block forms are what I use), both are simply blocks that returns true or false to validate the data.  One is the single field condition which is passed the pending value directly and attached directly to your descriptions.  It&#8217;s as simple as&#8230;</p>
<pre>
addCondition:[:value | value withBlanksTrimmed size > 3]
</pre>
<p>The other is the multi field validation which works on the memento which I&#8217;ll describe below.</p>
<pre>
	addCondition: [:memento |
		(memento cache at: CAUser descriptionPassword) isNil or:
			[(memento cache at: CAUser descriptionPassword)
				= (memento cache at: CAUser descriptionConfirmedPassword)]]
	labelled: &#8216;Passwords must match&#8217;;
</pre>
<p>I&#8217;ve <a href="http://onsmalltalk.com/programming/smalltalk/multiple-field-validation-rules-in-magritte/">posted about these previously</a>.  They are attached to your containers description which has access to all the fields.  </p>
<p>Conditions are one of the few things about Magritte that I&#8217;m still iffy on.  There are advantages to having your rules outside your domain objects, especially if you&#8217;re taking advantage of Magritte as an Adaptive Object Model where users can build rules from the UI.  It also allows the mementos to easily test data for validity outside the domain object and gives you a nice place to hook into the validation system in the components.  It bothers me a little because it weakens the domain model, I&#8217;m still trying to find my balance here and decide just how much I&#8217;ll allow as conditions.  </p>
<p>Magritte is very pluggable, should I decide I want all my rules in my domain objects, I could plug in my own memento subclass to handle that, but I haven&#8217;t felt the need just yet.</p>
<h3>MAMemento</h3>
<p>When components read and write to domain objects, they do it using mementos rather than working on the objects directly.  The default memento is MACheckedMemento, a subclass of MACachedMemento.  The mementos give Magritte a place to store invalid form data prior to allowing the data to be committed to the object.  It also allows Magritte to detect concurrency conflicts for shared in image objects.  By never committing invalid data to domain objects, there&#8217;s never a need to roll anything back.  Should you feel the need, just override #mementoClass on your domain object to provide your own.</p>
<h3>MAAccessor</h3>
<p>When a memento writes valid data to its model, it does so through accessors which are also defined by the descriptions.  MAAccessor subclasses allow you to define how a value gets written to your class.  For example, while I have a read selector for my collections like #users, I prefer to encapsulate #add and #remove on the domain object itself rather than having a writable selector for #users:.  When creating a description for that collection, I can specify my custom #accessor: rather than using the default #selectorAccessor: which then writes to my domain object with #addUser: and #removeUser:.</p>
<p>Another valuable use for accessors can be found when you want to flatten several domain objects into a single form.  Say you have a User object with an Address object, and a CreditCard object but you want to edit them all as a single form.  You can create your form and dynamically wire up some MAChainAccessors like so&#8230;</p>
<pre>
userTemplate
	^((((CAUser descriptionEmail, CAUser descriptionPassword , CAUser descriptionConfirmedPassword)
		addAll: (CAAddress description collect: [:each |
			each copy accessor:
                            (MAChainAccessor accessor: (MASelectorAccessor selector: #address) next: each accessor)]);
		addAll: (CACreditCard description collect: [:each |
			each copy accessor:
                             (MAChainAccessor accessor: (MASelectorAccessor selector: #creditCard) next: each accessor)]))
                yourself)
            asComponentOn: self session user)
            addValidatedForm: {  (#save -> &#8216;Update Profile&#8217;)};
            yourself.
</pre>
<p>Which basically just composes the users descriptions with the addresses and credit cards descriptions while chaining the accessors together to allow the addresses fields to be written to the address object rather than directly to the customer object.  Any non trivial UI will contain many such forms and this is the ability I&#8217;m the most grateful for in Magritte.  Also notice in the example above how I changed the label for the save button to &#8220;Update Profile&#8221;, also something you&#8217;ll need to do often that isn&#8217;t immediately obvious how to do.</p>
<h3>MADescriptionComponent</h3>
<p>Components control how your objects display.  Magritte widgets are subclasses of this component.  Some descriptions have an obvious one to one relationship with a UI component while others could easily be shown by several different components.  For example, an MAMemoDescription would be represented by a text area, but a MABooleanDescription could be a checkbox, or a drop down with true and false, or a radio group with true and false.  </p>
<p>Each description defaults to a component, but allows you to override and specify any component you choose, including any custom one you may write.  For example, suppose I built a special component to render checkboxes as fancy graphics rather than ordinary html checkboxes.  I could plug it in by changing the description as follows.</p>
<pre>
descriptionIsClosed
    ^ (MABooleanDescription new)
          selectorAccessor: #isClosed;
          label: 'Is Closed';
          priority: 1000;
          componentClass: CAFancyCheckbox;
          yourself
</pre>
<p>These are essentially meta components written in standard Seaside.  They work on mementos and have access to your descriptions.  This is where all that meta data comes in handy.  If you&#8217;re building a dropdown list, it&#8217;ll get its option list from the description.  When you render an element&#8217;s label, that&#8217;s also read from the description.  </p>
<p>When you build your own descriptions, you&#8217;ll add fields to them for custom data that you&#8217;ll want available in your custom components.  At first, you&#8217;ll mostly use built in descriptions and components, but as you grow comfortable with Magritte you&#8217;ll start wanting to build your own descriptions and components because you&#8217;ll want to do things beyond the basic framework like Ajax.  Magritte provides a solid foundation for extension.</p>
<h3>MAComponentRenderer</h3>
<p>By default, Magritte forms are rendered using MATableRenderer which renders the fields in a table with errors at the top and labels to the left of input fields.  This is the default because it&#8217;s the easiest thing to do automatically that looks halfway decent.  This can be overridden like so&#8230;</p>
<pre>
buildComponentFor: aModel
    ^((ModelClass descriptionFieldOne, ModelClass descriptionFieldTwo, ModelClass descriptionFieldThree)
            componentRenderer: MACssRenderer;
            asComponentOn: aModel)
        addValidatedForm;
        yourself
</pre>
<p>This hook allows you to render the form as you please, should you want to display errors differently, or change how elements are wrapped, or how the outer container itself is wrapped.  It&#8217;s handy to control how container classes are tagged with css classes to have the form dynamically change its appearance for various phases like valid/invalid.  If you don&#8217;t want your forms to look like auto-generated forms, you will use this.</p>
<p>For each of the classes I just described, you&#8217;ll want to pull up a hierarchy browser and explore all the subclasses to see examples of how they are specialized.  Find some example projects in SqueakSource that use Magritte to see how others create custom descriptions and components.  As with any framework, successful use depends on understanding it, and understanding how the pieces fit together.  Magritte will not doing everything you want out of the box, it isn&#8217;t meant to, but it&#8217;s an excellent foundation to base your application on.  It will save you many hours of tedious work building forms by hand.  It will also give your objects extra metadata that you may find handy for purposes other than building forms.</p>
<p>Along with Seaside, Magritte is also an excellent example of extremely well written object oriented code that is worth reading to see exactly what it takes to make a truly flexible and pluggable framework.  Because it was originally a masters thesis, it&#8217;s also far better commented than you&#8217;d likely find in a similar &#8220;real&#8221; world framework.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/using-magritte-with-seaside/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Smalltalk In Action</title>
		<link>http://onsmalltalk.com/programming/smalltalk/smalltalk-in-action/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/smalltalk-in-action/#comments</comments>
		<pubDate>Sat, 04 Aug 2007 17:11:41 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/smalltalk-in-action/</guid>
		<description><![CDATA[Explaining why Smalltalk developers like their images is a hard experience to convey to someone who&#8217;s accustomed to working with files.  Here&#8217;s a video I found that shows what it is to work on a running program.  
He&#8217;s demonstrating some of the features of the refactoring browser on a running instance of the [...]]]></description>
			<content:encoded><![CDATA[<p>Explaining why Smalltalk developers like their images is a hard experience to convey to someone who&#8217;s accustomed to working with files.  <a href="http://www.cincomsmalltalk.com/files/bobw/screencasts/Refactoring_Steroids/">Here&#8217;s a video I found</a> that shows what it is to work on a running program.  </p>
<p>He&#8217;s demonstrating some of the features of the refactoring browser on a running instance of the classic Asteroids game.  He extracts a method to a component, changes the color of the asteroids, then shows off undo and redo.  He does so while the game is running without ever having to break his flow with something as silly as a compile, debug, run cycle that we&#8217;ve all grown so accustomed to in most other languages.</p>
<p>It doesn&#8217;t matter how fancy modern refactoring browsers get, as long as they&#8217;re still working on dead files instead of a live running program, they&#8217;ll never be able to compete with Smalltalk when it comes to developer productivity and maintaining flow.</p>
<p><strong>Featured Resources</strong>&#8230;</p>
<p>Whenever you look at a <a href="http://www.killerwebz.com">web design</a>, you will notice that it&#8217;s usually not free from <a href="http://www.staticwebsites.com">3d animation</a> effects. These features bring out the human interaction elements at its best. An <a href="http://www.omnilinkservices.com">affordable hosting</a> will have you earn the desired outcomes from your website. There is a need of a good <a href="http://www.hostseeq.com/c/backup_file_sharing.htm">backup</a> plan for your <a href="http://www.envisionwebhosting.com">business hosting</a> as the data security becomes a great concern in this case. And you will enjoy it&#8217;s advantages.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/smalltalk-in-action/feed/</wfw:commentRss>
		</item>
		<item>
		<title>9 July 2007 Upgrading Seaside</title>
		<link>http://onsmalltalk.com/programming/smalltalk/9-july-2007-upgrading-seaside/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/9-july-2007-upgrading-seaside/#comments</comments>
		<pubDate>Mon, 09 Jul 2007 15:52:34 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/9-july-2007-upgrading-seaside/</guid>
		<description><![CDATA[Here&#8217;s some very valuable info posted by Philippe Marschall (core Seaside developer) in the mailing list&#8230;
This is a short list of things to do when migrating for an older to a newer version of Seaside in the wiki at:
http://www.squeaksource.com/Seaside.html
2.6 to 2.7 must:

every component that uses the old default WAHtmlBuilder must do so explicity by returning [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s some very valuable info posted by Philippe Marschall (core Seaside developer) in the mailing list&#8230;</p>
<p>This is a short list of things to do when migrating for an older to a newer version of Seaside in the wiki at:<br />
http://www.squeaksource.com/Seaside.html</p>
<p><strong>2.6 to 2.7 must:</strong></p>
<ul>
<li>every component that uses the old default WAHtmlBuilder must do so explicity by returning it in #rendererClass</li>
<li>evaluate WADispatcher resetAll</li>
<li>use WATagBrush >> #title: instead of WATagBrush >> #tooltip:</li>
<li>move to new image map api, check all senders of #imageMap, see WAImageMapTag for details</li>
</ul>
<p><strong>2.6 to 2.7 should:</strong></p>
<ul>
<li>move to new header api, modify implementors of #updateRoot:</li>
<li>remove the implemtors of #rendererClass that return WARenderCanvas</li>
<li>migrate to WARenderCanvas</li>
<li>migrate from WAScriptLibrary and WAStyleLibrary to WAFileLibrary</li>
<li>use WAAnchorTag >> #with: instead of WAAnchorTag >> #text:</li>
<li>check for deprecated message sends</li>
<li>replace users of WAChangePassword, WAEditDialog, WAEmailConfirmation, WAGridDialog, WALoginDialog, WANoteDialog</li>
</ul>
<p><strong>2.7 to 2.8 must:</strong></p>
<ul>
<li>migrate to WARenderCanvas</li>
<li>backtrack state by implementing #states (check all senders of #registerObjectForBacktracking: and #registerForBacktracking)</li>
<li>move to new header api, modify #updateRoot:. #linkToStyle becomes #stylesheet #url, #linkToScript becomes #javascript #url:, check all implementors of #updateRoot:</li>
<li>use WAAnchorTag >> #with: instead of WAAnchorTag >> #text:</li>
<li>replace users of WAChangePassword, WAEditDialog, WAEmailConfirmation, WAGridDialog, WALoginDialog, WANoteDialog</li>
<li>every component that implements #initialize must send this message also to super (use SLint)</li>
<li>if you use Squeak 3.7 load SeasideSqueak37 after Seaside</li>
<li>if you use Squeak do not load into an image that has an earlier version of Seaside already loaded</li>
</ul>
<p><strong>2.7 to 2.8 should:</strong></p>
<ul>
<li>check for deprecated message sends</li>
<li>migrate from WAScriptLibrary and WAStyleLibrary to WAFileLibrary</li>
<li>remove the implementors of #rendererClass that return WAHtmlCanvas</li>
</ul>
<p>I&#8217;m sure this list is not complete and I forgot stuff. So if you spot something that is missing send a message to me or the list or fix it directly. This is not on the Seaside homepage so anyone can edit it.<br />
It will probably be moved to the homepage at a future point.</p>
<p>Cheers, Philippe</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/9-july-2007-upgrading-seaside/feed/</wfw:commentRss>
		</item>
		<item>
		<title>On Simple Functional Idioms</title>
		<link>http://onsmalltalk.com/programming/smalltalk/on-simple-functional-idioms/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/on-simple-functional-idioms/#comments</comments>
		<pubDate>Sat, 07 Jul 2007 05:30:28 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/on-simple-functional-idioms/</guid>
		<description><![CDATA[I ran across an post by David Altenburg about the enumerate, map, filter, accumulate pattern.  These are certainly common functional techniques, but they&#8217;re also common Smalltalk techniques.  We call them do:, collect:, select:, and inject:into:.  
He showed a Java implementation of a simple and common programming problem&#8230;

int maxSalary = 0;
for (Employee employee [...]]]></description>
			<content:encoded><![CDATA[<p>I ran across an post by David Altenburg about <a href="http://gensym.org/2007/4/7/enumerate-map-filter-accumulate">the enumerate, map, filter, accumulate pattern</a>.  These are certainly common functional techniques, but they&#8217;re also common Smalltalk techniques.  We call them do:, collect:, select:, and inject:into:.  </p>
<p>He showed a Java implementation of a simple and common programming problem&#8230;</p>
<pre>
int maxSalary = 0;
for (Employee employee : employees) {
  if (Role.PROGRAMMER.equals(employee.getRole())) {
    int salary = employee.getSalary();
    if (salary > maxSalary) {
      maxSalary = salary;
    }
  }
}
</pre>
<p>Comparible to a C# 1.0 version&#8230;</p>
<pre>
int maxSalary = 0;
foreach(Employee employee in employees) {
    if(employee.Role == Role.PROGRAMMER
        &#038;&#038; employee.Salary > maxSalary) {
        maxSalary = employee.Salary;
    }
}
</pre>
<p>Then he does a Scheme version using a more functional style&#8230;</p>
<pre>
(define (salary-of-highest-paid-programmer records)
  (accumulate
      max 0
        (map salary
          (filter programmer? records))))
</pre>
<p>And a Ruby version of similar style, note the Smalltalk&#8217;ishness of it&#8230;</p>
<pre>
employees.
  select {|emp| :programmer == emp.role }.
    map {|emp| emp.salary }.
      inject {|m, v| m > v ? m : v}
</pre>
<p>And for comparison here&#8217;s a Smalltalk version&#8230;</p>
<pre>
(employees
    select: [:emp | emp role = #programmer ]
    thenCollect: [:emp | emp salary ])
        inject: 0 into: [:a :b | a max: b ]
</pre>
<p>Though if I found the pattern that common I&#8217;d define a quick helper method on Collection to clean up the syntax to this&#8230;</p>
<pre>
employees
    select: [:emp | emp role = #programmer ]
    collect: [:emp | emp salary ]
    inject: 0 into: [:a :b | a max: b ]
</pre>
<p>What&#8217;s interesting about them to me is really the difference between the Java/C# approaches and the more composable Scheme/Ruby/Smalltalk style.  Because Java/C# 1.0 lack first class functions (C# actually has them now in 2.0 and a nice lambda syntax in 3.0) and a literal syntax for declaring them, everything ends up being a special case of for/foreach.  They lack the ability to factor out common patterns like select:, collect:, and inject:into: into higher order functions.</p>
<p>As a side effect, select: turns into nested if&#8217;s and a loop, collect: into a temporary variable and a loop, and inject:into: into both an if, a temporary variable, and a loop.  You end up writing these patterns inline over and over rather than just reusing existing versions from the base library.</p>
<p>Languages that can&#8217;t support and make idiomatic the use of higher order functions, aren&#8217;t worth using these days in most domains.  They&#8217;re just too damn much work.  However, using functional techniques doesn&#8217;t at all mean using a functional language.  All of these work quite well in good object oriented languages like Smalltalk and Ruby.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/on-simple-functional-idioms/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A Squeak Smalltalk Development Example</title>
		<link>http://onsmalltalk.com/programming/smalltalk/a-squeak-smalltalk-development-example/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/a-squeak-smalltalk-development-example/#comments</comments>
		<pubDate>Wed, 04 Jul 2007 17:41:24 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/a-squeak-smalltalk-development-example/</guid>
		<description><![CDATA[Stephan Wessels has put up a very large tutorial showing the complete test driven development of a game in Squeak.  It covers quite a few things new Squeakers will want to know such as using SUnit to do test driven development, using Morphic to create Squeak widgets, using the debugger, and packaging the code [...]]]></description>
			<content:encoded><![CDATA[<p>Stephan Wessels has put up a very large tutorial showing the complete <a href="http://squeak.preeminent.org/tut2007/html/index.html">test driven development of a game in Squeak</a>.  It covers quite a few things new Squeakers will want to know such as using SUnit to do test driven development, using Morphic to create Squeak widgets, using the debugger, and packaging the code with Monticello.  It&#8217;s a great tutorial and I&#8217;m sure will become a popular resource.</p>
<p>However, despite the <strong>awesome effort</strong> (which I do appreciate), I have some problems with it.  As with many other Squeak tutorials, it makes the mistake of using a standard Squeak image as you&#8217;d find on Squeak.org.  This only helps further propagate the impression among newbies that Squeak is ugly, old fashioned, and lacking in all the features they expect from a more modern IDE.  What you see in the screenshots is not a Squeak I&#8217;d use.  Plain black code, ugly fonts, no intellisense, no use of the Refactoring Browser, no Shout Workspace.</p>
<p>Most developers who use Squeak would have a plethora of extra tools and utilities installed that make developing a much nicer experience than what you see in this tutorial.  Do yourself a favor and start your Squeaking with a real developer&#8217;s image loaded with all the proper goodies like the <a href="http://damien.cassou.free.fr/">SqueakDev</a> image maintained by Damien Cassou.  </p>
<p>Squeak.org still hasn&#8217;t figured out that its core audience should be developers, not children.  They don&#8217;t seem to realize the base image they distribute actually scares away more people than it encourages to join the community.  Though they do have a link to Damien&#8217;s SqueakDev image, they don&#8217;t encourage it like they do the base image, a mistake that leads new developers to open up Squeak for the first time, browser a tutorial or two, and toss it aside as a silly toy, never having seen the real power or beauty that is Smalltalk.</p>
<p>So all you developers out there using Squeak, please, stop showing people ugly images.  Marketing matters, looks matter, and that stuff scares people away.  Load up some decent fonts, setup the <strong>minimum *required* goodies like Shout, the Refactoring Browser, and ECompletion</strong>.  And if you aren&#8217;t using these goodies, you should be, and you shouldn&#8217;t be making tutorials without them because it gives people a false impression of what Squeak is.  Squeak is an awesome development environment that sadly doesn&#8217;t come out of the box that way, you have to start with the <a href="http://damien.cassou.free.fr/squeak-dev">right box</a> or learn to build your own.</p>
<p><a href="http://squeak.org">Squeak.org</a> could learn a lot about marketing Squeak by looking at how <a href="http://rubyonrails.org">rubyonrails.org</a> markets Rails.  If there&#8217;s one thing Ruby does vastly better than Smalltalk, it&#8217;s marketing.  Smalltalk continues to languish not because of technical merits, but because of bad marketing.  Beaten by Java, and now beaten by Ruby, by marketing alone.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/a-squeak-smalltalk-development-example/feed/</wfw:commentRss>
		</item>
		<item>
		<title>On the Smalltalk Browser</title>
		<link>http://onsmalltalk.com/programming/smalltalk/on-the-smalltalk-browser/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/on-the-smalltalk-browser/#comments</comments>
		<pubDate>Sun, 17 Jun 2007 20:15:38 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[General]]></category>

		<category><![CDATA[Lisp]]></category>

		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[Seaside]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/on-the-smalltalk-browser/</guid>
		<description><![CDATA[Some of the comments in a the Barrier To Entry post bring up the point that maybe the Smalltalk IDE itself is one of those barriers.
It&#8217;s an interesting thing, the Smalltalk browser.  Unlike most IDEs, it&#8217;s optimized for reading code rather than writing code.  Other IDEs allow you to see any number of [...]]]></description>
			<content:encoded><![CDATA[<p>Some of the comments in a the <a href="http://onsmalltalk.com/programming/smalltalk/what-are-the-barriers-to-entry-for-smalltalk-and-seaside/">Barrier To Entry post</a> bring up the point that maybe the Smalltalk IDE itself is one of those barriers.</p>
<p>It&#8217;s an interesting thing, the Smalltalk browser.  Unlike most IDEs, it&#8217;s optimized for reading code rather than writing code.  Other IDEs allow you to see any number of methods all at once, cutting and pasting text giant chunks at a time, they sure make you feel like you&#8217;re working.  They don&#8217;t however, allow you to navigate the semantic structure of the code very well nor do they encourage the writing of well organized code.</p>
<p>Modern IDEs are getting better at this, but they&#8217;re doing it by copying Smalltalk.  Smalltalk&#8217;s various code browsers (hierarchy, method, inheritance, senders, implementors, protocol, category, package, refactoring) let you explore the structure and relationships between existing code and its tools (transcript, workspace, method finder, message names) make finding and using existing code, or understanding existing APIs vastly easier than any other language I know of.  Seeing the structure of code is always but a context menu or hotkey away.</p>
<p>Smalltalk&#8217;s browser is rather opinionated, luckily, thanks to Rails, opinionated software seems to be having somewhat of a revival.  When it comes to writing code, the browser forces you into a certain mindset, one that other languages don&#8217;t force you into.  When I create a method in Java/C#/Ruby, I have to choose little more than what file and class it belongs in.  I *can* organize the code well, but there&#8217;s little incentive to do so and my unit of work is rather undefined, I could be slicing and dicing methods, classes, namespaces, etc., usually with the full screen devoted to code across various files or even god forbid in one giant file.  This encourages a code now and organize later approach.  Sadly, later often never comes, and the code is left functional but messy.</p>
<p>Smalltalk on the other hand, defines my unit of work as *the method* and by doing so forces me at every turn, to continually organize my code in semantically meaningful ways.  When I create a method, I have to choose a class category, a class, and a method category to put the method in.  If I don&#8217;t, Smalltalk kindly categorizes the method for me in a protocol called &#8220;as yet unclassified&#8221;.  It&#8217;s almost an insult, but it&#8217;s also a not so subtle reminder than I&#8217;m writing code sloppily, faster than I&#8217;m thinking.  It reminds me to slow down, think for a second, where does this thing belong.  </p>
<p>It only takes a second to pick a meaningful category name, and these names are idiomatic, I see them all the time when I&#8217;m looking for code.  Aha, we&#8217;ve linked writing code to reading code.  By taking the time to properly categorize my methods I also learn where to look for code later, when I&#8217;m in reading mode.  It&#8217;s a feedback loop, the more I read the better I write and the better I write the more I learn to read with accuracy, looking only where necessary.  It&#8217;s as if the code itself *is* a concise form of documentation hyperlinked by semantic meaning using things that Smalltalkers call browsers.  Browsers and hyperlinks, bah, that&#8217;ll never work!</p>
<p>And RDoc, what the fuck is that, looks curiously like a Smalltalk browser to me, but why should class comments be anywhere except on the class itself?  Oh that&#8217;s right, Ruby doesn&#8217;t have a Smalltalk browser, they code in files, how quaint.</p>
<p>As for editing the method itself,  I work on and view only one method at a time, and only the lower half of the browser is for editing code which punishes me if I write long methods that can&#8217;t fit into that tiny pane.  Smalltalk at every turn encourages me to read more code than I write, reuse more code than I otherwise might, and write smaller simpler methods than I likely would in a text editor.  </p>
<p>Writing smaller methods forces me to give them meaningful names.  Giving them meaningful names and putting them in meaningful places makes the code easier to read and easier to find.  Code that is easier to read and easier to find, is easier to reuse, easier to understand, and easier to compose into new solutions.  It&#8217;s called bottom up programming, the foundation of which is small composeable methods.  </p>
<p>I keep using the word small, maybe that&#8217;s a mistake on my part, what I really mean is concise.  Methods with a single purpose that is clearly summed up by their name.  These kinds of methods happen to be short in general, but that&#8217;s a side effect of their being focused on a single task.  The Smalltalk browser encourages these kinds of methods by making writing long methods or paying attention to too many methods painful.  Text editors are general purpose editor aimed at text, that could be anything from a blog post to a novel.  Surely an editor intended only for code, and only for a particular style of code, can be made much more *domain specific*.  </p>
<p>The Smalltalk browser is such an editor, its domain is highly factored heavily structured bottom up style object oriented code.  If that&#8217;s the style of code you like to write, you&#8217;ll find the Smalltalk browser wonderful, if not, you&#8217;ll find it painfully opinionated and rude.</p>
<p>Take a peek at decompiled .Net framework sources, or Ruby sources and what you&#8217;ll find, are average line per method counts in the 50+ to even 100+ ranges.  In Smalltalk, around 10 or so.  To me, this is a clear indication that text editors are the wrong interface for writing clean simple well factored reusable code.  Sure, I just pulled these numbers out of my ass, but they reflect my experiences and even then, I&#8217;m being polite, 1000 line methods are not at all uncommon in .Net.</p>
<p>Maybe adjusting to the Smalltalk browser is similar to adjusting to Lisp&#8217;s parenthesis.  It&#8217;s something you desperately want to fix as a newbie and make it work like other languages.  In Lisp&#8217;s case, trying to design an infix Lisp while in Smalltalk it&#8217;s a text and file based editor.  In both cases, once you stop fighting the language and realize the difference is actually a great strength of the language rather than something that needs fixed.  You realize it&#8217;s you that needs to change, you open your mind, accept that sometimes different is good, and take advantage of the new power these tools give you.</p>
<p>Experienced Lispers love their parenthesis and experienced Smalltalkers love their browsers.  Rather than seeing the Smalltalk browser as a barrier, maybe, just maybe, you&#8217;d be better off seeing it as a new toy to play with.  Something new to learn.</p>
<p>UPDATE: Here&#8217;s a few admitidly cramped screenshots of the various browsers.  They do of course look much better maximized on your monitor.</p>
<div>
<img src='http://onsmalltalk.com/wp-content/uploads/2007/06/browser8.jpg' alt='browser8.jpg' />
<p>
<img src='http://onsmalltalk.com/wp-content/uploads/2007/06/browser7.jpg' alt='browser7.jpg' />
<p>
<img src='http://onsmalltalk.com/wp-content/uploads/2007/06/browser6.jpg' alt='browser6.jpg' />
<p>
<img src='http://onsmalltalk.com/wp-content/uploads/2007/06/browser5.jpg' alt='browser5.jpg' />
<p>
<img src='http://onsmalltalk.com/wp-content/uploads/2007/06/browser4.jpg' alt='browser4.jpg' />
<p>
<img src='http://onsmalltalk.com/wp-content/uploads/2007/06/browser3.jpg' alt='browser3.jpg' />
<p>
<img src='http://onsmalltalk.com/wp-content/uploads/2007/06/browser2.jpg' alt='browser2.jpg' />
<p>
<img src='http://onsmalltalk.com/wp-content/uploads/2007/06/browser1.jpg' alt='browser1' />
</p></div>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/on-the-smalltalk-browser/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Functional Programming in Smalltalk</title>
		<link>http://onsmalltalk.com/programming/smalltalk/functional-programming-in-smalltalk/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/functional-programming-in-smalltalk/#comments</comments>
		<pubDate>Wed, 13 Jun 2007 03:44:52 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Lisp]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[General]]></category>

		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/functional-programming-in-smalltalk/</guid>
		<description><![CDATA[Smalltalk is generally considered to be an object oriented language but it&#8217;s actually a mixture of object oriented and functional techniques that made it so great.  It&#8217;s the functional stuff, closures, anonymous functions, and higher order functions that make Smalltalk code so terse and easy to read.  The objects provide the overall structure, [...]]]></description>
			<content:encoded><![CDATA[<p>Smalltalk is generally considered to be an object oriented language but it&#8217;s actually a mixture of object oriented and functional techniques that made it so great.  It&#8217;s the functional stuff, closures, anonymous functions, and higher order functions that make Smalltalk code so terse and easy to read.  The objects provide the overall structure, but the functional stuff glues them all together and makes Smalltalk what it is.</p>
<p>I was considering writing more about it but a quick Google search turned up this great reference <a href="http://www.exept.de:8080/doc/online/english/programming/stForLispers.html">Smalltalk for Lispers</a> from the Smalltalk/X Programmers Guide that gives an excellent introduction from a more functional point of view.</p>
<p>If you mix object oriented programming, manifest types, and procedural programming, you get Java or C#, not exactly a fun or flexible combination of language features.  Mix object oriented programming, dynamic types, and light functional programming and you get Smalltalk and Ruby, much more fun and much more flexible and productive.  </p>
<p>People often seem to forget &#8220;object&#8221; is meant as an abstract term that means &#8220;thing&#8221;.  Object oriented programming is about programming with &#8220;things&#8221;.  In that sense, functions are objects too.  Not all objects need be created with named classes, and all too often people who complain about OO are really complaining about their misguided view of OO and the often made newbie mistake of trying to model everything with a class.  It&#8217;s not called class oriented programming, it&#8217;s called object oriented programming.  Maybe approaching Smalltalk from a more functional point of view will shed some light on more interesting ways to solve problems.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/functional-programming-in-smalltalk/feed/</wfw:commentRss>
		</item>
		<item>
		<title>What are the Barriers to Entry for Smalltalk and Seaside?</title>
		<link>http://onsmalltalk.com/programming/smalltalk/what-are-the-barriers-to-entry-for-smalltalk-and-seaside/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/what-are-the-barriers-to-entry-for-smalltalk-and-seaside/#comments</comments>
		<pubDate>Wed, 13 Jun 2007 02:59:28 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/what-are-the-barriers-to-entry-for-smalltalk-and-seaside/</guid>
		<description><![CDATA[It&#8217;s been two or three years since I began using Smalltalk and Seaside and I&#8217;m so comfortable in the environment I think I&#8217;ve forgotten how difficult it was to get going.  By the time I started this blog, I was already quite comfortable using both Smalltalk and Seaside that I think a bunch of [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been two or three years since I began using Smalltalk and Seaside and I&#8217;m so comfortable in the environment I think I&#8217;ve forgotten how difficult it was to get going.  By the time I started this blog, I was already quite comfortable using both Smalltalk and Seaside that I think a bunch of the little things I could have written about have been overlooked.  </p>
<p>I&#8217;ve been so busy with work lately that I haven&#8217;t felt much like writing but I think it&#8217;s about time I give the blog a little more love.  So those of you looking to get into Smalltalk, or Seaside, where&#8217;s your pain?  What things are tripping you up that you can&#8217;t find answers to?  What things are getting in your way that keep you from getting into the flow and really doing something in Seaside?  </p>
<p>I&#8217;m just looking for some ideas for some bite sized yet useful articles covering topics I haven&#8217;t already covered that&#8217;ll help ease someone&#8217;s pain just a bit and get me back into the writing mood.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/what-are-the-barriers-to-entry-for-smalltalk-and-seaside/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Maintaining Loose Coupling in Seaside Components</title>
		<link>http://onsmalltalk.com/programming/smalltalk/maintaining-loose-coupling-in-seaside-components/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/maintaining-loose-coupling-in-seaside-components/#comments</comments>
		<pubDate>Tue, 24 Apr 2007 17:48:21 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/maintaining-loose-coupling-in-seaside-components/</guid>
		<description><![CDATA[There is an interesting question that often comes up often when writing components.  How do my components communicate with each other in a way that doesn&#8217;t bind them together explicitly.  How does a child component call a method on a parent component without explicitly knowing who the parent is.  
Knowing who the [...]]]></description>
			<content:encoded><![CDATA[<p>There is an interesting question that often comes up often when writing components.  How do my components communicate with each other in a way that doesn&#8217;t bind them together explicitly.  How does a child component call a method on a parent component without explicitly knowing who the parent is.  </p>
<p>Knowing who the parent is prevents the component from being re-used in other contexts with different parents.  There is a general solution to this whole class of problems and it was solved quite elegantly by <a href="http://blog.3plus4.org/">Vassili Bykov</a> with his <a href="http://www.cincomsmalltalk.com/userblogs/vbykov/blogView?showComments=true&#038;entry=3310034894">Announcements framework</a>.</p>
<p>The basic idea is to setup an announcer somewhere global, in the session for example.  </p>
<pre>
MySession>>announcer
    ^ announcer ifNil: [announcer := Announcer new]
</pre>
<p>Then subclass Announcement for any interesting thing that might happen like removing a child.  </p>
<pre>
Announcement subclass: #RemoveChild
    instanceVariableNames: 'child'

RemoveChild class>>child: aChild
    ^self new
        child: aChild;
        yourself

RemoveChild>>child: anChild
    child := anChild

RemoveChild>>child
    ^child
</pre>
<p>Any component interested in this announcement registers its interest when it initializes.</p>
<pre>
Parent>>initialize
    super initialize.
    self session announcer on: RemoveChild do:[:it | self removeChild: it child]

Parent>>removeChild: aChild
    self children remove: aChild
</pre>
<p>And any component who wants to fire this event simply announces it by sending in an instance of that custom announcement object.</p>
<pre>
Child>>removeMe
    self session announcer announce: (RemoveChild child: self)
</pre>
<p>Works great, and depending on where you place the announcer, you could even have different sessions sending events to each other, or different applications.</p>
<p><a href="http://onsmalltalk.com/downloads/SeasideAnnouncementDemo.st">Here&#8217;s a file out of a commented working demo</a> that has a child remove itself from the parent via an announcement.</p>
<p>UPDATE: I use the port of Announcements from <a href="http://mc.lukas-renggli.ch">Lukas Renggli&#8217;s public repository</a>.  The one on SqueakSource is a different port.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/maintaining-loose-coupling-in-seaside-components/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Small Reddit, A Seaside Sample Application</title>
		<link>http://onsmalltalk.com/programming/smalltalk/small-reddit-a-seaside-sample-application/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/small-reddit-a-seaside-sample-application/#comments</comments>
		<pubDate>Sat, 21 Apr 2007 07:16:38 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Magritte]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/small-reddit-a-seaside-sample-application/</guid>
		<description><![CDATA[I just uploaded a simple reddit clone sample Seaside application to SqueakSource.  It&#8217;s meant be a very simple reference application to learn from, it&#8217;s only about 4 hours work total. There are comments throughout, and various techniques are used to demonstrate different ways of doing things. Some forms are generated directly via Seaside and [...]]]></description>
			<content:encoded><![CDATA[<p>I just uploaded a simple <a href="http://www.squeaksource.com/SmallReddit.html">reddit clone sample Seaside application</a> to SqueakSource.  It&#8217;s meant be a very simple reference application to learn from, it&#8217;s only about 4 hours work total. There are comments throughout, and various techniques are used to demonstrate different ways of doing things. Some forms are generated directly via Seaside and some other by Magritte.  Persistence is implement in image using dictionaries and collections.</p>
<p>Features include login, register, add entry, vote on entry, comment on entry, comment on comment.  There are probably a few bugs.  I&#8217;m not making any claims of best practice, only showing various ways I accomplish things to suite my needs.</p>
<p>Hopefully such an application will make Seaside more approachable for the newbie and help ease the lack of documentation available.  I know when I first started learning, I was far more interested in actual samples than outdated documents.  Enjoy!</p>
<p>UPDATE: Loading this code requires that you create a repository in Monticello.  Just create a new HTTP repository with the following template using the +Repository button.</p>
<pre>
MCHttpRepository
    location: 'http://www.squeaksource.com/SmallReddit'
    user: ''
    password: ''
</pre>
<p>Once done, you can open the repository, select the package, and load it.  It will create an application on localhost at /seaside/smallReddit, on whatever port you&#8217;re running Seaside on.  You could also just download the mcz file directly and drag and drop it into your squeak image, at which point you&#8217;ll be prompted and asked what you&#8217;d like to do.</p>
<p>See my previous <a href="http://onsmalltalk.com/programming/smalltalk/screencast-how-to-package-smalltalk-code-with-monticello/">screencast about using Monticello</a> for a quick visual on using Monticello.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/small-reddit-a-seaside-sample-application/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Pollak On Seaside</title>
		<link>http://onsmalltalk.com/programming/smalltalk/pollak-on-seaside/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/pollak-on-seaside/#comments</comments>
		<pubDate>Wed, 11 Apr 2007 21:04:23 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/general/pollak-on-seaside/</guid>
		<description><![CDATA[Found on a Rails blog&#8230;
&#8220;IMHO Seaside is the benchmark by which all web frameworks should be measured&#8221; &#8212; David Pollak
My thoughts exactly.  It&#8217;s not about the language, it&#8217;s about the approach.  Seaside is the right recipe for writing real applications, not just fancy websites.  No other framework can do what Seaside does, [...]]]></description>
			<content:encoded><![CDATA[<p>Found on a Rails blog&#8230;</p>
<p>&#8220;IMHO Seaside is the benchmark by which all web frameworks should be measured&#8221; &#8212; <a href="http://blog.lostlake.org/">David Pollak</a></p>
<p>My thoughts exactly.  It&#8217;s not about the language, it&#8217;s about the approach.  Seaside is the right recipe for writing real applications, not just fancy websites.  No other framework can do what Seaside does, as easily as Seaside does it.  Real components with their own state, real objects, no pages, no templates, Ajax in pure Smalltalk by simply wiring events together on the server side, calls to other components are actual method calls rather than hacked up URL conventions.</p>
<p>For Rails fans (myself included), don&#8217;t compare Seaside to Rails, rather compare Seaside to ActionPack, the view controller layer within Rails.  If you want to see an apples to apples comparison of the entire stack, it&#8217;d be something like&#8230;</p>
<p>ActionMailer == Existing Squeak services<br />
ActionPack == Seaside<br />
ActionWebservice == SoapCore<br />
ActiveRecord == Glorp<br />
ActiveSupport == Existing Squeak code, the image is full of DSL mini languages to make everything pretty</p>
<p>Seaside isn&#8217;t the well integrated full stack solution that Rails is, but all the parts are there, you can mix and match your own perfect framework.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/pollak-on-seaside/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Why Smalltalk</title>
		<link>http://onsmalltalk.com/programming/smalltalk/why-smalltalk/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/why-smalltalk/#comments</comments>
		<pubDate>Wed, 04 Apr 2007 05:27:25 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Lisp]]></category>

		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/why-smalltalk/</guid>
		<description><![CDATA[As always, I enjoy reading what someone thinks of Smalltalk after a proper demonstration.  I find Edwards thoughts on Smalltalk typical of that aha you get when you really see what Smalltalk&#8217;ers can do.  
Edward was lucky, he had a Smalltalker handy to show him the ropes, few have that opportunity.  I&#8217;m [...]]]></description>
			<content:encoded><![CDATA[<p>As always, I enjoy reading what someone thinks of Smalltalk after a proper demonstration.  I find <a href="http://www.rippleinteractive.com/blog/2007/04/02/1175579880000.html">Edwards thoughts on Smalltalk</a> typical of that aha you get when you really see what Smalltalk&#8217;ers can do.  </p>
<p>Edward was lucky, he had a Smalltalker handy to show him the ropes, few have that opportunity.  I&#8217;m still amazed by how many people think they can grok Smalltalk by seeing syntax examples.  Smalltalk isn&#8217;t its syntax, it&#8217;s its environment.  Smalltalk is a living world of running objects, there are no files, no applications, just what&#8217;s running.  To understand Smalltalk, you have to either actually use it for a while, or have a seasoned Smalltalker demonstrate it to you.  Reading sample code just won&#8217;t cut it.</p>
<p>For better or for worse, Smalltalk is a world unto itself.  It&#8217;s much more an operating system than a programming language.  When Steve Jobs stole the idea for a windowing system and mouse from Xerox (not that they invented it), it was Smalltalk he was seeing.  Even he readily admits he was so dazzled by the GUI he didn&#8217;t even notice Smalltalk, or the fact it was all networked with email, things we take for granted now but didn&#8217;t exist widely back then.</p>
<p>Sure, we package code and use source control, but our methods aren&#8217;t file based.  Our source control systems are language aware, they can diff and merge code at the method level, auto merge and allow you to select, method by method, which version you want to keep.  Smalltalk is different, top to bottom, it&#8217;s just different.  Everything is live, code changes are live, applications don&#8217;t start, they&#8217;re simply always running.  Object oriented programming means something entirely different to a Smalltalker than to someone doing OO in another language.  </p>
<p>Ruby comes very close to Smalltalk.  It&#8217;s a nice introduction to many if not most of Smalltalk&#8217;s ideas.  It&#8217;s very pragmatic, fits in with the world around it, it&#8217;s based on files, works with your favorite text editor, etc. etc.  But Ruby still isn&#8217;t Smalltalk.  I use Ruby, I like Ruby, but Smalltalk is more productive when I&#8217;m working in unknown territory.  Smalltalk is better for prototyping ideas quickly.  A read eval print loop and hyper-linked documentation just doesn&#8217;t compare to a real Smalltalk workspace and a real Smalltalk browser where the code itself is hyper-linked and navigable and objects are things you can actually pick up and shake.</p>
<p>Smalltalk doesn&#8217;t have to be pragmatic, because it&#8217;s better than its imitators and the things that make it different are also the things that give it an advantage.  Its syntax isn&#8217;t weird, C&#8217;s is.  Weird isn&#8217;t even the right word, because what&#8217;s weird is totally relative and very dependent on your background experience.  Smalltalk&#8217;s syntax is simply better.</p>
<pre>
Window window = new Window(0, 0, 800, 600);
</pre>
<p>Simply isn&#8217;t as expressive as&#8230;</p>
<pre>
window := Window top: 0 left: 0 width: 800 height: 600.
</pre>
<p>And this is a trivial example, the more complicated the code gets, the more of an advantage Smalltalk has.  Ruby chose to go with a C&#8217;ish syntax, but by convention, mostly tries to fake the Smalltalk style anyway because it&#8217;s simply better.</p>
<pre>
window = Window.new :top => 0, :left => 0, :width => 800, :height => 600
</pre>
<p>So, if you still haven&#8217;t tried Smalltalk, and I mean really tried it, by writing an application in it, give it a go.  You&#8217;ll never regret it, because everything you learn, and you&#8217;ll learn a lot, you&#8217;ll be able to bring back with you to whatever language you call home.  Smalltalk will change the way you think, no matter what language you&#8217;re coming from.  Whether it changes it for better or for worse is of course entirely up to you.  If you&#8217;re afraid to try Smalltalk, then at least try Smalltalk Lite&#8230; uh, I mean, Ruby, you&#8217;ll enjoy it and still be able to use your existing tools.  You can work your way up to the real thing.</p>
<p>PS: Lisp and Haskell are two other equally mind bending languages that I think everyone should learn, however, neither of them can touch Smalltalk&#8217;s development environment.  That being said, learn them anyway.</p>
<p><strong>Featured Resources</strong>&#8230;</p>
<p>Just like Smalltalk stands different than the rest, there is a wide range of <a href="http://www.hostingrevealed.com">cheap web hosting</a> companies offering their <a href="http://www.unifyhosting.com">best hosting</a> packages. You will be able to <a href="http://www.1domainguru.com">register domain</a> very quickly with some of these. If you have many <a href="http://www.registeranydomain.com">domains</a>, you can still avail this facility. For small business owners, the hosting companies like <a href="http://www.businesshostingprovider.com/hosting/startlogic.htm">startlogic</a> are coming up with the best solutions for their needs.</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/why-smalltalk/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Scaling Seaside Redux: Enter the Penguin</title>
		<link>http://onsmalltalk.com/programming/smalltalk/scaling-seaside-redux-enter-the-penguin/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/scaling-seaside-redux-enter-the-penguin/#comments</comments>
		<pubDate>Wed, 14 Mar 2007 05:33:24 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/scaling-seaside-redux-enter-the-penguin/</guid>
		<description><![CDATA[In my last post titled My Journey to Linux I spoke about Linux.  Having decided to use Linux to host my Seaside servers, I was now faced with picking a distro.  I chose Ubuntu Server.  I&#8217;ve heard good things about Debian and Ubuntu and I wanted something clean, free of bloat, and [...]]]></description>
			<content:encoded><![CDATA[<p>In my last post titled <a href="http://onsmalltalk.com/programming/smalltalk/seaside/my-journey-to-linux/">My Journey to Linux</a> I spoke about Linux.  Having decided to use Linux to host my Seaside servers, I was now faced with picking a distro.  I chose <a href="http://www.ubuntu.com/products/GetUbuntu/download#lts">Ubuntu Server</a>.  I&#8217;ve heard good things about Debian and Ubuntu and I wanted something clean, free of bloat, and designed to be used as a server.  I also wanted to try a distro I&#8217;d never tried before.  In the past, I&#8217;ve tried Red Hat, its offshoot Fedora, and Slackware.  I almost tried Suse but it seemed too aimed at the desktop and I was looking for something to use as a server.    Ubuntu seemed to fit the bill nicely.  I grabbed a spare test box, and decided to explore the idea of hosting Seaside on a Linux server by installing Ubuntu.</p>
<p>I popped in the CD burned from downloading the ISO image and was greeted with a nice menu asking me what I wanted to do.  I chose to install server to hard drive and proceed through an install that reminded me very much of the old NT4 install but better.  The install finished, successfully detected all the hardware, auto configured the network (using the local DHCP server), and left me with a command line login prompt, exactly what I wanted.  At this point, I was very impressed, setting up a Linux server takes a fraction of the time of setting up a Windows server and was completely trouble free.  I wouldn&#8217;t use DHCP for a production server, but it&#8217;ll do fine for testing purposes.</p>
<p>Now, on to what I thought would be the hard part, setting up the necessary software.  I haven&#8217;t yet loaded emacs, so I&#8217;ll use pico and to whip the server into shape.</p>
<p>I spent a few minutes looking into <a href="http://www.debian.org/doc/FAQ/ch-pkgtools.en.html#s-apt-get">Debian&#8217;s package system</a>, learned what I needed, and then away I went.  First I needed to ensure the server was up to date.</p>
<pre>
sudo apt-get update
sudo apt-get upgrade
</pre>
<p>OK, that was easy.  Now I need to install some software.  Two of the main things I wanted weren&#8217;t in the default Ubuntu repositories.  Squeak and Daemontools.  Squeak for hosting Seaside and Daemontools because I found out that&#8217;s what <a href="http://www.lukas-renggli.ch/blog">Lukas</a> uses to maintain his Seaside services, and HAProxy to load balance the processes.  I quickly found repositories for all of them and added them to the list of repositories available.</p>
<pre>
sudo pico /etc/apt/sources.list
</pre>
<p>and added&#8230;</p>
<pre>
#daemontools
deb http://smarden.org/pape/Debian/ sarge unofficial
deb-src http://smarden.org/pape/Debian/ sarge unofficial
#squeak
deb http://ftp.squeak.org/debian/ stable main
deb-src http://ftp.squeak.org/debian/ stable main
#haproxy
deb http://ftp.sysif.net/debian sid main
</pre>
<p>Install the cert for HAProxy site</p>
<pre>
wget http://ftp.sysif.net/debian/apt_key.asc
sudo apt-key add apt_key.asc
</pre>
<p>Now fetch the new lists by updating again&#8230;.</p>
<pre>
sudo apt-get update
</pre>
<p>OK, time to install everything I want.  I need Squeak, an FTP server, Apache, Daemontools for managing services, a SSH server for remote access, HAProxy for load balancing, Samba for networking with my other windows servers, and Emacs because I&#8217;m going to be using it.  I chose HAProxy for two reasons, there&#8217;s no official Ubuntu version of Apache2.2 with mod_proxy_balancer so installing is a pain, and even with mod_proxy_balancer I haven&#8217;t been able to get it to work successfully with Seaside.  So, on to the install, simple enough&#8230;</p>
<pre>
sudo apt-get install squeak daemontools vsftpd
sudo apt-get install apache2 apache2-utils
sudo apt-get install openssh-server emacs21 haproxy samba
</pre>
<p>This was actually one command but 3 fits nicer on the blog.  Now configure the ftp server&#8230;</p>
<pre>
sudo emacs /etc/vsftpd.conf
</pre>
<p>and make a few changes&#8230;</p>
<pre>
anonymous_enable=NO
local_enable=YES
write_enable=YES
</pre>
<p>and restart the ftp service&#8230;</p>
<pre>
sudo /etc/init.d/vsftpd restart
</pre>
<p>Now setup Apache with the modules I need&#8230;</p>
<pre>
sudo a2enmod rewrite
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod deflate
</pre>
<p>and restart the Apache service&#8230;</p>
<pre>
sudo /etc/init.d/apache2 restart
</pre>
<p>And I&#8217;m mostly setup.  Wow, that was easy, much easier than I&#8217;d assumed it would be.</p>
<p>Time to setup Seaside.  I&#8217;m no Linux expert, but I see other services running out of /etc/serviceName so I&#8217;ll setup my Seaside services the same way.   I&#8217;m going to run 10 processes, so I&#8217;ll create one directory per process, i.e. squeak1, squeak2, etc.  Using daemontools I simply have to setup a directory for my service with the files it needs and a shell script called &#8220;run&#8221; that will kick off the service.  Here&#8217;s the script&#8230;</p>
<pre>
#!/bin/bash
exec squeakvm -mmap 200m -headless SqueakProd "" port 3001
</pre>
<p>I&#8217;m using mmap to limit each process to a maximum of 200 megs of ram and then feed Seaside the port number to start on, so squeak1 runs on port 3001, squeak2 on 3002, etc.  In each folder I put SqueakProd.image, SqueakProd.changes, SqueakV39.sources and chmod 755 the run script.</p>
<p>Because I&#8217;m using daemontools, I can now start my services by simply creating a symbolic link in the /service directory to the /etc/squeakX directory for each directory I created.</p>
<pre>
sudo ln -s /etc/squeak1 /service/squeak1
</pre>
<p>My services are started within a few seconds and maintained by daemontools.  Now lets setup the load balancer.  Seaside requires session persistence to do the magic it does, so we need to configure HAProxy to use a cookie to ensure a user gets routed to the appropriate server each time.  All that talk about statelessness being necessary is crap, <a href="http://smallthought.com/avi/?p=20">an old onion in the web framework recipe</a> that isn&#8217;t at all necessary and is actually crippling.</p>
<pre>
sudo emacs /etc/haproxy/haproxy.cfg
</pre>
<p>using these settings for now (these could change based on load testing later)&#8230;</p>
<pre>
global
    log 127.0.0.1 local0
    maxconn 32000
    chroot /usr/share/haproxy
    pidfile /var/run/haproxy.pid
    uid 33
    gid 33
    daemon

defaults
    log global
    mode http
    option httplog
    option dontlognull
    retries	3
    redispatch
    contimeout 5000
    clitimeout 50000
    srvtimeout 50000

listen smalltalk 0.0.0.0:8080
    mode http
    cookie SEASIDE insert nocache
    balance roundrobin
    server app1 127.0.0.1:3001 cookie app1inst1 check
    server app2 127.0.0.1:3002 cookie app1inst2 check
    server app3 127.0.0.1:3003 cookie app1inst3 check
    server app4 127.0.0.1:3004 cookie app1inst4 check
    server app5 127.0.0.1:3005 cookie app1inst5 check
    server app6 127.0.0.1:3006 cookie app1inst6 check
    server app7 127.0.0.1:3007 cookie app1inst7 check
    server app8 127.0.0.1:3008 cookie app1inst8 check
    server app9 127.0.0.1:3009 cookie app1inst9 check
    server app10 127.0.0.1:3010 cookie app1inst10 check
</pre>
<p>Then I need to enable the proxy, it&#8217;s disabled by default.</p>
<pre>
sudo emacs /etc/default/haproxy
</pre>
<p>and set&#8230;</p>
<pre>
STARTUP=1
</pre>
<p>then restart the service</p>
<pre>
sudo /etc/init.d/haproxy restart
</pre>
<p>Now I hit the box on port 8080 with a web browser to ensure everything works, it does.  I now have 10 load balanced sticky session enabled instances of Seaside running behind HAProxy, sweet!  Time to setup Apache as the front end to this beast to offload all the static content, URL rewriting, HTTP compression, HTTPS, and logging to it.  Only dynamic requests will be proxied to the Seaside cluster.  This also allows me to mix in other frameworks when necessary (Rails, .Net), all proxied behind Apache.</p>
<p>Now I want to disable the default site and create a new virtual host&#8230;</p>
<pre>
sudo a2dissite default
sudo emacs /etc/apache2/sites-available/linuxweb1
</pre>
<p>with the following settings&#8230;</p>
<pre>
NameVirtualHost *:80

&lt;VirtualHost *:80&gt;
    ServerName linuxweb1
    DocumentRoot /var/www
    RewriteEngine On
    ProxyRequests Off
    ProxyPreserveHost On
    UseCanonicalName Off

    # http compression
    DeflateCompressionLevel 5
    SetOutputFilter DEFLATE
    AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml text/javascript text/css
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

    #proxy to seaside if file not found
    RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
    RewriteRule ^/(.*)$ http://localhost:8080/$1 [P,L]

    # Logfiles
    ErrorLog  /var/log/apache2/linuxweb1.error.log
    CustomLog /var/log/apache2/linuxweb1.access.log combined
&lt;/VirtualHost&gt;
</pre>
<p>Now I need to enable Apache&#8217;s proxy, it&#8217;s disabled by default.  </p>
<pre>
&lt;Proxy *&gt;
    Order allow,deny
    Allow from all
&lt;/Proxy *&gt;

ProxyVia Block
</pre>
<p>and enable the new site and reload Apache</p>
<pre>
sudo a2ensite linuxweb1
sudo /etc/init.d/apache2 force-reload
</pre>
<p>Now I just check the box by hitting it in my web browser, http://linuxweb1/seaside/config, verify everything works.  It does, my session sticks to a single Seaside instance.  It&#8217;s easy to tell if something is setup wrong, without sticky sessions no Seaside link works.  All in all, I&#8217;m very pleased with this setup, it runs great, performs well, and being Linux, should be easy to replicate to new servers as I add them.</p>
<p>I&#8217;ll just pretend everything actually went this smooth, in reality, there were many points during this install where I had to stop and learn something new about Linux, or about configuring the various components required.  In reality, my brain hurts a little after all this, but in a good way.  I tackled a lot of new stuff all at once, but I had a lot of fun doing it.</p>
<p>If anyone has a better setup or pointers about mistakes I&#8217;ve made, I&#8217;d love to hear about it, this is my first crack at using Linux as a web server.</p>
<p>NOTE: I left out the samba setup because it deals with various things with my local windows network that aren&#8217;t relevant to this setup.  As with any article of this detail, I may have overlooked some step I took but forgot to write down while doing so, so I&#8217;ll make corrections as they come up in any comments.</p>
<p>UPDATE: Thanks to a tip in the comments, and having learned Linux a little better now, I use &#8220;aptitude update/upgrade/install&#8221; rather than &#8220;apt-get update/upgrade/install&#8221; because aptitude will track dependencies and clean them out automatically when I uninstall stuff.</p>
<p>UPDATE: Since I&#8217;ve switched to Linux, my Seaside site has become incredibly stable and much faster than when it was hosted on Windows 2003 server.  Part of the speedup comes from HTTP compression, however, the CPU load is now less than before.  The hardware is slightly different as well.  I went from 3 dual processor windows servers to 2 dual (both hyper-threaded so looks like 4) processor Linux servers.  So it&#8217;s not an apples to apples comparison, but I&#8217;ll give Linux the credit anyway ;)</p>
]]></content:encoded>
			<wfw:commentRss>http://onsmalltalk.com/programming/smalltalk/scaling-seaside-redux-enter-the-penguin/feed/</wfw:commentRss>
		</item>
		<item>
		<title>My Journey to Linux</title>
		<link>http://onsmalltalk.com/programming/smalltalk/seaside/my-journey-to-linux/</link>
		<comments>http://onsmalltalk.com/programming/smalltalk/seaside/my-journey-to-linux/#comments</comments>
		<pubDate>Sun, 11 Mar 2007 23:02:18 +0000</pubDate>
		<dc:creator>Ramon Leon</dc:creator>
		
		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Seaside]]></category>

		<category><![CDATA[Lisp]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Smalltalk]]></category>

		<category><![CDATA[Sql]]></category>

		<guid isPermaLink="false">http://onsmalltalk.com/programming/smalltalk/seaside/my-journey-to-linux/</guid>
		<description><![CDATA[I&#8217;m a Windows guy, I&#8217;ve always been a Windows guy.  Windows today is more stable than ever.  Seems now would be the best time of all to be a Windows guy.  Slowly but surely though, I&#8217;m becoming a Linux guy.
Truth is, I was always a Microsoft guy, and that simply included Windows [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a Windows guy, I&#8217;ve always been a Windows guy.  Windows today is more stable than ever.  Seems now would be the best time of all to be a Windows guy.  Slowly but surely though, I&#8217;m becoming a Linux guy.</p>
<p>Truth is, I was always a Microsoft guy, and that simply included Windows along with all of their development products.  I used to be a hardware/network technician.  I&#8217;d setup and maintain networks for medium to small businesses.  Windows was always the way to go here, it&#8217;s what the users were accustomed to and expected.  I&#8217;d usually setup a Windows NT server and from a dozen to maybe 30 client computers running various version of Windows including NT workstation.  So Windows was just something I was always familiar with.</p>
<p>Even back then, I had the occasional urge to try other things.  One of my first experiences with Linux involved using it as a firewall for a windows network on some cheap throwaway hardware that wasn&#8217;t good for much else.  But it always seemed a pain to use, and I didn&#8217;t really understand it, despite having it working quite well for what I intended.  I just didn&#8217;t see the point of not having a nice GUI and using cryptic commands to do everything.</p>
<p>Later, I learned to program in VBScript and VB using ASP and SQL.  I became a web developer and abandoned the hardware gig.  Software was so much more interesting.  ASP became ASP.net, and VB became C# when I realized how crappy a language VB actually was.   What made me want to change was my discovery of the <a href="http://www.c2.com/cgi/wiki?WelcomeVisitors">original Wiki</a>.  I found a place where real programmers hung out and discussed anything and everything.  I realized the world was bigger than VB.  VB.Net fixed many of the issues with VB and is pretty much equiva