<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6201102787326924156</id><updated>2012-01-25T22:04:40.123-08:00</updated><category term='rest'/><category term='cocoa'/><category term='elegant'/><category term='iphone'/><category term='emacs'/><category term='javascript'/><category term='java'/><category term='tips'/><category term='apple'/><category term='programming'/><category term='dropbox'/><category term='best practices'/><category term='commenting'/><category term='ipad'/><category term='design'/><category term='habits'/><category term='http'/><category term='backup'/><category term='chrome'/><title type='text'>Bryan Kyle's Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://bryan-kyle.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>57</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-4012368237747269749</id><published>2012-01-23T06:09:00.001-08:00</published><updated>2012-01-23T06:09:09.218-08:00</updated><title type='text'>Waking Up at 5am to Code: A Response</title><content type='html'>&lt;p&gt;I recently read a post by &lt;a href="http://www.mattgreer.org"&gt;Matt Greer&lt;/a&gt; titled &lt;a href="http://www.mattgreer.org/post/2fiveam"&gt;Waking Up at 5am to code&lt;/a&gt;.  I&amp;#8217;ve been doing something similar for about a year now so I figured I&amp;#8217;d post my 2 cents on the matter.&lt;/p&gt;&lt;h2 id="alittlebackground"&gt;A little background&lt;/h2&gt;&lt;p&gt;Quite some time ago I realized that the amount of time I spent working on personal projects had been greatly diminished.  I wanted to spend time working on those projects, but during core waking hours my time was tied up with work and family commitments.  I needed to spend time at work during the day on week days, I wanted to spend time during the evening and weekends with my family.&lt;/p&gt;&lt;p&gt;Since pretty much all of my waking hours were accounted for I thought I&amp;#8217;d try getting up earlier.  At first I started getting up at 6:00am.  That gave me about an hour or so to get some work done.  And it worked well for a while, but life changes and so does the family schedule.  As a result I started having to get up even earlier: 5:30am.&lt;/p&gt;&lt;p&gt;Getting up at 5:30am is were I&amp;#8217;m at these days.  In theory, that gives me a solid 1 1/2 hours to get stuff done in the morning.  Reality on the other hand isn&amp;#8217;t as optimistic.  It usually takes a good 10 minutes for the morning fog to clear.  I also have a few small morning chores that need to be done no later than 6:00am.  Since I don&amp;#8217;t want to interrupt my flow I need to get those done early too; those take an additional 10 minutes.  Lastly, in order to make sure everyone is able to get themselves ready and out of the house on time I need to be completely dressed and out of the bathroom (we only have one) by about 7:00am.  Figure 15-20 minutes there for the morning routine.&lt;/p&gt;&lt;p&gt;By the time these taxes are paid my gross working time has gone from 1 1/2 hours down to 50-55 minutes.  It can be really demotivating to realize that I don&amp;#8217;t even have a full hour to get things done.  But on the flip side it can also light a fire to make sure everything that needs to get done gets done.&lt;/p&gt;&lt;p&gt;I&amp;#8217;ve had some success with my morning routine over the past year.  It&amp;#8217;s been a rocky road, but for the most part I think I&amp;#8217;ve done alright.  I haven&amp;#8217;t produced much, as my desire to work on side projects comes and goes.  Having the time set aside does really help though.  I know that I&amp;#8217;ll have guaranteed time to work on things that I&amp;#8217;d like to.  But typically that time is spent reading or relaxing; everyone needs down time, and I find that without that morning time I don&amp;#8217;t get enough of it.&lt;/p&gt;&lt;h2 id="forthoseofyoudoingthisorwantingtodothis"&gt;For those of you doing this or wanting to do this&lt;/h2&gt;&lt;p&gt;Ultimately rearranging your schedule can be a fairly disruptive change in your life.  The disruptions for myself have been quite minimal, but you need to make sure that those closest to you understand what you&amp;#8217;re doing, why you want to do it, and are on board with it.  If they aren&amp;#8217;t you might start running into some problems.  For those considering this kind of change, here are a few pointers:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;If you&amp;#8217;re up early, people start assuming that you won&amp;#8217;t mind doing things for them.  This encroaches massively on personal time and can be a real problem.  Saying &amp;#8220;No&amp;#8221; is vitally important to protecting your few precious hours.  That being said you can&amp;#8217;t always say no.  There will always be times when you have to carve off a piece of those hours as needed; just keep those to a minimum.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Don&amp;#8217;t be militant about getting up early every day.  Sometimes you need a break.  I find myself sleeping in about 1 day a week.  It&amp;#8217;s a nice treat, just don&amp;#8217;t get used to it.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Getting up early also means going to bed earlier.  This can be a social problem if you have friends and family that are night owls.  Staying up late on their account will only serve to sap your energy for the next morning.  Don&amp;#8217;t stay up late unless you&amp;#8217;re ok with sleeping in the next morning.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Always have a plan for what to do the next morning.  If you don&amp;#8217;t wake up and know exactly what you need to work on or get accomplished you&amp;#8217;ll either not want to get out of bed or get up and zone out.  Neither of these is desireable; so make sure you have a plan for the next morning.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Make sure your work area is comfortable.  I&amp;#8217;m sure this goes without saying, but having a comfortable, and in the winter warm, work place really helps to motivate you to get out of bed.  If the bed is warm and comfortable, why would you want to sit in a cold office in an uncomfortable chair?&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-4012368237747269749?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4012368237747269749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4012368237747269749'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2012/01/waking-up-at-5am-to-code-response.html' title='Waking Up at 5am to Code: A Response'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-1673002776366537231</id><published>2012-01-21T17:24:00.001-08:00</published><updated>2012-01-21T17:24:12.936-08:00</updated><title type='text'>Mute Switch Bike Sheds</title><content type='html'>&lt;p&gt;A few days ago there was a big kerfuffle about the ring/silence switch on the iPhone.  People have been coming out of the woodwork with their thoughts and opinions on the matter.  Don&amp;#8217;t worry.  I&amp;#8217;m not going to post my thoughts on the issue here.  Yes, I have an opinion, but really what I want to highlight is the debate itself.  More importantly, I want to discuss why this is such a polarizing issue.&lt;/p&gt;&lt;h2 id="butfirstalittlebackground"&gt;But first, a little background&lt;/h2&gt;&lt;p&gt;If you&amp;#8217;re reading this post anywhere near the posting date you can safely skip this section.&lt;/p&gt;&lt;p&gt;During a performance of the New York Philharmonic a very distinctly iPhone ring started to play.  It continued making noise for quite some time.  Finally the conductor had had enough and stopped the performance to confront whomever had their phone ringing.  Unbeknownst to the owner, his phone had an alarm that was set to go off during the performance.  He didn&amp;#8217;t know about the alarm as he was given the phone just prior to the performance and thought he had set the phone to mute.&lt;/p&gt;&lt;p&gt;Due to the design of the iPhone, alarms will sound even if the mute&lt;sup id="fnr1-20120121"&gt;&lt;a href="#fn1-20120121"&gt;1&lt;/a&gt;&lt;/sup&gt; switch is turned to off.  Pundits and non-pundits alike have been arguing the finer points of the switch and the design over the past few days.&lt;/p&gt;&lt;p&gt;Should the mute switch prevent the device from making any noise, or should it make noise for some select or important events?  That&amp;#8217;s what everyone seems to be focused on.  What I&amp;#8217;m interested in is: why does everyone have an opinion on this issue?&lt;/p&gt;&lt;h2 id="whydoeseveryoneandtheirdoghaveanopinion"&gt;Why does everyone and their dog have an opinion?&lt;/h2&gt;&lt;p&gt;The mute switch is a &lt;a href="http://bikeshed.com/"&gt;bike shed&lt;/a&gt;.  No, it&amp;#8217;s not literally a bike shed, but as a solution to a problem it is.  What is a bike shed problem exactly?  A bike shed is a problem that&amp;#8217;s reasonably well understood by the common person.  Since the problem is well understood everyone feels that they are entitled to an opinion on it.  In fact, it&amp;#8217;s been said that the amount of noise in the decision making process is inversely proportional to the complexity of the problem.&lt;/p&gt;&lt;p&gt;From the definition of a bike shed:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Parkinson shows how you can go in to the board of directors and get approval for building a multi-million or even billion dollar atomic power plant, but if you want to build a bike shed you will be tangled up in endless discussions.&lt;/p&gt;&lt;p&gt;Parkinson explains that this is because an atomic plant is so vast, so expensive and so complicated that people cannot grasp it, and rather than try, they fall back on the assumption that somebody else checked all the details before it got this far.   Richard P. Feynmann gives a couple of interesting, and very much to the point, examples relating to Los Alamos in his books.&lt;/p&gt;&lt;p&gt;A bike shed on the other hand.  Anyone can build one of those over a weekend, and still have time to watch the game on TV.  So no matter how well prepared, no matter how reasonable you are with your proposal, somebody will seize the chance to show that he is doing his job, that he is paying attention, that he is &lt;em&gt;here&lt;/em&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Since everyone has a stake in how the mute switch on the iPhone should work, and the complexity of the problem is low, everyone has an opinion.  Those following the debate will point out that the complexity of this problem is anything &lt;em&gt;but&lt;/em&gt; low.&lt;/p&gt;&lt;p&gt;It&amp;#8217;s a difficult problem with no 100% correct solution.  Regardless of the choice made by the designers there would be some class of user that the solution was wrong for.  However, that won&amp;#8217;t stop people from arguing over what colour this bike shed should be.&lt;/p&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li id="fn1-20120121"&gt;I say mute switch because that&amp;#8217;s the common term for it.  In actuality it&amp;#8217;s call the Ring/Silence switch.  The difference between the terms is splitting hairs as far as customers are concerned.&lt;a href="#fnr1-20120121"&gt;&amp;#8617;&lt;/a&gt;&lt;/ol&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-1673002776366537231?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1673002776366537231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1673002776366537231'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2012/01/mute-switch-bike-sheds.html' title='Mute Switch Bike Sheds'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-7779874717566836359</id><published>2011-12-22T05:50:00.001-08:00</published><updated>2011-12-22T05:50:51.795-08:00</updated><title type='text'>Twelve South Compass iPad Stand</title><content type='html'>&lt;p&gt;I recently had a chance to try out the Twelve South Compass iPad stand.  I&amp;#8217;ve had my eye on it for a long time but never had opportunity to give it a test run for myself.&lt;/p&gt;&lt;h2 id="thepackaging"&gt;The Packaging&lt;/h2&gt;&lt;p&gt;Unlike pretty much every other accessory maker, Twelve South totally nails it when it comes to packaging.  They know that the packaging is the first taste of the product that the customer gets.  Well designed, tasteful, easy to open packaging gives the customer a glimpse of how much effort they put into designing the product inside.&lt;/p&gt;&lt;p&gt;In the case of the Compass stand, the package consists of a box containing the stand encased in a plastic shell.  The box doesn&amp;#8217;t have a lid so the customer can see the stand inside the box through the outer plastic shell.  There&amp;#8217;s no tape to fuss with, just open the packaging and slide out the box.  The Compass sits on a cardboard table in the box and is held in place with white elastic.  The fact that they chose to use elastic instead of twist ties is a gift in and of itself.&lt;/p&gt;&lt;p&gt;Underneath the cardboard table there&amp;#8217;s a slipcase.  The slipcase is simple and speaks for itself.  Under the slipcase is a spartan instruction manual with the sole words &amp;#8220;Thank You&amp;#8221; emblazened on the front.  The instruction manual is fairly short: one page.  Simple directions for how to use the stand are included.  At the end of the instructions is a whimsical section on some uses for the box that the stand came in.&lt;/p&gt;&lt;p&gt;These little touches: the easy to open packaging, well designed box, the full front page of the instructions dedicated to thanking the customer, and whimsical instructions aren&amp;#8217;t frivolous.  They all come together to give the customer a great first experience.  Not just a great first experience with the product, but potentially these details serve as an introduction to the company that made them.  They exhibit the ethos of the maker: its attention to detail, its gratitude towards customers, and its fun side.&lt;/p&gt;&lt;p&gt;But enough about the packaging, lets talk about the stand.&lt;/p&gt;&lt;h2 id="thestand"&gt;The Stand&lt;/h2&gt;&lt;p&gt;The Compass isn&amp;#8217;t just an iPad stand, it&amp;#8217;s a work of art.  The stand is solidly built and feels great.  It&amp;#8217;s heavier than you&amp;#8217;d think for something of its size.  The brushed finish nicely matches the finish on Apple&amp;#8217;s own hardware making the Compass feel at home with your iPad and MacBook Air.&lt;/p&gt;&lt;p&gt;When folded up the Compass is very compact; it&amp;#8217;s small enough that you could fit it easily in your pocket or bag and hardly know its there — aside from the weight that is.  The small carrying pouch for Compass is a nice touch; it protects not only the stand but anything else that might be rattling around with it in your bag.&lt;/p&gt;&lt;p&gt;The Compass has 2 different modes when unfolded.  It can either prop the iPad up like an easel or lay the iPad down at an incline providing for a nice keyboarding surface.  When using the Compass as an easel the iPad can sit in either landscape or portrait orientation.  In addition, the legs that the iPad stands on are quite a bit longer than needed.  The legs being longer means that the compass will work with both iPad 1 and 2, with or without a case.  Both of these features make the Compass stand one of the most versatile stands I&amp;#8217;ve seen.  The versatility coupled with its elegant design, and compact size make for a very compelling and attractive stand.&lt;/p&gt;&lt;p&gt;Unfortunately, as compelling and attractive as the stand is, it has some problems.  The main problem I found with the Compass is that the hinge on the back leg was extremely loose.  When handling the stand I had to be careful otherwise it would open up.  Putting it in its case could sometimes be troublesome as well.  But these are minor inconveniences when compared to the biggest problem with the hinge being loose.  After some use the Compass would fold itself up and collapse.&lt;/p&gt;&lt;p&gt;The rubberized feet on the bottom of the legs, the shallow angle of the back leg, and the loose hinge worked together to produce a perfect storm.  Tapping around the center of the screen would cause the front 2 legs of the stand to lift off the table.  With all the force in the back leg and the loose hinge the leg would eventually move into a position where it would fold up and collapse onto the table.  If the hinge were tighter not only would this not be a problem, but the stand would also feel much higher quality.&lt;/p&gt;&lt;p&gt;I&amp;#8217;m sure they had good reasons for the hinge having as much friction as it does.  But a tighter hinge isn&amp;#8217;t the only solution.  A pin or something similar that holds the back leg in one of two positions would do the trick.&lt;/p&gt;&lt;p&gt;Ignoring the collapsing issue, I&amp;#8217;m not sure that the Compass provides a lot of value if you have and iPad 2 with a Smart Cover.  The only thing that the Compass provides over the Smart Cover is the freedom to choose orientation — portait or landscape.&lt;/p&gt;&lt;h2 id="conclusions"&gt;Conclusions&lt;/h2&gt;&lt;p&gt;While the Compass Stand looks and feels great, but it&amp;#8217;s expensive for what benefit you may get out of it.  If you have an iPad 2 you likely already have a Smart Cover which provides more value for your money.  Regardless, the fact that the stand collapses after moderate tapping is a major problem in my books.  &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-7779874717566836359?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7779874717566836359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7779874717566836359'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2011/12/twelve-south-compass-ipad-stand.html' title='Twelve South Compass iPad Stand'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-189307375082107890</id><published>2011-11-24T06:50:00.001-08:00</published><updated>2011-11-24T06:50:25.670-08:00</updated><title type='text'>The iPad HDMI Connector</title><content type='html'>&lt;p&gt;I've been fighting a bit of a cold for the last few days.  With a baby and mom that I don't want to give it to I've been sleeping downstairs on our futon.  It's actually suprisingly comfortable.  But one thing that's been getting tedious over the past few nights is our selection of movies.  I usually like to turn on a movie as I wind down for the night, but since our Apple TV with Netflix is upstairs ensconced in the bedroom I've been forced to watch DVDs.  As I'm sure you can imagine, its been a while since we've bought any of those, so our selection is pretty thin.&lt;/p&gt;&lt;p&gt;Seeing as I have a perfectly good iPad and HDMI connector I thought I'd give watching Netflix on the TV using the iPad a shot.  The good news is that it works as advertised; you plug it all together, set the input on the TV the voila: your Netflix movie on the TV.  The bad news is the decidedly un-Apple-like experience of using the thing.&lt;/p&gt;&lt;p&gt;To start its ugly, if utilitarian.  It connects through the only multipurpose port on the device: the 30-pin connector.  The connector is really wide and the HDMI port is offset to one side with a 30-pin connector next to it.  This design makes the whole thing feel bigger than it is and awkward.  A better design might have been vertically stacking the HDMI and 30-pin connector ports so that there is a closer ratio of size between the two ends of the HDMI connector.&lt;/p&gt;&lt;p&gt;Thick HDMI cables have a mind of their own in terms of how they bend.  Through its own force of will it bends the HDMI connector in all sorts of directions that seem like they'll either break the wires in the connector by twisting them or pull the connector out of the iPad by its weight.  I found the contortions of the HDMI connector with a thick HDMI cable to be really worrying.&lt;/p&gt;&lt;p&gt;If I was trying to use the HDMI connector to mirror the iPad's display for a presention it would certainly feel awkward.  But these things don't really matter that much if you're just using the dongle as a way of getting the iPad's screen on to the TV for watching a movie as I was.  Once the connector and HDMI cable were connected and the iPad was laying down these issues weren't so bad.  But then I ran into another problem:  the device cannot be asleep while playing and the Smart Cover has to be open.&lt;/p&gt;&lt;p&gt;Once you close the Smart Cover or press the sleep/wake button the signal to the TV shuts off.  I can see why this is done when you're running on battery; you want to conserve power so if someone has put the iPad to sleep then don't waste power sending the display over the HDMI connector.  I get that, but its a horrible user experience in some situations.  A better design would have been to just turn off the display if full screen video is playing when the device is put to sleep and the HDMI connector is attached.  Then after the video stops playing automatically sleep the whole device after a minute or two.  Wouldn't it be better for battery life to allow the display to be off when the user is doing something non-interactive and using the HDMI connector?&lt;/p&gt;&lt;p&gt;In any case, it did what I needed done so for that I'm thankful.  But there are a few design bugs that I think need to be worked out.  For an extra $60 you can get an Apple TV that does display mirroring without having to physically attach your iPad to the TV, plus a whole lot more.  Either way you go, the iPad has to be awake when the display is mirrored to the TV which is an issue I hope gets addressed in a future release.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-189307375082107890?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/189307375082107890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/189307375082107890'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2011/11/ipad-hdmi-connector.html' title='The iPad HDMI Connector'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-4607771522133189969</id><published>2011-10-31T06:27:00.001-07:00</published><updated>2011-10-31T06:27:10.020-07:00</updated><title type='text'>SuperDuper! Pro Tip</title><content type='html'>&lt;p&gt;As much as I love my new MacBook Air, the transition to the new machine hasn't been completely seamless.  Like any transition to a new computer, there are bound to be hiccups.  One of these hiccups was around my backups.  Since I take my backups very seriously, this was something that really bothered me until I was able to figure out what was going wrong.&lt;/p&gt;&lt;p&gt;After migrating all of my data to the new machine I made sure to run SuperDuper! (the best disk cloning software in the universe).  It ran perfectly for quite some time but after a few weeks it started to fail by running out of disk space on the backup drive.&lt;/p&gt;&lt;p&gt;When I first partitioned my backup drive I made the clone parition the same size as the boot drive: 120GB.  But the MacBook Air has a larger drive in it, double the size at 250GB.  I've been careful to make sure that I don't use more than 120GB on the new machine, so &lt;em&gt;surely&lt;/em&gt; the problem wasn't that I was using more space than I should be.  Or at least that's what I thought.&lt;/p&gt;&lt;p&gt;It turns out that Lion comes with some enhancements to Time Machine.  Under Lion, if your backup drive is not connected, Time Machine will continue to run.  The backups are stored in &lt;code&gt;/.MobileBackups&lt;/code&gt; -- a hidden folder at the root of the boot drive.  Since this is effectively temporary storage, Lion doesn't report any of the space used by this directory in the Unix &lt;em&gt;disk free&lt;/em&gt; or &lt;code&gt;df&lt;/code&gt; command or in the Finder.  Essentially, Lion hides the fact that it's using this space from you at all.  It does this because it will automatically remove old backups to make room for new files written to disk if need be.&lt;/p&gt;&lt;p&gt;Since SuperDuper! didn't know this it would attempt to copy this directory to the  backup drive.  Ordinarily this wouldn't be a problem since the clone drive is usually the same size as the drive being cloned.  This wasn't the case for me however.  After I figured this out I created a new backup script and excluded the &lt;code&gt;/.MobileBackups&lt;/code&gt; directory.  After applying the changes I haven't had any problems.&lt;/p&gt;&lt;p&gt;So, if SuperDuper! is complaining about running out of disk space when running on Lion, you might want to either:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;ensure that the size of the drive you're cloning from is the same size as the drive you're cloning to. or;&lt;/li&gt;&lt;li&gt;exclude &lt;code&gt;/.MobileBackups&lt;/code&gt; from your SuperDuper! backup script.&lt;/li&gt;&lt;/ol&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-4607771522133189969?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4607771522133189969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4607771522133189969'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2011/10/superduper-pro-tip.html' title='SuperDuper! Pro Tip'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-9014980779403461287</id><published>2011-10-27T05:43:00.001-07:00</published><updated>2011-10-27T05:43:57.834-07:00</updated><title type='text'>MacBook Air</title><content type='html'>&lt;p&gt;A few months back I bought a new MacBook Air.  I absolutely love it, it's the best computer I've ever owned.  I'm pretty sure I say that about every new computer I get, but this one is head and shoulders above the rest.&lt;/p&gt;&lt;p&gt;Upgrades in the past used to be just incremental updates to the processor, memory, and hard drive.  This machine has all of that, but what's amazing is how much faster it feels than every other upgrade I've done.  It's really no surprise when you think about it.&lt;/p&gt;&lt;p&gt;There are really only 2 main driving forces that relate to the performance of any application: its use of the procesor, and its use of the hard drive&lt;sup&gt;&lt;a href="#1"&gt;1&lt;/a&gt;&lt;/sup&gt;.  Yes, I'm simplifying here, but typically when you want to optimze a program you need to look at those 2 things.&lt;/p&gt;&lt;p&gt;When a program uses a lot of processor cycles its said to be CPU-bound.  That is, the program's performance is bound by the speed of the processor.  Conversely, when a program reads and writes to the hard drive a lot it's said to be I/O bound; the performance of the program is bound by how quickly it can read and write data.  Very rarely will you ever see a program that's solely CPU bound or I/O bound.  Usually different parts of every program have different performance characteristics.&lt;/p&gt;&lt;p&gt;So why is it no surprise that the MacBook Air feels so much faster than any other computer I've ever owned?  The MacBook Air has a solid state drive.  Solid state drives are a new class of storage media.  They optimize for speed while sacrificing total size.  To give you an example, you can buy a 256GB SSD for roughly the same price as a 4TB spinning rust&lt;sup&gt;&lt;a href="#2"&gt;2&lt;/a&gt;&lt;/sup&gt; drive.  But the speed of these drives is amazing due to how they work.  SSDs have more-or-less direct access to any piece of information on the drive.  Traditional hard drives have to  wait for a spinning platter to come within range of a little arm that can picks the data off the drive.  There are physics involved here, traditional hard drives will never be as fast as an SSD, but if you need a lot of storage space you can't go wrong.&lt;/p&gt;&lt;p&gt;You can get an SSD for pretty much any computer, but at this point they're a fairly expensive upgrade.  It's been said before that installing an SSD is just like getting a new computer. And while my MacBook Air is certainly a new computer, it feels amazing every time I use it.  It's fast.  Faster than anything I've ever used before, and that's mostly thanks to the SSD.&lt;/p&gt;&lt;p&gt;There's a lot more that can be said about the MacBook Air.  It's simple, tossing out things that most people rarely need anymore like DVD drives, FireWire, and extra USB ports.  It's ultra lightweight, something that's really nice to have regardless of whether you care about the weight or not.  The choices you have to make are pretty minimal; pick a screen size, processor and memory.  The price is very reasonable for a premium product.  The fit and finish is excellent.  All told, the MacBook Air truly is the Volkscomputer.&lt;/p&gt;&lt;p&gt;&lt;small&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a name="1"&gt;&lt;/a&gt; Yes, I'm simplifying quite a bit here.  Performance can also be affected by how much parallel computation a program can do, the layout of the program in memory so that it makes efficient use of the CPU's caches, etc.&lt;/li&gt;&lt;li&gt;&lt;a name="2"&gt;&lt;/a&gt;The term spinning rust refers to the fact that traditional mechanical hard drives contain rust colored platters that spin.  Wikipedia has a &lt;a href="http://en.wikipedia.org/wiki/Hard_disk_drive"&gt;great article&lt;/a&gt; about how these types of drives work.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;/small&gt;&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-9014980779403461287?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/9014980779403461287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/9014980779403461287'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2011/10/macbook-air.html' title='MacBook Air'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-8720933048240166754</id><published>2011-10-02T21:06:00.001-07:00</published><updated>2011-10-02T21:06:20.332-07:00</updated><title type='text'>5 Things You Can Do to Ensure Safety of Your Data and Recoverability of Your Computer</title><content type='html'>&lt;p&gt;In my previous article I described some of the problems with the approach most people use to secure their data.  The problems were all essentially the same: security theatre.  In this article I'll outline 5 things that you can do to ensure that your data is safe and increase the likelyhood that you'll be able to get your computer returned.&lt;/p&gt;&lt;p&gt;The advice in this column isn't meant to be prescriptive.  Instead, read through the suggestions and make sure that they make sense to you, and for your situation.  If you have backups and don't need to be bothered with ensuring the returnabilty of your computer by all means, tighten your machine down.  If you're like the rest of us, read on.&lt;/p&gt;&lt;h2&gt;1. Backup Your Data -- Offsite&lt;/h2&gt;&lt;p&gt;This one's a no-brainer.  Backing up your data is one thing, but making sure that you have a good copy of it off site is another.  If someone breaks into your house a backup isn't going to be much good to you if it's sitting on the external hard drive conveniently located next to your computer.  It doesn't matter if you use one of those automated off site backup solutions like &lt;a href="http://www.backblaze.com/partner/af2220"&gt;Backblaze&lt;/a&gt; or &lt;a href="http://www.carbonite.com/en/"&gt;Carbonite&lt;/a&gt;, or if you use an old fashioned sneakernet like me.  Just make sure you have a recent copy of your data off site.&lt;/p&gt;&lt;h2&gt;2. Make Your Computer as Inviting as Possible&lt;/h2&gt;&lt;p&gt;If you're used to a higher level of security, this tip might not make a ton of sense.  It's true, your computer will be wide open if you do this.  While you may want to lock down your computer for the most part, in order to ensure the safe return of your computer you'll want me make it as easy and inviting as possible for a thief to use your computer.  If you make it too difficult either they'll never use it, or they'll find someone to wipe it clean so that they can start fresh.  If they do the latter you'll never see your data again.&lt;/p&gt;&lt;p&gt;So what do I mean by "make your computer as inviting as possible"?  I mean that  you should:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Set up your account to automatically log in.&lt;/li&gt;&lt;li&gt;Remove a power-on password&lt;/li&gt;&lt;li&gt;Remove disk encryption&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;By doing these things you'll ensure that anyone that sits down at your computer will be able to use it for whatever purposes they want.  It also means that everything on your computer will be wide open to anyone that wants access to it.  To fix that you're going to want to:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;1. Lock your keychain
2. Use encrypted disk images
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;3. Lock your Keychain&lt;/h2&gt;&lt;p&gt;The Keychain Access application on the Mac is the unsung hero of password management.  Applications use it to store credentials for web sites you go to and services you use.  The Finder uses it to store passwords for remote file shares, logins for wireless access points, etc. By default the password to unlock your keychain is synchronized with your login password, and the Keychain remains unlocked while you're logged in.  These defaults optimize for user experience, not necessarily security.  But hey, at least these can be configured.&lt;/p&gt;&lt;p&gt;To change these settings your going to want to open the Keychain Access application and open its preferences.  From the preferences window select the &lt;em&gt;First Aid&lt;/em&gt; tab and uncheck the last 2 checkboxes: Set login keychain as default, and Keep login keychain unlocked.&lt;/p&gt;&lt;p&gt;By changing these settings you will need to enter your password whenever an application wants to access some data within the keychain.  This will certainly be more annoying than the default settings, but your passwords and anything else stored in the keychain will remain safe should your computer fall into the wrong hands.&lt;/p&gt;&lt;h2&gt;4.  Use Encrypted Disk Images&lt;/h2&gt;&lt;p&gt;As I discussed in a &lt;a href="/2011/09/safety-and-security.html"&gt;previous post&lt;/a&gt;, encrypting your entire hard disk is a one way street.  Your data will be safe if your computer gets lost or stolen, but it also means that the computer is completely useless to anyone that finds it.  But what if you have sensitive data on your computer?  Clearly you want that data to be secure, you just don't want blanket security across the entire hard drive.  That's where encrypted disk images come in.&lt;/p&gt;&lt;p&gt;Disk Utility will allow you to create encrypted disk images to store any sensitive data.  You can make them virtually any size you want, and use either 128- or 256-bit AES encryption.  As of later releases of Mac OS X you can also use a sparse image format.  Sparse formats allow you to create a disk of virtually any size, but it will only take up as much physical space on disk as the files that are contained within it.  For example if you had a 500MB sparse image but only put 50MB of data in it, the image on disk would only be about 50MB.  The best format to use a whole other discussion.  But for our purposes, it doesn't matter which one you pick, just make sure its encrypted.&lt;/p&gt;&lt;p&gt;Once you have an encrypted disk image you can then store all of your files within the image.  Images can be configured to be mounted automatically upon login by adding them as a login item, but if you don't need to access those files very frequently, its best to leave the images un-mounted until they're needed.&lt;/p&gt;&lt;p&gt;With all of your sensitive data stored in encrypted disk images you can be assured that your data will be safe if your computer gets lost or stolen.&lt;/p&gt;&lt;h2&gt;5. Install a Snooping Tool&lt;/h2&gt;&lt;p&gt;Lastly, to have any hope of getting a stolen computer back, you're best bet is to install a snooping tool.  These tools take screen shots and pictures with a computer's camera, report location and IP information, and do many other things to snoop on a thief or help get your computer back.  An excellent and free tool that does this is &lt;a href="http://preyproject.com/"&gt;Prey&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Once installed, Prey sits idle until you log into the web site to report your computer as lost or stolen.  From there you can configure it to snoop on the thief  at selected intervals.  By using information gathered by Prey and the help of police many people have been able to retrieve their stolen computer.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-8720933048240166754?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8720933048240166754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8720933048240166754'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2011/10/5-things-you-can-do-to-ensure-safety-of.html' title='5 Things You Can Do to Ensure Safety of Your Data and Recoverability of Your Computer'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-427998191324627314</id><published>2011-09-25T22:41:00.001-07:00</published><updated>2011-09-25T22:41:01.070-07:00</updated><title type='text'>Safety and Security</title><content type='html'>&lt;p&gt;It occurred to me recently that if someone were to steal a computer there are really 2 things the victim needs to think about: the privacy of their data, and whether or not they'll be able to get their computer back.  These goals aren't entirely opposed, but it does require a little bit of work in order to have it both ways.&lt;/p&gt;&lt;p&gt;There are lots of choices available to ensure the privacy of your data.  You can use a power-on password to prevent the machine from being booted without the correct password.  This is a fairly good trade off between a hassle for you and protection, but it does have some serious flaws.  Using a power-on password doesn't actually do anything other than the name implies.  The data on the disk is still unencrypted.  If someone wants to get at the data, they can simply put the hard drive in another machine and have free range access to anything on the disk.  A power-on password will just make the machine less valuable to the average thief, but they won't know that until after they've taken it.&lt;/p&gt;&lt;p&gt;Another option is to leave the machine without a power-on password but instead password protect your account.  In this scenario, the computer will boot into the OS, but will not allow anyone to use it without first logging in.   The only difference between account passwords and power-on passwords is that it requires the password later.  Account passwords have a side benefit in that if you forget your password you can re-install the OS and retain all of the user files from the previous install.  Your data isn't safe; someone can put the hard drive into another machine to get access to your information.  But it does make the machine slightly less valuable.  And as with power-on passwords they won't know until after they've taken it.&lt;/p&gt;&lt;p&gt;These solutions are all privacy theatre; they appear to protect your data when in actuallity your data is still unsafe, just more difficult to access.  As any security expert&lt;a href="#1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; will tell you, security through obscurity is not security.  The only true way to protect your data is to encrypt it.  Most operating systems support some for of full disk encryption, whether its built into the operating system ala Mac OS X Lion, or provided by a 3rd party with PGP.  Full disk encryption does what the name implies.  It encrypts the entire contents of the disk.  If someone was to take the encrypted disk from one computer and put it into another, the contents of the disk would still be inaccessible without a password.  This is about your only option in terms of ensuring the privacy of your data.&lt;/p&gt;&lt;p&gt;But this is all for naught if you need your data and your computer gets stolen.  It doesn't matter how private your data is if you'll never see it again&lt;a href="#2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;.  If you've got &lt;a href="/2011/03/my-backup-strategy.html"&gt;a backup strategy&lt;/a&gt; then at least your data will be safe, but computers aren't cheap and if you're like me, you'd like to get it back&lt;a href="#3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;.  So what can you do to protect your data and help to ensure that you get your computer back if it gets stolen?&lt;/p&gt;&lt;p&gt;That's a good question, worthy of its own post.  Come back next week to find out.&lt;/p&gt;&lt;p&gt;&lt;small&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a name="1"&gt;&lt;/a&gt;Is there really such a thing as a security expert?&lt;/li&gt;&lt;li&gt;&lt;a name="2"&gt;&lt;/a&gt;It does matter since all of your secrets will remain secrets.  But if you're storing that data it's likely that you need it.&lt;/li&gt;&lt;li&gt;&lt;a name="3"&gt;&lt;/a&gt;Really, I'm not sure I'd want&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;/small&gt;&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-427998191324627314?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/427998191324627314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/427998191324627314'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2011/09/safety-and-security.html' title='Safety and Security'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-8160639287272574525</id><published>2011-08-13T06:35:00.001-07:00</published><updated>2011-08-13T06:35:03.968-07:00</updated><title type='text'>Starting a New Project</title><content type='html'>&lt;p&gt;I'm between personal projects right now.  I don't have any ideas for interesting applications or libraries to write, so I've been doing a lot of thinking.  I've come to the conclusion that when starting a new project, there's simply too much room for choice.  I don't think I'm alone in feeling this way, but I'm convinced that it's not a problem most developers experience.&lt;/p&gt;&lt;p&gt;There's only one reason anyone starts a new project: to solve a problem.  The average developer doesn't need to look much further than their known solution domain to start their new project.  They have one language and some libraries that they're comfortable with and they forge the solution using them, not pausing to think about whether the tools are the right fit for the solution.&lt;/p&gt;&lt;p&gt;Thinking about whether the tools are right for the job is something that more senior developers tend consider.  They tend to think about their craft in way different from other developers.  Through experience they've developed a spidey-sense about how well tools and solutions work together, and when that spidey-sense starts tingling they can look back one their experience to find a set of tools that will work well for the solution, or at least something that they know will work.&lt;/p&gt;&lt;p&gt;The problem I think I'm running into is that, while I think I've developed that spidey-sense, I'm not satisfied with any of the tools I have for something so personal as a project to call my own.  Sure, I can look at my experience and pull out some tools to get the job done, but I also want to enjoy the experience.  So what's a guy to do when he's unhappy with all of the tools he has?  Start learning how to use some new ones.&lt;/p&gt;&lt;p&gt;When I speak of tools I don't mean just frameworks and libraries, languages are tools too.  They define what you can do and how you can do it.  None of the languages I know feel right for me.  They're all too constricting, or inconsistent, or too new, or too complicated etc.  As for frameworks and libraries: there's just too many of them, and most of them have the same afflictions.  Supposing that I do find a language and framework that I like there's always nagging question of where the holes are.  Usually these tools were written for a specific need.  Once that need was addressed they didn't develop it further, and therefore there will be things that I want to do that either just aren't possible or are only possible with herculean efforts.  Neither of these is what I would consider a good time.&lt;/p&gt;&lt;p&gt;Unfortunately, near as I can tell I have 2 choices.  Either go with the status quo or blindly forge ahead into the unknown with tools and languages that I don't know.  The former while boring is less frustrating.  I know I'll be able to accomplish whatever I want to accomplish.  I may not have the best time doing it, and I probably won't learn much of anything.  But at least I'll have produced what I set out to produce.  The latter offers no guarantees.  I might succeed in accomplishing what I set out to do, or I might not.  I might enjoy the experience, or I might not.  At least with the latter I'll learn something new, which definitely counts for something.&lt;/p&gt;&lt;p&gt;So where do I go from here?  While waiting for an idea to pop into my head I've started going through the &lt;a href="http://rubykoans.com/"&gt;Ruby Koans&lt;/a&gt;.  After that I'll have to take a look at Scala.  Maybe inspiration will strike, maybe it won't.  But at least I'll have a deeper pool of knowledge to pull from when inspiration does strike.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-8160639287272574525?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8160639287272574525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8160639287272574525'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2011/08/starting-new-project.html' title='Starting a New Project'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-4782075815968697163</id><published>2011-05-11T07:15:00.001-07:00</published><updated>2011-05-11T07:15:27.733-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>The JavaScript Curse</title><content type='html'>&lt;p&gt;There are 2 fundamentally opposing approaches to programming language design: large and small. Large languages have lots of features, most of which will include some sort of syntax. As the language gets larger, so too does the syntax. This means that there can be a lot of memorization involved for the programmer. In extreme cases (C++) no one really uses the entire language. Instead everyone uses their own subset that they&amp;#8217;re comfortable with. One nice thing about large languages is that they have codified a way of performing certain tasks. For example: there is a single way to define a class. There are only a handful of ways to loop over a list or branch.&lt;/p&gt;&lt;p&gt;Small languages by contrast are very spartan in terms of their syntax, but this by no means affects what the language is capable of. Small language designers tend to pull in very few, but few powerful features that can be combined in numerous ways. Since the language is so small everyone tends to use all of it. However, there is such a thing as too much power. While larger languages have a chosen and blessed way of performing certain fundamental tasks small languages do not. Instead each developer comes up with their own way of doing things. This is the crux of the &lt;a href="http://www.winestockwebdesign.com/Essays/Lisp_Curse.html"&gt;Lisp Curse&lt;/a&gt;.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Lisp is so powerful that problems which are technical issues in other programming languages are social issues in Lisp.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I posit that this same curse affects JavaScript, however the penalty for this curse isn&amp;#8217;t nearly as high in JavaScript as it is in Lisp. Before I explain why I think that, let me first try to convince you that JavaScript is also affected by the curse.&lt;/p&gt;&lt;h2 id="classesvsprototypes"&gt;Classes vs Prototypes&lt;/h2&gt;&lt;p&gt;JavaScript took a different approach when it came to designing its object system. Unlike most other object-oriented languages JavaScript uses prototypal inheritance instead of the more common class-based model. We could argue until we&amp;#8217;re blue in the face about which is better or more expressive, but that&amp;#8217;s not the point. Developers weren&amp;#8217;t happy with this model. And so, since the language is extremely malleable and the effort required to implement class-based inheritance is minimal everyone and their dog rolled their own.&lt;/p&gt;&lt;p&gt;Now we have a fractured situation. Every JavaScript library has their own prescriptive way of doing inheritance. Learning a new library is no longer about learning an API, now you have to learn an object system and its library-specific syntax too. Granted, all of the different syntaxes are made of the common building blocks present in JavaScript, but how they&amp;#8217;re assembled is generally quite different. The issue of how-do-I-write-a-class is now a social issue since how you do it depends on the library you or your company decides to work with.&lt;/p&gt;&lt;h2 id="concurrency"&gt;Concurrency&lt;/h2&gt;&lt;p&gt;JavaScript is a single threaded language. This means there is only ever a single thread of JavaScript code running at a time. Some might consider this a good thing, I know I do. It makes JavaScript programs easier to reason about since you don&amp;#8217;t have to worry about dead locks, race conditions or much of the complexities of writing a multi-threaded program. This also means that it needs a strategy for performing long running operations &amp;#8220;in the background.&amp;#8221;&lt;/p&gt;&lt;p&gt;In the context of a web browser, a typical long running operation would be using the XMLHttpRequest object to make an HTTP request. Due to network conditions or response size the amount of time it takes to make a request and get a response varies. If this were done in a single thread as a blocking call the JavaScript thread would pause until the response was received. This in turn means that the browser&amp;#8217;s UI thread would block as well. Effectively it would look to the user as if the browser had hung. The solution to this problem is to perform the request asynchronously (hence the first A in AJAX &amp;#8211; Asynchronous JavaScript And XML).&lt;/p&gt;&lt;p&gt;Asynchronous requests work by registering a callback and performing the operation in another OS thread. Given the restrictions of the language this implies that the asynchronous call is done by a native component (XMLHttpRequest). When the operation is complete or something interesting happens the a call to the callback is issued. This more or less works well. But cracks start to appear when you need to chain asynchronous operations together or perform several operations concurrently and proceed when they all complete.&lt;/p&gt;&lt;p&gt;In my experience this is something that happens quite often when writing programs in node.js. At least, when you&amp;#8217;re doing asynchronous I/O with node.js. The language itself gives you no help at all. Instead you need to either handle the complexity yourself or use a library that someone else built. While this is not a trivial as implementing classes, it&amp;#8217;s a fairly well understood problem and a library can be written if fairly short order. As with classes, this issue which should be addressed at the language level ends up being addressed at the library level, which in turn becomes a social issue.&lt;/p&gt;&lt;h2 id="thewayforward"&gt;The Way Forward&lt;/h2&gt;&lt;p&gt;Hopefully I&amp;#8217;ve convinced you that JavaScript has at least a few problems. The language is extremely powerful in terms of its capabilities. But some of the fundamental building blocks that are needed or expected aren&amp;#8217;t present. And due to the power of the language, developers can and go off and write the pieces that they&amp;#8217;re missing.&lt;/p&gt;&lt;p&gt;This effort at the library level, while fun and impressive, is ultimately not productive. Every body either writes their own library or uses an existing one leading to fragmentation. Since there a hundreds of different libraries for doing essentially something that should have been provided at the language level, the language suffers.&lt;/p&gt;&lt;p&gt;This is similar to the Lisp Curse in that the power of the language enables developers to do this sort of thing. The language can be tailored to the needs of the developer or software under development. While this was a curse for Lisp which lead to its niche status, the same fate will not befall JavaScript.&lt;/p&gt;&lt;p&gt;There were several issues that lead to Lisp&amp;#8217;s downfall, but the biggest one, aside from having too much power, was the ability for developers to switch platforms. Developers could retreat to another language that better suited their needs. They could do this because Lisp works at the machine level. Programs developed in Lisp are compiled directly into machine code. This effectively puts Lisp on the same footing as C, C++, and other native languages. With JavaScript this isn&amp;#8217;t the case.&lt;/p&gt;&lt;p&gt;JavaScript is the native language of the web. To compare, writing in JavaScript is akin to writing in assembler. There isn&amp;#8217;t a level below JavaScript that a web developer can write to. It goes without saying that JavaScript as a language is fairly stagnant. Sure, the mailing lists are quite active, and Mozilla is incorporating new features from the standards body. But ultimately there is a several year delay on the wide spread use of these language features. Older browsers that are still in use and supported don&amp;#8217;t get these updates. As a result, developers tend to aim for the lower common denominator. In order to get a more modern language there is only one way to go: up.&lt;/p&gt;&lt;p&gt;Languages and tools have started to emerge over the past few years that allow developers to write code for the web in languages other than JavaScript. &lt;a href="http://code.google.com/webtoolkit/"&gt;Google Web Toolkit&lt;/a&gt;, &lt;a href="http://jashkenas.github.com/coffee-script/"&gt;CoffeeScript&lt;/a&gt;, &lt;a href="http://cappuccino.org/"&gt;Objective-J&lt;/a&gt; are a few examples. These languages treat JavaScript as their target, much like a traditional compiler would treat assembler or machine code. But why are these new languages croping up instead of enhancements to JavaScript? I think it goes without saying&lt;/p&gt;&lt;p&gt;So while the Lisp Curse was fatal to Lisp, it is simply a nuisance that most developers have to deal with. For a few there are languages that compile down into JavaScript that can provide the missing features that we&amp;#8217;ve all come to expect from a modern language. But, as I&amp;#8217;ll discuss in a later post, these present their own issues.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-4782075815968697163?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4782075815968697163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4782075815968697163'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2011/05/javascript-curse.html' title='The JavaScript Curse'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-4828803956151563527</id><published>2011-03-10T06:45:00.001-08:00</published><updated>2011-03-10T06:45:05.415-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Xcode 4 Features Single Window Interface, new Price Tag</title><content type='html'>&lt;p&gt;Yesterday afternoon a noticed a big storm of tweets about Xcode 4.  One in particular caught my interest:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;a href="https://twitter.com/jimroepcke/status/45579474577801217"&gt;@JimRoepcke&lt;/a&gt; Can you imagine being a Mac App Store Reviewer, looking at your queue and seeing Xcode 4?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;At first I figured it was just a thought experiment but a few minutes later I started seeing more tweets about Xcode 4 and Mac App Store.  Since the Developer Preview for Lion was sent out through the store I put 2-and-2 together and figured that Xcode 4 was finally released.  What I found out shortly there after is that you now have to pay for it.&lt;/p&gt;&lt;p&gt;That's right, Apple now charges for its developer tools.  The whopping 4.6GB (that's giga, with a G) is $4.99.  Naturally, this set &lt;a href="http://www.reddit.com/r/programming/comments/g0o01/xcode_4_is_out_new_features_a_price_tag/"&gt;Reddit&lt;/a&gt;, &lt;a href="http://news.ycombinator.com/item?id=2306289"&gt;Hacker News&lt;/a&gt; and my &lt;a href="http://twitter.com/bryan_kyle"&gt;Twitter feed&lt;/a&gt; on fire.&lt;/p&gt;&lt;p&gt;Now, I'm not opposed to paying for developer tools.  Back in the day I used to do a lot of development on Windows.  I went through several versions of Delphi (best language evar) and numerous editions of Visual Studio.  The price though, $4.99?  What's that about?&lt;/p&gt;&lt;p&gt;After a few minutes of thought a tweeted that the price seemed too low to offset the bandwidth costs.  But bandwidth costs aren't what this is about.  Neither is offsetting the cost of development for that matter.  Remember a few years back when iPod Touch owners were charged a nominal fee to upgrade to a later version of iOS 3.0?  After some thought I'm guessing that the same thing is happening again.  And like the iOS on iPod Touch, later versions of Xcode will probably not cost anything.&lt;/p&gt;&lt;p&gt;Putting the precedent of iOS 3.0 aside, Apple has come out on several occasions and touted that they give away all the same tools to build apps that they themselves use.  This has been a big point for them in the past and it's unlikely that they'd want to make a change now.  Granted, Apple has been known to change its mind, and make decisions that are in its best interests.  But $4.99 is too low of a price to charge if their planning on breaking even.  Especially when you look at the fact that Google gives away all of the development tools for Android -- a platform that currently has more market share.&lt;/p&gt;&lt;p&gt;No, I'm pretty sure that this isn't a money grab.  It's probably just a blip required by the bean counters.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-4828803956151563527?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4828803956151563527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4828803956151563527'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2011/03/xcode-4-features-single-window.html' title='Xcode 4 Features Single Window Interface, new Price Tag'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-4291944759310987722</id><published>2011-03-08T00:21:00.001-08:00</published><updated>2011-03-08T09:09:07.196-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='backup'/><title type='text'>My Backup Strategy</title><content type='html'>&lt;p&gt;Both my wife and I have suffered through a catastrophic hard drive failure in
the past.  Neither of us really enjoyed losing irreplaceable photos or countless
hours trying to piece back together our digital lives.  Since then, we've
learned our lesson and took a few steps to reduce the likelihood of ever going
through that again.  So what exactly did we do?  In short, we've started
applying the &lt;a href="http://www.dpbestflow.org/backup/backup-overview#321"&gt;3-2-1 backup rule&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;We recommend keeping 3 copies of any important file (a primary and two
backups) We recommend having the files on 2 different media types (such as
hard drive and optical media), to protect against different types of hazards.
1 copy should be stored offsite (or at least offline).&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;The Hardware&lt;/h2&gt;&lt;p&gt;Recently I bought 2 1TB hard drives.  I opted for the &lt;a href="http://www.wdc.com/en/products/products.aspx?id=120"&gt;Western Digital Caviar Green&lt;/a&gt;.  They offered a decent amount of size and performance for the price.  An added benefit of these drives is that they're fairly quiet and turn themselves off when they aren't in use.  For drives that are only in use sporadically throughout the day these were perfect.&lt;/p&gt;&lt;p&gt;To hold these drives, I first considered using a SATA drive dock.  However, being a Mac user I prefer the things on my desk to be well designed and look great.  I had a really hard time finding a dock that met my standards.  Design concerns aside, I've got a few cats that like to walk all over my desk.  I'm not sure that having exposed electronics would be such a good idea.  Moreover, I also needed a safe place to store the drive that wasn't in use.  Hard cases do exist, but NCIX, the place I ordered my backup stuff from didn't sell any -- yet another nail in the SATA dock coffin.&lt;/p&gt;&lt;p&gt;Instead, I opted to get a few enclosures by &lt;a href="http://www.macally.com/EN/Product/Homes.asp"&gt;Macally&lt;/a&gt; -- the &lt;a href="http://www.macally.com/EN/Product/ipod4show.asp?ArticleID=255"&gt;G-S350SUAB&lt;/a&gt; to be precise.  These enclosures look just like tiny Mac Pro towers.  Being made of aluminum they don't require any fans to keep quiet, and since the tolerances are fairly tight they don't rattle when the drive spins up.&lt;/p&gt;&lt;h2&gt;The Software&lt;/h2&gt;&lt;p&gt;I sliced up each of the drives into 3 partitions: a 120GB, 240GB, and 640GB.&lt;/p&gt;&lt;p&gt;The 120GB partition is the same size as the internal drive in my MacBook Pro and is used as a clone of the internal drive -- cloned with &lt;a href="http://www.shirt-pocket.com/SuperDuper/SuperDuperDescription.html"&gt;SuperDuper!&lt;/a&gt; an awesome tool for cloning drives for the Mac.  Having a clone means that I don't need to go to the trouble of replacing the internal drive, installing the OS, and restoring data immediately.  All I need to do is reboot off of the clone and I'm up and running with a fairly recent backup.  However, just having a clone isn't enough.  Typically cloning takes a long time to run and therefore is done less often.  In my case it's done nightly but sometimes I'll go a few days without running it.&lt;/p&gt;&lt;p&gt;With the 240GB partition I use Time Machine.  Every hour or so Time Machine will make an incremental backup of what's on my Mac.  Having this partition be larger than the internal drive means that I can keep several revisions of files in case I need to restore old versions or deleted files.  Incremental backup decreases the mean time between backups.  I can't boot off of the Time Machine backup, but the number of files changed since the last clone will probably be small and can be restored to the clone if need be.&lt;/p&gt;&lt;p&gt;The last partition, large partition stores archived data -- photos, music, old projects, etc.  Stuff that I don't need to work with regularly.  The archived files on this partition are cloned from a Time Capsule I have running on the network (2 copies of everything, remember).&lt;/p&gt;&lt;p&gt;In order to get the offline side of the 3-2-1 backup I swap out the hard drives once a week.  If the house were to burn down, or someone stole everything the most I'd be out is a week's worth of work.  And since most of my work is stored in &lt;a href="http://db.tt/FAo6Cjy"&gt;Dropbox&lt;/a&gt; anyway it's likely that I'd lose less than that.&lt;/p&gt;&lt;h2&gt;Weaknesses and Pain Points&lt;/h2&gt;&lt;p&gt;So far this strategy is working fairly well.  It can be a pain to have to swap the drives but since I only have to do this once a week the pain is tolerable.  I could have opted for an online storage system like &lt;a href="http://www.carbonite.com/"&gt;Carbonite&lt;/a&gt; or &lt;a href="http://www.crashplan.com/"&gt;Crashplan&lt;/a&gt; but decided that I wanted to do the whole thing myself without worrying about long restore operations, monthly fees, or feeling socially obligated to host someone else's backup.  This does mean, however, that if there were an earthquake and the city was levelled I'd lose my data but I'm pretty sure that my data would be the last thing I'd be thinking of if that were to happen.&lt;/p&gt;&lt;p&gt;Time Machine automatically remembers some identifying information about the drive used as the backup drive.  When I do my weekly swap I have to force Time Machine to do an initial backup.  This prompts Time Machine to warn me that I might be backing up to another drive and performs a fairly long scan and backup on that first hit.  It doesn't back up every file, it's still smart about just backing-up the files that have changed, so it's not as bad as it could be.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;In the end I'm fairly happy with my backup plan.  It's not perfect, but I feel safe knowing that my data is well protected and that the chance of me losing all of my and my families important data is low.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-4291944759310987722?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4291944759310987722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4291944759310987722'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2011/03/my-backup-strategy.html' title='My Backup Strategy'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-7147645767050066314</id><published>2011-02-13T07:11:00.001-08:00</published><updated>2011-02-13T07:11:13.803-08:00</updated><title type='text'>Scripting Inkscape</title><content type='html'>&lt;h2&gt;tl;dr&lt;/h2&gt;&lt;pre&gt;&lt;code&gt;$INKSCAPE/Contents/Resources/bin/inkscape in.svg -e out.png -D -h 100 -w 100
&lt;/code&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;p&gt;SVGs, like all other vector graphics formats are scalable and work well for any
sort of graphic that needs to scale well to different resolutions.  So if you
have an image that needs to displayed at many different sizes vector graphics
are a good bet.&lt;/p&gt;&lt;p&gt;Vector graphics take much more overhead to render than do raster images.  Since
raster graphics are simply an array of bytes in memory that represent each pixel
of the image they are relatively simple for a computer to perform operations on.
Vector graphics on the other hand are usually stored as a series of drawing
operations: draw a rectangle, fill it with a gradient, clip it with circle, etc.
Because these operations have to be executed in order, sometimes drawing over
the same pixels a few times they can be slower.  Hence, vector graphics
applications, such as Inkscape, have a rasterizer in them that takes the output
of the SVG and converts it into a raster image.  You might think of a vector
graphic as a recipe, or the source code, for a raster graphic.&lt;/p&gt;&lt;p&gt;Using Inkscape to rasterize images can be a chore since you have to open
manually adjust the size of the output graphic and filename for each different
size that you want to generate.  Luckily inkscape includes a command line
rasterizer that you can script!&lt;/p&gt;&lt;p&gt;On the Mac, the actual executable is within the Inkscape.app bundle in
Contents/Resources/bin/inkscape.  You can invoke it from the terminal with
options to control the height and width of the output graphic, it's name as well
as a few other options.  Running &lt;code&gt;inkscape --help&lt;/code&gt; will list all of the
available options.  The ones we're concerned with are: &lt;code&gt;-e&lt;/code&gt;, &lt;code&gt;-C/-D&lt;/code&gt;, &lt;code&gt;-h&lt;/code&gt;, and
&lt;code&gt;-w&lt;/code&gt;.  &lt;code&gt;-C&lt;/code&gt; is used when you want to export the drawing and &lt;code&gt;-D&lt;/code&gt; when you want
to export the entire page.  The difference between the two being that exporting
the page will export everything including white space around your drawing and
exporting the drawing will trigger Inkscape to find the smallest rectangle that
includes everything you've drawn (which might be smaller than the page) and
export that.&lt;/p&gt;&lt;p&gt;To export the drawing contained in "Scenery.svg" to a 100x100 PNG called
"Scenery.png" you would use the following command in Terminal:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$INKSCAPE/Contents/Resources/bin/inkscape Scenery.svg -e Scenery.png -D -h 100 -w 100
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Where &lt;code&gt;$INKSCAPE-APP&lt;/code&gt; is the location of Inkscape.app.&lt;/p&gt;&lt;p&gt;Since rasterizing SVGs is something you might be doing frequently you can always
write a script to run the above command with different sizes and output names.
If you want to get fancy you could even automate the process using Make or
another build tool.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-7147645767050066314?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7147645767050066314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7147645767050066314'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2011/02/scripting-inkscape.html' title='Scripting Inkscape'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-934587159723120881</id><published>2010-11-18T22:33:00.001-08:00</published><updated>2010-11-18T22:34:57.218-08:00</updated><title type='text'>The Playbook</title><content type='html'>&lt;p&gt;RIM recently released a &lt;a href="http://www.youtube.com/watch?v=s72rGDUn2uo&amp;feature=player_embedded"&gt;video&lt;/a&gt; "previewing some of the cool stuff [they're] doing with the Blackberry Playbook browser."  From the video, it certainly looks like the Playbook wipes the floor with the iPad.  It loads pages faster.  It supports "dynamic" content, by which they mean Adobe Flash.  It passes the ACID3 test.  Of course the video is incredible, they'd be fools to release a video that wasn't.  But after thinking about it for a little while, I came to the realization that it wasn't really that amazing at all.&lt;/p&gt;&lt;p&gt;This video is showing a speed comparison between 2 devices.  Yes, they're both tablets but it's not really a fair comparison.  The iPad has been shipping to customers for about a year.  Since Apple doesn't rev the hardware between releases that makes the hardware at least a year old, if not older.  As for the Playbook, there's no official release date yet.  All we've so far is early 2011, which means sometime between January and March.  Assuming that the Playbook's hardware specs have been nailed down, the video is comparing a brand new device with one that's a year old.  Of course the new one's going to be faster, no surprise there.&lt;/p&gt;&lt;p&gt;The sites that RIM picked for the demo were obviously not chosen at random.  Clearly these were sites that they knew would show off the features of the Playbook.  Almost any site would loaded faster and performed better on the Playbook given that it's newer.  Similarly, the Playbook claims that it has better ACID compliance than the iPad.  Both devices, as far as I know, use WebKit.  Safari on the iPad is just using an older version of it.  Maybe we'll see better ACID compliance out of Safari on iOS 4.2 which should be released in the next week or so.&lt;/p&gt;&lt;p&gt;While the video was certainly impressive at first glance, after some thought it's really not that amazing at all.  In fact, it leaves a lot of open questions.  What's the battery life like on the Playbook?  Sure the device appears faster and supports flash, but if you can only use it for a few hours what's the point?  How smooth is the UI?  Where are the Apps?  I'm sure RIM has a good answer for all of these questions, I just wish they'd stop releasing marketing material and just ship the damn thing and let it stand for itself.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-934587159723120881?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/934587159723120881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/934587159723120881'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/11/playbook.html' title='The Playbook'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-3152346302860031913</id><published>2010-10-26T21:55:00.001-07:00</published><updated>2010-10-26T21:55:42.653-07:00</updated><title type='text'>Do Smart IDEs Cause Dumbening?</title><content type='html'>&lt;p&gt;The other day I read an interesting blog post from Luke Palmer the other day
titled &lt;a href="http://lukepalmer.wordpress.com/2010/10/18/idewtf/"&gt;IDEWTF&lt;/a&gt;.  In the
article Luke discusseshow IDEs appear to be falling behind in the
state-of-the-art compared to creative tools like Photoshop, Premiere, AutoCAD,
etc.  Luke's main point is that as developers we should be able to create and
use the best tools for our craft.  IDEs should be much more advanced than they
currently are.  While I agree with his point in spirit, I'm not sure that making
our IDEs do more is the best thing for developers.&lt;/p&gt;&lt;p&gt;In 2003, a study
(&lt;a href="http://igitur-archive.library.uu.nl/dissertations/2008-0401-200600/nimwegen.pdf"&gt;pdf&lt;/a&gt;)
was conducted by a psychologist named Christof van Nimwegen.  In the study 2
groups of people were asked to play a logic game.  The game involved transfering
colours balls according to a set of rules.  One group was given a piece of
software that assisted them in playing the game.  For example, the software
would highlight moves the player could make at a given point in time.  The other
group was given software that was not helpful -- it would not highlight
permitted moves.&lt;/p&gt;&lt;p&gt;In the beginning, the group that was given the helpful software was able to
solve the problems faster than the group that had the non-helpful software.
However as the study progressed the group that was given the non-helpful
software became much more proficient.  In the end, the group using the
non-helpful software was able to solve the puzzles using fewer extra moves, and
produced fewer dead-end states where no more moves were possible.&lt;/p&gt;&lt;p&gt;The two groups were brought back in 8 months later to re-run the tests and try a
different, but similar, logic puzzle.  The group that had initially used the
non-helpful software hit the ground running, so to speak.  Not only were they
able to solve the puzzles faster than the group using the helpful software but
they were able to adapt their knowledge to the second puzzle.&lt;/p&gt;&lt;p&gt;This study suggests that helpful software, or software that offloads complexity
from the user onto the software, makes us reliant on it.  This doesn't say that
it's a zero-sum game in which by the IDEs getting smarter the developers must
get dumber.  Far from it.  I believe that we need to strike a balance between
HAL 9000 and Notepad.&lt;/p&gt;&lt;p&gt;If the IDEs become too smart, and coddle the developer too much the developer
will learn to rely on it.  Automatic correction of syntax, imports, exceptions,
etc are not in and of themselves bad.  They certainly improve productivity.  But
the developer then learns to rely on their presence, like a drug.  If the
developer ever tries to work with a language that doesn't have the kind of
tooling their used to they will pay a huge cognitive price up front, something
that might be enough to scare them away.&lt;/p&gt;&lt;p&gt;So where do we draw the line?  Which features improve both long term and short
term productivity, and which cause dependence?  I think the line is right
between those features that do something automatically for the developer and
those that provide advice.  A feature that does something for the developer
effectively offloads the cognitive complexity from the developer to the
software; the developer is freed from having to think about it -- at least
that's how they see it.  With features that simply provide advice to the
developer the IDE is allowing them to be more productive without having to pay a
long term price.&lt;/p&gt;&lt;p&gt;An IDE like Eclipse has many of types of features.  The classic example of an
automatic feature is "Quick Fix".  When Eclipse notices that something is wrong
with the code that it can fix, it allows the user to tell the IDE to fix the
problem for them.  Developers that are experienced without the IDE will probably
understand what it's doing.  They would have been able to make the correction
themselves without the help of the IDE.  To them, this automatic feature is
simply a way of improving their productivity.  For the less experienced
developer however, its mode insidious.  Because the user doesn't understand what
the IDE is doing, or why it needs to the user becomes more dependent.&lt;/p&gt;&lt;p&gt;Eclipse also has a variety of features that are designed to assist the
developer.  Call Hierarchy, and Class Hierarchy are two great examples.  The
developer still needs to understand what these features are used for; the tool
simply gives the user advice, quick information that helps them make a decision
or explore a code base.  These features still cause a sort of dependence, but
since the developer understands what the tools are for, and why they need to use
them the dependence is less insidious.  Without these tools the developer can
still do her job, but productivity might be affected.  In contrast with
automatic tools where the developer wouldn't be able to do his job.&lt;/p&gt;&lt;p&gt;So, do smarter IDEs cause dumbening?  You be the judge.&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Footnote: I know "dumbening" is not grammatically correct.  The word comes from
a Simpsons episode where Lisa worries that she's losing her intelligence and
writes in her journal:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Dear log. Can it be true? Do all Simpsons go through a process of dumbening?
Wait, that's not how you spell dumbening... waaait, dumbening isn't even a word!&lt;/p&gt;&lt;/blockquote&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-3152346302860031913?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3152346302860031913'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3152346302860031913'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/10/do-smart-ides-cause-dumbening.html' title='Do Smart IDEs Cause Dumbening?'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-2780825994087872796</id><published>2010-10-20T22:23:00.001-07:00</published><updated>2010-10-20T22:23:20.419-07:00</updated><title type='text'>Predictions Report Card</title><content type='html'>&lt;p&gt;So Apple held their much anticipated &lt;em&gt;Back to the Mac&lt;/em&gt; event today.  Since &lt;a href="http://bryan-kyle.blogspot.com/2010/10/predictions-for-wednesday.html"&gt;I made some predictions&lt;/a&gt;, I thought I'd follow up to see how well I did on my first attempt and predicting what was going to be shown.&lt;/p&gt;&lt;p&gt;To recap, I made the following predictions.  I'll address each of these in turn.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Sneak peek of OS X 10.7, to be called Lion&lt;/li&gt;&lt;li&gt;New OS will have more user facing features&lt;/li&gt;&lt;li&gt;New OS will have over-the-air syncing with portables&lt;/li&gt;&lt;li&gt;OS will be seeded to developers shortly&lt;/li&gt;&lt;li&gt;OS will be generally available around WWDC '11&lt;/li&gt;&lt;li&gt;New release of iWork&lt;/li&gt;&lt;li&gt;New release of iLife&lt;/li&gt;&lt;li&gt;New MacBook, MacBook Pro and MacBook Air&lt;/li&gt;&lt;li&gt;Minor speed improvements for new models&lt;/li&gt;&lt;li&gt;SSD becoming standard equipment&lt;/li&gt;&lt;li&gt;USB 3.0&lt;/li&gt;&lt;li&gt;No Blueray&lt;/li&gt;&lt;li&gt;No iPad&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Sneak peek of OS X 10.7&lt;/h2&gt;&lt;p&gt;Sure enough, Apple did announce a new version of OS X today.  As expected the new release is called Lion.  I got this one right.  It was a gimme, but I'll take it.&lt;/p&gt;&lt;h2&gt;New OS will have more user facing features&lt;/h2&gt;&lt;p&gt;In the announcement today Apple talked about a few new things that they were adding to the OS X 10.7.  These included Mission Control, Launchpad, and Full Screen apps.  These are clearly user facing features but since I was extremely general with my prediction I'm only going to give myself a half a point.&lt;/p&gt;&lt;h2&gt;New OS will have over-the-air syncing with portables&lt;/h2&gt;&lt;p&gt;Apple didn't make any announcements about whether over-the-air syncing would be available.  Even as I was writing that prediction it seemed a little far-fetched to me.  That sort of announcement really only makes sense at an iOS/iTunes announcement, not a Mac event.  I missed this one.&lt;/p&gt;&lt;h2&gt;New OS will be seeded to developers shortly&lt;/h2&gt;&lt;p&gt;Apple didn't make any announcements regarding when the OS would be going out to developers.  Since it could be released any time I'm going to hold off on saying whether or not I got this one.&lt;/p&gt;&lt;h2&gt;OS will be generally available around WWDC '11&lt;/h2&gt;&lt;p&gt;According to Apple, OS X 10.7 is on track to be shipping during the summer of 2011.  WWDC is typically in June which puts it in (the beginning) of summer.  Since I was more specific than Apple, and these dates tend to slip I'll only give myself a half a point on this one.&lt;/p&gt;&lt;h2&gt;New release of iWork&lt;/h2&gt;&lt;p&gt;There was no announcement regarding a new release of iWork.  I flat out missed this one.&lt;/p&gt;&lt;h2&gt;New release of iLife&lt;/h2&gt;&lt;p&gt;A new release of iLife was announced.  I got it.&lt;/p&gt;&lt;h2&gt;New MacBook, MacBook Pro and MacBook Air&lt;/h2&gt;&lt;p&gt;This one's tricky.  While a new MacBook Air was announced there was no mention of revving the MacBook and MacBook Pro line.  I'm going to give myself 1/3 of a point for that one.&lt;/p&gt;&lt;h2&gt;Minor speed improvements for new models&lt;/h2&gt;&lt;p&gt;Sure enough, there were speed improvements for the MacBook Air line. +1 for me.&lt;/p&gt;&lt;h2&gt;SSD becoming standard equipment&lt;/h2&gt;&lt;p&gt;Again, SSDs are standard equipment on the MacBook Air.  I got it.&lt;/p&gt;&lt;h2&gt;USB 3.0&lt;/h2&gt;&lt;p&gt;No USB 3.0.  No points for me.&lt;/p&gt;&lt;h2&gt;No Blueray&lt;/h2&gt;&lt;p&gt;As expected, there was no Blueray announcement.  But since the MacBook Air doesn't have an optical drive I'm not going to count this one for or against me.&lt;/p&gt;&lt;h2&gt;No iPad&lt;/h2&gt;&lt;p&gt;No new iPad was announced.  +1 for me.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;In total I made 13 predictions.  Of those one is pending an outcome in the next few weeks and one I've rationalized away leaving me with a total of 11 predictions that I can grade myself on today.  According to a completely impartial jury I got 6 and a 1/3 out of 11 right.  That's better than half.  Not bad for a first timer.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-2780825994087872796?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/2780825994087872796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/2780825994087872796'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/10/predictions-report-card.html' title='Predictions Report Card'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-674016862404188745</id><published>2010-10-18T22:49:00.001-07:00</published><updated>2010-10-18T22:49:10.893-07:00</updated><title type='text'>Predictions for Wednesday</title><content type='html'>&lt;p&gt;Apple has a Mac press event coming up on the 20th of October.  Usually, I don't do this but I thought I'd take a stab at some predictions for the event.  So, without further ado, here's what I think we'll see.&lt;/p&gt;&lt;h2&gt;Sneak Peek of Mac OS X 10.7&lt;/h2&gt;&lt;p&gt;The &lt;a href="http://www.guardian.co.uk/technology/blog/2010/oct/13/apple-lion-10-7-teaser"&gt;invitation&lt;/a&gt; that was sent out to the press for the event includes a picture of a lion peeking out from behind an Apple logo.  Given that all releases of Mac OS X are named after large cats it doesn't take a genius to put two and two together.  Clearly a new version of the operating system will be previewed, and its name will be Lion.&lt;/p&gt;&lt;p&gt;The last release, Snow Leopard, was mostly about the plumbing.  Lion will need to have more user facing features.  I'm willing to bet we're going to see some better integration between the Mac and Apple's portable devices: iPad, iPhone and iPod.  The new OS will probably include over-the-air syncing with mobile devices and some new APIs to support it.  As for other features, I don't have a clue.&lt;/p&gt;&lt;p&gt;I don't think the new OS will be released at the event.  Apple seeds a few releases to the developers before shipping it publicly.  This will be a preview only, the developers will probably get their copies within a few weeks and the new OS will ship around WWDC '11 next year.&lt;/p&gt;&lt;h2&gt;iWork and iLife&lt;/h2&gt;&lt;p&gt;The last release of both iLife and iWork was in 2009.  Usually Apple likes to release new versions of its productivity software at the beginning of the year, but seeing as the last release is almost 2 years old it could use an update.  Plus, with &lt;a href="http://www.macworld.com/article/142266/2009/08/office_2010_outlook.html"&gt;Microsoft due to release Office 2010&lt;/a&gt; soon it makes sense for Apple to release its competitive software around the same time, hopefully to knock the wind out of Microsoft's sails in the consumer market.&lt;/p&gt;&lt;h2&gt;New MacBook, MacBook Pro and MacBook Air Portables&lt;/h2&gt;&lt;p&gt;According to the &lt;a href="http://buyersguide.macrumors.com/"&gt;MacRumors.com buyer's guide&lt;/a&gt; all of the portables have been out for about 6 months.  In the case of the MacBook Air much longer than that.  I'm guessing we'll see speed bumps across the board, SSDs becoming a standard component and USB 3.0.  With Apple supporting high-def video through rentals and purchases in the iTunes Store I don't see Apple including a Blueray player.&lt;/p&gt;&lt;h2&gt;No iPad&lt;/h2&gt;&lt;p&gt;I don't think we're going to see an update to the iPad.  iPad was first announced late January 2010 and didn't start shipping until March.  That means the 1st generation iPad hasn't been shipping for a full calendar year yet.  With the holiday season coming soon and a well oiled supply line on the device it doesn't make sense for Apple to announce a new one and canabalize its holiday sales.&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;This is the first time I've ever done a predictions entry, and usually I don't pay much attention to what's going on.  So don't quote me!&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-674016862404188745?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/674016862404188745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/674016862404188745'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/10/predictions-for-wednesday.html' title='Predictions for Wednesday'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-4566059751333868420</id><published>2010-10-16T21:43:00.001-07:00</published><updated>2010-10-16T21:43:38.588-07:00</updated><title type='text'>How To Deal With Customers</title><content type='html'>&lt;p&gt;I was at a local computer store this afternoon and I overhead a conversation between who I believe to be the owner and a customer.  I didn't hear the whole conversation since I walked in half way through, but the part that I did hear I found startling.&lt;/p&gt;&lt;p&gt;The customer was ranting and raving about how much he hated the computer that he had brought in.  He was livid about how it constantly lost data, crashed and generally didn't do what he wanted.  He kept saying that he was going to try a Mac because of all of the problems.&lt;/p&gt;&lt;p&gt;Instead of talking the man down gently and being generally agreeable the owner decided to get into a verbal fist-fight with the customer.  For every knock the customer had against his computer the owner had something to say about it.&lt;/p&gt;&lt;p&gt;"It just turns itself off after an update!"
"It doesn't just shut down, it give you 5 minutes to save what you're doing!"&lt;/p&gt;&lt;p&gt;"The screen doesn't work right."
"These things work fine.  If yours isn't working it's probably a faulty card or something."&lt;/p&gt;&lt;p&gt;The owner kept trying to give the customer reasons that he should stick with a Windows PC.&lt;/p&gt;&lt;p&gt;"The Mac has 1 trillionth the amount of software."
"I don't care. It's not a toy, it's a tool.  I don't need lots of software, I just need something that allows me to get my work done!"&lt;/p&gt;&lt;p&gt;The icing on the cake came towards the end of the conversation when the owner said, and I quote: "90% of the world can't be wrong."&lt;/p&gt;&lt;p&gt;In this case, I think the customer was angry when he walked in the door.  He was looking for a fight.  Clearly the owner doesn't have children.  If he did he'd have realized what the customer was doing to him.  Instead of fighting with the guy, he should have just agreed with all of his points and suggested that he do try a Mac.  The customer had already made up his mind that he wanted to try one. &lt;br /&gt;
When the customer asked questions that he didn't know the answer to he should have picked up the phone and called one of the Mac stores in town.  That would have diffused the situation and earned him some emotional currency.  He could have even gone as far as to ask one of the stores if they do rentals or have a try-before-you-buy program.  That customer didn't come in to buy anything, he came in for some help.  So help him.&lt;/p&gt;&lt;p&gt;If the customer did ultimately decide to go with the Mac, he'd only have good things to say about the store.  He'd refer business over to them if anyone asked and was in the PC market.  In the age when brick and mortar stores are close to extinction any way that you can distinguish yourself from a faceless web site and earn some emotional currency is worth the price.  Yes you might lose a sale, but you'll just have earned some in the future.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-4566059751333868420?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4566059751333868420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4566059751333868420'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/10/how-to-deal-with-customers.html' title='How To Deal With Customers'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-1814830153278473179</id><published>2010-10-11T20:54:00.001-07:00</published><updated>2010-10-11T21:43:19.186-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><title type='text'>Nil Advice</title><content type='html'>&lt;p&gt;Recently &lt;a href="http://bryan-kyle.blogspot.com/2010/09/some-thoughts-on-cocoa-and-objective-c.html"&gt;I wrote&lt;/a&gt; that one of the things I really like about Objective-C is how
it handles nil-values when calling methods.  It certainly makes for code that's
easier to read however it does have a downside as mentioned by Daniel Jalkut of
Red Sweater software.  In &lt;a href="http://www.red-sweater.com/blog/1423/dont-coddle-your-code"&gt;Don't Coddle Your Code&lt;/a&gt;, Daniel writes:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;It s also worth noting that LaMarche s defense of nil ing out instance
variables hinges on the presumption that messaging nil is safe. True,
messaging nil will not cause a crash. But is that safe? Not if it changes the
behavior of your code in unpredictable ways.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;He goes on to demonstrate his point with some contrived but applicable code:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;if ([mDiplomat didReturnGestureOfPeace] == NO)
{
    [[NuclearWarehouse nuclearMissile] launch];
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Daniel's point is this:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The biggest disservice you can do to your users is to allow them to run code
that has unpredictable behavior. The whole point of programming is to make
computers accomplish tasks in predictable ways.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I think he makes an excellent point.  To paraphrase -- and I'm sure C++
developers will agree -- &lt;strong&gt;just because you can do something doesn't mean that
you should.&lt;/strong&gt; This language feature is a boon for those that understand how to
use it effectively and design interfaces that work well with it.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-1814830153278473179?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1814830153278473179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1814830153278473179'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/10/nil-advice.html' title='Nil Advice'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-3129914037595000979</id><published>2010-10-06T22:22:00.001-07:00</published><updated>2010-10-06T22:22:58.352-07:00</updated><title type='text'>Why FizzBuzz is a Great Interview Question</title><content type='html'>&lt;p&gt;Interviewing can be really hard and stressful.  You need to make a decision
about how well someone will fit into your organization.  That in and of itself
is hard enough; combined with the fact that you aren't given anywhere near the
amount of time you need to assess their skill level and personally makes it even
more difficult.&lt;/p&gt;&lt;p&gt;The best way to assess skill level is to ask questions that give the candidate
questions that allow them to demonstrate their knowledge.  But what kind of
questions should you ask?  Given that &lt;a href="http://www.joelonsoftware.com/items/2005/01/27.html"&gt;199 of out
200&lt;/a&gt; applicants can barely
code, it makes sense to ask a question to weed out the 199.  FizzBuzz is just
the type of question to do this.&lt;/p&gt;&lt;p&gt;FizzBuzz, if you aren't, is a question that asks the candidate to write a simple
program.  Typically it's proposed similar to the following:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Write a program that prints the numbers from 1 to 100. But for multiples of
three print  Fizz  instead of the number and for the multiples of five print
 Buzz . For numbers which are multiples of both three and five print
 FizzBuzz .&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This question is specifically targets problem solving skills; something that all
good programmers need to have.  It also has the advantaged of targeting the 3
most fundamental concepts in computation: sequence, selection, and iteration.
That is, it has loops, conditionals and the sequence of them matters to the output.&lt;/p&gt;&lt;p&gt;The way in which the question is asked usually trips people up too.
Implementing the program exactly as it's specified will end up working
incorrectly.  Why?  Have a look at this JavaScript implementation:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;for (var i=1; i&amp;lt;=100; i++) {
   if (i % 3 === 0 )
      print("Fizz");
   else if (i % 5 === 0)
      print("Buzz");
   else if (i % 3 === 0 &amp;amp;&amp;amp; i % 5 === 0)
      print("FizzBuzz");
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Anything strike you as odd?  The last condition is in the wrong place.  If the
value is divisible by 3 or 5 the if/else construct would have been broken out of
in the first 2 conditions.&lt;/p&gt;&lt;p&gt;Whether or not someone gets the correct answer doesn't really matter.  What's
really being tested is the candidate's ability to convert a problem description
into the language of logic in a reasonable amount of time.  What's reasonable?
Accounting for nerves I'd say it shouldn't take longer than 10 minutes.  A good
programmer should be able to solve inside of 5.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-3129914037595000979?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3129914037595000979'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3129914037595000979'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/10/why-fizzbuzz-is-great-interview.html' title='Why FizzBuzz is a Great Interview Question'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-2859671719335491717</id><published>2010-09-21T22:31:00.001-07:00</published><updated>2010-09-21T22:31:35.159-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Some Thoughts on Cocoa and Objective-C</title><content type='html'>&lt;p&gt;I originally started writing this about a year and a half ago.  It's been sitting on my desktop waiting to be published but for one reason or another I never got around to it.  My thoughts now seem trite, but it's interesting to look back.  One of these days I should write a post that covers the more interesting aspects of Objective-C's design; more than just what's covered here.&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;I've been dipping my toes in Cocoa again lately, and I'm really starting to enjoy it.  I first played with Cocoa when I got my first Mac in 2004.  I really thought there was something promising there but I couldn't wrap my head around how all the pieces fit together.  After being abused by other OOP languages and their GUI frameworks Cocoa seemed really backwards.  Delegation instead of subclassing.  Freeze dried objects and connections that are brought back to life at runtime, etc.  And the language.  Why this bizarre language with it's odd syntax?&lt;/p&gt;&lt;p&gt;Each of the choices in isolation appear to be fairly arbitrary, or different for difference's sake.  But as you learn more about the development model you can definitely see a method to their madness.  The choice of language is a rather interesting one because it forms the foundation of how applications are written for the Mac.  So why Objective-C?  In order to understand why Cocoa, OS X's native framework is written in it it's important to know where OS X came from.&lt;/p&gt;&lt;p&gt;In the late 80s NeXT Computer was building high end computer workstations for education and businesses.  The crown jewel of NeXT  was its operating system: NextSTEP.  NeXTStep was a performant, object-oriented, preemptively multitasking operating system with a graphical user interface.  In order to quickly build the operating system and its application software a very performant, dynamic, reflective language was needed.  At the time the best choice was probably a little-known superset of C called Objective-C.&lt;/p&gt;&lt;p&gt;In the early to mid 90s Apple was looking for a successor to its aging operating system.  After several failed attempts to build one in-house Apple was approached by NeXT.  NeXT convinced Apple that it had the technology that Apple needed.  In the end NeXT Computer was bought by Apple, and NeXT Step was transformed into Mac OS X.  If you've ever wondered why classes are prefixed with &lt;em&gt;NS&lt;/em&gt; in Cocoa now you know why.&lt;/p&gt;&lt;p&gt;I've found Objective-C to be a really interesting and fairly elegant language.  One of the more interesting things I found was that Objective-C uses a completely different calling metaphor from traditional OOP languages that I've learned.  What most languages refer to as calling methods, Objective-C calls message sending.  The distinction is more than skin deep, it's a fundamentally different paradigm.  If you're experienced with the mainstream OOP languages you've spent a great deal of time thinking aboout class taxonomy and how classes relate to each other.  You're trained to think that classes are types and methods are associated with the types.  This makes a lot of sense if you look at the problem from a compiler's perspective.  If you know the class and method at compile time then you can statically jump to the appropriate address.  It's faster than a dynamic lookup but you pay for the boost in performance and the currency is developer time.&lt;/p&gt;&lt;p&gt;A message sending paradigm on the other hand is quite different.  When you want an object to perform some operation you send a message to that object with some arguments.  The object that receives the message will dispatch the appropriate method for the message.  Typically there is a one-to-one mapping between messages and methods but in some cases you might want to respond to messages that don't correspond to a method.&lt;/p&gt;&lt;p&gt;You might boil the difference between method calls and message sending down to a difference in who is responsible for finding and invoking the appropriate code.  In the method calling convention the caller is responsible (via the compiled code) for determining the address to jump to.  Message sending on the other hand leaves the receiver of the messag to determine what method to invoke.  Another interesting side effect of message sending is that sending a message to a non-existant object is perfectly legal whereas calling a method on a non-existant object is not.  In Objective-C sending a message to &lt;code&gt;nil&lt;/code&gt; returns &lt;code&gt;nil&lt;/code&gt;.  You can chain these together without any problems.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    return [[[a firstChild] nextSibling] nextSibling];
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As I mentioned earlier, when an object receives a message that it doesn't understand it is allowed to perform any operation that it wants to.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-2859671719335491717?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/2859671719335491717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/2859671719335491717'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/09/some-thoughts-on-cocoa-and-objective-c.html' title='Some Thoughts on Cocoa and Objective-C'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-7835147345468061281</id><published>2010-07-20T22:41:00.001-07:00</published><updated>2010-07-20T22:52:08.192-07:00</updated><title type='text'>Apple is not going to Open Source OS X</title><content type='html'>&lt;p&gt;Last week I was listening to &lt;a href="http://twit.tv/mbw203"&gt;episode 203&lt;/a&gt; the &lt;a href="http://twit.tv/mbw"&gt;MacBreak
Weekly Podcast&lt;/a&gt;.  I agree with most everything that's talked
about on the episodes I've listened to and for the most part this one was much
the same, except for the one member of the panel insisting that Apple should open
source OS X.  Let me be one to say that there is absolutely no way that OS X
will &lt;em&gt;ever&lt;/em&gt; be open sourced.  There are so many reasons that this will never
happen it's ridiculous.  Here's a few off the top of my head:&lt;/p&gt;&lt;h2&gt;Traditional computing devices aren't dead yet&lt;/h2&gt;&lt;p&gt;The notebook is far from dead.  The desktop maybe, but not the notebook.  iOS
isn't feature rich enough to replace a traditional computer for the vast
majority of people.  There are lots of places where the OS shines, but for
general purpose computing it's not there yet.  You can tell that this sentiment
is echoed by Apple in the fact that iDevices are treated as satellites that have
to sync up with the mothership Mac.&lt;/p&gt;&lt;h2&gt;OS X is required for iOS development, why lose out on a sale?&lt;/h2&gt;&lt;p&gt;Right now the only platform that you can develop iOS applications on is OS X.
The only hardware that you can (legally) run OS X on is a Mac.  Apple makes a
sizeable amount of revenue off of Mac sales.  If they were to open source the
platform they'd been losing Mac sales.  Why would they want to cut off that
revenue stream?&lt;/p&gt;&lt;h2&gt;OS X is encumbered&lt;/h2&gt;&lt;p&gt;Probably the main reason that Apple will not open source OS X is that it legally
can't.  Unlike full open source operating systems like Linux, OS X probably
contains lots of code that's been licensed from third parties.  What code might
that be?  It could be anything.  For an example of this, have a look at OS/2.&lt;/p&gt;&lt;p&gt;Unlike OS X, OS/2 was actually discontinued.  Some years later devoted users and
businesses that had bought into the operating system wanted it to be open
sourced.  IBM refused citing licensing problems over some of the code that makes
up the OS.  This is coming from a company that does a lot of open source work.
If they could, I'm sure they would open source it but legally they can't.  It's
not worth their time or the potential for law suits.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Apple is &lt;em&gt;not&lt;/em&gt; going to open source OS X.&lt;/strong&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-7835147345468061281?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7835147345468061281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7835147345468061281'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/07/apple-is-going-to-open-source-os-x.html' title='Apple is not going to Open Source OS X'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-4536431220484869688</id><published>2010-07-06T21:11:00.001-07:00</published><updated>2010-07-06T21:11:13.709-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Design Matters</title><content type='html'>&lt;p&gt;It's summer time again, and with summer comes a change in wardrobe.  I have two
pairs of shorts in my small wardrobe that are extraordinarily similar.  They're
just about the same color and cut, and fit very well.  Where they differ is in
the design of their velcro-shut pockets.&lt;/p&gt;&lt;p&gt;Now, I'm not talking about design in the sense of expensive clothing designers.
No, no.  I'm talking about their general design and the thought that went into
it by whoever designed them.  Let me explain, as best I can, the general design
of the pockets on each of these.  Lets call the first pair &lt;em&gt;A&lt;/em&gt; and the second
pair &lt;em&gt;B&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Pair &lt;em&gt;A&lt;/em&gt; was designed as a standard pocket is - a slit on the fabric with a
pouch sewn in.  The band of velcro is attached right at the top on the inside of
the pocket.  Pair &lt;em&gt;B&lt;/em&gt; on the other hand has a flap that covers the opening of
the pocket when it's closed.  The soft side velcro strip is attached to the
inside of the flap, while the rough side is attached to the outside of the
pocket.&lt;/p&gt;&lt;p&gt;Both of these seem fairly straight forward and obvious.  But do either of these
strike you as bad designs?  I can guarantee you that it isn't obvious until
you've used this configuration for a little while.  Think about it for a minute.&lt;/p&gt;&lt;p&gt;Did you figure it out?  That's right!  Design &lt;em&gt;A&lt;/em&gt; is the bad design.  Because
the the velco is on the inside of the pocket whenever you try to pull anything
out of the pocket your knuckles get scraped on the rough side of the velcro.
It's not so bad the first few times but after a while it can wear your knuckles
raw.  With design &lt;em&gt;B&lt;/em&gt; the only the soft side of the velcro will come in contact
with your hand.&lt;/p&gt;&lt;p&gt;Now for the $64,000 Question: Which of these designs do you think was on the
more expensive pair of shorts?  Yeah, that's right.  Design &lt;em&gt;A&lt;/em&gt;, the
scrape-your-knuckles-raw design was more expensive, but that's not what's
important.  What's important is that &lt;strong&gt;design matters&lt;/strong&gt;.  It matters a &lt;em&gt;lot&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;When you're designing something you need to really think hard and sweat the
details.  What you don't think is a problem could turn into real, actual,
physical pain for your users.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-4536431220484869688?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4536431220484869688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4536431220484869688'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/07/design-matters.html' title='Design Matters'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-3159914912917347735</id><published>2010-07-03T08:26:00.001-07:00</published><updated>2010-07-03T08:46:27.286-07:00</updated><title type='text'>You're an Artist!</title><content type='html'>&lt;p&gt;Do you know anyone that refuses to show you what they're working on until it's
perfect?  I know I do.  What drives this person to polish and buff their
creation before showing it to the world?  I think they do it because they're
scared of what people might think.  They're scared that someone might ridicule
their hard work.  To this person I say: don't worry about what other people
think.  I know it sounds trite, but seriously.  If you're too scared to show off
your creation then why did you create it?&lt;/p&gt;&lt;p&gt;Putting something out in front of people isn't easy.  Everything you create is a
piece of art, it says something about you both personally and professionally.
It's a very scary thing, but you have to get over that.  If you never show
people your half-finished project how will you ever know if you're on the right
track?  I heard an excellent analogy that sums this up very nicely: You can't
steer your boat until it leaves the dock.&lt;/p&gt;&lt;p&gt;What's the worst thing that could happen if you show off your creation?  If
someone tells you what they think that's great!  It doesn't matter if it's good
feedback or bad.  The fact that someone is taking the time to tell you what they
think means they have some feelings about what you're doing.  And isn't that
what you're trying to do?  As an artist you should be striving to make people
feel &lt;em&gt;something&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;What, you don't think you're an artist?  Do you know what the definition of
artist is?&lt;/p&gt;&lt;dl&gt;&lt;dt&gt;Artist&lt;/dt&gt;&lt;dd&gt;n. A person whose creative work shows sensitivity and imagination.&lt;/dd&gt;&lt;/dl&gt;&lt;p&gt;If you've created something from nothing that shows creativity.  If it's
something that's never existed before, that's imagination.  And there's no doubt
that a program shows sensitivity.  Have you ever used a program or seen some
code that you thought was beautiful?  I'm sure we all have, that's sensitivity.
So, believe it or not but you, a programmer, are an artist.  So stop pretending
to be something you're not.  Create something that people will have feelings
about and unleash it on the world.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-3159914912917347735?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3159914912917347735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3159914912917347735'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/07/you-artist.html' title='You&amp;#39;re an Artist!'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-7500092728515202230</id><published>2010-05-18T20:29:00.001-07:00</published><updated>2010-05-18T20:38:39.122-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='elegant'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>An Elegant Design: Maildir</title><content type='html'>&lt;p&gt;One of the most elegant software designs I've seen is that of Dan Bernstein's
Maildir.  Maildir is a way of storing email messages common to Unix platforms.
It's the successor to an earlier format called MBox.  These two formats differ
in a very big way.  To better understand the driving factors behind Maildir it's
important to know the flaws that it's trying to address.  The flaw in MBox, it
turns out, is baked into its design and cannot be fixed without throwing out the
design and starting fresh; which is exactly what Dan did with Maildir.&lt;/p&gt;&lt;p&gt;The MBox format keeps all messages in a single text file in the user's home
directory, or anywhere for that matter.  Each message is delimited by a &lt;em&gt;From&lt;/em&gt;
line, that is, a line that starts with &lt;em&gt;from:&lt;/em&gt;.  As you can imagine, this design
makes is easy to count the number of messages in the file by counting the number
of &lt;em&gt;from&lt;/em&gt; lines.  Another benefit of this format is that since messagse are
appended on to the end of the file all of the messages are in chronological
order.  These benefits, are not without their drawbacks.&lt;/p&gt;&lt;p&gt;Since MBox stores everything in a single file that file needs to be locked
anytime a process wants to write to it.  That means that message delivery agents
(MDAs) need to lock the file while accepting mail for a user limiting the total
number of messages that can be accepted for a user at a given time to one.
Locking isn't the only problem that occurs when you store lots of information in
a single file.  When a message user agent (MUA) wants to remove a message from
the middle of the file it has to rewrite the entire file without the message
that the user wants to delete.  Along the same lines, in order to get a listing
of the messages in the mailbox the MUA must scan the entire file from the first
byte to the last -- apparently listing and deleting messages were not considered
a common use case.  Another problem, albeit one that only reveals itself in
extreme cases, is that if a mailbox gets extremely large it could potentially
run up against the operating system's file size limitations.  Lastly, the file
format is extremely fragile -- an errant &lt;em&gt;From:&lt;/em&gt; line coult corrupt the mailbox
and render the mailbox unreadable to MUAs.  When designing systems it's
important to balance speed, efficiency, robustness, and simplicity; MBox seems
to be designed for simplicity at the expense of others.&lt;/p&gt;&lt;p&gt;Clearly the bar is set fairly low for other mailbox formats.  Luckily, Maildir
wasn't designed as an incremental improvement over MBox, it was designed to
maximize speed, efficiency, and simplicity; and it did so in an amazingly
elegant and robust way.&lt;/p&gt;&lt;h2&gt;Enter Maildir&lt;/h2&gt;&lt;p&gt;Maildir, as the name implies stores its data in a directory structure. This is a
crutial difference between Maildir and MBox.  Maildir, unlike MBox purports to
be a lock-free system -- the mailbox can be read and written to at the same
time.  Under high load this is a really good feature to have.  The most
interesting piece is that Maildir maintains its lock-free design even when the
mailbox is stored on a remote system and mounted using NFS (network file
system).&lt;/p&gt;&lt;p&gt;Not only is the system lock-free it also doesn't fall victim to the other
problems faced by MBox; receiving and deleting messages are O(1) operations --
meaning that they take a constant amount of time to complete, instead of an
amount of time proportional to the amount of messages in the mailbox.  Another
advantage to storing the mailbox as a directory is that the number of messages
can be found by counting the number of files in the mailbox directories -- the
MUA doesn't need to open the files at all unless it wants to get information
from them.&lt;/p&gt;&lt;p&gt;So how does it work?  Maildir is a fairly simple system which has the nice side
effect of making it robust.  A Maildir mailbox is a directory that contains 3
subdirectories to store messages: &lt;em&gt;tmp&lt;/em&gt;, &lt;em&gt;new&lt;/em&gt;, and &lt;em&gt;cur&lt;/em&gt;.  Messages that are
being delivered are placed into &lt;em&gt;tmp&lt;/em&gt; while they are being received.  Once
messages have been received they are moved to &lt;em&gt;new&lt;/em&gt; before being read. After a
user reads a new message it's moved into &lt;em&gt;cur&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;So far this seems like a fairly simple system; but what are the files that
contain the messages called?  Each message is given a unique name.  The unique
name is made up of a combination of machine and process dependent information
such as the host name, current time, PID of the MDA delivering the message, etc.
By concatenating a few of these together a globally unique name can be created;
in the event that a collision occurs Maildir specifies that the MDA wait at
least one second before trying again.  This timeout is meant only to ensure that
enough time has elapsed that the data used to create another unique name will be
different.&lt;/p&gt;&lt;p&gt;That's effectively all there is to the mailbox format.  Certainly it's simple,
but how is it elegant or robust?  To get a handle on that it's important to
have an understanding of the properties of the Unix file system.&lt;/p&gt;&lt;h2&gt;Unix File Systems 101&lt;/h2&gt;&lt;p&gt;When most people think of a file on their computer they percieve a one-to-one
mapping between file names and data; that is, a file and its data are
synonyms.  Under Unix this isn't the case.  Unix treats file names and data as
two separate things.  What you might think of as the data in the file is
actually known to the operating system as a unique number called an &lt;em&gt;inode&lt;/em&gt;.
Files are simply references to an inode.  When you create a new file the file
system allocates a new inode and associates the data you're saving with it.  The
name you specified for the file references the inode.  When you delete the file
you're deleting the reference to the inode.  When the file system sees that
there are no longer any references to the inode it knows that the space being
used by that inode can be reclaimed.&lt;/p&gt;&lt;p&gt;Since multiple names can reference the same inode you can save disk space and
headaches by having multiple names for the same inode.  The process for creating
a new name for an inode is called &lt;em&gt;linking&lt;/em&gt; and there are two APIs (application
programming interfaces) exposed by POSIX (the portable operating system
interface [for unix]) that manage links: &lt;em&gt;link&lt;/em&gt; and &lt;em&gt;unlink&lt;/em&gt;.  As you can gather
from the name &lt;em&gt;link&lt;/em&gt; creates a new name while &lt;em&gt;unlink&lt;/em&gt; removes a name.&lt;/p&gt;&lt;p&gt;Linking and unlinking inodes is an atomic operation -- an operation that occurs
instantly without the possibility of being interupted part way through.  When a
new link for a file is created the file is completely accessible, there's no
delay while the data is copied on the disk. Simply put linking amounts to adding
some accounting information in the file system but doesn't need to shuffle data
around on the disk.  This property of atomicity can be used by any application
that requires that readers have a consistent view of the world.&lt;/p&gt;&lt;p&gt;Another feature of the Unix file system, and file systems in general is that the
metadata -- the data about the files -- is stored separately from the file data.
The stat information includes, but is not limited to: creation, modification and
access times as well as size and ownership information.  Having this information
at the file system level means that it's relatively inexpensive to load
information about a file or directory.  Loading information about a file is
called &lt;em&gt;stating&lt;/em&gt; a file based on the name of the POSIX function &lt;em&gt;stat&lt;/em&gt;.  Since
this information is standard information stored by the file system and isn't
buried within a data file access to this data doesn't require specialized APIs
-- the ones exposed by the OS are sufficient.&lt;/p&gt;&lt;h2&gt;How Maildir Exploits the Unix File System&lt;/h2&gt;&lt;p&gt;The features of the Unix file system mentioned previously are exploited very
well by the design of Maildir.  In order to ensure currency Maildir stores mail
that is being received in a temporary directory, &lt;em&gt;tmp&lt;/em&gt;.  This ensures that
readers of the mailbox, who read messages from the &lt;em&gt;new&lt;/em&gt; and &lt;em&gt;cur&lt;/em&gt; directories
will not see messages that have not been completely received.  Once a message is
completely received it is &lt;em&gt;link&lt;/em&gt;ed over to the &lt;em&gt;new&lt;/em&gt; directory.  At the moment
that the file system is updated with the new link to the file in &lt;em&gt;new&lt;/em&gt;, all
readers of the mailbox can see the message -- and the message they see is the
full message, not a partially written one.  In a similar vein, the &lt;em&gt;stat&lt;/em&gt;
information makes is very easy to get the size and received date of each message
without having to parse the message file.&lt;/p&gt;&lt;p&gt;These benefits are extremely tangible, especially when considered in concert
with the notion that a user's mailbox is generally located on a remote machine
mounted using a Networked File System (NFS).  Accessing files over a network is
an order of magnitude slower than accessing files that are local to a particular
machine; however the networked file system is presented to the system as any
other file system -- neatly abstracted away behind the standard POSIX calls.
From a user's perspective an NFS doesn't look any different than any other file
system, it's just slower.  But since Maildir is optimized to use the POSIX calls
for many common operations, the whole experience is greatly improved.&lt;/p&gt;&lt;p&gt;Consider the case where an MUA wants to get a listing of the number of messages
and sort them by date.  An MUA that uses MBox would need to first lock the
mailbox file, then read and parse its entire contents before it could provide
the listing.  For large mailboxes this is an expensive operation -- and an order
of magnitude more expensive when the mailbox is on a remote machine.  The MUA
using Maildir would need to simply stat the file system.  The data returned
doesn't need to be parsed since its already in a standard POSIX structure.  To
get email specific information from each message such as subject, sender, etc
Maildir helps by reducing the amount of I/O that needs to be performed.  An MUA
can simply read the first few lines of any message it's interested in to parse
the headers.  Contract this with MBox where it must read the entire mailbox file
since the only way to know that you've reached the last message is when you hit
the end of the file.&lt;/p&gt;&lt;h2&gt;An Example -- How MTAs Accept Mail for Maildir Mailboxes&lt;/h2&gt;&lt;p&gt;As mentioned previously the Maildir directory consists of at least 3
subdirectories: &lt;em&gt;tmp&lt;/em&gt;, &lt;em&gt;new&lt;/em&gt;, and &lt;em&gt;cur&lt;/em&gt;.  When writing new mail to a Maildir
mailbox the &lt;em&gt;tmp&lt;/em&gt; and &lt;em&gt;new&lt;/em&gt; directories are used.&lt;/p&gt;&lt;p&gt;When a new message arrives, the system constructs a (possibly) unique identifier
for the message.  The MTA then checks &lt;em&gt;tmp&lt;/em&gt; directory for a file with the same
name.  If a file with that name exists the MTA waits for 1 second and constructs
a new unique identifier and tries again until it finds a unique identifer that
doesn't clash with an existing file.  The 1 second delay allows enough time for
any time-related information used in the unique identifier to change.&lt;/p&gt;&lt;p&gt;The MTA then writes the message data to the uniquely named file in the &lt;em&gt;tmp&lt;/em&gt;
diectory.  When the file has been completely recieved a new &lt;em&gt;link&lt;/em&gt; is created to
the message file in the &lt;em&gt;new&lt;/em&gt; directory. The file is then &lt;em&gt;unlinked&lt;/em&gt; from the
&lt;em&gt;tmp&lt;/em&gt; directory leaving a single link to the file in &lt;em&gt;new&lt;/em&gt;.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;The design of Maildir leverages the facilities provided by POSIX to produce an
elegant solution that is simple, efficient and robust.  Its clever use of the
Unix file system and associated POSIX APIs demonstrates that it's possible to
design a robust and scalable inter-process communication (IPC) mechanism using
nothing but these facilites.  In general, Maildir is a great example of what can
be accomplished by having an understanding of the pieces of technology that a
system is built on.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-7500092728515202230?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7500092728515202230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7500092728515202230'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/05/elegant-design-maildir.html' title='An Elegant Design: Maildir'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-5187432538317709683</id><published>2010-04-16T20:22:00.000-07:00</published><updated>2010-04-16T23:28:17.611-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='dropbox'/><category scheme='http://www.blogger.com/atom/ns#' term='ipad'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>The iPad, iPhone OS 4.0 and Dropbox</title><content type='html'>&lt;p&gt;From the looks of the iPad it's designed to be used primarily as a content consumption device with support for content creation.  It's a good position for a first release since consumption doesn't require Apple to work out all of the kinks around how to use this brand new computing device as a way to create content.  However, Apple seems to be slightly schizophrenic about the device with the release of the iWork applications for the platform.  From what I've been reading the problems with using the device as a content creation platform are numerous.  Most of the complaints I've read fall into one of two buckets: the device is designed as a touch screen device and input is fraught with problems, and there's no built in support for syncing work between the iPad and another machine.&lt;/p&gt;&lt;p&gt;Obviously Apple is aware that people aren't going to get any serious work done with a touch screen keyboard, hence the iPad Keyboard Dock and support for Bluetooth keyboards.  But allowing users to hook up a keyboard to the device is only a half solution; you still need to interact physically with the device to perform some operations.  John Gruber of &lt;a href="http://daringfireball.net"&gt;Daring Fireball&lt;/a&gt; sums this up nicely in &lt;a href="http://daringfireball.net/2010/04/the_ipad"&gt;his article about the iPad&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The iPad is fundamentally a touchscreen device. You absolutely do not need a hardware keyboard for it. But if you re hoping to do any amount of serious writing with it ... you re going to want one. There are a few places in the iPad UI where I really wish the keyboard was useful but it isn t. For example, Safari location field suggestions. ... On the iPad, you must use touch to select from the list. Since you re already typing if you re entering a URL, this is just begging for arrow key support. (Ditto for suggested results from the Google search field in Safari.) The Esc key does not dismiss popovers, but that s probably OK. It s only possible to invoke popovers via touch, so it seems OK that you must dismiss them via touch as well.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;As an aside, it's nice that Apple's including the Bluetooth functionality for the iPhone as well.  I'm not sure how much use it will be, but it's a nice little feature that other phones won't have.&lt;/p&gt;&lt;p&gt;The other issue that's been brought to light is that the sync story for apps on the iPad, as well as the iPhone and iPod Touch, is really weak.  Apple hasn't provided an API to allow apps to sync their data with a Mac.  In fact, given that the iWork apps don't sync with the Mac I'm not even convinced that the functionality exists.  Sure, you could say that since the iWork apps are smaller, lighter versions of the iWork applications for the Mac they might not want to automatically sync since there isn't feature-set parity between the two suites.&lt;/p&gt;&lt;p&gt;The lack of any syncing support is really surprising to me given that Apple is trying to position the iPad as a light-weight computer.  The fact that it wasn't available in the initial release is forgivable but when the iPhone OS 4.0 announcement came and went without any indication of it being in the pipeline I was annoyed.&lt;/p&gt;&lt;p&gt;The lack of a native sync story for 3rd party apps has really turned out to be a ghetto.  Each application has its own way of synchronizing data between the sattelite - the iPad, iPhone, iPod Touch - and the mothership - the Mac.  Developers are forced to come up with their own way of syncing data between the two devices.  Obviously this isn't a good place to be in for developers or users.&lt;/p&gt;&lt;p&gt;From the developer's perspective they have to either write their own custom syncing protocol or use something like WebDAV, FTP or iDisk to transfer the data to location that's accessible to both the Mac and the device.  Clearly this is a waste of time on the developer's behalf and it's not even that good of a solution since it has the fatal flaw that the app can only sync data if it's running on the mobile device.&lt;/p&gt;&lt;p&gt;As for users: it's a complete usability nightmare.  Each app has to have its syncing configured separately.  The app on the mobile device has to be running for the sync to work and potentially so does the sibling application on the Mac.  If either isn't running the sync will fail and user's will have to figure out why.  This shouldn't be.  Syncing is one of those things that users just expect to work.  Period.&lt;/p&gt;&lt;p&gt;Synchronizing data is a common enough problem that the platform really should address it in a standard way.  The fact that sync support didn't make it into iPhone OS 4.0 but iAds, an advertising API did is just appalling.&lt;/p&gt;&lt;p&gt;So, if you read the title of this post I think you'll know where I'm headed: &lt;a href="https://www.dropbox.com/"&gt;Dropbox&lt;/a&gt;.  For the un-initiated, Dropbox is a service that automatically keeps a directory on multiple machines synchronized.  Best of all, for small amounts of data - up to 2GB - it's free!  Dropbox could provide the infrastructure needed for mobile and desktop devices to keep their data synchronized, a great place to be.  The fact that Apple's dropped the ball on such an important piece of the puzzle leaves an opening for Dropbox to become a de-facto standard for synchronizing between mobile and desktop devices.&lt;/p&gt;&lt;p&gt;There's only one slight problem: as of this moment there is no public API available for Dropbox.  This means that even if developers &lt;em&gt;want&lt;/em&gt; to integrate with Dropbox they can't.  From what I've heard an API is in the works, but it's not ready quite yet.  All I have to say is that they had better get their act together and soon before Apple comes along and eats their lunch with an integrated solution.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-5187432538317709683?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/5187432538317709683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/5187432538317709683'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/04/ipad-iphone-os-40-and-dropbox.html' title='The iPad, iPhone OS 4.0 and Dropbox'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-7171348255826204570</id><published>2010-04-06T23:25:00.000-07:00</published><updated>2010-04-07T21:00:22.862-07:00</updated><title type='text'>What is Source Code?</title><content type='html'>&lt;dl&gt;
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Hey, I've got a question for you.  Can you define source code?&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Seriously?  Source code is source code.  What's wrong with you?&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;No, seriously!  I'm having a philosophical debate with myself about what source code is and so far I'm losing.  I need an outside opinion.&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Let's see.  Hmmmm.  Well, I'd say that source code is some human readable form that tells a computer what to do.&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;What do you mean by 'human readable?'  Do you mean that it's made of letters and numbers and other things that humans write with?&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt; &lt;dd&gt;Yeah, human readable, like with words and numbers and stuff.&lt;/dd&gt;
  &lt;dt&gt;Bryan&lt;/dt&gt; &lt;dd&gt;Does it have to make sense to people in order for it to be human readable?'&lt;/dd&gt;
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Well, I guess so.  To a certain degree anyway.  I mean you wouldn't expect just anybody to be able to read it and make sense of it.&lt;/dd&gt;
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Ok, so source code is something that's human readable, in the sense that some people may be able to make sense of it, that tells a computer what to do.&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Yeah, how does that sound?&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Full of holes!&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Such as?&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Well, your definition seems to imply that the human readable form is run directly by a computer.  So basically everything that most people think of as 'source code' falls outside of your definition.&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Like what?&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;How about source code that's run through an interpreter, or a compiler, or a VM!?&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;You know what I mean!&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Suppose I don't!  That's the point of the debate!&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Alright.  Source code is something that's human readable, in the sense that some people may be able to make sense of it,  that is processed in some way to produce some output that then tells a computer what to do.&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;That's better.  But let's say hypothetically there is a computer that can understand and follow the instructions in the human readable form?&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;I think you're splitting hairs here.&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Humor me.&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Fine. Source code is something that's human readable, in the sense that some people &lt;em&gt;may&lt;/em&gt; be able to make sense of it, that &lt;em&gt;may&lt;/em&gt; be processed in some way to produce some output that then tells a computer what to do, or is interpreted directly by the computer.  Satisfied?&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Not even close.  What's this computer you speak of?&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;You're kidding me, right?&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Nope.&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;A computer, ya know?  A thing that runs the source code or the stuff output by the process that processes it.&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Interesting take on things.  Ya know, I seem to recall the word 'computer' has many meanings.  Before there were computing machines there were people whose job was to run computations.  They were called computers.  So far both the machine and the human definition of 'computer' fit your definition of 'source code'.&lt;/dd&gt;
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Oh god, what's wrong with you?&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Pedantry.  But I wouldn't say it's something that's wrong with me.  Can you define computer for me?&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;...&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;A computer is an electronic device that performs computations.&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Humans use electrical impulses...&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;ARGH! Fine, an electronic device &lt;em&gt;that you plug in&lt;/em&gt; that performs computations.&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Well, that definition seems rather crude, but I'll accept it just to keep the ball rolling.  So what about configuration files?  They're human readable and tell a computer what to do.  Take emacs for example, its configuration is a bunch of data structures that get interpreted by emacs, well the lisp interpreter part of emacs anyway and are run.&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;What's with you and that stupid editor?&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;What's with &lt;em&gt;you&lt;/em&gt; and &lt;em&gt;your&lt;/em&gt; stupid editor?  What's it called again?  'six?'&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;It's called 'vim' and if you're truely going to be pedantic, VIM in roman numerals is 6000.&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Whatever, both the fact and question remain.&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;What fact?&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Your editor sucks.&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;It does not suck, it's awesome.  You just don't grok it.&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;Look, why are you arguing with me about text editors?  We're supposed to be talking about source code.&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Very well.  I'm not sure that I agree with your assertion that configuration counts as source code.  It doesn't tell the computer what to do, it tells a program what to do.&lt;/dd&gt;
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;That's true, it does tell the program what to do not the computer.  But the configuration is still human readable, and processed, and tells the computer what to do.  Maybe there's no intermediate form that's produced but I don't see that as being the sole determinant between source code and configuration.  If that were the case then source code for an interpreted language would be considered configuration if the interpreter simply walked over the AST.&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Yeah but, it's configuration.  I think you picked a bad example since most people think of lisp as a language, not configuration.  What about simple configuration files that are just key-value pairs.&lt;/dd&gt;  
  &lt;dt&gt;Bryan&lt;/dt&gt;
  &lt;dd&gt;I would argue that it could still be considered source code depending, of course, on what's reading and interpreting the configuration.  I would say Turing-completeness shouldn't enter the picture at all.  Simple configuration or extremely rich configuration doesn't matter.  Some people consider HTML and CSS to be source code, but neither are Turing-complete.  Conversely what about TeX and PostScript?  Both are Turing-complete but nobody considers documents in either to be source code.&lt;/dd&gt;  
  &lt;dt&gt;Kyle&lt;/dt&gt;
  &lt;dd&gt;Look, I'd love to debate with you about what is and isn't source code but I have some work to do that involves &lt;em&gt;writing&lt;/em&gt; source code, not just thinking about it.&lt;/dd&gt;
&lt;/dl&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-7171348255826204570?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7171348255826204570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7171348255826204570'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/04/what-is-source-code.html' title='What is Source Code?'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-3595174954257699491</id><published>2010-02-23T21:56:00.001-08:00</published><updated>2011-04-19T13:02:14.901-07:00</updated><title type='text'>A Programmer's Toolbox</title><content type='html'>&lt;p&gt;Every programmer needs to have a scripting language in their toolbox. &amp;nbsp;The more languages the better, but at least one is a necessity. &amp;nbsp;For the longest time I've been torn between a few different general purpose scripting languages. &amp;nbsp;Endlessly debating over the relative strengths and weaknesses of each: &amp;nbsp;"Python is a fairly ubiquitous, but the libraries aren't consistent." &amp;nbsp;"Ruby has consistent libraries but there seems to be a steep learning curve before I can be a ninja." &amp;nbsp;Forgetting, of course that in the end it doesn't matter which one I choose, just so long as it solves a particular problem.&lt;/p&gt;
&lt;p&gt;Well, the other day I had just a problem that I needed a scripting language to solve. &amp;nbsp;I was re-re-reading one of Steve Yegge's terrific blog posts (yes, I've read them a few times). &amp;nbsp;Specifically it was the one about &lt;a href="http://steve.yegge.googlepages.com/ten-challenges"&gt;10 challenging books&lt;/a&gt; every programmer should read. &amp;nbsp;One of the books he mentioned was &lt;a href="http://www.amazon.com/Structure-Interpretation-Computer-Programs-Engineering/dp/0262011530/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1266987134&amp;amp;sr=1-1"&gt;Structure and Interpretation of Computer Programs&lt;/a&gt; by Harold Abelson and Gerald Sussman. &amp;nbsp;I'd heard of the book before, and being a fan of lisp I'd always wanted to read it but somehow never got around to it. &amp;nbsp;I'd even seen the &lt;a href="http://mitpress.mit.edu/sicp/full-text/book/book.html"&gt;free copy online&lt;/a&gt; and the lectures posted on the &lt;a href="http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/"&gt;book's website&lt;/a&gt;. &amp;nbsp;Finally I decided that I'd done enough procrastinating and while I wasn't going to want to read through the book, the lectures might be a good thing to watch when I have some time. &amp;nbsp;The only problem was I didn't want to have to download each of the 20 torrents and start them up myself. &amp;nbsp;Clicking on links is for suckers, in case you didn't know.&lt;/p&gt;
&lt;p&gt;I needed a way to automate the downloading of all of the torrent files. &amp;nbsp;I'd heard of a library for Python called &lt;a href="http://www.crummy.com/software/BeautifulSoup/"&gt;Beautiful Soup&lt;/a&gt;, but I'd also heard good things about &lt;a href="http://www.google.ca/search?sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;q=_why"&gt;the late _why&lt;/a&gt;'s &lt;a href="http://github.com/whymirror/hpricot"&gt;Hpricot&lt;/a&gt;. &amp;nbsp;Since I'd already dipped my toes in the Ruby water for a &lt;a href="http://github.com/bkyle/xml-tool"&gt;small tool&lt;/a&gt; I started working on the other day (more on that another time) I figured I'd try Hpricot. &amp;nbsp;After about 10 minutes of playing around with the library I had a working script that would scan through the page and download all of the torrents of the .avi versions of the lectures. &amp;nbsp;Below is the code I wrote, with an explanation to follow.&lt;/p&gt;
&lt;pre&gt;require 'rubygems'
require 'hpricot'
require 'open-uri'

url = 'http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/'
document = open(url) { |f| Hpricot(f) }

document.search('a') do |a|
  if a[:href] =~ /.avi.torrent/ then
    open(File.basename(a[:href]), 'wb') do |f|
      f.write open(url + a[:href]) { |f| f.read }
    end
  end
end
&lt;/pre&gt;
&lt;p&gt;The above code makes some fairly heavy use of blocks, one of my favourite features of Ruby. &amp;nbsp;The code is fairly straight forward if you understand that functions and blocks implicitly return the result of their last expression. &amp;nbsp;Here's a play-by-play of what's going on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lines 1-3: A few libraries are loaded.&lt;/li&gt;
&lt;li&gt;Line 6: The web page containing the links I want to read is loaded and parsed. &amp;nbsp;Since the block being passed returns the result of its last expression the document is returned.&lt;/li&gt;
&lt;li&gt;Line 8: The document is searched for all of its links. &amp;nbsp;For each of the elements found the passed block is executed.&lt;/li&gt;
&lt;li&gt;Line 9: Weed out any links that don't target the files I'm looking for.&lt;/li&gt;
&lt;li&gt;Line 10: Open a local file to write the contents of the file pointed to by the link.&lt;/li&gt;
&lt;li&gt;Line 11: Read the target of the link. &amp;nbsp;The result of the block passed will be written to the local file.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That's it. &amp;nbsp;15 lines of code and I didn't have to click a single one of the links. &amp;nbsp;Yes, I probably could have done it faster manually, but by taking the time to write a script this little task is a great &lt;a href="http://www.codinghorror.com/blog/2009/03/sharpening-the-saw.html"&gt;saw sharpening&lt;/a&gt; exercise and the amount of productivity gained from that is well worth the investment of time.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-3595174954257699491?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3595174954257699491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3595174954257699491'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/02/programmer-toolbox.html' title='A Programmer&amp;#39;s Toolbox'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-1270920931804447510</id><published>2010-02-06T20:50:00.000-08:00</published><updated>2010-04-10T22:46:23.818-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><title type='text'>Integrating Growl - A Quick Start Guide</title><content type='html'>&lt;p&gt;As promised, here is a quick start guide to integrating Growl support into a Cocoa application.  The documentation expects that you've worked with Xcode before and are familiar with creating new build phases and writing Objective-C code.  For the impatient and those that just want to play around &lt;a href="http://gist.github.com/297221"&gt;I've created a gist with the project&lt;/a&gt;.  You'll probably want to clone the project instead of looking at it online because it contains some binaries..&lt;/p&gt;&lt;pre&gt;&lt;code&gt;git clone git://gist.github.com/297221.git gist-297221
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first thing you'll need to get started is a copy of &lt;a href="http://growl.info/"&gt;Growl.framework&lt;/a&gt;.  As of this writing the latest is version 1.2.  Once you have a copy of the framework you'll need to link your application against it.  To do so, simply drag and drop the framework onto the &lt;em&gt;Linked Frameworks&lt;/em&gt; item in your Xcode project.  Since the framework will need to be shipped along with your application you'll also need to ensure that it gets copied into your application's bundle.  Create a new &lt;em&gt;Copy Files&lt;/em&gt; build phase for your application's target, make sure that you set the &lt;em&gt;Destination&lt;/em&gt; to &lt;em&gt;Frameworks&lt;/em&gt;.  Drag and drop &lt;em&gt;Growl.framework&lt;/em&gt; from &lt;em&gt;Linked Frameworks&lt;/em&gt; to the newly created build phase.  At this point your application will compile against the framework and include it when building.&lt;/p&gt;&lt;p&gt;The next thing you'll need to do is create a plist file called &lt;em&gt;Growl Registration Ticket.growlRegDict&lt;/em&gt; containing the registration information that will be required by the framework.  Below is an example of such a file.  You'll need to make sure that this file makes it into the application, this can be done by ensuring that its in the &lt;em&gt;Copy Bundle Resources&lt;/em&gt; build phase.&lt;/p&gt;&lt;script src="http://gist.github.com/297221.js?file=Growl+Registration+Ticket.growlRegDict"&gt;&lt;/script&gt;&lt;p&gt;In order for Growl to allow your application to send notifications you'll need to register the notifications that your application will be sending with the framework.  To do this you'll need to create and implement a bare-bones delegate.  All that's required is that you implement the &lt;code&gt;(NSDictionary*) registrationDictionaryForGrowl&lt;/code&gt; method.  The implementation of this method will simply need to return a dictionary whose contents come from the plist file created previously.  The body of this method can be as simple as:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;- (NSDictionary*) registrationDictionaryForGrowl {
   NSString* path = [[NSBundle mainBundle] pathForResource: @"Growl Registration Ticket" ofType: @"growlRegDict"];
   NSDictionary* dictionary = [NSDictionary dictionaryWithContentsOfFile: file];
  return dictionary;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once this method is implemented, and an instance of the class is set as Growl's delegate by calling &lt;code&gt;[GrowlApplicationBridge setGrowlDelegate: X]&lt;/code&gt; you'll be able to send messages to Growl using &lt;code&gt;[GrowlApplicationBridge notifyWithTitle:description:notificationName:iconData:priority:isSticky]&lt;/code&gt;&lt;/p&gt;&lt;p&gt;That's about all there is to it.  It's a fairly simple framework to integrate with, but the documentation neglects the fact that you have to implement &lt;code&gt;(NSDictionary*) registrationDictionaryForGrowl&lt;/code&gt;&lt;/p&gt;&lt;p&gt;An &lt;a href="http://gist.github.com/297221"&gt;example project&lt;/a&gt; exists as a gist on github.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;git clone git://gist.github.com/297221.git gist-297221
&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-1270920931804447510?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1270920931804447510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1270920931804447510'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/02/integrating-growl-quick-start-guide.html' title='Integrating Growl - A Quick Start Guide'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-328699929976950041</id><published>2010-02-04T22:48:00.001-08:00</published><updated>2010-04-17T08:20:39.457-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><title type='text'>Trials and Tribulations with Growl</title><content type='html'>&lt;p&gt;A few nights ago I had just finished getting the core piece of a new application I started working on.  It occurred to me that my little application and its users would benefit from having &lt;a href="http://growl.info/"&gt;Growl&lt;/a&gt; support.  It was pretty late, midnight or so and I didn't want to be up much later so I just downloaded the framework and had a quick skim of the &lt;a href="http://growl.info/documentation/developer/"&gt;developer&lt;/a&gt; &lt;a href="http://growl.info/documentation/developer/implementing-growl.php"&gt;documentation&lt;/a&gt;.  It seemed pretty simple, but it was late and I knew that if I started that late I'd be up few a few more hours getting no where and end up going to bed feeling defeated.  "Tomorrow, " I thought, "I'll do this tomorrow.  If its as easy as the docs say then I'll have enough time to add at least 2 other features!".&lt;/p&gt;&lt;p&gt;I got up the next morning feeling great, I knew that come that evening I'd have integrated Growl support.  Evening rolled around and I sat down and got to work.  I re-read the documentation...well, skimmed is more acurate, and started following the instructions.  I created the plist file containing the information that the documentation said I needed.  I added a build step to copy the plist to my application's Resources directory.  I double checked the name of the file -- the documentation says it's case-sensitive.  I linked Growl.framework to my application.  I added a build step to copy the framework to my application's Frameworks directory.  And lastly I added the code from the documentation to send a notification to Growl ensuring, of course, I was sending one of the notification names that was in my plist file.&lt;/p&gt;&lt;p&gt;I clicked the Build and Run button, and my application compiled and my application's Dock icon started to bounce.  By this point I felt like a kid at Christmas.  I'd written my letter to Santa, stuffed it in an envelope, and very carefully, in my &lt;em&gt;tidiest&lt;/em&gt; printing I wrote the address: "North Pole."  I placed my stamp and tossed it in the mailbox.  My letter must have gotten there, it hadn't been returned to sender so I knew that good stuff was heading my way.&lt;/p&gt;&lt;p&gt;The Dock icon stopped bouncing and my application's window opened up.  "This is it, " I thought to myself "the moment of truth!"  I clicked the button to fire off the notification aannnddd...nothing.&lt;/p&gt;&lt;p&gt;Silence.&lt;/p&gt;&lt;p&gt;"That's ok," I thought "it's probably some silly little thing I did wrong."&lt;/p&gt;&lt;p&gt;I looked at my run logs and they were eerily quiet.  No messages at all.  Surely if I'd done something wrong the framework would tell me.  That must mean that the framework didn't get copied to my application's bundle.  But if that's the case, then shouldn't there have been an error in the log about my code trying to perform a selector on a class that didn't exist?  So that must mean that my code that posts the notification was never called.  This sounds like a job for Captain Breakpoint!&lt;/p&gt;&lt;p&gt;I placed a breakpoint on the first line of my method and started the application again.  Application startup under the debugger always takes longer so I was caught off guard when my application's window opened up.  I moved my mouse cursor over the button, knowing that I was one mouse click away from finding out that my code wasn't being called thereby giving me all the information I'd need to fix the problem.  My eyes narrowed as I pressed the button.&lt;/p&gt;&lt;p&gt;Half a second later I was staring at the Xcode debugger, my line with the breakpoint highlighted and a stack trace showing me that execution was indeed stopped in my method.  I felt totally disarmed like I'd just gathered up my courage to tell &lt;em&gt;that guy&lt;/em&gt; what I &lt;em&gt;really&lt;/em&gt; thought of him only to be knocked off my feet by an overpowering wall of cheap cologne.&lt;/p&gt;&lt;p&gt;"What...the...what?"&lt;/p&gt;&lt;p&gt;I gingerly stepped through the method stopping just shy of executing the line to post the notification.  Pausing for a second to think about what could possibly happen next.  If the debugger tosses me out of my method, I know that either the framework doesn't exist or my parameters are causing it to barf.  If the debugger stops and the next statement in this method...well that doesn't sound easy to debug, so lets hope that doesn't happen.  I stepped over the line and found myself looking back that beautiful line of code just after the call into the framework.&lt;/p&gt;&lt;p&gt;This doesn't make sense.  The framework accepted my parameters without problem, ostensibly did something with them and succeeded.  So what could it possibly be?  The framework didn't log anything, so it must not be a problem with my code.  But no notification showed up, so the problem must be that Growl just isn't running.  At that moment notification showed up in Growl -- but not from my application. &lt;/p&gt;&lt;p&gt;"Well, if other apps can send notifications then it's gotta be something I'm doing wrong."  Since the documentation told me that all I needed to do was create a plist file and make sure it was in my application's Resources folder I figured I'd double check, and sure enough it was there.  I'd just been banished to developer's purgatory where I have to debug configuration..&lt;/p&gt;&lt;p&gt;I thought to myself, "If my application has to have one of these plists, then other apps must have to have them too!"  The first few applications I found didn't have one of those plists and they were working just fine.  Finally I found an application that had a plist.  So I compared them to make sure I'd done it right and sure enough I found a problem with my configuration.  I updated my file, saved, built and ran the app again.  My application's window popped up and I clicked the button and this time...nothing happened...again.&lt;/p&gt;&lt;p&gt;Silence.&lt;/p&gt;&lt;p&gt;Not believeing that it was something that I'd done I cleaned, rebuilt, and ran the application a few times knowing that it shouldn't make any difference in the world but hoping that it would just magically start working.  After several runs in vain I figured that maybe The Google would have an answer for me.  Sure enough, after trying a few google-y incantations I found some source code buried on a page that showed how to initialize Growl implementing a delegate method.  I modified my code in a similar way, saved and ran again.  I clicked the button and was surprised to see my little notification appear on the screen - only an hour after I started.&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Truth be told, the Growl documentation did mention that one could would have to implement a delegate if you were attempting to talk to Growl 0.7, but since my code was running against 1.2 I didn't think I'd need to.  In any case I managed to get it to work, but not without some frustrations that could have very easily been avoided had the Growl team produced some other artifacts that were as easy to find as the developer's documentation.&lt;/p&gt;&lt;p&gt;The first of these is some sort of a quick-start guide that just provides the bare minimum steps that are needed to use the framework.  The developer's guide was  littered with documentation about old versions.  I don't need to know that stuff.  Just assume that I have the latest and tell me exactly what I need to do.&lt;/p&gt;&lt;p&gt;Another thing that would have really helped, especially for developers that like to get dirty is a downloadable example.  I'm sure they have one somewhere, but I wasn't linked to from their documentation so it effectively didn't exist.&lt;/p&gt;&lt;p&gt;Last lastly, but certainly not least is some level of logging in the framework itself.  This would have been immensely helpful since I'd be able to tell if the framework was finding my plist or not, or whether there was a problem with my parameters.  Don't just leave me to figure it out on my own, give me some help!&lt;/p&gt;&lt;p&gt;I hope what I'm saying doesn't label me an &lt;a href="http://mikethecoder.com/2009/11/16/the-number-one-rule-of-open-source/"&gt;Open Source Douchebag&lt;/a&gt;.  Honestly, I'm really just trying to improve the project by making it easier to get people up to speed.  And in the next few days (hopefully) I'm planning on uploading some sample code along with a quick-start blog post.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-328699929976950041?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/328699929976950041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/328699929976950041'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/02/trials-and-tribulations-with-growl.html' title='Trials and Tribulations with Growl'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-6652194483117740835</id><published>2010-01-28T21:54:00.000-08:00</published><updated>2010-03-28T22:07:45.684-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>On Subclassing</title><content type='html'>&lt;p&gt;And now for another excursion into the depths of my experience and thinking about object oriented design and philosophy.  This time I'm going to talk about some pitfalls I've seen with one of the most commonly used, and abused tools in the object oriented developer's toolbox: subclassing and access modifiers.&lt;/p&gt;&lt;p&gt;Subclassing has been around since the dawn of objected oriented programming.  It's just one of many ways to enhance code reuse, but I've seen enough blood shed due to the misuse of this feature that I've stopped using it in cases where I can get away with another approach.  The core of the problem with subclassing tends to be an eagerness to reuse as much code as possible without any consideration of how code reuse decisions will effect the overall design.  Yes, reusing code means that there are fewer places to change when a change must be made, but subclassing is a merely a means to an end.  There are other, better approaches that give the same benefits without the problems.&lt;/p&gt;&lt;p&gt;So what are some of the problems with subclassing?  I think the central failing is that subclassing is &lt;strong&gt;the most tight form of coupling there is&lt;/strong&gt;.  When you decide to subclass an implementation, you've solidified part of your implementation.  A common word of wisdom is that you should always code to interfaces so that implementations can be changed at a later date with a minimal of fuss.  By subclassing an implementation you are publically declaring that you are and always will be a subclass of X.&lt;/p&gt;&lt;p&gt;Another problem with subclassing is that you cannot narrow the interface of the class to anything smaller than the subclasses interface, even if it doesn't make sense.  A textbook example of this in Java is the &lt;code&gt;java.util.Stack&lt;/code&gt; class.  &lt;code&gt;java.util.Stack&lt;/code&gt; extends &lt;code&gt;java.util.Vector&lt;/code&gt; which in turn extends &lt;code&gt;java.util.AbstractList&lt;/code&gt; which is an abstract implementation of &lt;code&gt;java.util.List&lt;/code&gt;.  The &lt;code&gt;java.util.List&lt;/code&gt; interface contains methods such as &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;indexOf&lt;/code&gt;, etc.  If you've followed along that means that &lt;code&gt;java.util.Stack&lt;/code&gt;, in addition to its own interface also has these methods.  A stack should really only have two methods for mutating the stack (&lt;code&gt;push&lt;/code&gt; and &lt;code&gt;pop&lt;/code&gt;) and perhaps some methods to determine how many items are on the stack.  By subclassing, &lt;code&gt;java.util.Stack&lt;/code&gt; has guaranteed that it implements the &lt;code&gt;java.util.List&lt;/code&gt; interface and therefore has methods that allow a developer to work around the stack encapsulation.  Ah, but you can override those methods in the subclass with ones that do nothing or throw a &lt;code&gt;java.lang.MethodNotImplemented&lt;/code&gt; exception.  Certainly you could, but then if an instance of &lt;code&gt;java.lang.Stack&lt;/code&gt; was passed to a method that accepted &lt;code&gt;java.util.List&lt;/code&gt; it would not produce the desired result -- either by throwing an exception or not performing the operation.&lt;/p&gt;&lt;p&gt;No discussion of subclassing would be complete without mentioning the &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;Liskov Substitution Principle&lt;/a&gt;.  I think it's great advice it theory, but as we've all seen it's not exactly easy to follow.  If the JDK developers can make such an error with all of their review process, how does a lowly developer stand a chance?&lt;/p&gt;&lt;p&gt;Aside from these problems there's always the minefield of access modifiers.  In my opinion there should really only be 2 at the class level: public and private.  Protected variables are a major cause of headaches since subclasses can easily muck around with the internals of a superclass, violating encapsulation.  Protected methods provide a second interface to the class which has to be maintained and documented -- as if a single interface wasn't enough problems.  So, private and public is really all that's needed - stuff that's internal and stuff that's public.&lt;/p&gt;&lt;p&gt;So if not subclassing then what?  In a word &lt;em&gt;delegates&lt;/em&gt;, specifically the &lt;a href="http://en.wikipedia.org/wiki/Delegation_pattern"&gt;delegation pattern&lt;/a&gt;.  With the delegation pattern you simply implement interfaces, if applicable, and delegate parts of the implementation to a concrete class.  By doing so you don't have to expose any information about how your class works internally.  And since you're not subclassing you don't inherit interface that doesn't make sense for your class.  As an added bonus, since you're using the public interface to the concrete class you don't have to worry about methods internal to the implementation changing or becoming deprecated.&lt;/p&gt;&lt;p&gt;Delegates are also an effective strategy for reusing code.  You can encapsulate logic into a single class and use it from anywhere in your application.  This is a great benefit when you have an irregular class heirarchy, it effectively gives you mixins without the headaches of trying to figure out which pieces of implementation are coming from which mixin.&lt;/p&gt;&lt;p&gt;Obviously there are times when subclassing is the right thing to do. But in my experience I see it used much more often than it should be and usually for the wrong reasons.  I hope my thoughts have given you something to think about next time you reach for that subclassing hammer.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-6652194483117740835?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/6652194483117740835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/6652194483117740835'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/01/on-subclassing.html' title='On Subclassing'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-4206056776099317333</id><published>2010-01-16T21:40:00.001-08:00</published><updated>2010-03-28T22:17:20.564-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><title type='text'>First Impressions of Cocoa</title><content type='html'>&lt;p&gt;Over the past few months I've been doing a lot of playing around with development on the Mac using &lt;a href="http://developer.apple.com/cocoa/"&gt;Cocoa&lt;/a&gt;. Although I do disagree with some of the design decisions that have been made, but for the most part I really like both Objective-C and Cocoa.  The developer community is extremely vibrant and very helpful, a feeling I haven't had elsewhere.&lt;/p&gt;&lt;p&gt;One of the things I really like about Cocoa is that it handles a lot of the mundane tasks for you.  There's a technology called &lt;a href="http://developer.apple.com/macosx/coredata.html"&gt;CoreData&lt;/a&gt; that handles object graph persistence.  You simply setup your data model and the framework takes care of the rest.  This is really great since one initial hurdle I always run into when coding, and where I usually lose steam is in persisting and reading data that my application is working with, CoreData takes care of this beautifully.&lt;/p&gt;&lt;p&gt;Another great technology is &lt;a href="http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/CocoaBindings/CocoaBindings.html"&gt;Bindings&lt;/a&gt; which is built on top of &lt;a href="http://developer.apple.com/mac/library/documentation/cocoa/conceptual/KeyValueCoding/"&gt;Key-Value-Coding&lt;/a&gt; and &lt;a href="http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html"&gt;Key-Value-Observing&lt;/a&gt;.  In essence, Bindings allows you to visually tie the value of a control to a piece of data in your data model.  This removes the need for reams of "glue" code that you'd otherwise have to write to keep your View and Model consistent.  With these two technologies all you really have to do is write your Controllers.&lt;/p&gt;&lt;p&gt;Granted, the Controller is generally where the rubber meets the road, but since the frameworks take care of the Model and View you're free to think almost exclusively on the problems and structure of the Controller.&lt;/p&gt;&lt;p&gt;So far I've been really happy with the results that I've been able to achieve with only a small time investment.  Between the results and how supportive the developer community is I think the Mac is a great platform to develop for and look forward to doing so in the future.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-4206056776099317333?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4206056776099317333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4206056776099317333'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2010/01/first-impressions-of-cocoa.html' title='First Impressions of Cocoa'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-4945647547655543342</id><published>2009-10-31T23:30:00.000-07:00</published><updated>2010-03-28T22:08:32.491-07:00</updated><title type='text'>The Polyglot Programmer</title><content type='html'>&lt;p&gt;Those that know me know that I'm a real programming language geek.  I'm always reading about programming languages.  Why am I constantly seeking out new language while most other developers are happy knowing one or two languages?  I think it comes down to not being satisfied with the status quo.  When you code in a language for a long enough period of time you think in terms of the constructs that the language provides you.&lt;/p&gt;&lt;p&gt;This is certainly a good thing in terms of productivity.  Thinking in a language is akin to speaking it as your native tongue.  Your brain becomes hard wired to think in that way.  The time from concept to implementation is shortened because you don't have to do any mental translation to convert a solution from one language to another.  While this is all well and good, thinking only in the constructs of one language prevents you from seeing .  As the old saying goes: when all you have is a hammer, every problem looks like a nail.&lt;/p&gt;&lt;p&gt;But while this is great in some respects, learning more languages has certain benefits.  Each language is different, exposing you to different ways of approaching problems and different tools for solving them.  As you step further and further away from the comfortable object oriented Aglol descendants you'll notice that the languages you used to use to solve every problem is woefully inadequate at solving certain classes of problems.&lt;/p&gt;&lt;p&gt;This comes from the fact that not all languages are created equal.  Each language has a certain level of friction for a given problem domain.  It's true that you can solve a problem in any turing complete language, but that doesn't mean that the solution will be easy to read, write, or maintain.  By learning a variety of languages you'll be able to see which language are better suited to a particular problem.&lt;/p&gt;&lt;p&gt;Also, since each language tends of offer a different set of tools, you'll expand your mind.  There is more to programming than what &lt;a href="http://en.wikipedia.org/wiki/Blub#Blub"&gt;blub&lt;/a&gt; languages give you.  For example, JavaScript gives you a language with dynamic typing, first class functions, closure, and prototypal inheritance.  None of those features are available in a language like Java.&lt;/p&gt;&lt;p&gt;Features aren't the only thing that new languages expose you to either.  As you venture further off of the beaten path you'll find some very interesting languages that look strange and alien.  Take &lt;a href="http://factorcode.org/"&gt;Factor&lt;/a&gt; for example.  Factor is a concatenative language which is a language that is based around the idea of a mutable stack.  Concatenative languages are just one class of languages and there are many others, all of which have interesting properties.&lt;/p&gt;&lt;p&gt;As you become exposed to more and more language concepts you'll be able to pick up new languages much more easily.  Having been exposed to the concepts of a new language before, you will have flattened the learning curve of that language.&lt;/p&gt;&lt;p&gt;The most effective languages tend to be called &lt;em&gt;Domain Specific Languages&lt;/em&gt;.  A domain specific language is a language that is tailor made for solving problems in a specific domain.  A great example of a domain specific language that most of us have dealt with is CSS.  CSS provides a language to specifying styling of HTML elements.  It doesn't have loops, it doesn't have conditionals, just pure unadulterated declarations that can be combined.  Certainly there are problems with implementations of the language, but that isn't my point.  My point is that CSS fills a void.  You could probably do what CSS does with a general purpose language, but why?  CSS is tailored to the problem it's trying to solve.&lt;/p&gt;&lt;p&gt;I'll leave you with an interesting thing I've noticed as more applications are moved into the web realm:  if you want to stay relevant, you need to become a &lt;a href="http://en.wikipedia.org/wiki/Polyglot"&gt;polyglot&lt;/a&gt;.  Most applications aren't simply constrained to one language anymore.  Modern web applications use at least 4 distinct languages between the server side, client side, build scripts, and configuration.  If you can't be effective with all of them then you've got some learning to do.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-4945647547655543342?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4945647547655543342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4945647547655543342'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2009/10/polyglot-programmer.html' title='The Polyglot Programmer'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-7376099013421450437</id><published>2009-08-20T21:12:00.000-07:00</published><updated>2010-03-28T22:08:57.398-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Exception in thread "main" java.lang.NullPointerException</title><content type='html'>&lt;p&gt;I've learned over my years of programming in object oriented languages is that null values can be really painful.  Due to poor decisions by API designers code has to be littered with null checks to ensure that values returned from API calls return something other than null.  Failing to make these kind of checks while oftentimes harmless, can cause problems once you start testing code off of the happy-path.&lt;/p&gt;&lt;p&gt;There are few things a consumer of a poorly designed class can do other than simply read the documentation, add null checks and test thoroughly.  So, if you're designing a new class it's really important that you get it right the first time.  While I can't give much advice about the design of your specific class, I can give some hints nulls and when it's appropriate to use them. &lt;/p&gt;&lt;p&gt;These rules aren't hard and fast, there are times when these rules are completely wrong.  But it's been my experience that these rules are applicable in almost all cases.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Return null when you mean null.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;A common mistake that programmers make (myself included) is to simply default values to null.  I attribute this to laziness.  It's much easier to simply use null as a default value instead of some sensible value.  Certainly there are times when null is a good choice, but I think as programmers we tend to fall into the trap of using null because its convenient.&lt;/p&gt;&lt;p&gt;The first thing to understand about null is that it means the absence of a value.  It means there's nothing to see here, move on.  It doesn't mean empty string, it doesn't mean 0, it doesn't mean empty instance of a class it means that there is nothing to refer to, no value.  Unless your program needs to distinguish between an empty value and no value provided there is little need to use null.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Return an empty list or collection instead of null.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;If you have a method that is supposed to return a list of something, you should always return a list regardless of whether there is anything to put in the list.  Typically, when a caller asks for a list they are usually going to loop over its contents performing some operation.  Since a loop over an empty collection is effectively a no-op returning an empty collection simplifies the calling code by removing the need to check for null.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Return a safe instance instead of null.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;When possible, return a do-nothing instance of a class instead of null.  This is really useful for classes that contain other objects that are used frequently.  This allows callers chain method calls together without having to worry about null return values.  Typically this is useful for classes that are treated as services.&lt;/p&gt;&lt;p&gt;An example of this might be an a getXPathEngine() method of a Document class.  If there is no implementation of XPathEngine available, then Document.getXPathEngine() should return a safe implementation of XPathEngine instead of null that way callers don't have to constantly check for the presence of the engine, they can assume that it exists.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-7376099013421450437?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7376099013421450437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7376099013421450437'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2009/08/exception-in-thread-main.html' title='Exception in thread &quot;main&quot; java.lang.NullPointerException'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-4239027277653597657</id><published>2009-07-14T23:32:00.000-07:00</published><updated>2010-03-28T22:18:52.079-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='habits'/><title type='text'>The Tailor</title><content type='html'>&lt;p&gt;This is the story of two developers, Curtis and Dean.  Both happily work on the same project, and have strikingly similar experience.  In almost every aspect Curtis and Dean are exactly the same.  The only place where the differ is in development pace.  Curtis tends to take slightly longer to accomplish his tasks when compared to Dean.  On a task that takes Dean 7 hours, it would take Curtis 8.&lt;/p&gt;&lt;p&gt;Things remained this way for a few months, but as time went on Curtis began to close the gap with Dean.  Before long, Curtis was doing his tasks much faster than Dean.  On the task that was taking Dean 7 hours, Curtis was completing it in 4 with the same degree of quality.  Curtis and his manager were happy with the improved pace.  Dean couldn't figure out how Curtis was doing it.&lt;/p&gt;&lt;p&gt;One day, Dean and Curtis were working together trying to solve a particular bug.  After a few minutes of watching it was apparent to Dean how Curtis was able to outpace him.  That extra time that Curtis had spent earlier wasn't going to waste.  He had been busy writing scripts to automate the routine micro-tasks he had to perform.  And the scripts were just the beginning of it.&lt;/p&gt;&lt;p&gt;Curtis had taken his attitude towards automating further than just scripts.  Any time he noticed himself doing something repeatedly he spent some time to make sure he was doing it in the most optimum way.  He had memorized the key bindings the commands in his IDE he used the most.  He extended his editor of choice, Emacs, with functions and triggers to automate almost every micro-task he did on a routine basis.&lt;/p&gt;&lt;p&gt;Curtis had tailored his environment perfectly to suit how he works and how he thinks.  Curtis' customization allowed him to get more done in a shorter amount of time than his peers.  Tailoring being what it is, the customizations to his environment were useless for anyone other than himself so he never bothered to share them.  To Curtis, this didn't matter.  He didn't make these customizations for anyone but himself.&lt;/p&gt;&lt;p&gt;----&lt;/p&gt;&lt;p&gt;Obviously the above story is fiction but it serves to outline a point:  you need to optimize your environment for the way you think and work.  If you don't, you're wasting time.  That doesn't give you a license to impose your thought patterns on anyone else, it simply means that your personal work bubble needs to be optimized.&lt;/p&gt;&lt;p&gt;To put it into object oriented terms:  Everyone must adhere to a common interface when working with one another.  The interface provides an abstraction, or facade for how the tasks are performed.  How the work is done is an implementation detail.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-4239027277653597657?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4239027277653597657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4239027277653597657'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2009/07/tailor.html' title='The Tailor'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-8939654324695082556</id><published>2009-04-20T21:39:00.000-07:00</published><updated>2011-04-19T13:01:45.416-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>Arrays and Objects</title><content type='html'>&lt;p&gt;In Javascript, arrays and objects are different but many people treat them the same.  This causes no end of grief because of the underlying differences in what it means to be an object versus what it means to be an array.  An object is in essence simply a hash table or a dictionary.  Another term for this construct, the term that I believe is responsible for much of the confusion, is "associative array."&lt;/p&gt;&lt;p&gt;The two constructs: hash tables and arrays are fairly similar in intent if you look at them in just the right way.  Generally both imply a performant data structure for storing and retrieving data.  These structures differ in their implementation, but fundamentally they both provide a way of associating a key with a value.  Hash tables allow you to associate an arbitrary key with a value whereas arrays only allow numbers for the keys.  Granted, there are usually some caveats to the numeric keys used for arrays.  For example, they usually contain an upper and lower limit.  But what why does this matter?  It matters because this is how Javascript sees an array: as a hash table with numerical keys among some other non-numerical keys.  Did I just blow your mind?  Probably.&lt;/p&gt;&lt;p&gt;In this regard, arrays in Javascript are no different from any other object that shares the same characteristics.  Where it differs is in the fact that an array is an object that is built into the interpreter and therefore has some special privileges granted to it, the main one of these being the "length" property which contains a value one greater than the largest numeric key.&lt;/p&gt;&lt;p&gt;Along with arrays and maps generally come looping constructs.  Javascript has several, but the most common when working with objects and arrays is the "for" loop which comes in two flavours: the vanilla C style for loop and the less flexible but just as tasty for-in.  The for-in loop iterates over the keys or properties of an object, not its values.  It doesn't matter what type of object you're looping over, it will always iterate over the keys.  For standard arrays both work fine, for example:&lt;/p&gt;&lt;p&gt;&lt;script src="http://gist.github.com/98934.js"&gt;&lt;/script&gt;&lt;/p&gt;&lt;p&gt;But what happens when someone starts &lt;a href="http://en.wikipedia.org/wiki/Monkey_patch"&gt;monkey patching&lt;/a&gt; arrays, or adding extra properties to an array.  Well, the for-in loop will cheerfully give you those keys as well.  Maybe this is what you want, but I would guess that if you're looping over an array you probably want its contents not its properties which unfortunately Javascript treats the same. &lt;/p&gt;&lt;p&gt;&lt;script src="http://gist.github.com/98938.js"&gt;&lt;/script&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;The take-away here is that arrays and objects in Javascript are fairly similar.  The language treats both of them in a universal manner which is refreshingly simple on one hand while jarring on the other.  The language, like other dynamic languages assumes that the programmer knows what he is doing and stays out of the way.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-8939654324695082556?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8939654324695082556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8939654324695082556'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2009/04/array-is-not-map-in-javascript-arrays.html' title='Arrays and Objects'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-3728448445349324903</id><published>2009-03-25T21:19:00.000-07:00</published><updated>2010-03-28T22:09:33.392-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='http'/><category scheme='http://www.blogger.com/atom/ns#' term='rest'/><title type='text'>GET Dirty!</title><content type='html'>&lt;p&gt;Recently I've been working to design some RESTful APIs and I've come into a situation where it makes sense to update server state in response to a GET method.  "What? Change state on a GET!?  Are you mad?  Are you insane?  Have you even read the HTTP spec?" I hear you saying.  But just hear me out, it's not as bad as you're thinking.&lt;/p&gt;&lt;p&gt;According to the &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html"&gt;HTTP 1.1 Specification&lt;/a&gt; GET is supposed to be both a safe and idempotent method, meaning that it doesn't have side effects and requesting once or a million times doesn't make any difference.  So how is it that I can convince myself that it's OK to change state on a GET?  Quite simply, by using a little used (in my experience) status code: &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.3"&gt;202 Accepted&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The HTTP 1.1 specification has the following to say about 202 Accepted (emphasis mine):&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;b&gt;The request has been accepted for processing, but the processing has not been completed.&lt;/b&gt; The request might or might not eventually be acted upon, as it might be disallowed when processing actually takes place. There is no facility for re-sending a status code from an asynchronous operation such as this.&lt;/p&gt;&lt;p&gt;The 202 response is intentionally non-committal. Its purpose is to allow a server to accept a request for some other process (perhaps a batch-oriented process that is only run once per day) without requiring that the user agent's connection to the server persist until the process is completed. The entity returned with this response SHOULD include an indication of the request's current status and either a pointer to a status monitor or some estimate of when the user can expect the request to be fulfilled.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;In essence, if a POST is made that returns a status code of 202 Accepted the data can be acted upon at some indeterminate time in the future.  &lt;b&gt;That time in the future might just so happen to be right before the GET is processed.&lt;/b&gt;  In this way, the GET is both safe and idempotent since the state change is only tied to the GET in that it's used as a trigger for processing some previously POSTed data.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-3728448445349324903?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3728448445349324903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3728448445349324903'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2009/03/get-dirty.html' title='GET Dirty!'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-5074329492814621876</id><published>2009-03-15T21:22:00.000-07:00</published><updated>2010-03-28T22:10:01.183-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='chrome'/><title type='text'>Chrome: The Downside of Process Isolation</title><content type='html'>&lt;p&gt;When Google Chrome first came out it was apparent that they had thought long and hard about pretty much everything that goes into a browser.  One thing that really stood out to me was that each tab ran in its own process.  For most surfers this doesn't mean anything, but the caliber of user that Chrome appeals to, at least when it first came out, wasn't your average surfer.  Typically a surfer that would use Chrome was a power-surfer.  They had many tabs open at any one time, typically one sites that are very resource intensive.  For this type of surfer the one-process-per-tab idea was a boon in the event that any one site misbehaves.&lt;/p&gt;&lt;p&gt;If each tab is a process that means that the operating system is free to work with them as independent processes.  Since each tab is a separate process the operating system is free to swap the whole tab out of memory if another process needs memory.  This is an interesting side benefit since tabs that aren't being used can be completely removed from memory until they are needed.  Contrast this with the all-tabs-in-one-process approach taken by every other browser where the operating system simply swaps out pages of memory that haven't been used recently.  In essence, the one-process-per-tab approach gives the operating system a hint as to how best to swap the application.&lt;/p&gt;&lt;p&gt;With all of these positives, there has to be a trade-off somewhere doesn't there?  In my experience: yes.  As a developer I'm typically running a lot of different applications at any one time, this means lots of memory usage.  It seems that when switching to a tab that isn't in memory the whole browser locks up.  I don't mean simply that the browser doesn't respond to anything you try to do I mean literally it locks up, I can't switch to another application while I wait.&lt;/p&gt;&lt;p&gt;I'm hoping that there is a fix for this issue in later builds because I've switched to using Chrome when I'm on Windows for all of my normal browsing.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-5074329492814621876?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/5074329492814621876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/5074329492814621876'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2009/03/chrome-downside-of-process-isolation.html' title='Chrome: The Downside of Process Isolation'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-1395647579080864773</id><published>2009-03-10T20:56:00.001-07:00</published><updated>2010-03-28T22:10:30.607-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='commenting'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Tell Me Why!</title><content type='html'>&lt;p&gt;Whenever I start trying to learn a new codebase, one of the first things I do is try to get an understanding of how the code works at a high level.  Generally this isn't too hard, I just find out where the program starts, which is usually pretty obvious, and work through the code from there.  But there's a problem I always run into the code only tells me what it does, it doesn't tell me the most important thing: &lt;b&gt;why&lt;/b&gt;.  Unfortunately, most projects don't maintain a good set of code-level documentation.  Instead all documentation is locked away inside of heads of its developers as tribal knowledge.&lt;/p&gt;&lt;p&gt;So if documentation is needed where's the best place to keep it?  In my opinion, the the documentation needs to be as close to the code as possible, so &lt;b&gt;put your documentation in the code&lt;/b&gt;.  The further away it is, the more likely it is that the documentation will get out of date, and the only thing worse than no documentation, is wrong documentation.&lt;/p&gt;&lt;p&gt;Now, what should be in those comments?  Well, as I eluded to previously, it should &lt;b&gt;tell me the why&lt;/b&gt;.  If someone is reading through the code they surely have enough knowledge to be able to tell what's happening to which objects, so you can safely leave that out.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-1395647579080864773?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1395647579080864773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1395647579080864773'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2009/03/tell-me-why.html' title='Tell Me Why!'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-8132625879637582291</id><published>2009-01-28T22:58:00.000-08:00</published><updated>2010-03-28T22:10:46.515-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Java's Got it All Wrong</title><content type='html'>&lt;p&gt;When I first started working on computers I was sold that Windows was the only way to go.  However as time went on I found that there was a lot that I was missing out on.  One of those things was Unix.  I've learned a lot about in the time since I was a hard-core Windows user.  The one thing in Unix that has really stuck with me is the elegance of its design.  In particular the approach of favouring processes over threads.  It has huge implications that you never really understand until you run into a system that does things the other way around.&lt;/p&gt;&lt;p&gt;Recently I've been spending a lot of time thinking about web applications, and I keep coming back to the thought that the current design of application servers in Java are flawed.  Typically application servers are designed to run as a single process with many threads servicing requests.  While this approach has been proven to work, I'm not convinced its the right approach.  The real problem as I see it is that there is no &lt;em&gt;process isolation&lt;/em&gt;, and it's a real problem when working with many applications deployed to the same server.  To illustrate my point, lets look at an analog: operating systems and processes.&lt;/p&gt;&lt;p&gt;One of the things operating systems do very well is manage processes.  Each process gets its own little sandbox to play in so that it can keep track of everything the process is doing:  what files it has open, how much memory it has allocated, etc.  Additionally, the information available to the operating system is also made available to the users of the system so they can monitor each process and terminate any that aren't working correctly.  By allowing the user to access the process information the operating system essentially saying "I'm a stupid machine and I only know how to handle obvious problems".  An intelligent user can determine if one process is using too much memory or CPU and kill it so that all the other processes can keep on working away.&lt;/p&gt;&lt;p&gt;Java application servers on the other hand only presents a single opaque process.  There's no way of telling which application is consuming all of the CPU cycles, sucking up all of the memory available to the VM, etc.  And if one of the applications crashes it takes down the entire server with it.  All of the applications within a server run under the same process and as such aren't really isolated from each other in any meaningful way -- there's no &lt;em&gt;process isolation&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;A better approach might be to follow the lead of the operating system.  Each application runs as a separate process or tree of processes tracked independently by the operating system.  The web server runs isolated from the applications that it's serving.  The operating system already provides great tools for managing processes, so why not use them?  This is by no means a new concept.  If the application process speaks HTTP, then the web server can setup a reverse proxy to map the application into its URL address space.  Alternatively, the application could just as easily speak FastCGI, a protocol that allows applications to respond to requests from a web server - similar to CGI, but without the overhead of starting up a process to service each request.&lt;/p&gt;&lt;p&gt;Unfortunately, I don't see anything changing anytime soon.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-8132625879637582291?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8132625879637582291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8132625879637582291'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2009/01/javas-got-it-all-wrong.html' title='Java&apos;s Got it All Wrong'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-976232514079330792</id><published>2009-01-17T23:07:00.000-08:00</published><updated>2010-03-28T22:21:31.486-07:00</updated><title type='text'>The Logitech Wave</title><content type='html'>&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.logitech.com/index.cfm/keyboards/keyboard/devices/3071&amp;amp;cl=US,EN"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="http://4.bp.blogspot.com/_oQFr7FUMIXs/SXLXGV4qAVI/AAAAAAAAACY/0QFyetXg7oE/s400/4487.1.0.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5292529016067719506" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Well, I've had my &lt;a href="http://www.logitech.com/index.cfm/keyboards/keyboard/devices/3071&amp;amp;cl=US,EN"&gt;Logitech Wave&lt;/a&gt; keyboard for a while now and I suppose I owe you a review.  So without any further ado, here we go.&lt;/p&gt;&lt;p&gt;I haven't spent too much time with the Wave since I bought it, but the time I have spent with it has been pretty good.  The keys have really good feedback and aside from the weirdo layout for the "6-pack" I haven't had too much trouble adapting to it.&lt;/p&gt;&lt;p&gt;One of the things I really wanted in a keyboard was a scroll wheel.  Unfortunately this one doesn't have that feature, but neither do any of the other ones I've seen.  What it does have, which is fairly common is a zoom control.  On the Mac the zoom control can be reconfigured to act as a scroll wheel.  I was a little skeptical at first about how well it would work but I was pleasantly surprised.&lt;/p&gt;&lt;p&gt;Windows however is a completely different story.  In order to treat the zoom control as a scroll wheel I had to install modifications to the drivers called &lt;a href="http://www.mstar.net/users/rlowens/uberOptions/"&gt;uberOptions&lt;/a&gt;.  It certainly gets the job done but not without its own problem.  The software had some weird quirk where it would hold on to the mouse cursor position and restore it when you stop scrolling.  It was really frustrating because I tend to like to use the mouse at the same time as scrolling, i.e. scroll on a page and click links, but this software just kept jumping the cursor back.  Argh!  I really don't like having to install extra software to get what seems like some trivial functionality, but if it actually worked I probably wouldn't complain.  The fact that it doesn't work as I would expect it just frustrating.&lt;/p&gt;&lt;p&gt;Since my use of the zoom control is slightly esoteric, I wouldn't hesitate recommending the Logitech Wave to anyone looking for a new keyboard.  But if you're looking for a keyboard with a scroll feature and are running Windows, stick with what you've got, or wait for the software to get an upgrade.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-976232514079330792?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/976232514079330792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/976232514079330792'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2009/01/logitech-wave.html' title='The Logitech Wave'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_oQFr7FUMIXs/SXLXGV4qAVI/AAAAAAAAACY/0QFyetXg7oE/s72-c/4487.1.0.jpg' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-3775849301258294549</id><published>2008-12-26T22:42:00.000-08:00</published><updated>2010-03-28T22:11:26.930-07:00</updated><title type='text'>Keyboards, the Neverending Saga</title><content type='html'>&lt;p&gt;If you're anything like me, you're very specific about your requirements for a keyboard.  I've been searching for a keyboard for about a year and a half, and so far I haven't been able to find anything that fits the requirements.  Maybe I'm just sentimental, but I really like the Logitech Elite keyboard that is no longer being made.  I bought one years ago and it's perfect for me.  One of the things I really like about it, and what I haven't been able to find in any other keyboard is the scroll wheel.  A keyboard with a scroll wheel?  Yeah, it may seem odd, but considering that &lt;a href="/2007/04/ergonomics.html"&gt;I use a trackball&lt;/a&gt; that doesn't have one it works really well.&lt;/p&gt;
&lt;p&gt;So what am I looking for in a keyboard?  Well, I'd like a keyboard, preferably black with a scroll wheel.  It has to be really comfortable but it doesn't have to be ergonomic.  It absolutely must have good, solid feedback.  I find it really awkward to type on something that's too spongey, and it hurts to wrists to use something that too stiff.  As much as I love the feel of the &lt;a href="http://www.daskeyboard.com/"&gt;Das Keyboard&lt;/a&gt; it's too loud, so another requirement is that it has to be pretty quiet.  Lastly, the layout of the 6-pack (home, end ...) has to be just that: a 6 pack.  I'm really getting sick of seeing all these otherwise decent keyboards having a really screwy layout for the keys that as a programmer I use all the time.&lt;/p&gt;
&lt;p&gt;In short:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Scroll wheel
&lt;/li&gt;&lt;li&gt;Comfortable
&lt;/li&gt;&lt;li&gt;Quiet
&lt;/li&gt;&lt;li&gt;Good Feedback
&lt;/li&gt;&lt;li&gt;Non-screwy 6-pack
&lt;/li&gt;&lt;li&gt;Mac compatible
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I almost forgot, as I use a Mac it needs to be Mac compatible.&lt;/p&gt;
&lt;p&gt;As I mentioned earlier, I've not been able to find a keyboard that fits these requirements other than the Logitech Elite.  So where does that leave me?  Well, certainly without a keyboard that meets my requirements without looking on ebay.  I guess I'll have to relax my requirements a bit, the only problem is that my search for keyboards hasn't been very fruitful.  Maybe that's because I only have 3 objective requirements, and I've only seen an answer to 2.  The others, I can only determine by using it.&lt;/p&gt;
&lt;p&gt;The only keyboard that comes close is the &lt;a href="http://www.logitech.com/index.cfm/keyboards/keyboard/devices/3071&amp;amp;cl=ca,en"&gt;Logitech Wave&lt;/a&gt; keyboard.  Granted it only meets one of my objective requirements, but my hope is that its answer to the subjective ones will far make up for the what it's missing.  I think I'll pick it up and see what happens.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-3775849301258294549?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3775849301258294549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3775849301258294549'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2008/12/keyboards-neverending-saga.html' title='Keyboards, the Neverending Saga'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-159468877878399732</id><published>2008-12-14T21:05:00.001-08:00</published><updated>2010-03-28T22:11:44.622-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='http'/><title type='text'>Javascript Development Tip #1:  no-cache</title><content type='html'>&lt;p&gt;When doing javascript development that requires files to be loaded from an HTTP server, caching can be a real pain.  Turning off browser caching is one solution, but I've always had mixed results.  The real solution is to turn off caching on the server side.  In order to prevent well behaved browsers from caching your files you simply need to add a header to every response.&lt;/p&gt;&lt;p&gt;The &lt;a href="http://www.ietf.org/rfc/rfc2616.txt"&gt;HTTP specification&lt;/a&gt; has a list of headers that user-agents and servers should understand, however I've always found the headers around caching to be a bit of a black art.  However, for our purposes, there's no magic necessary.  To tell the browser not to cache resources, the cache-control header must be set to no-cache.  This tells the browser not to cache the resource, not in memory, not in disk, just take the response entity, use it and forget you ever received it.&lt;/p&gt;&lt;p&gt;So, how do you go about adding this header to each response?  If you're serving your files from &lt;a href="http://httpd.apache.org/"&gt;Apache&lt;/a&gt;, you can use &lt;a href="http://httpd.apache.org/docs/2.0/mod/mod_headers.html"&gt;mod_headers&lt;/a&gt;.  mod_header allows you to add arbitrary headers to responses.  The module has a lot of capabilities, but only the basics are required for our purposes.&lt;/p&gt;&lt;p&gt;The first step is to enable the module by adding a line similar to the following to your httpd.conf.  Most installations of Apache have this line conmmented out.  If that's the case, just uncomment it.&lt;/p&gt;&lt;p&gt;&lt;pre&gt;LoadModule headers_module modules/mod_headers.so&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;With the module enabled, you can have to modify the headers of outgoing responses.  If can be configured server-wide, within a virtual host, a directory using .htaccess.  You can also enable it in &amp;lt;Directory&amp;gt;, &amp;lt;Location&amp;gt;, and &amp;lt;Files&amp;gt; sections.  Whichever you choose, just add the following line, save your changes and restart the server.&lt;/p&gt;&lt;p&gt;&lt;pre&gt;Header set cache-control "no-cache"&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;This tells mod_headers to set the cache-control header to no-cache for all responses within its configured scope.  If the cache-control header has already been set, it will be overriden by the value you've specified.&lt;/p&gt;&lt;p&gt;To verify that the configuration worked, clear your browsers cache and make a request to one of the resources covered by the configuration of mod_headers.  If you're using &lt;a href="http://www.getfirefox.com"&gt;Firefox&lt;/a&gt; and have &lt;a href="http://getfirebug.com/"&gt;Firebug&lt;/a&gt; installed, you can switch to the Net tab and look at the response headers.&lt;/p&gt;&lt;p&gt;So there you have it, an easy way to speed up development and reduce your stress by simply removing caching, the real way.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-159468877878399732?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/159468877878399732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/159468877878399732'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2008/12/javascript-development-tip-1-no-cache.html' title='Javascript Development Tip #1:  no-cache'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-8374632140210720014</id><published>2008-08-04T22:58:00.000-07:00</published><updated>2010-03-28T22:22:55.604-07:00</updated><title type='text'>del.icio.us Passwords</title><content type='html'>&lt;p&gt;Does anyone else think it's odd that &lt;a href="http://del.icio.us/"&gt;del.icio.us&lt;/a&gt; has strict password requirements? Given that it's a social bookmarking site, 99% of the user's data is public. It's not as though anyone is trying to hide what they're bookmarking.&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/bryan.kyle/BryanKyleSBlog/photo?authkey=odflMeZZWUo#5230910441478337426"&gt;&lt;img src="http://lh6.ggpht.com/bryan.kyle/SJftVPwys5I/AAAAAAAAAAg/f-5kRnoCKQI/s800/del.icio.us.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;Surely I'm missing something, there must be a sane and logical reason for all this.  Can anyone tell me what it is?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-8374632140210720014?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8374632140210720014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8374632140210720014'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2008/08/delicious-passwords.html' title='del.icio.us Passwords'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/bryan.kyle/SJftVPwys5I/AAAAAAAAAAg/f-5kRnoCKQI/s72-c/del.icio.us.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-2507225283928024275</id><published>2008-07-03T20:18:00.000-07:00</published><updated>2010-03-28T22:12:35.773-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>On Emacs</title><content type='html'>&lt;p&gt;I've been using &lt;a href="http://www.gnu.org/software/emacs/"&gt;Emacs&lt;/a&gt; for a few months now and after the initial steep learning curve I'm really enjoying it.  It's great for all of my text editing and coding needs, although I don't think it will ever replace Eclipse as my editor of choice for Java.  Since I'm so enamored with it, I figured I'd spend some time explaining why I came to Emacs instead of the zillion other editors out there.&lt;/p&gt;&lt;p&gt;I used to be a huge fan of &lt;a href="http://www.textpad.com/"&gt;TextPad&lt;/a&gt; on Windows, it worked well for every situation that ever came up, I've hammered out a few projects using it and not much else.  The main problem with it is that it wasn't very extensible.  Sure you could add tools, but what you could do was really quite limited.  At the time, I just accepted it for what it was and didn't look much further, but things changed when I bought a Mac.&lt;/p&gt;&lt;p&gt;When I bought a Mac, I had a hard time finding an editor I liked.  I tried the reigning king of editors &lt;a href="http://www.barebones.com/products/bbedit/index.shtml"&gt;BBedit&lt;/a&gt; and its free sibling &lt;a href="http://www.barebones.com/products/textwrangler/index.shtml"&gt;TextWrangler&lt;/a&gt;, but I didn't find them to be terribly usable.  At the time I was looking for TextPad for OS X, which neither of these were.  Eventually I found &lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt;, which was exactly what I was looking for.  I liked it so much that I bought a license for it, which says a lot given that in all the years of using TextPad I couldn't be bothered to fork out the cash for it, which at the time was about half the price of TextMate.&lt;/p&gt;&lt;p&gt;TextMate did have one major problem though, it only ran on OS X.  I do development on Windows and OS X, so I really needed something that was cross platform.  I'd given jEdit a try before, but I wasn't that impressed with it, so that wasn't going to work.   On Linux I'd always used &lt;a href="http://www.vim.org/"&gt;vim&lt;/a&gt;, which worked in a console environment but for some reason it didn't translate well to a windowed environment, so vim was going to work either.  When I started looking around, I had kinda-sorta been interested in Lisp.  I'd played briefly with &lt;a href="http://common-lisp.net/project/lispbox/"&gt;Lisp-in-a-box&lt;/a&gt; on Windows (Emacs+&lt;a href="http://common-lisp.net/project/slime/"&gt;SLIME&lt;/a&gt;+&lt;a href="http://www.sbcl.org/"&gt;SBCL&lt;/a&gt;), and while my initial experience with Emacs wasn't great, it was better than my experience with vim in a windowed environment.&lt;/p&gt;&lt;p&gt;After a few days of using it for simple text editing, I found it to be really productive.  Hidden behind a wall of weirdo key bindings was a fantastic editor.  As I used it more and more I found myself reading through the documentation learning that Emacs has an insane number of features that I'd always wanted in other text editors.  As I became more comfortable, I started to script it.  It's really quite amazing all the things you can do when your editor is designed from the ground up to be extensible.  None of the editors I'd tried before even came close to being as extensible, or if they were I never knew about it.&lt;/p&gt;&lt;p&gt;In the end, I think I've found the editor that best fits my needs.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-2507225283928024275?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/2507225283928024275'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/2507225283928024275'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2008/07/on-emacs.html' title='On Emacs'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-2181137200370818006</id><published>2008-05-23T22:06:00.001-07:00</published><updated>2011-04-19T13:01:29.897-07:00</updated><title type='text'>Unit Testing Graphics Code</title><content type='html'>&lt;p&gt;I was reading &lt;a href="http://reddit.com/r/programming/"&gt;reddit&lt;/a&gt; today when I came across a &lt;a href="http://reddit.com/r/programming/info/6khm8/comments/"&gt;post&lt;/a&gt; about the &lt;a href="http://binstock.blogspot.com/2008/05/is-popularity-of-unit-tests-waning.html"&gt;popularity of unit tests waning&lt;/a&gt;.  After reading a few of the comments I came across an &lt;a href="http://reddit.com/r/programming/info/6khm8/comments/c043tgj"&gt;interesting one&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;How do you assert that this image draws centered in this button? Writing an automated test for that is fiendishly hard. The few automated tests I attempted to write for graphical components were fragile, produced lots of failures-that-weren't, and became a maintenance headache. Meanwhile, testing the button by just-looking-at-the-damn-thing was trivial, and what I should have been doing all along.&lt;/blockquote&gt;

&lt;p&gt;I've recently had to write unit tests for graphics code so I thought I'd share my experience testing that code.&lt;/p&gt;

&lt;p&gt;One of the benefits of unit testing is that it forces you to think about your structure.  Typically if you can't unit test something then it isn't factored properly, and drawing routines are no different.  In the cited example, the developer needs to test to ensure that an image is displayed in the center of the components canvas.  Let's assume that the code that needs to be tested looks something like the following.&lt;/p&gt;

&lt;pre&gt;public class Button {

   private Image image = null;

   public Button(Image image) {
      this.image = image;
   }

   ...

   public void paint(Graphics g) {
      super.paint(g);

      int x = (this.getWidth() / 2) - (this.image.getWidth() / 2);
      int y = (this.getHeight() / 2) - (this.image.getHeight() / 2);

      g.drawImage(this.image, x, y);
   }
}&lt;/pre&gt;

&lt;p&gt;How can we test this? Well, looking at the code I see a few approaches to testing this.  One way is to stub out the Image and Graphics classes and test to make sure that methods are called with the arguments we expect.  Another is to factor out the logic inside the &lt;code&gt;paint&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Stubbing out the classes is you're best bet here if you can.  Given that you will probably need to test other code that uses these classes I think it'd be a wise investment of your time.But what if you can't stub out the classes?  What if the classes don't implement any interfaces, or the classes are declared as final?&lt;/p&gt;

&lt;p&gt;But what if you can't stub out the classes?  What if the classes don't implement any interfaces, or the classes are declared as final?  If you find yourself in this situation, you can break the logic of the &lt;code&gt;paint&lt;/code&gt; method out into smaller utility methods.  From there you can call those methods directly and assert that the results they give are what you expect.&lt;/p&gt;

&lt;pre&gt;public class Button {

   private Image image = null;

   public Button(Image image) {
      this.image = image;
   }

   ...

   public void paint(Graphics g) {
      super.paint(g);
      g.drawImage(this.image, calculateImagePositionX(), calculateImagePositionY());
   }

   private Point calculateImagePositionX() {
      return (this.getWidth() / 2) - (this.image.getWidth() / 2);
   }

   private int calculateImagePositionY() {
      return (this.getHeight() / 2) - (this.image.getHeight() / 2);
   }
}&lt;/pre&gt;

&lt;p&gt;Granted this example is a bit trivial, but I think it goes to show that it is possible to write unit tests for graphics code.  That being said, without physically looking at the canvas there's no way of being 100% sure, but at least you have tests that can run as part of any build.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-2181137200370818006?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/2181137200370818006'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/2181137200370818006'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2008/05/unit-testing-graphics-code.html' title='Unit Testing Graphics Code'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-3634485876918808359</id><published>2008-04-10T21:32:00.001-07:00</published><updated>2011-04-19T13:01:21.042-07:00</updated><title type='text'>Two Functions Enter.  One Function Leaves.</title><content type='html'>&lt;p&gt;What happens when two applications declare a function with the same name in the same namespace? &lt;b&gt;A huge headache.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;A big problem with Javascript as it is today is that there is no insulation between your application and someone else's.  When two functions are declared with the same name in the same scope, the last declaration "wins".  Given this sad state of affairs, how can you work around this problem?  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Defensively.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There's simple pattern for insulating your application.  It involves two things I've talked about before: closures and anonymous functions.  Consider the following code:&lt;/p&gt;

&lt;pre&gt;
(function(scope) {

   function doStuff() {
      ...
      doSomethingElse();
      ...
   }

   function doSomethingElse() {
      ...
   }

   scope.doStuff = doStuff;

})(this);
&lt;/pre&gt;

&lt;p&gt;When run, the above code will expose &lt;i&gt;doStuff&lt;/i&gt; by adding it to the passed object.  If that code is run in the global scope then &lt;i&gt;this&lt;/i&gt; refers to the global object.  Everything that doesn't need to be exposed stays neatly hidden inside the closure.  Congratulations, you've just reduced the surface area of your application to the bare minimum you'll be less susceptible to someone else's application trampling all over yours.&lt;/p&gt;

&lt;p&gt;Combining this pattern with the &lt;a href="http://en.wikipedia.org/wiki/Unobtrusive_JavaScript"&gt;unobtrusive Javascript&lt;/a&gt; methodology will effectively reduce your application's surface area to 0.  Short of another application overwriting event handlers and data on shared DOM elements you've insulated yourself.  What's even better is that if you don't need to expose anything a build script can bundle your sources files into one file wrapped it in an anonymous function and obfuscate it without you having to think.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-3634485876918808359?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3634485876918808359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/3634485876918808359'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2008/04/two-functions-enter-one-function-leaves.html' title='Two Functions Enter.  One Function Leaves.'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-4907073895395886428</id><published>2008-02-17T18:54:00.000-08:00</published><updated>2011-04-19T13:01:13.249-07:00</updated><title type='text'>Curried Functions</title><content type='html'>&lt;p&gt;So, currying, what's that all about?&lt;/p&gt;
&lt;p&gt;Currying is a technique of transforming a function that takes multiple arguments into a function that takes one argument.  In short, it's a way of defaulting parameters of a function call.&lt;/p&gt;
&lt;p&gt;In a language like Java, you could accomplish the same thing by delegating method calls.  For example:
&lt;pre&gt;int add(int a, int b) {
   return a + b;
}&lt;br/&gt;
int add_one(int b) {
   return add(1, b)
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;However, since functions aren't first class citizens in Java you're limited in what you can do.  In a functional language, the possibilities are a more open.  You can make use of currying to reduce the size of your code base and reduce the amount of boilerplate code you'd otherwise have to write.&lt;/p&gt;
&lt;p&gt;An example of this is a set of accessor methods where the code is boilerplate.  Modern IDEs will generate these for you, but wouldn't it be nice if you didn't have to see the code for them all the time?  What happens if some of your setters need to manipulate the value being set?  I suppose you could find all of the setters and update them manually...or if you're working in a functional language, you could just leverage the features of the language to make your job easier.&lt;/p&gt;
&lt;p&gt;Take a look at the following code:&lt;/p&gt;
&lt;pre&gt;function set(attribute_name, value) {
   this[attribute_name] = value;
}&lt;br/&gt;
function get(attribute_name) {
   return this[attribute_name];
}&lt;br/&gt;
function attr_reader(attribute_name) {
   return function() { 
      return get.call(this, attribute_name);
   }
}&lt;br/&gt;
function attr_writer(attribute_name) {
   return function(value) {
      set.call(this, attribute_name, value)
   };
}&lt;br/&gt;
function MyClass() {}
MyClass.prototype.setName = attr_writer('name');
MyClass.prototype.getName = attr_reader('name');&lt;br/&gt;
var o = new MyClass()
o.setName('Bryan');
o.getName();  // Bryan&lt;/pre&gt;
&lt;p&gt;In this example, we have two methods: &lt;i&gt;set&lt;/i&gt; and &lt;i&gt;get&lt;/i&gt; which are the most simplistic and generic setter and getter functions one could write.  We've also added a currying function for each of them.  We then call through the currying functions to create a curried call to getter and setters on the prototype of the constructor for &lt;i&gt;MyClass&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;While this example is not &lt;u&gt;the&lt;/u&gt; best possible code for currying getters and setters I believe it illustrates the concept of currying.&lt;/p&gt;
&lt;p&gt;If you can tell me why &lt;i&gt;attr_reader&lt;/i&gt; and &lt;i&gt;atter_writer&lt;/i&gt; return the functions curried using their call method you get bonus points.  If you can't, I'll explain later.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-4907073895395886428?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4907073895395886428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/4907073895395886428'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2008/02/curried-functions.html' title='Curried Functions'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-5047564906736808417</id><published>2008-02-12T20:47:00.000-08:00</published><updated>2011-04-19T13:00:55.242-07:00</updated><title type='text'>Closures and Javascript</title><content type='html'>&lt;p&gt;Ah Closures, one of the must misunderstood and accidentally used features of javascript.  But why is this the case?  Well, because it's so easy to accidentally use them few understand the mechanics behind them.  In this post I hope I can clear up the confusion and explain how they work.&lt;/p&gt;
&lt;blockquote&gt;In &lt;a href="http://en.wikipedia.org/wiki/Computer_science" title="Computer science"&gt;computer science&lt;/a&gt;, a &lt;b&gt;closure&lt;/b&gt; is a &lt;a href="http://en.wikipedia.org/wiki/Function_%28programming%29" title="Function (programming)"&gt;function&lt;/a&gt; that is evaluated in an environment containing one or more &lt;a href="http://en.wikipedia.org/wiki/Bound_variable" title="Bound variable"&gt;bound variables&lt;/a&gt;.
&lt;/blockquote&gt;
&lt;p&gt;Or, in normal people terms, a closure is a function that can access variables from the same scope that it was declared in.  You can think of it as a natural extension of the standard scoping rules where functions declared in the global scope can access global variables.&lt;/p&gt;
&lt;pre&gt;var my_global = "hello, world";

function printGlobal() {
   print(my_global);
}&lt;/pre&gt;
&lt;p&gt;In the above code the function printGlobal can access a global variable.  As an extension of the same principle, in the following code the function printLocal can access a local variable in its declaring scope.&lt;/p&gt;
&lt;pre&gt;function main() {
   var my_local = "hello, world";

   function printLocal() {
      print(my_local); 
   }
}&lt;/pre&gt;
&lt;p&gt;So that's all well and good, but why on earth would you ever want to use it?  All your life you've been told that global variables are evil (which they are), so surely closures must also be evil.  Well, if used incorrectly of course they're evil, but with great power comes great responsibility.&lt;/p&gt;
&lt;p&gt;Here's quick example of a function that returns a function to increment a value by another fixed value.&lt;/p&gt;
&lt;pre&gt;function incr(start, delta) {
   return function() {
      start = start + delta;
      return  start;
   }
}

var i = incr(10, 1);
i(); // 11
i(); // 12
i(); // 13&lt;/pre&gt;
&lt;p&gt;Pretty freakin' wild isn't it?  But how does that work?  When a call is made to the incr function start and delta are bound to its scope.  The function it returns simply holds onto these variables.  Since it has a reference to the variables (not just their values, but a place to store them) they can be freely modified.&lt;/p&gt;
&lt;p&gt;The next question you might be asking is, "So that's all well and good, but what if I call incr twice and hold on to both of the returned functions?  Won't the second call clobber the first?".  The answer is: NO!  Each call to the method creates a new local scope just for that invocation.  Exactly the same as how two calls to the same function at the same time won't interfere with each other.&lt;/p&gt;
&lt;p&gt;But by far, the most classic use of closures is to enable Currying, and I'm not talking about the delicious spice blend. No no, I'm talking about higher-order functions.  Functions that work with functions.  Functions that return functions that call other functions.  Functions that I'll explain in another post.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-5047564906736808417?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/5047564906736808417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/5047564906736808417'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2008/02/closures-and-javascript.html' title='Closures and Javascript'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-1632725505737211252</id><published>2007-11-13T07:51:00.000-08:00</published><updated>2010-03-28T22:23:38.908-07:00</updated><title type='text'>The Next Javascript</title><content type='html'>&lt;p&gt;Recently, I've been more interested in Javascript than I have been in a long time. However, after reading some of proposed features for Javascript 2, I feel like I'm watching a simple language with a few warts turn into a bloated C++.&lt;/p&gt;&lt;p&gt;From the proposal, I get the distinct impression that the committee designing Javascript 2 has some contempt for prototypical inheritance and dynamic typing.  The proposal includes support for packages, classes, static typing etc.  All things that appear to come straight from Java and other enterprise-y languages that I find are slow to develop in.  Thankfully, it will be optionally typed, meaning you don't have to statically type your variables unless you want to.   I haven't decided which side of the fence I fall on in terms of that debate yet, but I do feel like it statically typed languages can feel like a straight jacket from time to time.&lt;/p&gt;&lt;p&gt;All in all, the changes are way too much, way too quickly.  For starters, all of the major browsers will need to support this new, hugely unproven language right out the gate.   Undoubtedly there will be mistakes made in implementations, if they are even implemented at all.  No one from the Web Development community will be able to use Javascript 2 at all being that it's so vastly different from Javascript 1.x and there is still a need to support older browsers for their applications.&lt;/p&gt;&lt;p&gt;You simply cannot force the sort of change this new language spec imposes in one go.  It may as well be a new language for all the changes it includes.  I believe, a more fruitful approach to moving Javascript 1.x to where this committee thinks it should go would be to incrementally add these changes to the existing language.  I couldn't tell you where to start, as I'm fairly happy the current language, but I'm sure the community as a whole will be able to give feedback to the language designers in terms of what features are &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;actually needed&lt;/span&gt; as opposed to what the designers &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;think&lt;/span&gt; is needed.&lt;/p&gt;&lt;p&gt;In the end, if the committee goes forth with this specification for Javascript 2 it will be a long, hard, bumpy road to get stable, completely implementations in the browsers that are actually being used.  Perhaps, more effort should be spent tackling the issues around the same-origin policy instead of giving new features that we can't possibly use for another 5 years.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-1632725505737211252?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1632725505737211252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1632725505737211252'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2007/11/next-javascript.html' title='The Next Javascript'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-5076460376443657706</id><published>2007-11-07T20:39:00.001-08:00</published><updated>2010-03-28T22:24:13.089-07:00</updated><title type='text'>Leopard</title><content type='html'>&lt;p&gt;I upgraded to &lt;a href="http://www.apple.com/macosx/"&gt;Leopard&lt;/a&gt; the weekend after it came out and so far, I've been pretty happy.  There's only one thing I've noticed so far that's bothered me, Remote Desktop's VNC protocol is busted.&lt;/p&gt;&lt;p&gt;I did some research and it turns out I'm not the only person having this problem.  Luckily, some of the others that have been having problems found out that they could connect using &lt;a href="http://www.tightvnc.com/"&gt;TightVNC&lt;/a&gt;.  It's kind of a shame though, because RealVNC has been my Windows client of choice for the past few years.&lt;/p&gt;&lt;p&gt;So, while I wait for Apple to fix it, I suppose I'll have to settle with &lt;a href="http://www.redstonesoftware.com/products/vine/server/vineosx/index.html"&gt;Vine Server&lt;/a&gt; which has worked flawlessly for me for years.&lt;/p&gt;&lt;p&gt;As a side note, I never knew that Apple had VNC support under Tiger until I started trying to find out why it's Apple would ship a broken new feature under Leopard.  Shows how much I know.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-5076460376443657706?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/5076460376443657706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/5076460376443657706'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2007/11/leopard.html' title='Leopard'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-6482005309298242436</id><published>2007-10-17T21:33:00.000-07:00</published><updated>2011-04-19T13:00:40.303-07:00</updated><title type='text'>Functions ARE Objects!</title><content type='html'>Javascript is a functional, object-oriented language - but what exactly does that mean to you a developer?  It means that functions ARE objects.  You can add members to functions just as you could any object.  Take for example, the following function that keeps track of how many times it's been called:
&lt;pre&gt;function count_times() {
 count_times.call_count = (count_times.call_count || 0) + 1;
 print(count_times.call_count);
}
&lt;/pre&gt;Trivial example I know, but let your imagination go wild.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-6482005309298242436?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/6482005309298242436'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/6482005309298242436'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2007/10/functions-are-objects.html' title='Functions ARE Objects!'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-5550668151923150016</id><published>2007-10-10T22:04:00.000-07:00</published><updated>2011-04-19T13:00:15.321-07:00</updated><title type='text'>arguments.callee</title><content type='html'>Javascript Tip: Ever wonder what arguments.callee is for?  Well, it contains the function being evaluated, so you can write anonymous recursive functions like the following:
&lt;pre&gt;
(function(n) {
  if (n &gt; 1)
     return n * arguments.callee(n-1);
  else
     return 1;
})(5);
&lt;/pre&gt;
Which is the same as the following written in a more traditional way:
&lt;pre&gt;
function fact(n) {
   if (n &gt; 1)
      return n * fact(n-1);
   else
      return 1;
}

fact(5);
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-5550668151923150016?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/5550668151923150016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/5550668151923150016'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2007/10/argumentscallee.html' title='arguments.callee'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-1642191686737196382</id><published>2007-09-08T22:05:00.000-07:00</published><updated>2010-03-28T22:25:00.290-07:00</updated><title type='text'>Java 1, Bryan 0</title><content type='html'>&lt;p&gt;Java is a really bad language for getting things done quickly.  I don't mean in terms of processing speed, I mean in terms of the amount of time it takes to write something that works.&lt;/p&gt;&lt;p&gt;Friday I spent a bunch of time writing what I thought would be a trivial Java program with some pretty simple requirements.  My program was to open a stream to a URL and pump a file at it.  Additionally, I wanted my program to do this continuously with a bunch of threads.&lt;/p&gt;&lt;p&gt;After about an hour I had all but given up.  In that hour I'd had problems with ports being left open, and data just not showing up on the other end of the connection.  You might be tempted to say "oh the fool, he didn't close his streams", or "what an idiot, he never flushed the streams".  You'd be wrong on both counts.&lt;/p&gt;&lt;p&gt;I probably missed something, but you know what?  it doesn't matter.  Java just isn't in the language to be using when you need to get things done quickly.  Java is a systems language, not a get-things-done-quickly language.  I really should have written this in something like &lt;a href="http://www.ruby-lang.org"&gt;Ruby&lt;/a&gt; or &lt;a href="http://www.python.org"&gt;Python&lt;/a&gt;.  The only problem is that while I know the syntax of these languages, I'm not familiar with the libraries.&lt;/p&gt;&lt;p&gt;I'm willing to bet that I would have been able to get this simple program written in about an hour, even without knowing the libraries, and it would have worked, unlike my Java version.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-1642191686737196382?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1642191686737196382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/1642191686737196382'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2007/09/java-1-bryan-0.html' title='Java 1, Bryan 0'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-7360947844719358494</id><published>2007-08-14T19:37:00.000-07:00</published><updated>2010-03-28T22:25:28.500-07:00</updated><title type='text'>Erlang != NBL</title><content type='html'>&lt;p&gt;I was browsing InfoQ this morning and read a &lt;a href="http://www.cincomsmalltalk.com/userblogs/ralph/blogView?showComments=true&amp;printTitle=Erlang,_the_next_Java&amp;entry=3364027251"&gt;blog post&lt;/a&gt; about how Erlang may be the next big language after Java.&lt;/p&gt;&lt;p&gt;I tend to disagree with the points made.  Erlang seems to me to be more of a niche language, much like Smalltalk.  Sure it's powerful and grand, but the next big language it isn't.  The syntax, from what I've seen, isn't what programmers are used to.  That alone is probably the biggest strike against it.  Even if the syntax was more C-like, the language isn't well known outside of the functional language geek crowd, and it lacks a "killer app".&lt;/p&gt;&lt;p&gt;If you want my honest opinion, I agree with language that Steve Yegge alluded to in his &lt;a href="http://steve-yegge.blogspot.com/2007/02/next-big-language.html"&gt;The Next Big Language&lt;/a&gt; post a while back: Javascript.  It's used more than most people want to believe, it's functional, object-oriented, and embeddable.  In short, it's everywhere.  The only problem is that it's current implementations don't make concurrent programming any easier.  But since when has the next big language ever been about the right tool for the job?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-7360947844719358494?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7360947844719358494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7360947844719358494'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2007/08/erlang-nbl.html' title='Erlang != NBL'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-8805392773063497941</id><published>2007-04-23T21:00:00.001-07:00</published><updated>2010-03-28T22:26:16.343-07:00</updated><title type='text'>Ergonomics</title><content type='html'>&lt;p&gt;Today I'd like to take some time to say a special thank-you to Logitech for creating the &lt;a href="http://www.logitech.com/index.cfm/products/details/CA/EN,CRID=2150,CONTENTID=5003"&gt;Marble Mouse&lt;/a&gt;.  Without it I wouldn't be able to be a programmer anymore.&lt;/p&gt;&lt;p&gt;&lt;a href="http://1.bp.blogspot.com/_oQFr7FUMIXs/Ri2FNotXn-I/AAAAAAAAAAM/hjpbJxVJCE4/s1600-h/12302.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_oQFr7FUMIXs/Ri2FNotXn-I/AAAAAAAAAAM/hjpbJxVJCE4/s320/12302.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5056844425919438818" /&gt;&lt;/a&gt;In the summer of 2005 I noticed a pain in my right wrist.  I bought a wrist brace to help stabilize my wrist, and it worked great at night, when I had a hard time orienting my wrist in a neutral position while I slept, but it was too bulky to be able to use all the time.  As the weeks went on it became quite aparent that what I was doing wasn't working and I needed to try something else.&lt;/p&gt;&lt;p&gt;I talked to a few people at work.  Some suggested taking a vacation, others said accupuncture.  I was in school at the time and couldn't really afford a break, and I'm not a big fan of needles so I thought I'd try accupuncture as a last resort.  A few people suggested getting a trackball.  I had tried a trackball before and I found them to be horribly inaccurate so I was a little bit skeptical, but I thought I could get used to it.&lt;/p&gt;&lt;p&gt;I peeked over the cubicle wall, and a friend of mine was using the Logitech Marble Mouse.  It seemed a little bit odd but because my problem seemed to stem from clicking I figured it'd be a good one to try.  (The Marble Mouse is shaped kinda like a mouse, except there's a ball where the buttons should be and the buttons are on the side.  You just roll your hand to click).&lt;/p&gt;&lt;p&gt;I have to say, after an hour of using it I couldn't believe what a difference it made.  Not only that, but I was reasonably accurate with it too, unlike the thumb style ones I'd used before.&lt;/p&gt;&lt;p&gt;I'm not posting this hoping for free stuff, I'm posting it as one &lt;u&gt;&lt;b&gt;extremely&lt;/b&gt;&lt;/u&gt; satisfied customer.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-8805392773063497941?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8805392773063497941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/8805392773063497941'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2007/04/ergonomics.html' title='Ergonomics'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_oQFr7FUMIXs/Ri2FNotXn-I/AAAAAAAAAAM/hjpbJxVJCE4/s72-c/12302.jpg' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-6201102787326924156.post-7396296633270774902</id><published>2007-04-15T10:55:00.000-07:00</published><updated>2010-03-28T22:27:02.205-07:00</updated><title type='text'>DVORAK Keyboard Layout</title><content type='html'>&lt;p&gt;I just read a &lt;a href="http://ask.slashdot.org/askslashdot/07/04/15/0043237.shtml"&gt;Slashdot post about the DVORAK keyboard layout&lt;/a&gt;.  While I'll agree that it probably does improve your typing speed, I don't understand why a programmer would want to use it for that reason.&lt;/p&gt;&lt;p&gt;Unless your job is to crank out tons of code as fast as possible, improving your typing speed won't make you any faster.  Most programmers that I know (myself included) aren't I/O bound, they're CPU bound.  Just because we can type faster doesn't mean that we'll be able to produce more code, or that the code will be any better.&lt;/p&gt;&lt;p&gt;Not that I have any personal experience with XP, but I think this is probably the same reasoning behind pair programming.  And, the common thought that faster typing = more productive programmers is probably why everyone I've talked to balks at pair programming.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6201102787326924156-7396296633270774902?l=bryan-kyle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7396296633270774902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6201102787326924156/posts/default/7396296633270774902'/><link rel='alternate' type='text/html' href='http://bryan-kyle.blogspot.com/2007/04/dvorak-keyboard-layout.html' title='DVORAK Keyboard Layout'/><author><name>Bryan Kyle</name><uri>http://www.blogger.com/profile/00203916547608565106</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_oQFr7FUMIXs/S8H3ze686MI/AAAAAAAAAE8/0peVYkhc1WY/s1600-R/bef5260b9ca71ea4cf041c13f925e8bf.png'/></author></entry></feed>
