<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" 
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:admin="http://webns.net/mvcb/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
	<channel>
<title>LouFranco.com</title><link>http://www.loufranco.com/index.html</link><description>Entries from Lou Franco&#x27;s Blog</description><dc:language>en</dc:language><dc:creator>Lou Franco</dc:creator><dc:rights>Copyright 2008 Louis Franco</dc:rights><dc:date>2010-07-24T17:25:24-04:00</dc:date><admin:generatorAgent rdf:resource="http://www.realmacsoftware.com/" />
<admin:errorReportsTo rdf:resource="mailto:Lou Franco" /><sy:updatePeriod>hourly</sy:updatePeriod>
<sy:updateFrequency>1</sy:updateFrequency>
<sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase>
<lastBuildDate>Sat, 24 Oct 2009 12:02:37 -0400</lastBuildDate><item><title>LGPL and the iPhone</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2010-07-23T21:33:24-04:00</dc:date><link>http://www.loufranco.com/blog/files/lgpl-and-the-iphone.html#unique-entry-id-96</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/lgpl-and-the-iphone.html#unique-entry-id-96</guid><content:encoded><![CDATA[<span style="font-size:14px; ">The entire point of the LGPL is to give closed source applications access to an open-source library in a way that maintains the freedom of the library. Specifically, the user of the application must be able to change the LGPL library and have the application use it.<br /><br />To achieve this, the </span><span style="font-size:14px; "><a href="http://www.gnu.org/licenses/lgpl.html" rel="self">LGPL</a></span><span style="font-size:14px; "> gives you a few options for compliance. I am not a lawyer, but I believe that all of them are incompatible with iPhone apps delivered legally through the AppStore. I will lay out my reasoning here:<br /><br />Section 4d gives two options for compliance: Either provide the source or object files suitable for relinking (4d0) or use a shared library (4d1).<br /><br />Shared libraries are out, because Apple does not permit their use in the AppStore.<br /><br />Section 4d0 is a little more complicated. For an application targeted to a PC or Mac, it would be easy to comply by just packaging up your .o files, the LGPL library, a makefile, and documentation. However there are subclauses in section 4 that make me believe that there is no way to comply on the iPhone. Specifically:<br /><br />Section 4d0 not only specifies that you must convey the minimal source and object files, but you must also provide terms. Together they must &ldquo;permit the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work&rdquo;<br /><br />Section 4e requires that you provide instructions that allows some to change the LGPL portions, create a new combined work and install and execute that combined work.<br /><br />To do either of these things, the user would need to be enrolled in Apple&rsquo;s developer program which costs $99/year. These terms are implicitly part of your terms, meaning that it&rsquo;s basically equivalent to you charging $99/year for the user to make modifications.<br /><br />The GPL allows you to charge what you want to convey the Combined Work to begin with, but section 10 of the GPL (which I think still applies to the LGPL) states:</span><blockquote><p>You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License.</p></blockquote><span style="font-size:14px; ">Now, obviously, being able to develop isn&rsquo;t free, but those costs are not as directly related to exercising your rights as the $99/year is. Specifically, you cannot create an executable or put in on a device without the certificates you obtain from the program.<br /><br />Here&rsquo;s an alternative view from </span><span style="font-size:14px; "><a href="http://huyzing.com/2009/08/24/compatibility-between-the-iphone-app-store-and-the-lgpl/" rel="self">Huy Zing</a></span><span style="font-size:14px; "> -- I think the &ldquo;Spirit of the LPGL&rdquo; section in the blog is actually required by the text of the license.<br /><br />Here&rsquo;s a discussion on the cocos2d forum about </span><span style="font-size:14px; "><a href="http://www.cocos2d-iphone.org/forum/topic/5311" rel="self">switching away from LGPL</a></span><span style="font-size:14px; ">. They tried adding to the license at first and then moved to an MIT license.<br /><br />I haven&rsquo;t been able to find any official ruling on gnu.org, so I will write them and see if they can add to their FAQ (</span><span style="font-size:14px; "><a href="http://www.gnu.org/licenses/gpl-faq.html#LGPLJava" rel="self">as they did for Java when it was an issue</a></span><span style="font-size:14px; ">).</span>]]></content:encoded></item><item><title>Understanding EXC_BAD_ACCESS</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2010-07-22T08:19:49-04:00</dc:date><link>http://www.loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html#unique-entry-id-95</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html#unique-entry-id-95</guid><content:encoded><![CDATA[<span style="font-size:14px; ">A couple of days ago, I wrote about </span><span style="font-size:14px; "><a href="http://www.loufranco.com/blog/files/debug-iphone-crash-EXC_BAD_ACCESS.html" rel="self" title="Blog:How to Debug an iPhone App Crash, Part 1: EXC_BAD_ACCESS">how to debug a crash that reports EXC_BAD_ACCESS</a></span><span style="font-size:14px; ">. One thing I didn&rsquo;t cover is what EXC_BAD_ACCESS means, which I&rsquo;ll try to do now, as it will clear up a lot of the questions I&rsquo;m getting about the previous blog.<br /><br />The description here is a high-level way of thinking about it. The details are quite a bit more complicated, so I&rsquo;m simplifying it.<br /><br />On the iPhone (and most modern OS&rsquo;s), your application is given memory as you need it. The memory is given in chunks that are bigger than your request, and then the unused parts are parceled out over the next few requests. <br /><br />When you deallocate an object, that chunk can&rsquo;t be returned to the OS right away. It has to wait until all of the memory in the chunk is deallocated. <br /><br />Inside all of this memory is a complex data structure that is maintained by the alloc and dealloc messages to organize how each part of the allocated memory is being used. The pointers you hold are just part of that datastructure (where the object is), there are other parts that are only used by the allocator.<br /><br />What EXC_BAD_ACCESS is saying is that you did something that caused a pointer (yours, one internal to the iPhone, or one that the allocator is using) to be dereferenced and that memory location isn&rsquo;t inside one of the chunks assigned to your program.<br /><br />This could be because<br /></span><ol class="arabic-numbers"><li><span style="font-size:14px; ">The pointer used to point to memory that was ok, but its chunk was deallocated.</span></li><li><span style="font-size:14px; ">The pointer is corrupt.</span></li></ol><span style="font-size:14px; ">The line of code that your app crashes on is not the root cause of the problem. The problem in #1 is whatever line of code caused the premature deallocation, and the problem in #2 is whatever line of code corrupted the pointer. <br /><br /></span><span style="font-size:14px; font-weight:bold; ">Your goal in debugging this is to make the problem line of code be flagged by either the compiler or debugger.</span><span style="font-size:14px; "><br /><br />If you do that, then fixing it becomes a lot easier.<br /><br />Of the two possible problems, #1 is far easier to find. It&rsquo;s almost definitely because you didn&rsquo;t use retain/release correctly and there where either too many releases or too few retains. <br /><br />Do this:<br /></span><ol class="arabic-numbers"><li><span style="font-size:14px; ">Run Build and Analyze. Make sure you fix or understand every single error it flags. I personally have 0 Build and Analyze errors in every project I have and I go out of my way to keep it that way. If I ever get a false positive, I figure out how to make Build and Analyze understand what is going on, so that it doesn&rsquo;t flag it.</span></li><li><span style="font-size:14px; "><a href="files/scan-build-better-than-build-analyze.html" rel="self" title="Blog:scan-build finds things Build and Analyze does not">Run scan-build with all checks on</a></span><span style="font-size:14px; ">. This isn&rsquo;t built in, so if you&rsquo;re in a hurry, skip this for now. scan-build is the project that Build and Analyze is based on. It can be run with much more thorough settings.</span></li><li><span style="font-size:14px; ">Set up Xcode so that it never deallocates. Instead, it turns objects into Zombies that complain if they are used. </span><span style="font-size:14px; "><a href="files/debugging-memory-iphone.html" rel="self" title="Blog:Debugging memory based crashes on iPhone">See Tip #1 on this post for instructions</a></span><span style="font-size:14px; ">.</span></li></ol><span style="font-size:14px; ">If you have a clean Build and Analyze and no Zombies complain of being accessed, and you still get EXC_BAD_ACCESS, then it&rsquo;s a good bet that you are not accessing deallocated memory. It&rsquo;s not a sure bet, because the iPhone SDK gives you access to the C library which uses a different kind of allocation, which you could be using wrong.<br /><br />For #2, your task is harder. If a pointer is corrupt, there are lots of possible reasons<br /></span><ol class="arabic-numbers"><li><span style="font-size:14px; ">The pointer could have never been initialized.</span></li><li><span style="font-size:14px; ">The pointer could have been accidentally written over because you overstepped the bounds of an array</span></li><li><span style="font-size:14px; ">The pointer could be part of an object that was casted incorrectly, and then written to</span></li><li><span style="font-size:14px; ">Any of the above could have corrupted a different pointer that now points at or near this pointer, and using that one corrupts this one (and so on)</span></li></ol><span style="font-size:14px; "><br />If this is the situation you are in, then these are the things that will help<br /></span><ol class="arabic-numbers"><li><span style="font-size:14px; "><a href="files/debugging-memory-iphone.html" rel="self" title="Blog:Debugging memory based crashes on iPhone">Enable Guard Malloc (Tip #2)</a></span><span style="font-size:14px; "> - this makes the datastructure that represents the allocations much more sensitive to corruption. You need to use the enhanced features of the debugger to get anything out of it (explained in the tip).</span></li><li><span style="font-size:14px; ">The line of code that triggers the crash is a clue to what pointer is corrupt. If you move it around it might be able to help you narrow down the point of corruption.</span></li><li><span style="font-size:14px; ">If all else fails and you are desperate, try </span><span style="font-size:14px; "><a href="http://landonf.bikemonkey.org/code/iphone/iPhone_Simulator_Valgrind.20081224.html" rel="self">Valgrind</a></span><span style="font-size:14px; ">.</span></li></ol><span style="font-size:15px; "><br />Once one of these methods gives you a different problem (either a warning or another EXC_BAD_ACCESS), don&rsquo;t worry that it seems completely unrelated to your original problem -- that&rsquo;s a common problem with corruption.<br /><br />Also, random changes to your program may make this problem &ldquo;go away&rdquo; -- it&rsquo;s not really fixed, though. Your corruption or early deallocation is still there, but it&rsquo;s not triggering an EXC_BAD_ACCESS. Its effects could be far worse, however, so it&rsquo;s a good idea to try to keep reproducing it until you are sure you addressed the problem.<br /><br />Things to remember<br /></span><ol class="arabic-numbers"><li><span style="font-size:15px; ">Corrupting a pointer doesn&rsquo;t immediately trigger EXC_BAD_ACCESS. Neither does using a corrupted pointer unless it&rsquo;s specifically now pointing to memory that isn&rsquo;t mapped to your application.</span></li><li><span style="font-size:15px; ">Deallocating an object doesn&rsquo;t immediately release the memory to the operating system -- only when the chunk is unused, can it be returned.</span></li><li><span style="font-size:15px; ">The line of code that is triggering the EXC_BAD_ACCESS might not be the problem. It can be a good clue, but don&rsquo;t assume the problem is this code.</span></li></ol><span style="font-size:15px; "><br /></span><span style="font-size:14px; font-weight:bold; ">Get iPhone programming tips in your inbox with my </span><span style="font-size:14px; font-weight:bold; "><a href="../beginner-iphone-programming-tips/index.html" rel="self" title="Beginner iPhone Programming Tips">Beginner iPhone Programming Tips newsletter</a></span><span style="font-size:14px; font-weight:bold; ">.</span><span style="font-size:14px; "><br /></span>]]></content:encoded></item><item><title>How to Debug an iPhone App Crash&#x2c; Part 1: EXC_BAD_ACCESS</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2010-07-16T08:04:05-04:00</dc:date><link>http://www.loufranco.com/blog/files/debug-iphone-crash-EXC_BAD_ACCESS.html#unique-entry-id-94</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/debug-iphone-crash-EXC_BAD_ACCESS.html#unique-entry-id-94</guid><content:encoded><![CDATA[<span style="font-size:15px; ">This is going to be a multi-part series on how to debug an iPhone crash.<br /><br />This post is for how to debug crashes that show that the app received the signal EXC_BAD_ACCESS in the console. If you have this, the most likely thing that you are doing is sending a message to a released object. Another possibility is if you are using C/C++ allocations (or a library that uses it) and are overrunning memory or using freed memory.<br /><br /></span><span style="font-size:15px; font-weight:bold; ">Update: </span><span style="font-size:15px; font-weight:bold; "><a href="http://www.loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html" rel="self" title="Blog:Understanding EXC_BAD_ACCESS">I explain this much better in a follow-up to this blog</a></span><span style="font-size:15px; "><br /><br />Here are a few ways to debug that:<br /><br /></span><ol class="arabic-numbers"><li><span style="font-size:15px; ">Run Build and Analyze: This kind of Build is very good at finding retain/release bugs. Take a good look at everything it flags.</span></li><li><span style="font-size:15px; ">Even better, run scan-build. I did a test recently, and found that </span><span style="font-size:15px; "><a href="files/scan-build-better-than-build-analyze.html" rel="self" title="Blog:scan-build finds things Build and Analyze does not">some common errors are off by default in Build and Analyze</a></span><span style="font-size:15px; "> that can be turned on in scan-build.</span></li><li><span style="font-size:15px; ">Choose </span><span style="font-size:15px; font-weight:bold; ">Run > Enable Guard Malloc</span><span style="font-size:15px; "> in the menu, and then re-run your application. This finds a whole class of buffer overrun issues. If this detects it, you&rsquo;ll see a better error in the console. </span><span style="font-size:15px; "><a href="http://developer.apple.com/iphone/library/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html" rel="self">Read this to see how to use Guard Malloc once it&rsquo;s enabled</a></span><span style="font-size:15px; ">.</span></li><li><span style="font-size:15px; ">You can instruct the compiler to ignore release calls and then </span><span style="font-size:15px; "><a href="files/debugging-memory-iphone.html" rel="self" title="Blog:Debugging memory based crashes on iPhone">report if anyone is sending messages to objects that would have been deallocated</a></span><span style="font-size:15px; ">. This results in much better errors in the Console if it detects them.</span></li><li><span style="font-size:15px; ">Valgrind is the gold standard for finding memory bugs on Linux, and </span><span style="font-size:15px; "><a href="http://landonf.bikemonkey.org/code/iphone/iPhone_Simulator_Valgrind.20081224.html" rel="self">here&rsquo;s a way to get it working in the  iPhone Simulator</a></span><span style="font-size:15px; ">.</span></li></ol><span style="font-size:15px; "><br /></span><span style="font-size:14px; font-weight:bold; ">Get iPhone programming tips in your inbox with my </span><span style="font-size:14px; font-weight:bold; "><a href="../beginner-iphone-programming-tips/index.html" rel="self" title="Beginner iPhone Programming Tips">Beginner iPhone Programming Tips newsletter</a></span><span style="font-size:14px; font-weight:bold; ">.</span>]]></content:encoded></item><item><title>scan-build finds things Build and Analyze does not</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2010-07-14T21:46:29-04:00</dc:date><link>http://www.loufranco.com/blog/files/scan-build-better-than-build-analyze.html#unique-entry-id-93</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/scan-build-better-than-build-analyze.html#unique-entry-id-93</guid><content:encoded><![CDATA[<span style="font-size:14px; ">Ever since I started using the latest Xcode, I&rsquo;ve loved having scan-build built in as Build and Analyze. I did feel like it was less thorough, but I didn&rsquo;t have time to prove it -- now I have.<br /><br />There is one kind of bug that scan-build was very good at finding -- forgetting to set retained properties to nil in dealloc isn&rsquo;t found by default in Build and Analyze.  It&rsquo;s not even part of the default scan-build any more (not sure why -- it was great).<br /><br />Anyway, I recommend using scan-build directly instead of Build and Analyze. Here&rsquo;s how:<br /></span><ol class="arabic-numbers"><li><span style="font-size:14px; ">Download </span><span style="font-size:14px; "><a href="http://clang-analyzer.llvm.org/installation.html" rel="self">scan-build</a></span></li><li><span style="font-size:14px; ">Just unpack it into any directory and add that directory to your PATH</span></li><li><span style="font-size:14px; ">Open a Terminal and cd to your project&rsquo;s root directory</span></li><li><span style="font-size:14px; ">Run scan-build and view results</span></li></ol><span style="font-size:14px; "><br />Here is a scan-build line that works for iOS 4.0:<br /><br /></span><span style="font-size:14px; font-weight:bold; ">scan-build -analyzer-check-objc-missing-dealloc -analyzer-check-llvm-conventions --experimental-checks  -k -V -o scan-reports xcodebuild -configuration Debug -sdk iphonesimulator4.0 clean build<br /></span><span style="font-size:14px; "><br />I&rsquo;ve turned on all checks, and now it catches if you forget to set properties to nil in dealloc.<br /><br />Run Build and Analyze often in Xcode, but every once and a while, run a full scan-build with the latest version as it finds problems that the Xcode version will not.<br /></span><span style="font-size:15px; "><br /></span><span style="font-size:14px; font-weight:bold; ">Get iPhone programming tips in your inbox with my </span><span style="font-size:14px; font-weight:bold; "><a href="../beginner-iphone-programming-tips/index.html" rel="self" title="Beginner iPhone Programming Tips">Beginner iPhone Programming Tips newsletter</a></span><span style="font-size:14px; font-weight:bold; ">.</span>]]></content:encoded></item><item><title>Trainers for Programmers</title><dc:creator>Lou Franco</dc:creator><category>Programming</category><category>Novice Programmers</category><dc:date>2010-05-11T20:12:14-04:00</dc:date><link>http://www.loufranco.com/blog/files/trainers-for-programmers.html#unique-entry-id-92</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/trainers-for-programmers.html#unique-entry-id-92</guid><content:encoded><![CDATA[<span style="font-size:15px; ">Anyone who is interested in teaching programming to novices or non-programmers should check out what Zed Shaw is doing:<br /></span><blockquote><p>I've had an idea for an introductory book on programming that follows the model of "trainer" books for learning a musical instrument. Most of these books are organized like this:	<ol><li>There&rsquo;s a bunch of exercises.</li>	<li>Each exercise is 1 or 2 pages.</li>	<li>There&rsquo;s only a little bit of prose.</li>	<li>You do each exercise exactly, then move on.</li></ol></p></blockquote><span style="font-size:15px; "><br /></span><span style="font-size:15px; ">The results are at </span><span style="font-size:15px; "><a href="http://learnpythonthehardway.org" rel="self">Learn Python the Hard Way</a></span><span style="font-size:15px; ">.</span>]]></content:encoded></item><item><title>Favorite iPad apps</title><dc:creator>Lou Franco</dc:creator><category>iPad</category><dc:date>2010-04-06T21:19:48-04:00</dc:date><link>http://www.loufranco.com/blog/files/favorite-ipad-apps.html#unique-entry-id-91</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/favorite-ipad-apps.html#unique-entry-id-91</guid><content:encoded><![CDATA[<span style="font-size:15px; ">Here are some of my favorite iPad apps so far:<br /><br /></span><span style="font-size:15px; "><a href="http://iphone.wordpress.org/" rel="self">WordPress</a></span><span style="font-size:15px; ">: If you have a WordPress site, this is pretty essential. The iPhone version is pretty good too, but obviously the iPad is perfect for this. I&rsquo;ve found the WordPress admin to be wonky on Mobile Safari, so this is the best way to edit a WordPress site on iPhone OS.<br /><br /></span><span style="font-size:15px; "><a href="http://omaxmedia.com/" rel="self">MaxJournal</a></span><span style="font-size:15px; ">: This app is a great example of an iPad app -- it does one thing and it does it well. It looks great, has elegant date navigation, and strips a journal down to the bare bones. It needs a password feature, but apparently, the feature is done and waiting for approval. The developer is very responsive to feedback, which is a good sign.<br /><br />Kindle: Kind of obvious. The advantage over iBooks is that the books you buy are available on the iPhone or your Mac or PC (some books have a limit, I hit that with one of my books)<br /><br />Tweetdeck: Free and supports lists and other custom filters, which are essential for reading Twitter.<br /><br /></span><span style="font-size:15px; "><a href="http://www.omz-software.de/newsstand/" rel="self">NewsRack</a></span><span style="font-size:15px; ">: RSS reader that syncs with Google Reader. Well done, stable, with some nice touches.<br /><br />And the disappointments:<br /><br />CraigPhone: This is an iPad version of Craigslist. Tons of bugs. The app has an apology right on it (they put it in the AppStore without testing it on a real device). It&rsquo;s free, so I guess that&rsquo;s ok. Something about the interface just feels wrong though -- I suspect that they are using HTML views with some JavaScript drawing parts of the UI.<br /><br />Tweetdeck: It&rsquo;s the only usable twitter client for me, but it is crashtastic. Tweet-boom, tweet-boom -- move a column, buh-bye.  Anyway, it&rsquo;s free and I assume that they are working on it -- they need to check out my post about </span><span style="font-size:15px; "><a href="http://www.loufranco.com/blog/files/debugging-memory-iphone.html" rel="self" title="Blog:Debugging memory based crashes on iPhone">debugging memory crashes on the iPhone</a></span><span style="font-size:15px; "> and it probably wouldn&rsquo;t hurt to run a Build and Analyze once and a while.<br /><br />NYT Editor&rsquo;s Choice: First, you can&rsquo;t find this app by searching the store for &ldquo;NYTimes&rdquo; or &ldquo;NY Times&rdquo; because they named it with NYT.  And, you don&rsquo;t get the whole paper? But, I do if I go to the website? I don&rsquo;t get that -- just charge me.<br /><br />No Google apps or Facebook: Pretty surprised that these big players with great apps are absent from the AppStore on day one. Google made GMail work great on an iPad, though -- if they had done the same with Reader, I might not have bought an app.<br /><br /></span>]]></content:encoded></item><item><title>Amazon KDK Beta Program is Open for Applications</title><dc:creator>Lou Franco</dc:creator><category>Amazon KDK</category><dc:date>2010-02-08T20:12:48-05:00</dc:date><link>http://www.loufranco.com/blog/files/amazon-kdk-beta.html#unique-entry-id-90</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/amazon-kdk-beta.html#unique-entry-id-90</guid><content:encoded><![CDATA[<span style="font-size:15px; ">Amazon has opened their </span><span style="font-size:15px; "><a href="http://amazon.com/kdk" rel="self">KDK Beta program</a></span><span style="font-size:15px; ">. Amazon also published a </span><span style="font-size:15px; "><a href="https://kindlepublishing.amazon.com/gp/vendor/kindlepubs/kdk/get-content?id=200436000" rel="self">KDK FAQ</a></span><span style="font-size:15px; ">. As suspected, it&rsquo;s Java ME based with a custom API for the Kindle:</span><blockquote><p>[It will] provide UI components, JSON and XML parsers, HTTP and HTTPS networking, secure storage, and other features. Other APIs like audio and dictionary access will be available in a future release of the KDK.</p></blockquote><span style="font-size:15px; ">Development will be possible in an Java environment, but it appears that Eclipse will be supported more directly.</span>]]></content:encoded></item><item><title>What the iPad needs to be your only computer</title><dc:creator>Lou Franco</dc:creator><category>iPad</category><dc:date>2010-02-02T20:29:40-05:00</dc:date><link>http://www.loufranco.com/blog/files/what-ipad-needs.html#unique-entry-id-89</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/what-ipad-needs.html#unique-entry-id-89</guid><content:encoded><![CDATA[<span style="font-size:15px; ">There&rsquo;s been a lot of talk about how the iPad will be used by people that aren&rsquo;t experts in computers. This article makes a good case that </span><span style="font-size:15px; "><a href="http://northtemple.com/2010/02/01/on-ipads-grandmas-and-gam" rel="self">Grandmas and Technophobes will love the iPa</a></span><span style="font-size:15px; "><a href="http://northtemple.com/2010/02/01/on-ipads-grandmas-and-gam" rel="self">d</a></span><span style="font-size:15px; ">:</span><blockquote><p>The darndest thing happened in the last five days and I was fortunate to be privy to it. Apple has gotten people excited about computing. But this time, it&rsquo;s not nerds or geeks and certainly not IT industry analysts. It&rsquo;s everyone else. I had a curious set of three conversations this week. One with a grandma, one with a technophobe and the third with a self-proclaimed luddite.</p></blockquote><span style="font-size:14px; ">And th</span><span style="font-size:15px; ">is article explains the </span><span style="font-size:15px; "><a href="http://stevenf.tumblr.com/post/359224392/i-need-to-talk-to-you-about-computers-ive-been" rel="self">difference in computing habits between the Gen Xers that came of age during the </a></span><span style="font-size:15px; "><a href="http://stevenf.tumblr.com/post/359224392/i-need-to-talk-to-you-about-computers-ive-been" rel="self">PC revolution and the generation before and after us</a></span><span style="font-size:15px; ">.</span><blockquote><p>The reason I&rsquo;m starting to think the Old World is ultimately doomed is because we are bracketed on both sides by the New World, and those people being born today, post-iPhone and post-iPad, will never know (and probably not care) about how things used to work. Just as nobody today cares about floppies, and nobody has to care about manual transmissions if they don&rsquo;t want to.</p></blockquote><span style="font-size:15px; ">Both of these articles make a great case, and although, I need a regular computer to do development, I would like everything else to migrate to an iPad.<br /><br />I started to use Macs again after ten years when I got a digital camera. I read the instructions for the Windows software it came with and then just plugged it into a Mac I inherited -- it just worked. Since then, I&rsquo;ve  used a Mac for everything except my job (.NET SDK development).<br /><br />Which brings me to my first problem with the iPad -- how do I connect my digital camera? Steve Jobs talked about how great the iPad would be for photos, but how do they get on the iPad to begin with? Undoubtedly, this will be solved, but it&rsquo;s a problem that will make the iPad useless for a lot of people if this is their only computer.<br /><br />Secondly, I don&rsquo;t take a lot of pictures and almost no video and I have about 10-15 GB of photos (and 20-25 GB of music). 64 GB is just completely inadequate if this is going to be the only place to store them. For the iPhone, synching gives me downsampled photos and music if I want to save space, but I can&rsquo;t do that to my primary copy. I&rsquo;m sure iPads will get to bigger sizes, but I&rsquo;m also sure that we&rsquo;ll need more too.<br /><br />Even if the iPad had a terabyte, I really need some off device storage  -- iPads can be lost, which would be bad, but not as bad as losing all of my data. It&rsquo;s unclear how the iPad can be backed up if it&rsquo;s your only computer.<br /><br />I know that these problems will be solved eventually, but right now -- it&rsquo;s not really possible for the iPad to work without a host computer -- if it&rsquo;s like the iPhone, it depends on synching too much.<br /><br />I&rsquo;m not sure what the solution will be, but I have a Time Capsule -- if the iPad had Time Machine, and if the Time Capsule could suck the images off my digital camera (perhaps using the iPad as the UI), then I&rsquo;d be most of the way there.</span>]]></content:encoded></item><item><title>How the iPad will affect the Kindle</title><dc:creator>Lou Franco</dc:creator><category>Amazon KDK</category><category>iPad</category><dc:date>2010-01-30T15:25:38-05:00</dc:date><link>http://www.loufranco.com/blog/files/ipad-effect-kindle.html#unique-entry-id-88</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/ipad-effect-kindle.html#unique-entry-id-88</guid><content:encoded><![CDATA[<span style="font-size:15px; ">Amazon has no hope of competing with Apple to be the best general computing tablet platform, so trying to match the iPad feature for feature will drive up their cost and still leave them with an inferior product. The two other stable competitive positions are either to </span><span style="font-size:15px; "><a href="http://en.wikipedia.org/wiki/Porter_generic_strategies" rel="self">go cheap or to go niche</a></span><span style="font-size:15px; ">.</span><blockquote><p>In his 1980 classic Competitive Strategy: Techniques for Analysing Industries and Competitors, Porter simplifies the scheme by reducing it down to the three best strategies. They are cost leadership, differentiation, and market segmentation (or focus). Market segmentation is narrow in scope while both cost leadership and differentiation are relatively broad in market scope.</p></blockquote><span style="font-size:15px; ">This will be hard for Amazon because, before the iPad, they were clearly the differentiated premium market-leader, but now that market has been subsumed. The only hope for Kindle is to become the cost-leader and to let third-party developers turn the Kindle into cheap niche devices.<br /><br />Once the KDK is available, we&rsquo;ll see the top end come down to about $400. Amazon can do this because they&rsquo;re set to make money from their free 3G, in the form of subscription applications. I&rsquo;m sure a significant component of the $489 price is to offset the expected 3G use that isn&rsquo;t offset by book sales. <br /><br />This strategy is more in line with Amazon&rsquo;s online retail strategy. They currently compete on price and let third-party stores focus on niche markets. Even though Porter cautions against trying to have two strategies, it can be overcome if different business units focus on each strategy independently -- what could be more independent than a third-party.</span>]]></content:encoded></item><item><title>Hoping the Amazon KDK is Java based</title><dc:creator>Lou Franco</dc:creator><category>Amazon KDK</category><dc:date>2010-01-26T14:09:08-05:00</dc:date><link>http://www.loufranco.com/blog/files/hoping-amazon-kdk-is-java.html#unique-entry-id-87</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/hoping-amazon-kdk-is-java.html#unique-entry-id-87</guid><content:encoded><![CDATA[<span style="font-size:15px; ">The speculation on the KDK is that it&rsquo;s going to be Java based, and I hope that&rsquo;s right. We know for sure that it runs Linux, and that there&rsquo;s a JVM and obfuscated jars on the device. According to what I&rsquo;ve read, there&rsquo;s no perl or python or anything like that on it, so the only options will be C/C++ or Java. For the sake of the ecosystem, Amazon will need to pick Java and probably will run third-party code in a some kind of sandboxed environment.<br /><br />To me the best thing about it being Java based is that I will finally have a JVM that I care about targeting. One of my big problems with Java is that there&rsquo;s no place the JVM runs where something else doesn&rsquo;t run better or that I just like more. For web apps, I prefer python based frameworks, and for Windows apps, you have to use .NET or Win32 with C/C++. On a Mac, Objective C is the obvious choice. Java is a good choice on a lot of mobile devices, but I haven&rsquo;t cared about them, until now.<br /><br />And the main reason I want a JVM to target is because it gives me a practical reason to use </span><span style="font-size:15px; "><a href="http://clojure.org" rel="self">clojure</a></span><span style="font-size:15px; ">. I know it might not work out, and of course, I&rsquo;ll be writing Java at first to learn the API, but I&rsquo;m hoping I can transition to clojure eventually, or at least use a hybrid. <br /><br />In 2008, Rich Hickey came to speak in Northampton, and I prepared by learning and </span><span style="font-size:15px; "><a href="http://loufranco.com/blog/files/category-20-days-of-clojure.html" rel="self">blogging about clojure for the 20 days preceding it</a></span><span style="font-size:15px; ">. Since then, I&rsquo;ve been on a lookout for a JVM that I wanted to target. The closest I&rsquo;ve come is the Google AppEngine, but I still liked python and Django style better. It may turn out that the KDK just works better with Java, but clojure has shown that it&rsquo;s pretty good at driving OO frameworks like Swing, so I think it will work just fine.</span>]]></content:encoded></item><item><title>Why I think Amazon app store will be a be a better deal for developers</title><dc:creator>Lou Franco</dc:creator><category>Amazon KDK</category><dc:date>2010-01-25T19:09:08-05:00</dc:date><link>http://www.loufranco.com/blog/files/amazon-kdk-better-for-developers.html#unique-entry-id-86</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/amazon-kdk-better-for-developers.html#unique-entry-id-86</guid><content:encoded><![CDATA[<span style="font-size:15px; ">Amazon, clearly feeling the heat from the Apple device coming out in two days, is making some moves with Kindle. In the space of a few weeks, they have altered the </span><span style="font-size:15px; "><a href="http://phx.corporate-ir.net/phoenix.zhtml?c=176060&p=irol-newsArticle&ID=1376977&highlight" rel="self">publisher/Amazon split</a></span><span style="font-size:15px; ">, </span><span style="font-size:15px; "><a href="http://www.amazon.com/gp/feature.html/?ie=UTF8&docId=1000476231" rel="self">announced an SDK</a></span><span style="font-size:15px; ">, and are </span><span style="font-size:15px; "><a href="http://www.techcrunch.com/2010/01/20/amazon-kindle-free/" rel="self">offering a money-back guarantee for frequent book buyers</a></span><span style="font-size:15px; "> [links via </span><span style="font-size:15px; "><a href="http://daringfireball.net" rel="self">daringfireball.net</a></span><span style="font-size:15px; ">].<br /><br />Amazon has a real chance to win the hearts of developers because of few key differences between their offering and Apple&rsquo;s.<br /><br /></span><ol class="arabic-numbers"><li><span style="font-size:15px; ">Because of the free 3G, Amazon needs to have a class of apps that are subscription based. This may seem like a downside, but if you can keep the monthly cost low, this gives an Amazon app something that has been missing from the Apple AppStore: Recurring Revenue</span></li><li><span style="font-size:15px; ">Amazon is a clear leader and innovator in e-commerce -- specifically cross-selling. I think it&rsquo;s very likely that Amazon will be able to surface apps all over their store. Make an app that helps people choose a digital camera, and it may be promoted on every camera page.</span></li><li><span style="font-size:15px; ">The Kindle will be one-third to one-half the price of the Apple device, which makes it very attractive to do a large rollout to a mobile workforce. Insurance adjusters, delivery truck drivers, on-site construction, etc. need to read documents -- they don&rsquo;t need an iPod, fart apps, or games.</span></li><li><span style="font-size:15px; ">The Kindle will probably always be smaller, lighter, and use less power -- Apple could surprise me here, but the Kindle is so low-powered, it&rsquo;s unlikely that they can&rsquo;t keep up.</span></li><li><span style="font-size:15px; ">Hardware keyboard -- Apple could clearly innovate here -- I&rsquo;m guessing with an external bluetooth keyboard. If so, that adds bulk, weight and sucks battery.</span></li><li><span style="font-size:15px; ">The e-ink display -- no color is a downside, but the e-ink can be read outside -- again, think outdoor, mobile workforce.</span></li><li><span style="font-size:15px; ">Amazon&rsquo;s Kindle DRM and book deleting are cause for concern, but if they have any sense, they will learn from Apple&rsquo;s experience with AppStore rejections and loosen up. It doesn&rsquo;t appear that they will from </span><span style="font-size:15px; "><a href="files/amazon-kindle-sdk-kdk-first-looks.html" rel="self" title="Blog:Amazon Kindle SDK (KDK): First looks">my first looks at the KDK</a></span><span style="font-size:15px; ">.</span></li></ol><span style="font-size:15px; "><br />Subscription apps + good enough for business will be a big win for developers. Business apps don&rsquo;t go for $0.99 -- the equivalent might turn out to be $5/month for something simple, and businesses won&rsquo;t blink. Better than the up-front price is that you get a predictable income stream that isn&rsquo;t subject to the whim of the top 25 lists.<br /><br />This isn&rsquo;t to say that Kindle will beat Apple in any quantifiable way (number of apps, number of downloads, number of customers, etc), but I think that the kinds of stories of real businesses being built on the Kindle store will be quite different from the lottery that the iPhone app market appears to be.</span>]]></content:encoded></item><item><title>Amazon Kindle SDK (KDK): First looks</title><dc:creator>Lou Franco</dc:creator><category>Amazon KDK</category><dc:date>2010-01-24T20:25:07-05:00</dc:date><link>http://www.loufranco.com/blog/files/amazon-kindle-sdk-kdk-first-looks.html#unique-entry-id-85</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/amazon-kindle-sdk-kdk-first-looks.html#unique-entry-id-85</guid><content:encoded><![CDATA[<span style="font-size:15px; ">Last week, </span><span style="font-size:15px; "><a href="http://www.amazon.com/gp/feature.html/?ie=UTF8&docId=1000476231" rel="self">Amazon announced that they will be releasing an SDK for creating Kindle Apps.</a></span><span style="font-size:15px; "> I know that three days before the big Apple Tablet/Slate/Canvas announcement, I&rsquo;m supposed to be getting ready to tabletize my app, but the idea of developing for the </span><span style="font-size:15px; "><a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Fproduct%2FB0015TG12Q%3Fpf_rd%5Fm%3DATVPDKIKX0DER%26pf%5Frd%5Fs%3Dcenter-2%26pf%5Frd%5Fr%3D1T0MJ4C097B963ZXMYQA%26pf%5Frd%5Ft%3D101%26pf%5Frd%5Fp%3D470938631%26pf%5Frd%5Fi%3D507846&tag=chec01-20&linkCode=ur2&camp=1789&creative=9325" rel="external">Kindle</a></span><img src="http://www.assoc-amazon.com/e/ir?t=chec01-20&l=ur2&o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;"/> <span style="font-size:15px; ">is looking kind of interesting.<br /><br />Given that the beta isn&rsquo;t out yet -- there isn&rsquo;t a lot of information about the KDK yet. However, there have been some successful hacks of the Kindle and Amazon was forced by the GPL to publish their modifications, so we do know some things:<br /><br /></span><ol class="arabic-numbers"><li><span style="font-size:15px; ">The Kindle runs Linux</span></li><li><span style="font-size:15px; ">Kindle GUI&rsquo;s are written in Java</span></li><li><span style="font-size:15px; ">There will be three models of apps, free, one-time purchase, and subscription. The first two will have a monthly bandwidth cap of 100KB/user.</span></li><li><span style="font-size:15px; ">Advertising is listed as something you can&rsquo;t do -- perhaps they mean an app that only advertises, but even so, why not?  Mobile advertising is large part of the app ecosystem, so I assume in-app advertising will be allowed.</span></li><li><span style="font-size:15px; ">A generic reader is not allowed -- again, does this mean a PDF reader wouldn&rsquo;t be allowed? I can see Amazon not wanting the 3G being used to buy from other stores, but why not let me read content I get from other means (or from subscription apps).</span></li></ol><span style="font-size:15px; ">The brevity of the developer guidelines is welcome, but I hope they elaborate on them in the near future.<br /></span>]]></content:encoded></item><item><title>Strictly Professional Podcast</title><dc:creator>Lou Franco</dc:creator><category>Western MA</category><category>Entrepreneurship</category><category>Software Development</category><dc:date>2009-11-11T11:18:07-05:00</dc:date><link>http://www.loufranco.com/blog/files/strictly-pro-podcast.html#unique-entry-id-84</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/strictly-pro-podcast.html#unique-entry-id-84</guid><content:encoded><![CDATA[<span style="font-size:15px; ">I took part in a </span><span style="font-size:15px; "><a href="http://strictlyprofessional.wordpress.com/2009/11/10/podcast-001/" rel="self">Western MA Developers podcast</a></span><span style="font-size:15px; "> last week. It was a lot of fun and definitely captures the spirit of how our conversations usually go. We cover a broad range of topics including the bug tracker market, refunds in software, whether to be Rich or King in a venture, and a philosophical discussion of Rich Hickey's Time is the new Memory concept.</span>]]></content:encoded></item><item><title>InnovateHolyoke</title><dc:creator>Lou Franco</dc:creator><category>Western MA</category><dc:date>2009-10-26T19:16:24-04:00</dc:date><link>http://www.loufranco.com/blog/files/innovate-holyoke.html#unique-entry-id-83</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/innovate-holyoke.html#unique-entry-id-83</guid><content:encoded><![CDATA[<span style="font-size:15px; "><a href="http://www.innovateholyoke.com/" rel="self">InnovateHolyoke</a></span><span style="font-size:15px; "> is the online hub for information about the High Performance Computing Center that is set to open up in Holyoke in 2011.<br /></span><blockquote><p>The GHPCC planned for Holyoke will not only provide an invaluable increase in the computing capacity that would bring all these benefits to the partnering institutions. It would also serve as a showcase of green energy use and green facilities design, be scalable to meet the needs of additional partners and computational demands, and serve as a catalyst for economic, educational, and workforce development in Holyoke and the region.MIT had developed plans in 2007 to locate a high performance computing center in Holyoke due to the region&rsquo;s quality access to the internet, affordable land, and availability of low-cost and renewable energy.  The impact of the global economic recession led MIT to suspend their plans and subsequently reach out to leaders at the University of Massachusetts to jointly address capacity needs for high performance computing.</p></blockquote><span style="font-size:15px; ">This is an important development for the region and will help to establish a technology hub in Western MA. I have been appointed to the education/training subcommittee as a member of the Regional Employment Board and will hopefully have more to share as we start the work of the committee.</span>]]></content:encoded></item><item><title>FounderCast</title><dc:creator>Lou Franco</dc:creator><category>Entrepreneurship</category><category>Western MA</category><dc:date>2009-10-24T10:48:31-04:00</dc:date><link>http://www.loufranco.com/blog/files/foundercast.html#unique-entry-id-82</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/foundercast.html#unique-entry-id-82</guid><content:encoded><![CDATA[<span style="font-size:15px; ">A couple of friends and members of the Western MA Developers Group have started a PodCast called </span><span style="font-size:15px; "><a href="http://foundercast.com/" rel="self">FounderCast</a></span><span style="font-size:15px; "> that's worth a listen if you are interested in software entrepreneurship. <br /><br />The format is a roundtable of technology three company founders (</span><span style="font-size:15px; "><a href="http://twitter.com/DougMartin" rel="self">@dougmartin</a></span><span style="font-size:15px; ">, </span><span style="font-size:15px; "><a href="http://twitter.com/cemerick" rel="self">@cemerick</a></span><span style="font-size:15px; ">, and </span><span style="font-size:15px; "><a href="http://twitter.com/paulhake" rel="self">@paulhake</a></span><span style="font-size:15px; ">). In the first three episodes they have discussed the tools they use (development and sales), how they got their first customer, customer service and other topics. The pilot is unedited and rough, so don't judge it on that one -- by the third episode it got signicantly better. You can also follow </span><span style="font-size:15px; "><a href="http://twitter.com/foundercast" rel="self">@foundercast</a></span><span style="font-size:15px; "> on twitter.</span>]]></content:encoded></item><item><title>Ben Fry Speaking in Northampton</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>Presentations</category><category>Western MA</category><dc:date>2009-04-04T14:51:48-04:00</dc:date><link>http://www.loufranco.com/blog/files/ben-fry-northampton.html#unique-entry-id-81</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/ben-fry-northampton.html#unique-entry-id-81</guid><content:encoded><![CDATA[<span style="font-size:15px; ">Ben Fry, the creator of </span><span style="font-size:15px; "><a href="http://processing.org" rel="self">Processing</a></span><span style="font-size:15px; "> and the author of </span><span style="font-size:15px; "><a href="http://www.amazon.com/gp/product/0596514557?ie=UTF8&tag=chec01-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0596514557" rel="self">Visualizing Data</a></span><span style="font-size:15px; "> is coming to speak in Northampton. The event is sponsored by </span><span style="font-size:15px; "><a href="http://atalasoft.com" rel="self">Atalasoft</a></span><span style="font-size:15px; "> and </span><span style="font-size:15px; "><a href="http://snowtide.com" rel="self">Snowtide</a></span><span style="font-size:15px; ">.<br /><br /></span><span style="font-size:15px; font-weight:bold; ">When</span><span style="font-size:15px; ">: May 5th @ 6:30<br /></span><span style="font-size:15px; font-weight:bold; ">Where</span><span style="font-size:15px; ">: Snowtide Offices, 243 King St (Potpourri Mall, just across from Stop and Shop) Northampton, MA<br /><br />I'll post more details soon.</span>]]></content:encoded></item><item><title>Static Code Analysis for iPhone Apps</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2009-03-14T11:56:46-04:00</dc:date><link>http://www.loufranco.com/blog/files/scan-build-iphone.html#unique-entry-id-80</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/scan-build-iphone.html#unique-entry-id-80</guid><content:encoded><![CDATA[<span style="font-size:15px; ">Starting with Habits 1.1, I started incorporating </span><span style="font-size:15px; "><a href="http://clang.llvm.org/StaticAnalysisUsage.html" rel="self">static analysis</a></span><span style="font-size:15px; "> into my build. In my previous experience with things like Lint and FXCop -- I had found the signal to noise ratio to be too low to be useful.  It's hard to believe, but scan-build is 100% signal -- every single issue it flagged was legitimate and needed to be fixed. Now, keeping Habits free from issues is easy, since I only have to deal with one or two at a time.<br /><br />There were a couple of times I thought it was leading me in the wrong direction, but it was right so often that I just trusted it, and it was right about those too.  I had a particularly interesting case with a custom table cell, where I wasn't releasing properly, and causing a crash when I dealloced the window. Scan-build helped me make sure I found that before release.<br /><br /></span><span style="font-size:14px; font-weight:bold; ">Get iPhone programming tips in your inbox with my </span><span style="font-size:14px; font-weight:bold; "><a href="../beginner-iphone-programming-tips/index.html" rel="self" title="Beginner iPhone Programming Tips">Beginner iPhone Programming Tips newsletter</a></span><span style="font-size:14px; font-weight:bold; ">.</span>]]></content:encoded></item><item><title>Cocoa date functions are crazy</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2009-02-04T18:53:45-05:00</dc:date><link>http://www.loufranco.com/blog/files/cocoa-get-days-in-month.html#unique-entry-id-79</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/cocoa-get-days-in-month.html#unique-entry-id-79</guid><content:encoded><![CDATA[<span style="font-size:14px; ">I thought Java was bad.  Took me a while to figure this out and googling didn't help, so I am just putting this out there for the next person who needs this.<br /><br />To get the number of days in a month:<br /><br /></span><span style="font:10px Monaco; ">+ (</span><span style="font:10px Monaco; color:#5C2699;">NSInteger</span><span style="font:10px Monaco; ">) getDaysInMonth:(</span><span style="font:10px Monaco; color:#5C2699;">NSDate</span><span style="font:10px Monaco; ">*)date<br />{<br />	</span><span style="font:10px Monaco; color:#5C2699;">NSCalendar</span><span style="font:10px Monaco; "> * cal = [</span><span style="font:10px Monaco; color:#5C2699;">NSCalendar</span><span style="font:10px Monaco; "> </span><span style="font:10px Monaco; color:#2E0D6E;">currentCalendar</span><span style="font:10px Monaco; ">];<br />	</span><span style="font:10px Monaco; color:#AA0D91;">return</span><span style="font:10px Monaco; "> [cal </span><span style="font:10px Monaco; color:#2E0D6E;">rangeOfUnit</span><span style="font:10px Monaco; ">:</span><span style="font:10px Monaco; color:#2E0D6E;">NSDayCalendarUnit</span><span style="font:10px Monaco; "> </span><span style="font:10px Monaco; color:#2E0D6E;">inUnit</span><span style="font:10px Monaco; ">:</span><span style="font:10px Monaco; color:#2E0D6E;">NSMonthCalendarUnit</span><span style="font:10px Monaco; "> </span><span style="font:10px Monaco; color:#2E0D6E;">forDate</span><span style="font:10px Monaco; ">:date].</span><span style="font:10px Monaco; color:#5C2699;">length</span><span style="font:10px Monaco; ">;<br />}<br /><br /></span>]]></content:encoded></item><item><title>Reddit thread on iPhone Development</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2009-01-09T21:15:40-05:00</dc:date><link>http://www.loufranco.com/blog/files/iphone-thread-on-reddit.html#unique-entry-id-78</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/iphone-thread-on-reddit.html#unique-entry-id-78</guid><content:encoded><![CDATA[<span style="font-size:14px; ">There's a great thread by an </span><span style="font-size:14px; "><a href="http://www.reddit.com/r/programming/comments/7ojw5/my_first_app_just_got_published_to_the_app_store/" rel="self">iPhone developer on Reddit</a></span><span style="font-size:14px; ">.<br /></span><blockquote><p>Yay! It took several months but as of today I was able to search for my app and I saw it listed inside the app store. Now you may be saying "so what", but if you have ever looked into the steps that this takes, you know it's something to celebrate.My app is a very simple game, but I think I've learned enough during this process to distill some important lessons that may help you if this is something you've been wanting to do...</p></blockquote><span style="font-size:14px; ">I wrote a similar </span><span style="font-size:14px; "><a href="http://www.loufranco.com/blog/files/iphone-development-tips.html" rel="self" title="Blog:iPhone Development Tips">post when I finally finished my iPhone App</a></span><span style="font-size:14px; ">.</span>]]></content:encoded></item><item><title>New iPhone Blog</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2009-01-06T20:10:11-05:00</dc:date><link>http://www.loufranco.com/blog/files/new-iphone-blog.html#unique-entry-id-77</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/new-iphone-blog.html#unique-entry-id-77</guid><content:encoded><![CDATA[<span style="font-size:14px; ">Helen Crozier, the CalmTechCoach, has started a new iPhone Blog to keep all of her iPhone recommendations and reviews in one place. Check it out: </span><span style="font-size:14px; "><a href="http://thecalmtechcoach.typepad.com/myfabulousiphone/" rel="self">My Fabulous iPhone</a></span>]]></content:encoded></item><item><title>Start Habits not Resolutions</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><category>Habits</category><dc:date>2009-01-05T19:35:53-05:00</dc:date><link>http://www.loufranco.com/blog/files/start-habits-not-resolutions.html#unique-entry-id-76</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/start-habits-not-resolutions.html#unique-entry-id-76</guid><content:encoded><![CDATA[<span style="font-size:14px; ">I saw this </span><span style="font-size:14px; "><a href="http://www.didigetthingsdone.com/2009/01/02/amazons-top-10-new-years-resolutions/" rel="self">list of New Year's Resolutions</a></span><span style="font-size:14px; "> on the Did I Get Things Done blog (originally from Amazon)<br /><br /></span><ul class="disc"><li><span style="font-size:14px; ">Lose Weight</span></li><li><span style="font-size:14px; ">Get Your Finances in Order</span></li><li><span style="font-size:14px; ">Go Greener</span></li><li><span style="font-size:14px; ">Curb Your Vices</span></li><li><span style="font-size:14px; ">Get in Shape</span></li><li><span style="font-size:14px; ">Relax More</span></li><li><span style="font-size:14px; ">Pursue a New Career</span></li><li><span style="font-size:14px; ">Upgrade Your Technology</span></li><li><span style="font-size:14px; ">Organize and Optimize</span></li><li><span style="font-size:14px; ">Start a New Hobby</span></li></ul><span style="font-size:14px; "><br />The main reason that I have had a problem with a resolution is that I don't really think about them much a week or so after New Year's. A few years ago, I created a small web app for myself to log how well I was doing at keeping to resolutions I was making. A few months ago, I ported it to the iPhone as </span><span style="font-size:14px; "><a href="../habits/index.html" rel="self" title="Habits">Habits</a></span><span style="font-size:14px; ">.<br /><br />Instead of making resolutions this year, I created a few habits instead. I want to lose some weight this year (the #1 resolution), so I added a habit to run every 2-3 days, to do bicep/chest and shoulder/tricep weight training once a week. I want to keep my house in better order, so I added a habit to clean up and to process my mail pile more regularly.<br /><br />A lot of these resolutions should just be a recurring task that you try to do as often as possible.<br /></span>]]></content:encoded></item><item><title>Habits reviewed in Macworld</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><category>Habits</category><dc:date>2008-12-30T18:02:53-05:00</dc:date><link>http://www.loufranco.com/blog/files/macworld-reviewed-habits.html#unique-entry-id-75</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/macworld-reviewed-habits.html#unique-entry-id-75</guid><content:encoded><![CDATA[<span style="font-size:14px; "><a href="http://www.macworld.com/article/137803/2008/12/gtdapps.html" rel="self">Macworld reviewed some GTD iPhone applications</a></span><span style="font-size:14px; "> including Habits:<br /></span><blockquote><p>Habits by Louis Franco helps users form good habits, which sounds simple enough. But developing habits requires a bit of time and discipline. It requires repetition and awareness. Habits keeps your calendar free from clutter associated with routine tasks or the general stuff of life.</p></blockquote><span style="font-size:14px; "><br /></span>]]></content:encoded></item><item><title>Habits on Sale for &#x24;0.99 until the end of January</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><category>Habits</category><dc:date>2008-12-29T18:40:30-05:00</dc:date><link>http://www.loufranco.com/blog/files/habits-on-sale-until-end-of-january.html#unique-entry-id-74</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/habits-on-sale-until-end-of-january.html#unique-entry-id-74</guid><content:encoded><![CDATA[<span style="font-size:14px; ">Habits is the perfect application to make sure that you stick to your New Year's resolutions, so from now until the end of January, I am putting Habits on sale for $0.99.<br /><br />I am working on version 1.1, and I will post it at the end of January and return it to its old price. Until then, here's hoping that you're able to turn your resolutions into habits.<br /><br />(The AppStore takes time to fully update -- please make sure it says that the price is $0.99 before you buy)<br /><br /></span><span style="font-size:14px; "><a href="http://click.linksynergy.com/fs-bin/stat?id=CWAfWfo4sjA&offerid=146261&type=3&subid=0&tmpid=1826&RD_PARM1=http%253A%252F%252Fitunes.apple.com%252FWebObjects%252FMZStore.woa%252Fwa%252FviewSoftware%253Fid%253D297399691%2526mt%253D8%2526partnerId%253D30" rel="self">Buy Habits on the App Store</a></span>]]></content:encoded></item><item><title>O&#x27;Reilly&#x27;s iPhone AppStore Answers</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2008-12-08T18:47:11-05:00</dc:date><link>http://www.loufranco.com/blog/files/iphone-appstore-answers.html#unique-entry-id-73</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/iphone-appstore-answers.html#unique-entry-id-73</guid><content:encoded><![CDATA[<span style="font-size:14px; "><a href="http://blogs.oreilly.com/iphone/2008/12/some-app-store-answers.html" rel="self">iPhone AppStore Answers</a></span><span style="font-size:14px; "> from O'Reilly's Inside iPhone Blog. There are frustrations with the AppStore, but as O'Reilly acknowledges, Apple appears to be listening:<br /></span><blockquote><p>Changes have been relatively slow to come to the App Store. However, with the addition of review copies, as well as limiting ratings to those who've purchased applications, Apple has made changes that have been welcomed by developers. I'm hopeful that the App Store will continue to improve over time and address additional issues.</p></blockquote><span style="font-size:14px; ">The other major improvement is dropping the NDA for released SDK's, thus opening up the possibility of books, online tutorials and blogging about iPhone development.<br /></span>]]></content:encoded></item><item><title>More interesting iPhone pricing articles</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><category>Entrepreneurship</category><dc:date>2008-12-03T20:37:15-05:00</dc:date><link>http://www.loufranco.com/blog/files/more-iphone-pricing.html#unique-entry-id-72</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/more-iphone-pricing.html#unique-entry-id-72</guid><content:encoded><![CDATA[<span style="font-size:14px; ">From </span><span style="font-size:14px; "><a href="http://longtail.com" rel="self">Chris Anderson's The Long Tail blog</a></span><span style="font-size:14px; ">, I got this link to some interesting </span><span style="font-size:14px; "><a href="http://radar.oreilly.com/2008/12/iphone-app-store-first-five-mo.html" rel="self">iPhone pricing and sales data</a></span><span style="font-size:14px; ">.<br /></span><blockquote><p>Having more than doubled over the last two months, Gaming remains the largest category accounting for a quarter of all apps. The fastest growing categories were Education and Lifestyle. Medical is the newest app category and as of the end of November there were over 80 medical apps, the 10 most popular of which were free. Among Game apps, Racing, Music, and Sports were the fastest growing Game sub categories.</p></blockquote><span style="font-size:14px; ">And, here's another </span><span style="font-size:14px; "><a href="http://www.mobileorchard.com/price-and-popularity-the-iphone-app-stores-data-shows-whos-making-the-big-money/" rel="self">iPhone app pricing article</a></span><span style="font-size:14px; "> I got from </span><span style="font-size:14px; "><a href="http://daringfireball.net" rel="self">John Gruber's DaringFireball</a></span><span style="font-size:14px; ">. In the article, Peter Cooper uses popularity as a stand-in for units sold and and tries to figure out which apps have the most revenue. Put this one in your RSS feed if you are interested in hearing more as this installment covers mostly the Games category.</span>]]></content:encoded></item><item><title>Seth Godin&#x27;s iPhone App Ideas</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><category>Entrepreneurship</category><dc:date>2008-11-30T10:56:58-05:00</dc:date><link>http://www.loufranco.com/blog/files/seth-iphone-ideas.html#unique-entry-id-71</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/seth-iphone-ideas.html#unique-entry-id-71</guid><content:encoded><![CDATA[<span style="font-size:14px; ">Today, </span><span style="font-size:14px; "><a href="http://sethgodin.typepad.com/seths_blog/2008/11/an-iphone-app-t.html" rel="self">Seth Godin is giving away iPhone App ideas</a></span><span style="font-size:14px; ">, the first one helps you avoid traffic:<br /></span><blockquote><p>Have the iPhone use the gps data... upload where I was a minute ago and where I am now. Figure out my speed and route. Use the data to tell other RadaR users which route is best. It's worth $20 a month if you live in a place with traffic jams. It's a natural monopoly--once someone figures it out, why wouldn't everyone want to use the market leader?</p></blockquote><span style="font-size:14px; ">The Google Maps app on the iPhone has traffic data already--what's missing is that I don't think it takes that into account when selecting a route, or updates it if conditions change. If the traffic data is available with an API (like most google data), then this might be easier than even Seth thinks (no server side) -- of course, no lock-in either.<br /></span><span style="font-size:14px; "><br />The second idea needs some kind of server-side dialier because Apple doesn't let apps run in the background:</span><blockquote><p>Here's an easier one that you could probably sell as well. I type in a phone number and enter a time. Record a message and press go. I can cue up a bunch of messages that are based on time. I can have groups get the message I record, at the time I want them to get it.</p></blockquote>]]></content:encoded></item><item><title>Interesting iPhone App Pricing Articles</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><category>Entrepreneurship</category><dc:date>2008-11-29T16:28:31-05:00</dc:date><link>http://www.loufranco.com/blog/files/interesting-iphone-app-pricing-articles.html#unique-entry-id-70</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/interesting-iphone-app-pricing-articles.html#unique-entry-id-70</guid><content:encoded><![CDATA[<span style="font-size:14px; ">When I was trying to figure out a price for </span><span style="font-size:14px; "><a href="../habits/index.html" rel="self" title="Habits">Habits</a></span><span style="font-size:14px; ">, I found a few articles that were interesting. This one from Andy Finnell made the rounds on Reddit and advocates for busting through the $0.99 mentality and </span><span style="font-size:14px; "><a href="http://www.losingfight.com/blog/2008/11/15/how-to-price-your-iphone-app-out-of-existence/" rel="self">pricing applications in the $9.99 range</a></span><span style="font-size:14px; ">.<br /></span><blockquote><p>The fix for pricing too low is really simple: raise your prices. Most $0.99 apps should become $9.99, $4.99 apps should become $14.99, and so on. With a $9.99 app, you&rsquo;d make $7 per copy and at 16 copies per day, you&rsquo;d make about $40,000/year. That&rsquo;s not a great income, but that could potentially support one iPhone product being developed in some Iowan&rsquo;s wheat field.</p></blockquote><span style="font-size:14px; ">This </span><span style="font-size:14px; "><a href="http://www.losingfight.com/blog/2008/11/07/can-you-make-a-living-off-an-iphone-app/" rel="self">other article from Andy</a></span><span style="font-size:14px; "> is also good.<br /></span><span style="font-size:14px; "><br /></span><span style="font-size:14px; "><a href="http://daringfireball.net/linked/2008/11/16/finnell-app-store-pricing" rel="self">John Gruber made an interesting point</a></span><span style="font-size:14px; "> when he linked to Andy (software with higher prices needs demos and refunds)<br /><br />Tap, Tap, Tap has had a couple of AppStore hits, so what </span><span style="font-size:14px; "><a href="http://www.taptaptap.com/blog/how-to-prevent-the-app-store-from-becoming-the-crap-store/" rel="self">they have to say</a></span><span style="font-size:14px; "> is also very interesting.<br /></span><blockquote><p>iPhone apps are typically much smaller and more focused than desktop apps and as such, should be priced accordingly. In addition, you need to take into account the much larger market that you&rsquo;re dealing with here&hellip; Apple is selling well over 10,000 iPhones per day and these are all potential new customers, plus all the existing iPhone owners and iPod touch sales.</p></blockquote>]]></content:encoded></item><item><title>Unit testing on the iPhone</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><category>Software Development</category><dc:date>2008-11-28T10:42:11-05:00</dc:date><link>http://www.loufranco.com/blog/files/iphone-unit-testing.html#unique-entry-id-69</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/iphone-unit-testing.html#unique-entry-id-69</guid><content:encoded><![CDATA[<span style="font-size:14px; ">Thanks to Google, there's a </span><span style="font-size:14px; "><a href="http://code.google.com/p/google-toolbox-for-mac/wiki/iPhoneUnitTesting" rel="self">unit-testing framework for the iPhone</a></span><span style="font-size:14px; ">. There's not much more to say about it -- the instructions are crystal clear and it worked exactly as described. It's compatible with OCUnit (the Objective-C unit test framework in XCode), so once you set it up, you can just create test cases the way you would for any ObjC project.<br /><br />One quirk -- it instructs you to add a build step that runs the unit-tests during build time and shows the failures as compiler errors that you can then use XCode to track down. That's nice, but I have found that you don't really have enough of an environment to successfully run every kind of test -- they run fine if you run them in the simulator. The main problem I have is with setting up my database in my Documents folder -- I get errors at build-time that work just fine at run-time. <br /><br /></span><span style="font-size:14px; font-weight:bold; ">Get iPhone programming tips in your inbox with my </span><span style="font-size:14px; font-weight:bold; "><a href="../beginner-iphone-programming-tips/index.html" rel="self" title="Beginner iPhone Programming Tips">Beginner iPhone Programming Tips newsletter</a></span><span style="font-size:14px; font-weight:bold; ">.</span>]]></content:encoded></item><item><title>How I use Habits</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><category>Habits</category><dc:date>2008-11-25T19:16:18-05:00</dc:date><link>http://www.loufranco.com/blog/files/how-I-use-habits.html#unique-entry-id-68</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/how-I-use-habits.html#unique-entry-id-68</guid><content:encoded><![CDATA[<span style="font-size:14px; ">Habits was released last week, but before that, I had something like it on a private area of my website for me to use. This is what my Habits looks like right now (edited for brevity and to remove personal data):<br /><br /></span><p style="text-align:center;"><img class="imageStyle" alt="habits-lou" src="http://www.loufranco.com/blog/files/page2_blog_entry68_1.png" width="320" height="686"/><span style="font-size:14px; "><br /></span><span style="font-size:14px; "><br /></span></p><p style="text-align:left;"><span style="font-size:14px; ">Generally, I use Habits to help with Sharpen the Saw type of tasks -- things I want to make sure I do every once in a while, but not necessarily at a specific time. Also, unlike a recurring event in a calendar, I can record how well I do with them (if I do them late, early, or skip them).</span></p>]]></content:encoded></item><item><title>Debugging memory based crashes on iPhone</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2008-11-24T18:44:20-05:00</dc:date><link>http://www.loufranco.com/blog/files/debugging-memory-iphone.html#unique-entry-id-67</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/debugging-memory-iphone.html#unique-entry-id-67</guid><content:encoded><![CDATA[<span style="font-size:14px; ">On my Atalasoft blog, I wrote some </span><span style="font-size:14px; "><a href="http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/02/06/6-_2200_Pointers_2200_-on-Debugging-Unmanaged-Code.aspx" rel="self">tips for debugging unmanaged crashes in .NET</a></span><span style="font-size:14px; "> that I figured out by debugging our </span><span style="font-size:14px; "><a href="http://www.atalasoft.com/products/dotimage" rel="self" title=".NET Imaging SDK">.NET Imaging SDK</a></span><span style="font-size:14px; ">. The idea is the same for iPhone -- namely:<br /></span><blockquote><p>[...] crash as early as possible.  It's no fun to figure out a crash bug once the culprit function has already returned.  You really want the root cause somewhere on the call stack when it's detected.</p></blockquote><span style="font-size:14px; ">In Xcode, it's actually really easy to get information about how you might be managing memory incorrectly.<br /><br /></span><span style="font-size:14px; font-weight:bold; ">Tip 1: Set Deallocated objects to Zombies</span><span style="font-size:14px; "><br /><br />Go to Project->Edit Active Executable, go to the Arguments tab and in the environment variables section, add <br /><br />	NSAutoreleaseFreedObjectCheckEnabled<br />	NSZombieEnabled<br />	NSDebugEnabled<br /><br />And set each to YES.  You can leave them there unchecked, but if you check them, then your application will now do some extra checking on autorelease and release and give you a good stack trace when you have done it wrong. A common problem is to think you need to call release when the object is already set to autorelease (see </span><span style="font-size:14px; "><a href="http://www.loufranco.com/blog/files/managing-memory-iphone.html" rel="self" title="Blog:Managing memory in iPhone applications">yesterday's post</a></span><span style="font-size:14px; "> on what the rules are for that).<br /></span><span style="font-size:14px; font-weight:bold; "><br />Tip 2: Enable Guard Malloc</span><span style="font-size:14px; "><br /><br />If you think you are having an issue where you go out of bounds of a heap allocated memory block, then in the Run menu, you can check "Enable Guard Malloc".  This will tell you if you overrun your bounds. It's not going to be as handy as a Page Heap style check (where each heap allocation gets its own page and therefore crashes at the point of the mistake), but it's better than nothing.<br /><br />After doing this, you get more capabilities in the debugger. </span><span style="font-size:14px; "><a href="http://developer.apple.com/iphone/library/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html" rel="self">Read this article</a></span><span style="font-size:14px; "> to see how to use them.<br /><br /></span><span style="font-size:14px; font-weight:bold; ">UPDATE:</span><span style="font-size:14px; "> I wrote a much more detailed version of this that focuses on </span><span style="font-size:14px; "><a href="http://www.loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html" rel="self" title="Blog:Understanding EXC_BAD_ACCESS">Understanding EXC_BAD_ACCESS</a></span><span style="font-size:14px; ">.<br /><br /></span><span style="font-size:14px; font-weight:bold; ">Get iPhone programming tips in your inbox with my </span><span style="font-size:14px; font-weight:bold; "><a href="../beginner-iphone-programming-tips/index.html" rel="self" title="Beginner iPhone Programming Tips">Beginner iPhone Programming Tips newsletter</a></span><span style="font-size:14px; font-weight:bold; ">.</span><span style="font-size:14px; "><br /></span>]]></content:encoded></item><item><title>Managing memory in iPhone applications</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2008-11-23T14:34:45-05:00</dc:date><link>http://www.loufranco.com/blog/files/managing-memory-iphone.html#unique-entry-id-66</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/managing-memory-iphone.html#unique-entry-id-66</guid><content:encoded><![CDATA[<span style="font-size:14px; ">I program all day in C# and C++ at my day job, so Objective-C is both natural to me (because of a mostly familiar syntax) and unnatural (because of it's many differences). In terms of memory management, Objective-C splits the difference between C# and C++. On the iPhone, Objective-C does not have a GC, but NSObject (the base class for all of your classes) supports reference counting. Of course, you could build the exact same mechanism in C++, but it's pervasive and included in ObjC and there's also some support in the app runtime for an autorelease concept (release will get called for you on an object at some point when the runtime has control -- you are safe in the rest of your stack frame).<br /><br />When I first started </span><span style="font-size:14px; "><a href="http://www.loufranco.com/blog/habits" rel="self">Habits</a></span><span style="font-size:14px; ">, I didn't really read through the entire memory management API (there were so many other APIs to read) because I have been using reference counting for a long time (old COM programmer) and the awesome leak detector included in XCode was a good enough guide to what I was doing wrong.<br /><br />However, the rules are really simple, and now that I know them, I never run into memory management issues:<br /><br /></span><ol class="arabic-numbers"><li><span style="font-size:14px; ">Declare all of your object pointer @properties as retain unless you have a really good reason not to. Then the setter that is generated will automatically call retain when you assign. When you reassign, it knows to call release on the old value.</span></li><li><span style="font-size:14px; ">In your dealloc, assign all of your @properties to nil. This has the effect of calling release on the current values if they are not already nil.</span></li><li><span style="font-size:14px; ">alloc returns an object with a reference count of 1 -- so you have to balance with a release.</span></li><li><span style="font-size:14px; ">If you alloc, then you should try to release in that same function. To retain the value, assign it to something that retains. Exceptions are if you are a factory function that is returning a value up to be retained by the caller.</span></li><li><span style="font-size:14px; ">Obviously, each retain call needs a release.</span></li><li><span style="font-size:14px; ">Built-in convenience functions return objects that are autoreleased. That means you shouldn't call release on them -- the framework will call release at some point (they are registered in an autorelease pool that that is serviced when you return back to the framework). If you created the object without an alloc/init pair, you don't need to call release unless the docs say you do (but they probably don't)</span></li><li><span style="font-size:14px; ">Check all of your work with the leak detector. Also, if you crash, you're probably doing it wrong -- I will have more to say on that soon.</span></li></ol><span style="font-size:14px; "><br />I highly recommend that you read </span><span style="font-size:14px; "><a href="http://www.stepwise.com/Articles/Technical/2001-03-11.01.html" rel="self">Very Simple Rules for Memory Management in Cocoa</a></span><span style="font-size:14px; "> on stepwise.com. Keep in mind that the suggestions for building proper setters is handled automatically if you declare your @properties correctly.<br /><br /></span><span style="font-size:14px; font-weight:bold; ">Get iPhone programming tips in your inbox with my </span><span style="font-size:14px; font-weight:bold; "><a href="../beginner-iphone-programming-tips/index.html" rel="self" title="Beginner iPhone Programming Tips">Beginner iPhone Programming Tips newsletter</a></span><span style="font-size:14px; font-weight:bold; ">.</span><span style="font-size:14px; "><br /></span>]]></content:encoded></item><item><title>iPhone Development Tips</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2008-11-22T15:51:23-05:00</dc:date><link>http://www.loufranco.com/blog/files/iphone-development-tips.html#unique-entry-id-65</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/iphone-development-tips.html#unique-entry-id-65</guid><content:encoded><![CDATA[<span style="font-size:14px; ">Having now gone through getting </span><span style="font-size:14px; "><a href="http://www.loufranco.com/blog/habits" rel="self">Habits</a></span><span style="font-size:14px; "> built, tested and on the App Store, I wanted to share these tips on getting started with iPhone development:<br /><br /></span><ol class="arabic-numbers"><li><span style="font-size:14px; ">Go enroll in the </span><span style="font-size:14px; "><a href="http://developer.apple.com/iphone/program" rel="self">iPhone developer program</a></span><span style="font-size:14px; "> before you start.  Yeah, I know -- it's 99 bucks.  But if you have an idea and a reasonable chance of doing it, just take the plunge.  I joined after I finished, and that caused a lot of delays -- I could have been completing the other necessary steps in parallel.</span></li><li><span style="font-size:14px; ">As soon as you're in, go get your application contracts going.  If you want to make paid applications, you have to give Apple your tax and bank information. Again, it takes some time to get approved, so start early.</span></li><li><span style="font-size:14px; ">If you don't know Objective-C -- don't worry, that's the easy part. The </span><span style="font-size:14px; "><a href="http://developer.apple.com/iphone/gettingstarted/docs/objectivecprimer.action" rel="self">primer</a></span><span style="font-size:14px; "> on the iPhone developer site should be good enough if you know C/C++.</span></li><li><span style="font-size:14px; ">For Cocoa Touch, I recommend Erica Sadun's </span><span style="font-size:14px; "><a href="http://www.amazon.com/iPhone-Developers-Cookbook-Building-Applications/dp/0321555457" rel="self">iPhone Developer's Cookbook</a></span><span style="font-size:14px; ">. The chapter on coverflow is worth the price of the book, but everything else is there too (navigation, touch, location, contacts, etc)</span></li><li><span style="font-size:14px; ">I also highly recommend </span><span style="font-size:14px; "><a href="http://www.icodeblog.com" rel="self">iCodeBlog</a></span><span style="font-size:14px; ">. Once you have some basic knowledge of the framework, check out the </span><span style="font-size:14px; "><a href="http://icodeblog.com/2008/08/19/iphone-programming-tutorial-creating-a-todo-list-using-sqlite-part-1/" rel="self">to-do application tutorial</a></span><span style="font-size:14px; ">.</span></li></ol><span style="font-size:14px; "><br /></span><span style="font-size:14px; font-weight:bold; ">Update</span><span style="font-size:14px; ">: just found this </span><span style="font-size:14px; "><a href="http://cubiclemuses.com/cm/articles/2008/11/22/iphone-development-flowchart/" rel="self">great flowchart</a></span><span style="font-size:14px; "> of the right order to do things<br /></span><span style="font-size:14px; font-weight:bold; "><br />Get iPhone programming tips in your inbox with my </span><span style="font-size:14px; font-weight:bold; "><a href="../beginner-iphone-programming-tips/index.html" rel="self" title="Beginner iPhone Programming Tips">Beginner iPhone Programming Tips newsletter</a></span><span style="font-size:14px; font-weight:bold; ">.</span>]]></content:encoded></item><item><title>Habits accepted to iPhone AppStore</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2008-11-21T22:09:13-05:00</dc:date><link>http://www.loufranco.com/blog/files/habits-in-appstore.html#unique-entry-id-64</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/habits-in-appstore.html#unique-entry-id-64</guid><content:encoded><![CDATA[<span style="font-size:14px; "><a href="http://www.loufranco.com/blog/habits" rel="self">Habits</a></span><span style="font-size:14px; "> was accepted to the AppStore today.</span>]]></content:encoded></item><item><title>Announcing Habits</title><dc:creator>Lou Franco</dc:creator><category>iPhone</category><dc:date>2008-11-14T01:05:27-05:00</dc:date><link>http://www.loufranco.com/blog/files/announcing-habits.html#unique-entry-id-63</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/announcing-habits.html#unique-entry-id-63</guid><content:encoded><![CDATA[I have been working on my first iPhone app for the last few weeks. It is a GTD companion application to help with recurring to do items with an indefinite schedule. It's called Habits, because I think it will help you form (good) habits. Soon to be available on the App Store.]]></content:encoded></item><item><title>Pecha Kucha Posted</title><dc:creator>Lou Franco</dc:creator><category>Presentations</category><dc:date>2008-09-13T21:54:16-04:00</dc:date><link>http://www.loufranco.com/blog/files/117a2b28f0f8a0febc92b0ed1f3e7cdc-61.html#unique-entry-id-61</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/117a2b28f0f8a0febc92b0ed1f3e7cdc-61.html#unique-entry-id-61</guid><content:encoded><![CDATA[I posted my <a href="http://www.atalasoft.com/cs/blogs/loufranco/archive/2008/09/12/engineering-the-evaluation-funnel-pecha-kucha.aspx" rel="self">Engineering the Evaluation Funnel</a> Pecha Kucha at my Atalasoft blog.]]></content:encoded></item><item><title>Business of Software Pecha Kucha</title><dc:creator>Lou Franco</dc:creator><category>Personal</category><category>Presentations</category><dc:date>2008-09-06T11:45:15-04:00</dc:date><link>http://www.loufranco.com/blog/files/BoS-Pecha-Kucha.html#unique-entry-id-60</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/BoS-Pecha-Kucha.html#unique-entry-id-60</guid><content:encoded><![CDATA[Had a lot of fun with my Business of Software Pecha Kucha. My topic was <em>Engineering the Evaluation Funnel</em>, or how companies that have downloaded evaluations can still track usage with being creepy and sending back information from the application.<br /><br />I'm going to be recording a version of my presentation and posting it soon.]]></content:encoded></item><item><title>Ant Colony in F#</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2008-04-30T21:09:38-04:00</dc:date><link>http://www.loufranco.com/blog/files/ad21adc38f8d971de4ee96a20cffab5f-59.html#unique-entry-id-59</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/ad21adc38f8d971de4ee96a20cffab5f-59.html#unique-entry-id-59</guid><content:encoded><![CDATA[My colleague, Rick, is playing around with F#. He made this <a href="http://www.atalasoft.com/cs/blogs/rickm/archive/2008/04/25/10-hours-in-fsharp-exploring-concurrency-through-an-ant-colony-simulation.aspx" rel="self">ant colony in F#</a> that's based on <a href="http://blip.tv/file/812787/" rel="self">Rich's clojure one</a>. If you know clojure, and you want to see what F# is all about, you might want to take a look.]]></content:encoded></item><item><title>Clojure Day Blog Roundup</title><dc:creator>Lou Franco</dc:creator><category>20 Days of Clojure</category><category>Western MA</category><dc:date>2008-03-21T13:36:15-04:00</dc:date><link>http://www.loufranco.com/blog/files/c2702ef9e5a9c35e8cffcef1f4a62802-58.html#unique-entry-id-58</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/c2702ef9e5a9c35e8cffcef1f4a62802-58.html#unique-entry-id-58</guid><content:encoded><![CDATA[If you were there and blogged it, let me know:<br /><br />Here's what I found so far:<br /><br /><ul class="disc"><li><a href="http://www.atalasoft.com/cs/blogs/insertqualityhere/archive/2008/03/21/clojure.aspx" rel="self">Adam Scarborough</a></li><li><a href="http://blog.snowtide.com/2008/03/21/western-mass-developers-group-and-snowtide-host-rich-hickey-and-clojure" rel="self">Chas Emerick</a></li><li><a href="http://news.e-scribe.com/411" rel="self">Paul Bissex</a></li><li><a href="http://www.atalasoft.com/cs/blogs/rickm/archive/2008/03/21/clojure-impressions.aspx" rel="self">Rick Minerich</a></li></ul>]]></content:encoded></item><item><title>20 Days of Clojure: Day 20</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><category>Western MA</category><dc:date>2008-03-21T07:47:30-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-20.html#unique-entry-id-57</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-20.html#unique-entry-id-57</guid><content:encoded><![CDATA[Last night was our Clojure event with Rich Hickey. BTW, if you were there, regular meeting of the <a href="http://wmassdevs.org" rel="self">Western Mass Developers Group</a> are every other Thursday at Panera Bread in Hadley (7pm) --- most of the time, we just sit around and talk -- very informal -- hope to see you there.<br /><br />Back to the presentation -- hopefully the slides/video/etc will be up somewhere soon -- Rich focussed on the concurrency features of Clojure (Vars, Refs, and Agents). First he showed us the state of concurrency support in Java/C# today (locking) and identified the problem as having direct references to mutable objects. Clojure offers only immutable atoms and datastructures so that's how he addresses one part of the problem. However, since the mutability is how the world works, Clojure models change as a change to what a reference points to. So, if you view the world through refs, it will appear to change. Then he introduced the controlled ways in which refs can change.<br /><br />1. Vars are essentially thread local variables. They are a reference whose changes can only be seen in a single thread -- each thread gets an independent and isolated view of the variable. Like thread-local variables -- they are a very simple way to take code that looks like it's manipulating global state and give each thread its own isolated copy.<br /><br />2. Refs are mutable references to immutable objects. They can only be changed inside a transaction and all changes to all refs in a transaction appear to have happened at the time the transaction ends (to other threads). Inside the transaction, the changes are immediate. When two transactions are open and change the same ref, the second one to finish is automatically retried (so you should have no side-effects inside of transactions). All Refs read inside of a transaction will return the value that they had at the start of the transaction (so are consistent with each other).<br /><br />3. Agents (which I have explained <a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-11.html" rel="self" title="Blog:20 Days of Clojure: Day 11">before</a>) are for asynchronous changes to a reference.  Each agent hold a value and you send actions to it to change the value. Only one action will happen to an agent at a time and you can read the current state of the agent any time. Rich spent a little time to caution us against any comparison to Erlang's actors. They are a different concept with different tradeoffs. Agents have the advantage that they can be read from any thread conveniently (just dereference) whereas actors require sending a message to read (which is asynchronous). Clearly, Erlang's benefit is location transparency (for distributed code) -- which is what it was designed for.  Rich hinted that Clojure might have an Actor concept, but it would not be unified with Agents.<br /><br />What was new to me with agents is that there are two types of message sending mechanisms -- send and send-off (<a href="http://clojure.sourceforge.net/reference/agents.html" rel="self">which appear to be undocumented right now</a>) -- Rich used send-off which dedicates a thread to the agent (rather than run the action from a thread-pool). This is how you have to do it if agents block at all (which ants do because they have a small sleep).<br /><br />Then, he showed us an ant simulation -- I think he will make the code available. In short, there is a square world of cells, each one holds a Ref to what is in the cell (food, ant, pheromones, home base). Ants are represented by agents, which are sent a behave message. Behave picks a random action for the ant to do (move, turn, pick up food, drop food) and then mutates the world of cells in a transaction, then it sends itself another behave action. There is an agent responsible for painting the world, and another which evaporates pheromones in the background.<br /><br />Anyway, the demo was impressive -- since painting makes a copy of the world in a transaction, it has a completely consistent view of the world. Refs make sure that all changes to them are in transactions, so you have language support for where you need cooperation (contrasted to locking, which is not enforced). Agents also help you model the real world in a way that a coordinated single-looped simulation (calling behave on ants in a loop, then paint over and over again) could not. <br /><br />And clojure's agent mutating mechanism (sending a function to it), means that agents don't have to have any knowledge of the messages that might be sent to it (again contrasted to Erlang Actors).  Finally, various messages can take different times to complete and that would be represented in the simulation --- some ants might complete several small actions in the time it took another to complete one (which would not be the case in a behave loop).<br /><br />I'll have more on this when the slides, code, etc are available.]]></content:encoded></item><item><title>20 Days of Clojure: Day 19</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-19T07:41:01-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-19.html#unique-entry-id-56</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-19.html#unique-entry-id-56</guid><content:encoded><![CDATA[Ok, <a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-18.html" rel="self" title="Blog:20 Days of Clojure: Day 18">yesterday</a> I decided to try to implement a defclass macro which would hobble multimethods and force you to have some kind of class inheritance for polymorphism. Today, I'll try to implement that macro.<br /><br />First, I made this macro, which I think will be useful<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defmacro sym2key [s]<br />&nbsp;&nbsp;&nbsp;&nbsp;`(keyword (name (quote ~s)))&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;)</span><br /><br />Works like this:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;user=&gt; (sym2key rect)<br />&nbsp;&nbsp;:rect</span><br /><br />(I wrote the above this morning, and after several hours, I didn't get too far)<br /><br />I had to cheat a lot, but I finally got something -- here is my final OO minilanguage<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defclass shape <br />&nbsp;&nbsp;&nbsp;&nbsp;(defabstractmeth area) <br />&nbsp;&nbsp;)<br />&nbsp;&nbsp;(defclass rect <br />&nbsp;&nbsp;&nbsp;&nbsp;(defctor (fn [w h] (setprop w) (setprop h) )) <br />&nbsp;&nbsp;&nbsp;&nbsp;(defmeth area (fn [] (* (:w this) (:h this))))<br />&nbsp;&nbsp;)<br />&nbsp;&nbsp;(defclass circle <br />&nbsp;&nbsp;&nbsp;&nbsp;(defctor (fn [r] (setprop r)  )) <br />&nbsp;&nbsp;&nbsp;&nbsp;(defmeth area (fn [] (* (:r this) (:r this) (. Math PI))))<br />&nbsp;&nbsp;)</span><br /><br />I got that to be processed by these macros:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defmacro sym2key [s]<br />&nbsp;&nbsp;&nbsp;&nbsp;`(keyword (name (quote ~s)))&nbsp;&nbsp;<br />&nbsp;&nbsp;)<br /><br />&nbsp;&nbsp;(defmacro defclass [name & body]<br />&nbsp;&nbsp;&nbsp;&nbsp;(cons 'do<br />&nbsp;&nbsp;&nbsp;&nbsp;(loop [classbody# body parts# nil] <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if classbody#<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(recur (rest classbody#) (cons (concat (first classbody#) `(~name)) parts#))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parts#)))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;)<br /><br />&nbsp;&nbsp;(defmacro defabstractmeth [name class] `(defmulti ~name :type) )<br /><br />&nbsp;&nbsp;(defmacro setprop [x] { (sym2key x) x })<br /><br />&nbsp;&nbsp;(defmacro defctor [fndef name]<br />&nbsp;&nbsp;&nbsp;&nbsp;(let [&nbsp;&nbsp;arglist# (second fndef) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fnbody# (map second (nthrest fndef 2) ) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj# (reduce merge <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:type `(sym2key ~name)} <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map assoc (repeat {}) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map eval <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map sym2key fnbody#)) fnbody#))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`(defn ~name ~arglist# ~obj#)<br />&nbsp;&nbsp;&nbsp;&nbsp;)<br />&nbsp;&nbsp;)<br /><br />&nbsp;&nbsp;(defmacro defmeth [meth fndef name]<br />&nbsp;&nbsp;&nbsp;&nbsp;(let [&nbsp;&nbsp;arglist# (conj (second fndef) 'this)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fnbody# (first (nthrest fndef 2)) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;namesym# (eval `(sym2key ~name))<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`(defmethod ~meth ~namesym# ~arglist# ~fnbody#)<br />&nbsp;&nbsp;&nbsp;&nbsp;)<br />&nbsp;&nbsp;)<br /><br /></span>This code shows it in action:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(prn (rect 10 20))<br />&nbsp;&nbsp;(prn (area (rect 10 20)))<br />&nbsp;&nbsp;(prn (circle 10))<br />&nbsp;&nbsp;(prn (area (circle 10)))<br /></span><br />Outputs:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;{:type :rect, :h 20, :w 10}<br />&nbsp;&nbsp;200<br />&nbsp;&nbsp;{:type :circle, :r 10}<br />&nbsp;&nbsp;314.1592653589793<br /><br /></span>I am way too tired to explain this -- suffice to say, this is kind a crazy way to make something, but it sure beats not being able to make it.  My ctor implementation is so crazy, that you should just ignore it -- defclass and defmeth are worth looking at (ctor is a major hack -- assumes only setprop calls and turns them into a map).]]></content:encoded></item><item><title>20 Days of Clojure: Day 18</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-18T21:06:44-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-18.html#unique-entry-id-55</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-18.html#unique-entry-id-55</guid><content:encoded><![CDATA[I just got around to watching Clojure TV on sequences, which I guess I should have done earlier, but I guess I was too lazy --- thanks, I'm here all week.<br /><br />Ok -- since clearly, day 20 is going to be about <a href="http://wmassdevs.com/wordpress/2008/02/28/clojure-talk-with-rich-hickey-on-march-20/" rel="self">Clojure Day in Northampton</a>, I only have two days to explore more of clojure.  I haven't even gotten to <a href="http://clojure.sourceforge.net/reference/multimethods.html" rel="self">multimethods</a>, which are very cool, but pretty simple to understand. I want to keep working with macros.<br /><br />The hardest thing about thinking about macros is that not using a language that has one, I haven't started to think in macros yet. Kind of reminds me of <a href="http://www.imdb.com/title/tt0083943/" rel="self">Clint Eastwood in Firefox</a> who has to keep remembering to think in Russian in order to fly his stolen super-secret Soviet jet.<br /><br />Ok, since I think in OO, let me try to do some OO in clojure via macros -- maybe I get to use multimethods after all (let's hobble them with conventional OO polymorphism)<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defclass rect <br />&nbsp;&nbsp;&nbsp;&nbsp;(defctor (fn [w h] (setprop w) (setprop h) )) <br />&nbsp;&nbsp;&nbsp;&nbsp;(defmeth area (fn [] (* w h))) <br />&nbsp;&nbsp;)<br /><br />&nbsp;&nbsp;(defclass circle <br />&nbsp;&nbsp;&nbsp;&nbsp;(defctor (fn [r] (setprop r)))<br />&nbsp;&nbsp;&nbsp;&nbsp;(defmeth area (fn [] (* r r (. Math PI))))<br />&nbsp;&nbsp;)<br /></span><br />I want that to turn into<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defn rect [w h] {:type :rect :w w :h h})<br />&nbsp;&nbsp;(defmulti area :type)<br />&nbsp;&nbsp;(defmethod area :rect [r]<br />&nbsp;&nbsp;&nbsp;&nbsp;(* (:w r) (:h r)))<br /><br />&nbsp;&nbsp;(defn circle [r] {:type :circle :r r})<br />&nbsp;&nbsp;(defmulti area :type)<br />&nbsp;&nbsp;(defmethod area :circle [c]<br />&nbsp;&nbsp;&nbsp;&nbsp;(* (. Math PI) (* (:r c) (:r c))))</span><br /><br />I'm not even sure this is possible -- I just checked to see if it's legal to defmulti the same name, and it's not really because it kills the definition for rect.  Luckily, I have a precedent to fall back on -- in Java/C# style OO, area is only polymorphic if it came from a superclass. I can change the class structure to this:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defclass shape <br />&nbsp;&nbsp;&nbsp;&nbsp;(defabstractmeth area) <br />&nbsp;&nbsp;)<br /></span><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defclass rect :extends shape<br />&nbsp;&nbsp;&nbsp;&nbsp;(defctor (fn [w h] (setprop w) (setprop h) )) <br />&nbsp;&nbsp;&nbsp;&nbsp;(defmeth area (fn [] (* w h))) <br />&nbsp;&nbsp;)<br /><br />&nbsp;&nbsp;(defclass circle :extends shape<br />&nbsp;&nbsp;&nbsp;&nbsp;(defctor (fn [r] (setprop r)))<br />&nbsp;&nbsp;&nbsp;&nbsp;(defmeth area (fn [] (* r r (. Math PI))))<br />&nbsp;&nbsp;)<br /><br /></span>This is so ugly, I don't even know if I want to go through with this. I'll try for tomorrow.]]></content:encoded></item><item><title>20 Days of Clojure: Day 17</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-17T19:02:52-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-17.html#unique-entry-id-54</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-17.html#unique-entry-id-54</guid><content:encoded><![CDATA[(<a href="http://wmassdevs.com/wordpress/2008/02/28/clojure-talk-with-rich-hickey-on-march-20/" rel="self" title="Rich Hickey in Northampton">clojure day in Northampton, MA is Thursday, March 20th</a>)<br /><br /><div class="image-left"><img class="imageStyle" alt="viman" src="http://www.loufranco.com/blog/files/page2_blog_entry54_1.gif" width="200" height="144"/></div>I know I'll reveal myself as being tragically unhip for not using emacs or aquamacs or whatever (I'm a VI man after all), but I started this <a href="http://www.loufranco.com/blog/assets/clojure.zip" rel="self">TextMate Bundle for clojure</a>. I'll grow it as time goes by and probably move it to its own page or some repository for bundles once I figure this bundling stuff out.<br /><br />I do some rudimentary syntax coloring and automatically expand <strong>defn</strong>[Tab], <strong>def</strong>[Tab], <strong>let</strong>[Tab], and <strong>if</strong>[Tab].<br /><br />If you use TextMate and have some ideas for things to add, please send me a note.]]></content:encoded></item><item><title>20 Days of Clojure: Day 16</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-16T14:06:02-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-16.html#unique-entry-id-53</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-16.html#unique-entry-id-53</guid><content:encoded><![CDATA[Ok, time to look at macros. Being new to lisps, I'm especially new to macros. I have been meaning to read <a href="http://www.paulgraham.com/onlisptext.html" rel="self">On Lisp</a> for a few months, so like the SICP, I'll show you stuff from the macros chapter and then try to write them in clojure.<br /><br />In, On Lisp (Chapter 7), Paul Graham writes:<br /><blockquote><p>The expression generated by the macro will be evaluated in place of the original macro call. A macro call is a list whose first element is the name of the macro. What happens when we type the macro call into the toplevel? Lisp notices that [it] is the name of a macro, and<ol><li>builds the expression specified by the definition, then</li><li>evaluates that expression in place of the original macro call</li></ol></p></blockquote>Macros simply allow you to write code that gets executed at compile time to generate code, which is then run. There really isn't anything quite like them in popular non-lisp languages, though <a href="http://www.atalasoft.com/cs/blogs/loufranco/archive/2006/06/27/10323.aspx" rel="self">there are a couple of .NET languages with language altering macros</a>. They are much more powerful than the preprocessor macros in C, and C++ template meta-programming can sometimes get you the effect, but templates were not designed for this, so it is too cumbersome most of the time.<br /><br />We have been using macros in clojure throughout this series. In fact, since Lisps evaluate all of their arguments before calling a function, whenever you see code where all of the arguments are not evaluated, you are either looking at something built-in to the language (e.g. if) or a macro (e.g. cond). You can look at boot.clj to see the definitions of them. For example, here's lazy-cons:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defmacro lazy-cons [x & body]<br />&nbsp;&nbsp;&nbsp;&nbsp;(list 'fnseq x (list* `fn [] body)))</span><br /><br />Remember, we used lazy-cons to make lazy sequences. lazy-cons acts like cons, except it does not evaluate the rest-expr until rest is called on the resulting list. We can use macroexpand-1 (which returns the unevaluated macro expansion of a macro call) to see how this works:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;user=&gt; (defn rfn [] (prn "Called") '(3))<br />&nbsp;&nbsp;#&lt;Var: user/rfn&gt;<br />&nbsp;&nbsp;user=&gt; (rfn)<br />&nbsp;&nbsp;"Called"<br />&nbsp;&nbsp;(3)<br />&nbsp;&nbsp;user=&gt; (def lazylist (lazy-cons 1 (rfn)))<br />&nbsp;&nbsp;#&lt;Var: user/lazylist&gt;<br />&nbsp;&nbsp;user=&gt; (first lazylist)<br />&nbsp;&nbsp;1<br />&nbsp;&nbsp;user=&gt; (rest lazylist)<br />&nbsp;&nbsp;"Called"<br />&nbsp;&nbsp;(3)<br />&nbsp;&nbsp;user=&gt; (rest lazylist)<br />&nbsp;&nbsp;(3)<br />&nbsp;&nbsp;user=&gt; (macroexpand-1 '(lazy-cons 1 (rfn)))       <br />&nbsp;&nbsp;(fnseq 1 (clojure/fn [] (rfn)))<br />&nbsp;&nbsp;user=&gt; (first (eval (macroexpand-1 '(lazy-cons 1 (rfn)))))<br />&nbsp;&nbsp;1<br />&nbsp;&nbsp;user=> (rest (eval (macroexpand-1 '(lazy-cons 1 (rfn)))))<br />&nbsp;&nbsp;"Called"<br />&nbsp;&nbsp;(3)<br /></span><br />So, a lazy-cons is just a short hand to using a fnseq and wrapping the rest in a function that will be called whenever rest is called on the fnseq. That's a typical use of a macro -- codifying common uses to make your programs shorter. And, lazy-cons cannot be implemented as a function, because if it were, its arguments would need to be evaluated, which defeats the purpose.<br /><br />Ok, let's write some macros (Documentation on the <a href="http://clojure.sourceforge.net/reference/macros.html" rel="self">clojure macro page</a> and the <a href="http://clojure.sourceforge.net/reference/reader.html" rel="self">clojure reader page</a>). On Lisp, section 7.3 (Defining Simple Macros) presents this one for while.<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defmacro while (test &body body)<br />&nbsp;&nbsp;&nbsp;&nbsp;`(do () ((not ,test)) ,@body))<br /></span><br />Here it is in clojure:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defmacro while [test & body]<br />&nbsp;&nbsp;&nbsp;&nbsp;`(loop [] (if ~test (do ~@body (recur)))))<br /></span><br />In clojure, you don't have many mutable objects -- here's how you use while with a thread-local var binding:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(def x 10)<br />&nbsp;&nbsp;(prn (macroexpand '(while (> x 0) (prn x) (set! x (dec x)))))<br />&nbsp;&nbsp;(binding [x 10] (while (> x 0) (prn x) (set! x (dec x))))<br /><br /></span>Here's the output:<span style="font:12px Courier, mono; "><br /><br />&nbsp;&nbsp;(loop [] (if (> x 0) (do (prn x) (set! x (dec x)) (recur))))<br />&nbsp;&nbsp;10<br />&nbsp;&nbsp;9<br />&nbsp;&nbsp;8<br />&nbsp;&nbsp;7<br />&nbsp;&nbsp;6<br />&nbsp;&nbsp;5<br />&nbsp;&nbsp;4<br />&nbsp;&nbsp;3<br />&nbsp;&nbsp;2<br />&nbsp;&nbsp;1</span>]]></content:encoded></item><item><title>20 Days of Clojure: Day 15</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-15T13:43:40-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-15.html#unique-entry-id-52</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-15.html#unique-entry-id-52</guid><content:encoded><![CDATA[<a href="http://www.cgrand.net" rel="self">Christophe Grand</a> made two observations about <a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-14.html" rel="self" title="Blog:20 Days of Clojure: Day 14">my parallel prime code</a>, which improve it quite a bit.<br /><br />First, since primes-in-list is lazy, you have to (touch) it to get it to be completely created in the agent thread. That leaves you with this:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defn par-primes-in-list [potential-primes known-primes]<br />&nbsp;&nbsp;&nbsp;&nbsp;(let [ x 10 x-times-2 (* x 2)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(! w1 (fn[w pp kp] (</span><span style="font:12px Courier, mono; font-weight:bold; font-weight:bold; ">touch</span><span style="font:12px Courier, mono; "> (primes-in-list pp kp))) (take x potential-primes) known-primes) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(! w2 (fn[w pp kp] (</span><span style="font:12px Courier, mono; font-weight:bold; font-weight:bold; ">touch</span><span style="font:12px Courier, mono; "> (primes-in-list pp kp))) (take x (drop x potential-primes)) known-primes) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(await w1 w2)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let [new-primes (concat @w1 @w2) ]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if (= (count new-primes) 0) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(recur (drop x-times-2 potential-primes) known-primes)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let [real-primes <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if (> (first new-primes) x-times-2) new-primes (primes-in-list new-primes []))]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(lazy-cat real-primes (par-primes-in-list <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(drop x-times-2 potential-primes) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(into known-primes real-primes))))))))<br /></span><br />But, the bigger difference is picking the number of potential-primes to evaluate intelligently. I had experimented with trying to do this dynamically, but without the fix above, anything you do will probably result in primes being found lazily in the main thread. Here's Christophe's code:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;&nbsp;&nbsp;(defn par-primes-in-list [potential-primes known-primes]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let [p (first potential-primes) x (quot p 2)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(! w1 (fn[w pp kp] (touch (lazy-primes-in-list pp kp))) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(take x potential-primes) known-primes)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(! w2 (fn[w pp kp] (touch (lazy-primes-in-list pp kp))) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(take (- p x) (drop x potential-primes)) known-primes)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(await w1 w2)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let [new-primes (concat @w1 @w2) ]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(lazy-cat new-primes <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(par-primes-in-list<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(drop p potential-primes)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(into known-primes new-primes))))))<br /></span><br />Christophe's observation:<br /><blockquote><p>I use the property that no number in the interval [n .. 2*n-1] is divisible by n (except n itself) so it's safe to process the whole interval with the current set of known primes. Hence this interval can be divided into m intervals (where m is the number of cores) for parallel processing.</p></blockquote>The one issue with Christophe's code it part lazy and part eager, so it's applicability depends on whether you are trying to get to a specific number the fastest or just generate primes as fast as possible. Since the number of primes to try grows as it searches, it lazily generates bigger and bigger lists of primes. I tried to find a good value to ask for where it would perform well, and chose 20390 which is big enough to show a difference and doesn't make Christophe's code do too much extra.  Here are the results:<br /><br />Christophe's: "Elapsed time: 87266.119 msecs"<br />Mine (with a touch added): "Elapsed time: 108841.354 msecs"<br />Sequential: "Elapsed time: 151075.292 msecs"]]></content:encoded></item><item><title>20 Days of Clojure: Day 14</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-14T21:37:44-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-14.html#unique-entry-id-51</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-14.html#unique-entry-id-51</guid><content:encoded><![CDATA[Ok, I'm finally getting somewhere. To start with, Rich pointed out that I could use recur to make my last prime finder stack safe and faster. Here it is:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defn primes-in-list [potential-primes known-primes]<br />&nbsp;&nbsp;&nbsp;&nbsp;(let [p (first potential-primes)] <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if (nil? p) '()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if (is-prime? p known-primes) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(lazy-cat <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(list p) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(primes-in-list (rest potential-primes) (conj known-primes p)))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let [rest-primes (rest potential-primes)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(recur rest-primes known-primes))))))<br /></span><br />Here's how I parallelized it:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(def w1 (agent 0))<br />&nbsp;&nbsp;(def w2 (agent 0))<br /><br />&nbsp;&nbsp;(defn par-primes-in-list [potential-primes known-primes]<br />&nbsp;&nbsp;&nbsp;&nbsp;(let [ x 10 x-times-2 (* x 2)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(! w1 (fn[w pp kp] (primes-in-list pp kp)) (take x potential-primes) known-primes) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(! w2 (fn[w pp kp] (primes-in-list pp kp)) (take x (drop x potential-primes)) known-primes) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(await w1 w2)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let [new-primes (concat @w1 @w2) ]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if (= (count new-primes) 0) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(recur (drop x-times-2 potential-primes) known-primes)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let [real-primes <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if (> (first new-primes) x-times-2) new-primes (primes-in-list new-primes []))]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(lazy-cat real-primes (par-primes-in-list <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(drop x-times-2 potential-primes) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(into known-primes real-primes))))))))<br /></span><br />Basically, I send lists to the agents, wait for them, and then combine their answers. The original runs at about 100% of CPU, calculates 8000 primes in 21.6 seconds and this runs at about 125%, and calculates the primes in 17.1 seconds, or in about 80% of the time.]]></content:encoded></item><item><title>20 Days of Clojure: Day 13</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-13T20:08:56-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-13.html#unique-entry-id-50</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-13.html#unique-entry-id-50</guid><content:encoded><![CDATA[My brain still hurts from thinking about parallelizing prime number generation. I think the key is still to find primes two at a time in parallel, meaning that it's only useful if you want a list, which is necessary to find the nth prime anyway.<br /><br />So, I am starting with a rewrite of prime number generation -- this one is simpler for me to understand and for some reason runs three times faster.<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defn divisible? [x y]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(= (rem x y) 0)<br />&nbsp;&nbsp;)<br /><br />&nbsp;&nbsp;(defn is-prime? [p known-primes]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every? (fn [kp] (not (divisible? p kp))) known-primes)<br />&nbsp;&nbsp;)<br /><br />&nbsp;&nbsp;(defn primes-in-list [potential-primes known-primes]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let [p (first potential-primes)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if (is-prime? p known-primes) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(lazy-cons <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(primes-in-list (rest potential-primes) (conj known-primes p)))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(primes-in-list (rest potential-primes) known-primes)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br />&nbsp;&nbsp;)<br /><br />&nbsp;&nbsp;(def primes (primes-in-list (iterate inc 2) []))<br />&nbsp;&nbsp;(time (reduce + (take 1000 primes))) <br />&nbsp;&nbsp;(time (reduce + (take 1000 primes)))<br /><br /></span>It's also lazy. Not sure why it's so much faster. Now that I can provide a list of potentials, I'll be able to run two lists in parallel, and then I have to reduce them in the main thread. When I get the lists back, I need to make sure that they aren't divisible by each other (since they won't be in each others list of known primes).]]></content:encoded></item><item><title>20 Days of Clojure: Day 12</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-12T19:37:46-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-12.html#unique-entry-id-49</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-12.html#unique-entry-id-49</guid><content:encoded><![CDATA[So, Rich thinks I'm on a fool's errand, but I'm going to keep going with this.<br /><blockquote><p>I'm sorry to say I can't think of a less promising candidate for parallelization :( The 3 things you would want in something to parallelize are 
independent data/work, moderate-to-course-grained work units and/or 
complex coordination logic that would be simplified with threads. 
(Note - wanting it to run faster is not enough :) Here you have none of those - the data/work is interdependent (more 
later), the work is very fine grained (seq walk and a remainder test), 
and the logic was pretty elegant. </p></blockquote>So, in order to have something to parallelize, I need to get one of those things. Since I am trying to make a list of primes, I'll generate them two at a time. Each check is independent. There's probably better ways to do it, but to keep my life simple, I'll just generate pairs of primes lazily, but in parallel (each member of the pair in a separate thread).<br /><br />Hmmm. I'm too tired to figure this out right now. So, for some content today, I can explain a mistake that Rich pointed out in my <a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-10.html" rel="self" title="Blog:20 Days of Clojure: Day 10">original prime sieve</a>.<br /><br />I defined primes as a function that returns a lazy seq, but a key benefit of lazy seqs is that they cache values -- so by creating a new lazy seq for each call to primes, I lose caching.  The right way is to define primes as a seq this way:<br /><br />&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(def primes (sieve (iterate inc 2)))<br /><br /></span>Then, when you do this:<br /><br />&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(time (reduce + (take 1000 primes)))<br /></span>&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(time (reduce + (take 1000 primes)))<br /></span><br />You get this:<br /><br />&nbsp;&nbsp;<span style="font:12px Courier, mono; ">"Elapsed time: 1080.253 msecs"<br /></span>&nbsp;&nbsp;<span style="font:12px Courier, mono; ">"Elapsed time: 5.36 msecs"<br /></span>]]></content:encoded></item><item><title>20 Days of Clojure: Day 11</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-11T17:40:52-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-11.html#unique-entry-id-48</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-11.html#unique-entry-id-48</guid><content:encoded><![CDATA[Ok, so now we've covered some basic clojure as lisp with immutable datastructures and built-in support for streaming (lazy) interfaces. I was playing around with Erlang right before I found clojure because I was looking for a <a href="http://clojure.sourceforge.net/features/concurrent_programming.html" rel="self">language with direct support for concurrency</a>, the lispiness and the JVM hosting were the deciding factor for me.<br /><br />I'm just getting started with clojure's concurrency support, so you'll have to bear with me as I might struggle a bit. <a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-10.html" rel="self" title="Blog:20 Days of Clojure: Day 10">Yesterday</a>, I showed you a lazy prime number sieve built using the seq interface. Today, I'm going to try to parallelize it. Since I don't really know what I'm doing, I'll take you through my thinking.<br /><br />There are three ways in clojure to deal with memory in threads: <a href="http://clojure.sourceforge.net/reference/vars.html" rel="self">dynamic vars</a>, <a href="http://clojure.sourceforge.net/reference/refs.html" rel="self">software transactional memory</a>, and <a href="http://clojure.sourceforge.net/reference/agents.html" rel="self">agents</a>. I get dynamic vars and agents because I use things like them all the time. Dynamic vars are basically thread-local storage and agents are a kind of <a href="http://www.cs.wustl.edu/~schmidt/PDF/Act-Obj.pdf" rel="self">ActiveObject [pdf]</a>. Thread local storage isn't going to work for me since I need to gather answers from my worker threads, not have each work independently (there may be dynamic vars in the solution, but it's not the way you communicate between threads).  <br /><br />ActiveObject is a pattern that serializes access to an object so that one thing happens to it at a time. Individual calls are put in a queue which is serviced by a thread assigned to the object, and that thread is the only one to touch the object. In clojure, there's actually a thread pool that services all agents. Now, that I think about it -- maybe this will work. I kind of wanted to play with STM's, but I think I understand this better and I feel I can still make it streamable.<br /><br />Here's my naive idea. I'm going to make an agent per prime, then ask them all if a number is divisible by them, then wait for them all and if it is, make a new agent and go on.  That seems really dumb unless agents are super-cheap. Let's see. <br /><br />I'll start with something simple:<br /><br />&nbsp;<span style="font:12px Courier, mono; ">(defn divisible? [x y] (= (rem x y) 0))</span><br /><br />I'll define my agents to be maps that look like this at the start {:prime 2} and then define this:<br /><br />&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn check-divisible [agent x] <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(merge agent {:last x :notdivisible (not (divisible? x (:prime agent)))}))<br /></span><br />Here's a quick Repl session so far (no real agents yet)<br /><br />&nbsp;&nbsp;<span style="font:12px Courier, mono; ">user=> (check-divisible {:prime 2} 3)<br /></span>&nbsp;&nbsp;<span style="font:12px Courier, mono; ">{:last 3, :prime 2, :notdivisible true}<br /></span>&nbsp;&nbsp;<span style="font:12px Courier, mono; ">user=> (check-divisible {:prime 2} 4)<br /></span>&nbsp;&nbsp;<span style="font:12px Courier, mono; ">{:last 4, :prime 2, :notdivisible false}<br /></span>&nbsp;&nbsp;<span style="font:12px Courier, mono; ">user=> (check-divisible {:prime 2} 5)<br /></span>&nbsp;&nbsp;<span style="font:12px Courier, mono; ">{:last 5, :prime 2, :notdivisible true}<br /></span><br />Ok, now I'll start. Here's something weird -- I just did a CPU snapshot running the sequential prime sieve from yesterday and it looks like this:<br /><br /><img class="imageStyle" alt="cpu" src="http://www.loufranco.com/blog/files/page2_blog_entry48_1.png" width="124" height="98"/><br /><br />I don't know what to make of that -- I know purely functional programs are easy to parallelize, but this sieve seems particularly serial in implementation. Anyway, I'll press on:<br /><br />Here's my agent-sieve<br /><br />&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn agent-sieve [a ints]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(let [p (next-prime a ints)]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(lazy-cons p (agent-sieve (cons {:prime p} a) (iterate inc (inc p))))))<br /></span><br />I keep stuffing a new agent list into the rest of a lazy-cons -- just need to write next-prime:<br /><br />&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn next-prime [agents ints]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(let [x (first ints)]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(check-divisible-by-agents (take-nth 2 agents) x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(check-divisible-by-agents (take-nth 2 (drop 1 agents)) x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(apply await agents)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(if (every? (fn [a] (or (not= (:last @a) x) (:notdivisible @a))) agents)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">x<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(next-prime agents (rest ints)))))<br /></span><br />Ok, so I'm starting to see problems -- for one, I really want to short-circuit if an agent is divisible, but I also want to split up the work. So I decide to make a check-divisible-by-agents that will chain along each agent and stop when it finds an agent that divides into the prime. I start two chains each with half of the agents and wait -- this will mean that if one is done, the other won't know and it will keep going (which is bad).  I press on, here's the chain<br /><br />&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn check-divisible-by-agents [agents x]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(if (not= (count agents) 0)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(! (first agents) <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(fn [a y rest-agents]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(let [newstate (check-divisible a y)]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(if (:notdivisible newstate) <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(check-divisible-by-agents rest-agents y))         <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">newstate)) <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">x (rest agents))))<br /></span><br />So, I run a function on the first agent in the list (with !) that sets the new state to whether it was divisible. If it's not divisible then I recursively call the check on the rest of the agents. <br /><br />I'm not getting primes yet -- but it's close.  I don't think await works like I think it does -- even though I am chaining ! inside of !, I think that doesn't count for await.  Here's is next-prime rewritten.<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;(defn next-prime [agents ints]<br />&nbsp;&nbsp;&nbsp;&nbsp;(let [x (first ints)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(check-divisible-by-agents (take-nth 2 agents) x)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(check-divisible-by-agents (take-nth 2 (drop 1 agents)) x)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if (every? <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn [a] <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(await a)     <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or (not= (:last @a) x)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:notdivisible @a)))  <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;agents)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(next-prime agents (rest ints)))))</span><br /><br />Ok, I get primes now<br /><br />To tell the truth, I can't believe I got this working at all, but running (time) on the serial and parallel versions give me this:<br /><br /><strong>sequential:</strong> "Elapsed time: 9.517 msecs"<br /><strong>parallel:</strong> "Elapsed time: 251.025 msecs"<br /><br />So, obviously, this is not a good way to do this.  I don't know yet if it's because I'm using too many agents or the extra work I'm doing because I'm not short-circuiting. Anyway, that's enough for now.<br /><br /><strong>Update: </strong>After a night's rest, I think I know what's going on with the other thread in the sequential version. My guess is the GC. The only other alternative I can come up with is that under the hoods clojure parallelizes some things I'm using. I started a <a href="http://groups.google.com/group/clojure/browse_frm/thread/825e4e2bf4a7827e" rel="self">thread on parallelizing prime sieves on the clojure google group</a>.<br /><br />(<a href="http://wmassdevs.com/wordpress/2008/02/28/clojure-talk-with-rich-hickey-on-march-20/" rel="self" title="Rich Hickey in Northampton">clojure day (March 20) in Northampton, MA is coming soon</a>)]]></content:encoded></item><item><title>20 Days of Clojure: Day 10</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-10T20:51:29-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-10.html#unique-entry-id-47</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-10.html#unique-entry-id-47</guid><content:encoded><![CDATA[<span style="font-size:13px; ">Woo hoo -- half way through.  Well, not yet, but at the end of this entry. <br /><br /></span><span style="font-size:13px; "><a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-9.html" rel="self" title="Blog:20 Days of Clojure: Day 9">Yesterday, we saw sequences</a></span><span style="font-size:13px; ">. Now, here's a way to use them: the Prime Sieve of Eratosthenes. Here it is in Scheme from the </span><span style="font-size:13px; "><a href="http://video.google.com/videoplay?docid=-987280451799958416" rel="self">SICP lectures</a></span><span style="font-size:13px; ">:<br /><br /></span>&nbsp;<span style="font:13px Courier, mono; ">(define (sieve s)<br /></span>&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(cons-stream (head s)<br /></span>&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(sieve (filter<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(lambda  (x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(not <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(divisible? x (head s))))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(tail s)))))<br /><br /></span>&nbsp;<span style="font:13px Courier, mono; ">(define primes <br /></span>&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(sieve (integers-from 2)))<br /></span><span style="font-size:13px; "><br />And here is a complete clojure program (all undefined functions are defined as part of the seq interface)<br /><br /></span>&nbsp;<span style="font:13px Courier, mono; ">(defn sieve [s]<br /></span>&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(lazy-cons (first s)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(sieve (filter<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(fn [x]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(not<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(= (rem x (first s)) 0)))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(rest s)))))<br /><br /></span>&nbsp;<span style="font:13px Courier, mono; ">(defn primes []<br /></span>&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(sieve (iterate inc 2)))<br /><br /></span>&nbsp;<span style="font:13px Courier, mono; ">(prn (take 10 (primes)))<br /></span><span style="font-size:13px; "><br />Here's how it works. The function sieve is a sequence and takes a sequence (in this case we pass in all numbers greater than or equal to two).<br /><br />Working from the inside, this filter:<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(filter<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(fn [x]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(not<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(= (rem x (first s)) 0)))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:13px Courier, mono; ">(rest s))<br /></span><span style="font-size:13px; "><br />Filters the rest of the passed in stream based on whether the items are divisible by the first, so only the ones not divisible are passed. So for (iterate inc 2) we get a stream of all numbers not divsible by two.<br /><br />The first of that stream is 3, and it is passed into sieve, so the resulting stream is all those not divisible by two (already filtered) or three. Once the stream is returned (lazily), the heads are lazy-cons'd on (that means that you get a stream with a given first and the rest set to the given stream). The first head was 2, the second was 3, the next one is 5 (the first number not divisible by 2 and 3), and so on.<br /><br /></span>(<a href="http://wmassdevs.com/wordpress/2008/02/28/clojure-talk-with-rich-hickey-on-march-20/" rel="self" title="Rich Hickey in Northampton">clojure day (March 20) in Northampton, MA is coming soon</a>)<br /><br />Update: It may look like sieve is an infinitely recursive function, but it's not. lazy-cons is a macro that doesn't evaluate its argument until rest is called on its return value. I haven't looked at the implementation, but I imagine its implemented similarly to how cons-stream in the SICP lecture is.<br /><br />Update: <a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-12.html" rel="self" title="Blog:20 Days of Clojure: Day 12">This prime sieve has been corrected here</a>.]]></content:encoded></item><item><title>20 Days of Clojure: Day 9</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-09T12:16:59-04:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-9.html#unique-entry-id-46</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-9.html#unique-entry-id-46</guid><content:encoded><![CDATA[<span style="font-size:13px; ">News from Rich on a </span><span style="font-size:13px; "><a href="http://groups.google.com/group/clojure/browse_thread/thread/52d11c95895af4df?hl=en" rel="self">optimization he found for vectors</a></span><span style="font-size:13px; ">:<br /></span><blockquote><p>I re-read Okasaki's paper yesterday and woke up today with an idea for speeding up the Clojure vector conj and pop. They are now 2-5x fasterthan they were. The trick is to keep the tail of the vector out of the tree until it is a full (32-element) node. Note that this greatlyspeeds up vector construction, which typically consists of repeatedly conj'ing onto [].</p></blockquote><span style="font-size:13px; ">Today, I'm going to look at sequences. I think it's helpful to go back to the SICP -- this time, the lecture on stream machines:<br /><br /></span><object width="425" height="355"><param name="movie" value="http://www.youtube.com/v/RcPhdoL8RcE"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/RcPhdoL8RcE" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object><span style="font-size:13px; "><br /></span><span style="font-size:13px; "><br />This is just a small part of the whole </span><span style="font-size:13px; "><a href="http://video.google.com/videoplay?docid=-7496022041893185723&q=structure+computer+programs+abelson+site%3Avideo.google.com&total=21&start=0&num=10&so=0&type=search&plindex=5" rel="self">SICP stream machine lecture</a></span><span style="font-size:13px; "> (and </span><span style="font-size:13px; "><a href="http://video.google.com/videoplay?docid=-987280451799958416" rel="self">Streams Part II</a></span><span style="font-size:13px; ">).<br /><br /></span><span style="font-size:13px; "><a href="http://clojure.sourceforge.net/reference/sequences.html" rel="self">Sequences in clojure</a></span><span style="font-size:13px; "> are lazy like stream as described in the video, and if you watch the whole lecture, you will see a rich stream library built up that is present in clojure. <br /><br />This means that many operations can be incredibly efficient, but seem like they are operating on gigantic data structures at once (since my day job is image processing, this is especially intriguing to me -- maybe more on that later). To really see this, you need to play with infinite sequences. In clojure, it's easy to create an infinite sequence with cycle -- (cycle [1 2 3]) returns a sequence which continuously yields 1, 2, 3, 1, 2, 3, etc. If you use sequence operations on it, you can get a feel for how laziness works because it's obvious that these functions could not possibly be consuming the whole sequence.  Here's a clojure Repl script.<br /><br /></span><span style="font:13px Courier, mono; ">user=> (def cyc123 (cycle [1 2 3]))<br />#&lt;Var: user/cyc123&gt;<br />user=> (every? (fn [x] (= 1 x)) cyc123)                       <br />false<br />user=> (take 5 cyc123)<br />(1 2 3 1 2)<br />user=> (take 5 (filter (fn [x] (= x 1)) cyc123))<br />(1 1 1 1 1)<br />user=> (take 5 (drop 1 cyc123))<br />(2 3 1 2 3)<br />user=> (take 5 (interleave cyc123 cyc123))<br />(1 1 2 2 3)<br />user=> (take 5 (take-nth 3 cyc123))<br />(1 1 1 1 1)<br />user=> (take 10 (for [x cyc123] (< x 3) x))<br />(1 2 1 2 1 2 1 2 1 2)<br />user=> (mapcat (fn [x y] (list x y)) cyc123 '(10 11 12))<br />(1 10 2 11 3 12)<br /></span><span style="font-size:13px; "><br />More on this tomorrow.<br /></span>]]></content:encoded></item><item><title>20 Days of Clojure: Day 8</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-08T11:14:55-05:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-8.html#unique-entry-id-45</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-8.html#unique-entry-id-45</guid><content:encoded><![CDATA[<span style="font-size:13px; ">Rich Hickey comments on </span><span style="font-size:13px; "><a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-7.html" rel="self" title="Blog:20 Days of Clojure: Day 7">yesterday's post</a></span><span style="font-size:13px; "> on the </span><span style="font-size:13px; "><a href="http://groups.google.com/group/clojure/browse_frm/thread/52d11c95895af4df" rel="self">clojure google group</a></span><span style="font-size:13px; ">:<br /></span><blockquote><p>An interesting point of comparison with purely-functional solutions such as that which Okasaki writes about is that the Clojure vector can be log<sub>32</sub>N specifically because I can use mutation - when cloning, i.e. the tree is log<sub>32</sub>N deep and a node can be copied in O(1) time due to arraycopy + indexed array set. And yes, the vectors are optimized for lookup - in practice, log<sub>32</sub>N blows logN out of the water.</p></blockquote><span style="font-size:13px; ">Exactly -- PersistentVector's internals are not purely functional. New objects (during construction only) make an array copy of Object arrays from existing vectors, then make changes to the copied array before returning. As Rich points out, this makes some operations O(1). And for comparison, a clojure vector of 32k elements is only 2 levels deep, but if implemented with a log</span><sub>2</sub><span style="font-size:13px; ">N structure would be 15 deep (with average access in maybe 7 operations). Since access by index is a very common operation, you can see that this would make a big difference.<br /><br />Today, I want to look at PersistentHashMap.java which is the implementation of clojure hash-maps. There are actually four implementations of the map interface (hash-map, sorted-map, struct-map, and array-map), but hash-map is what the reader will give you for when you build up a map with {}.<br /><br />A comment on the top of the source file says that it's a persistent version of </span><span style="font-size:13px; "><a href="http://lampwww.epfl.ch/papers/idealhashtrees.pdf" rel="self">Phil Bagwell's Hash Array Mapped Trie</a></span><span style="font-size:13px; ">. According to that paper, it looks like the bits of hashes of the key are used to traverse a </span><span style="font-size:13px; "><a href="http://en.wikipedia.org/wiki/Trie" rel="self" title="Wikipedia entry on Trie">trie</a></span><span style="font-size:13px; ">. Let's see how it's done in clojure.<br /><br />The first thing I like to look at is how lookup is done, that gives me a sense of the structure. So, to start with, here's entryAt:<br /><br /></span>&nbsp;<span style="font:13px Courier, mono; ">public IMapEntry entryAt(Object key){<br /></span>&nbsp;&nbsp;<span style="font:13px Courier, mono; ">return root.find(RT.hash(key), key);<br /></span>&nbsp;<span style="font:13px Courier, mono; ">}<br /></span><span style="font-size:13px; "><br />Simple enough -- it uses the root node to start the traversal. The root node is an INode, and clojure uses polymorphism to get different behavior for different nodes. There are five types of nodes, </span><span style="font-size:13px; font-weight:bold; ">EmptyNode</span><span style="font-size:13px; ">, </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; ">, </span><span style="font-size:13px; font-weight:bold; ">HashCollisionNode</span><span style="font-size:13px; ">, </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; ">, and </span><span style="font-size:13px; font-weight:bold; ">FullNode</span><span style="font-size:13px; ">. An empty hash-map has its root set to an instance of </span><span style="font-size:13px; font-weight:bold; ">EmptyNode</span><span style="font-size:13px; ">, which is an implementation of the </span><span style="font-size:13px; "><a href="http://www.cs.oberlin.edu/~jwalker/nullObjPattern/" rel="self">Null Object design pattern</a></span><span style="font-size:13px; ">, and find() on it returns null (by the way, the entire structure is a </span><span style="font-size:13px; "><a href="http://en.wikipedia.org/wiki/Composite_pattern" rel="self">Composite design pattern</a></span><span style="font-size:13px; ">, and by using each node type to handle part of traversal, I guess he's also using a </span><span style="font-size:13px; "><a href="http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern" rel="self">Chain of Responsibility</a></span><span style="font-size:13px; "> -- I mention this because there are many OO design patterns used in the Java implementation of clojure -- some by name, so if you are going to look at the code, you'll want to be familiar with these </span><span style="font-size:13px; "><a href="http://en.wikipedia.org/wiki/Design_Patterns" rel="self">patterns</a></span><span style="font-size:13px; ">). <br /><br />If I assoc() onto a hash-map, root.assoc() is called which is supposed to return a new root. EmptyNode.assoc() simply creates a </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; "> with the hash, key and value, so a map with one key has its root set to a </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; ">.<br /><br />If I call find() on a </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; ">, that's pretty simple too.  If this is the node I am looking for, it returns this, otherwise null.<br /><br />If I assoc onto a </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; ">, here is what can happen:<br /></span><ol class="arabic-numbers"><li><span style="font-size:13px; ">If the key and value match the </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; ">, then it is just returned -- nothing is created since you haven't changed anything.</span></li><li><span style="font-size:13px; ">If just the key is the same as this node, a new </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; "> is created with the same key and the new value and returned (remember, this is a persistent data-structure, so we do not change the </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; ">, we create new nodes to build up a new hash-map). </span></li><li><span style="font-size:13px; ">If the hash is the same, but the key is different, then a new </span><span style="font-size:13px; font-weight:bold; ">HashCollisionNode</span><span style="font-size:13px; "> is created that holds onto this </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; "> and a new one that has the same key and the new value. </span><span style="font-size:13px; font-weight:bold; ">HashCollisionNodes</span><span style="font-size:13px; "> simply hold onto an array of </span><span style="font-size:13px; font-weight:bold; ">LeafNodes</span><span style="font-size:13px; "> whose keys have the same hash.</span></li><li><span style="font-size:13px; ">If the new key doesn't have the same hash (the common case), then a </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; "> will be created. At first it contains just the old </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; "> in its array of nodes, and then assoc() is called on it with the new key and value. </span></li></ol><span style="font-size:13px; ">Case #4 is where we start to build up the trie. The hash of the key is going to be used to traverse the trie later, and a </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; "> knows if it contains the </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; "> you are looking for. A </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; "> has a bitmap of 32 bits. The bit corresponding to the bottom five bits of the hash of the LeafNode is turned on to indicate that the </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; "> is to be found in this branch (it can have 32 branches). For example if the bottom five bits of the key hash are 01100, then the 12th bit of the bitmap is turned on, and the node is put at this branch.<br /><br />If the bitmap bit for the new leaf node is off, then a new </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; "> is created with a new bitmap with the new bit turned on, and the node is put in its array which will be one bigger than the one we started with. If we kept doing this and hit each bit, the 32nd assoc would result in a </span><span style="font-size:13px; font-weight:bold; ">FullNode</span><span style="font-size:13px; "> -- which is a simple case of a </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; ">, except it knows that if it had a bitmap, all bits would be set. Again, remember, we create a new node because we never change nodes in a persistent data structure.<br /><br />If the new leaf node has a bottom five bits that match a node already in this </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; "> (the corresponding bit is already turned on), then we assoc() this key/value onto the node with the same five bits. <br /><br />I haven't mentioned this yet, but assoc takes a shift argument -- so far, that has always been 0 and that meant to use the bottom five bits (use a 0 shift) of the hash in any </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNodes</span><span style="font-size:13px; ">. On this assoc call, we're now going to pass in (shift+5) so that the next 5 bits will be used on any </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNodes</span><span style="font-size:13px; "> created under here. Later when we traverse, we'll use the bottom five bits on the first </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; "> we see, then the next five bits on the next one and so on. When we've used up all 32 bits of the hash, we should be at our </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; "> or a </span><span style="font-size:13px; font-weight:bold; ">HashCollisionNode</span><span style="font-size:13px; "> (meaning all 32 bits matched).<br /><br />So here's find(): <br /></span><ol class="arabic-numbers"><li><span style="font-size:13px; ">If the node is an </span><span style="font-size:13px; font-weight:bold; ">EmptyNode</span><span style="font-size:13px; ">, it returns null. </span></li><li><span style="font-size:13px; ">If the node is a </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; ">, it returns itself if the key matches, otherwise null.</span></li><li><span style="font-size:13px; ">If the node is a </span><span style="font-size:13px; font-weight:bold; ">HashCollisionNode</span><span style="font-size:13px; ">, it calls find() on each </span><span style="font-size:13px; font-weight:bold; ">LeafNode</span><span style="font-size:13px; "> it holds, if any return themselves, then that is returned, otherwise null. </span></li><li><span style="font-size:13px; ">If the node is a </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; ">, it first checks to see if it has a node where the five bits being used matches and then calls find() on it, if it doesn't, it returns null. </span></li><li><span style="font-size:13px; ">If the node is a </span><span style="font-size:13px; font-weight:bold; ">FullNode</span><span style="font-size:13px; ">, it acts like a </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; "> with all bits of the bitmap set, so it just calls find() on the node corresponding the five bits in the hash at its level.</span></li></ol><span style="font-size:13px; "><br />The data structure is persistent because it never changes constructed nodes. During an assoc, all non-traversed paths will be shared, and only the path that changed will be new.<br /><br />I should also mention that </span><span style="font-size:13px; font-weight:bold; ">FullNode</span><span style="font-size:13px; "> is purely an optimization -- a </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; "> could be used in its place, but it saves some branch calls to have them sprinkled throughout the map. Also, using a bitmap in </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNode</span><span style="font-size:13px; "> is also an optimization. An INode array of 32 elements could have always been constructed with null signifying that there was no nodes in that branch, but that would be very wasteful in space, and so by using the bitmap,  </span><span style="font-size:13px; font-weight:bold; ">BitmapIndexedNodes</span><span style="font-size:13px; "> have an INode array of the exact length they need.</span>]]></content:encoded></item><item><title>20 Days of Clojure: Day 7</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-07T21:06:51-05:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-7.html#unique-entry-id-44</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-7.html#unique-entry-id-44</guid><content:encoded><![CDATA[Ok, I'm going to try to describe how vectors are implemented in clojure. The implementation is in:<br /><br />&nbsp;&nbsp;&nbsp;src/jvm/clojure/lang/PersistentVector.java <br /><br />if you want to see the code.  I'm going to try to go through the important bits here.<br /><br />The PersistentVector object has three members: two ints named cnt and shift, and an Object[] named root. A simple PersistentVector built from this line:<br /><br />&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(def v1 [1 2 3])</span><br /><br />would look like this (using curly braces for root because it is a Java array):<br /><br />&nbsp;&nbsp;&nbsp;<strong>cnt:</strong> 3<br />&nbsp;&nbsp;&nbsp;<strong>shift:</strong> 0<br />&nbsp;&nbsp;&nbsp;<strong>root:</strong> { 1, 2, 3 }<br /><br />cnt is the count of elements and (count v1) simply returns it and is O(1)  -- I'll explain shift later, and root is the object array. When shift is 0, this line:<br /><br />&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(nth v1 1)</span><br /><br />Just simply resolves to root[1], and returns 2, and in this simple case is also O(1). If I do this:<br /><br />&nbsp;&nbsp;&nbsp;(def v2 (assoc v1 1 4))<br /><br />which returns a new vector, but with the value at index 1 set to 4, you get another PersistentVector that looks like this:<br /><br />&nbsp;&nbsp;&nbsp;<strong>cnt:</strong> 3<br />&nbsp;&nbsp;&nbsp;<strong>shift:</strong> 0<br />&nbsp;&nbsp;&nbsp;<strong>root:</strong> { 1, 4, 3 }<br /><br />The 1 and the 3 are shared between the v1 and v3 array. If I do this:<br /><br />&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(conj v1 5)</span><br /><br />I'll get yet another PersistentVector that looks like this:<br /><br />&nbsp;&nbsp;&nbsp;<strong>cnt:</strong> 4<br />&nbsp;&nbsp;&nbsp;<strong>shift:</strong> 0<br />&nbsp;&nbsp;&nbsp;<strong>root:</strong> { 1, 2, 3, 5 }<br /><br />with the 1, 2, and 3 shared with v1 (and the 1 and 3 shared with v2). This is all very simple until, you conj onto a vector of 32 elements. When the root array has 32 elements, then adding one more element (33) returns a new PeristentVector that looks like this (assume the starting array had 1, 2, 3, ... 32)<br /><br />&nbsp;&nbsp;&nbsp;<strong>cnt:</strong> 33<br />&nbsp;&nbsp;&nbsp;<strong>shift:</strong> 5<br />&nbsp;&nbsp;&nbsp;<strong>root:</strong> { {1, 2, 3, ...,  32 }, { 33 } }<br /><br />Root is a Java Object[] with the 0th element set to the Object[] from the input vector to conj (not a clone, but the actual one), and the next element is an array of just the new value. If I conj onto that, I get a new Vector:<br /><br />&nbsp;&nbsp;&nbsp;<strong>cnt:</strong> 34<br />&nbsp;&nbsp;&nbsp;<strong>shift:</strong> 5<br />&nbsp;&nbsp;&nbsp;<strong>root:</strong> { {1, 2, 3, ...,  32 }, { 33, 34 } }<br /><br />Now, I can explain <strong>shift</strong>. When a method that takes an index is called, a bit shift is done on it to determine how many levels deep in the structure we need to go to get to the part of the datastructure that has the element at that index. For instance, here is the main Java for nth(i):<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">Object[] arr = root;<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">for(int level = shift; level > 0; level -= 5)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">arr = (Object[]) arr[(i >>> level) & 0x01f];<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">return arr[i & 0x01f];</span><br /><br />so, when i < 32, then i >>> level is 0, and arr will be root[0] (the array of 32 elements). Then we return arr[i & 0x01f] (which is i % 32), to get the ith element in that array. <br /><br />When i == 32, then (i >>> level) is 1, arr is root[1], and then we return arr[i%32] which is the 0th element. Now, if I do an assoc to set the 0th element to 100, I get this PersistentVector:<br /><br />&nbsp;&nbsp;&nbsp;<strong>cnt:</strong> 34<br />&nbsp;&nbsp;&nbsp;<strong>shift:</strong> 5<br />&nbsp;&nbsp;&nbsp;<strong>root:</strong> { {100, 2, 3, 4, ...,  32 }, { 33, 34 } }<br /><br />assoc calls a recursive function (doAssoc). First it clones root so that the new root is an array of two elements, each an object array. Then it determines that index 0 is in the 0th branch and does an assoc on that, decrementing the shift by 5 and setting the index to (index % 32). This recursive call clones the array at root[0]. Since shift is now 0, it is at the base case of the recursion, and so it sets root[0][0] to 100. All of the numbers and the entire array at root[1] is shared with the starting vector.  Here is the Java code for that (doAssoc is called with the arguments shift, root, the index, and the new value) -- the return is the new root:<br /><br />&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">private static Object[] doAssoc(int level, Object[] arr, int i, Object val){<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">Object[] ret = arr.clone();<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">if(level == 0)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">{<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">ret[i & 0x01f] = val;<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">}<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">else<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">{<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">int subidx = (i >>> level) & 0x01f;<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">ret[subidx] = doAssoc(level - 5, (Object[]) arr[subidx], i, val);</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">}<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">return ret;<br /></span>&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">}</span><br /><br />By now, you might have realized that we are building up a tree.  If I keep conjing on numbers in order starting at 1, eventually I will conj on 65. If so, I get this<br /><br />&nbsp;&nbsp;&nbsp;<strong>cnt:</strong> 65<br />&nbsp;&nbsp;&nbsp;<strong>shift:</strong> 5<br />&nbsp;&nbsp;&nbsp;<strong>root:</strong> { {1, 2, 3, 4, ...,  32 },  { 33, 34, 35, ... 64 }, { 65 } }<br /><br />Graphically, it looks like this (for 1..32 elements)<br /><br /><span style="font:12px Courier, mono; ">+-------------+<br />|{1,2,3,...32}|<br />+-------------+</span><br /><br />and then for up to 32<sup>2</sup>, it looks like this:<br /><br /><span style="font:12px Courier, mono; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+-------+<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;{&nbsp;&nbsp;&nbsp;}&nbsp;|<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+--+-+--+<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;|<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+--------+&nbsp;+----------+<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />+------+------+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+--------+-------+<br />|{1,2,3,...32}|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|{33,34,35,...64}|<br />+-------------+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+----------------+</span><br /><br />And, we get another level at 32<sup>2</sup>+1 (1025) elements, and another at 32k+1. This explains how index access is O(log<sub>32</sub>N). Another important point, is that not only is a PersistentVector immutable from an interface perspective, but it's internally immutable, and each individual Object[] that makes up the tree is never changed in a constructed vector. If it needs to change in a new vector, it is cloned and the changed clone is used in the new PersistentVector -- the benefit of this is that the vector never needs to lock. This may seem like a small point, but I believe that this is not a requirement of Persistence -- but this extra work makes vector very suitable for concurrent applications.<br /><br />This implementation is different from the one described in the Okasaki paper from <a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-6.html" rel="self" title="Blog:20 Days of Clojure: Day 6">yesterday</a>. Rich appears to be trading away O(1) consing for better index performance, which was O(log<sub>2</sub>N) in that paper.<br /><br />(<a href="http://wmassdevs.com/wordpress/2008/02/28/clojure-talk-with-rich-hickey-on-march-20/" rel="self" title="Rich Hickey in Northampton">clojure day (March 20) in Northampton, MA is coming soon</a>)<br /><br />Update: Made a few corrections]]></content:encoded></item><item><title>20 Days of Clojure: Day 6</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-06T00:19:51-05:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-6.html#unique-entry-id-43</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-6.html#unique-entry-id-43</guid><content:encoded><![CDATA[So far, I've been working on the "clojure is a dialect of Lisp" part of the description of clojure. One of the things Lisps allow is purely functional programming, but to enforce it you need immutable datatypes. One of the things that bothered me as a C programmer, is that I could never understand how it worked for anything more complicated than a string.  Then I saw persistent data-structures. Their existence in clojure is what made me think that purely functional programming could work in real programs.<br /><br />The <a href="http://clojure.sourceforge.net/reference/data_structures.html" rel="self" title="Clojure Data Structures">clojure page on data structures,</a> but more importantly check out <a href="http://clojure.blip.tv/#714056" rel="self" title="Clojure TV on Data Structures">clojure TV on collections</a>.<br /><br />If you're interested in how these data structures are implemented, you want to read Okasaki. I would start here with his description of a <a href="http://citeseer.ist.psu.edu/okasaki95purely.html" rel="self">persistent random access list</a>, which I think is one of the more accessible.<br /><br />Tomorrow, I'm going to try to expand on this by describing how vectors are implemented in clojure.]]></content:encoded></item><item><title>20 Days of Clojure: Day 5</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-05T07:04:31-05:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-5.html#unique-entry-id-42</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-5.html#unique-entry-id-42</guid><content:encoded><![CDATA[This SICP lecture shows some of the power of Lisp by building a symbolic differentiator in a very small amount of code, and is also the first one to introduce the idea that code is data and data is code (watch from the beginning to 29:00 -- at 13:00 he starts talking about using Lisp as the data format):<br /><br /><embed style="width:400px; height:326px;" id="VideoPlayback" type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docId=5571878527594356342&hl=en" flashvars=""> </embed><br /><br />Here is the first symbolic differentiator he writes (but, in clojure)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn atom? [x]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(not (instance? clojure.lang.IPersistentCollection x)))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn const? [expr val] (and (atom? expr) (not= expr val)))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn same-var? [expr val] (and (atom? expr) (= expr val)))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn arith? [expr sym] (and (not (atom? expr)) (= (first expr) sym)))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn sum? [expr] (arith? expr '+))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn prod? [expr] (arith? expr '*))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn a1 [expr] (frest expr))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn a2 [expr] (first (rrest expr)))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn m1 [expr] (frest expr))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn m2 [expr] (first (rrest expr)))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn deriv [expr val] (<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">cond <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(const? expr val) 0 <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(same-var? expr val) 1<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(sum? expr) <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(list '+ (deriv (a1 expr) val) (deriv (a2 expr) val))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(prod? expr) <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(list '+ (list '* (m1 expr) (deriv (m2 expr) val)) <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(list '* (m2 expr) (deriv (m1 expr) val))<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(:else) nil<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">)<br /><br /></span>The things to note:<br /><ol class="arabic-numbers"><li>Quote syntax, which uses '</li><li>first and rest which are car and cdr.  Clojure also supports combinations like frest (cadr) and rrest (cddr)</li><li>In clojure, extra parens are usually not necessary -- look at how cond is implemented to use variable arguments rather than a single list argument (which would require extra parens)</li><li>My first usage of Java interop (using instance? to find out if an expression is atomic or a collection)</li></ol>]]></content:encoded></item><item><title>20 Days of Clojure: Day 4</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-04T13:31:47-05:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-4.html#unique-entry-id-41</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-4.html#unique-entry-id-41</guid><content:encoded><![CDATA[Continuing from yesterday, we made our first <a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-3.html" rel="self" title="Blog:20 Days of Clojure: Day 3">function that takes a function and returns a function</a>. Go to 43:00 in this video to see why (you can stop at 54:00):<br /><br /><embed style="width:400px; height:326px;" id="VideoPlayback" type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docId=-3980624564484146912&hl=en" flashvars=""> </embed><br /><br />In this example, we take the first-order functions idea further and define a derivative function (that takes and returns functions) and a newton function (which takes a function and uses fixed-point).  Here it is in clojure (you can find fixed-point and other functions in yesterday's post):<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn square [x] (* x x))<br /></span><span style="font:12px Courier, mono; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn deriv [f]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(let [dx 0.000001]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(fn [x] (/ (- (f (+ x dx)) (f x)) dx))))<br /></span><span style="font:12px Courier, mono; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn newton [f guess]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(let [df (deriv f)]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(fixed-point (fn [x] (- x (/ (f x) (df x)))) guess)))<br /></span><span style="font:12px Courier, mono; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn sqrt [x] (newton (fn [y] (- x (square y))) 1))</span><br /><br />(<a href="http://wmassdevs.com/wordpress/2008/02/28/clojure-talk-with-rich-hickey-on-march-20/" rel="self" title="Rich Hickey in Northampton">clojure day (March 20) in Northampton, MA is coming soon</a>)]]></content:encoded></item><item><title>20 Days of Clojure: Day 3</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-03T12:53:51-05:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-3.html#unique-entry-id-40</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-3.html#unique-entry-id-40</guid><content:encoded><![CDATA[Ok, so first we made <a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-1.html" rel="self" title="Blog:20 Days of Clojure: Day 1">a very hard-coded sqrt</a>, then we improved it by adding <a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-2.html" rel="self" title="Blog:20 Days of Clojure: Day 2">the concept of fixed points</a>, which made the algorithm easier to see in the code. Here's how we can improve it even further. Go to 32:30 in this video (stop at the break at 43:00):<br /><br /><embed style="width:400px; height:326px;" id="VideoPlayback" type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docId=-3980624564484146912&hl=en" flashvars=""> </embed><br /><br />First we define an average-damp function. This function takes a function as its argument and returns another function which takes a number and returns the average of that number and result of calling the function argument on the number.  It's easier to say that in clojure:<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn average-damp [f]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(fn [x] (average x (f x))))<br /></span><br />f is a function, average-damp creates a new function that takes x (a number) and that new function averages x and f(x).<br /><br />Now that I have that, I define sqrt like this (you can find <a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-2.html" rel="self" title="Blog:20 Days of Clojure: Day 2">average and fixed-point in yesterday's post</a>):<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn sqrt [x] (fixed-point (average-damp (fn [y] (/ x y))) 1))</span><br /><br />Tomorrow, we'll use this to implement another way of finding sqrt.]]></content:encoded></item><item><title>20 Days of Clojure: Day 2</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-02T12:04:27-05:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-2.html#unique-entry-id-39</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-2.html#unique-entry-id-39</guid><content:encoded><![CDATA[<a href="http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-1.html" rel="self" title="Blog:20 Days of Clojure: Day 1">Yesterday</a>, we built a simple sqrt using Heron of Alexandria's algorithm. The problem with the code is that it had some generically useful ideas, but it was all hard-coded to only work with sqrt. Also, it was not clear what exactly the algorithm was.<br /><br />In the SICP lecture they fix it by passing functions around since Lisp treats functions as first-class data-types. Here's the fix explained (23:30 in the video, stop at 32:30):<br /><br /><embed style="width:400px; height:326px;" id="VideoPlayback" type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docId=-3980624564484146912&hl=en" flashvars=""> </embed><br /><br />See the video for the Scheme implementation. Here it is in clojure.<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn sum ([] 0)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">([x] x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">([x & more] (+ x (apply sum more) )))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn average<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">([] 0)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">([x] x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">([x & more]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(/ (+ x (apply sum more)) (+ 1 (count more)))))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn abs [x] (if (< x 0) (- x) x))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn close-enough? [u v]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(let [tolerance 0.00001]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(< (abs (- u v)) tolerance)))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn fixed-point [f start]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(loop [old start new (f start)]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(if (close-enough? old new)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">new<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(recur new (f new)))))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn sqrt [x] (fixed-point (fn [y] (average (/ x y) y)) 1 ))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(prn (sqrt 9))<br /></span><br />A fixed point of a function f is a value y such that f(y) = y. This improved code, which implements the same algorithm as before, uses a generic fixed-point function that takes a function and a guess and tries to find the fixed point by setting the next guess to f(guess). You can see it all in the video. The things in clojure you need to know:<br /><br /><ol class="arabic-numbers"><li>fn [arg1 arg2] is lambda (&lambda;), so where fixed-point takes a function as the first argument, we create one on the fly to be (average (/ x y) y) where x is the argument to sqrt (closed around our function) and y is the argument defined by fn.</li><li>Since clojure compiles to Java and uses Java calling conventions, it does not have automatic tail-recursion. Instead, you use the recur special operator which will create a constant space loop back to the last loop or function definition.  <a href="http://clojure.sourceforge.net/features/functional_programming.html" rel="self">Loop/recur is explained on the Functional Programming page</a> of the clojure site (at the bottom).</li></ol>But, even this can be improved, as we'll see tomorrow.<br />]]></content:encoded></item><item><title>20 Days of Clojure: Day 1</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>20 Days of Clojure</category><dc:date>2008-03-01T10:11:57-05:00</dc:date><link>http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-1.html#unique-entry-id-38</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-1.html#unique-entry-id-38</guid><content:encoded><![CDATA[Ok, this might be hard to keep up, but nothing ventured ...<br /><br /><a href="http://wmassdevs.com/wordpress/2008/02/28/clojure-talk-with-rich-hickey-on-march-20/" rel="self" title="Rich Hickey in Northampton">Rich Hickey is going to be coming to Northampton on March 20th to talk about clojure</a>. In preparation for that, I am going to blog every day in March about clojure -- then, hopefully we can post the results of his talk.<br /><br />If you don't have clojure yet -- go get it. Start here to learn <a href="http://clojure.sourceforge.net/reference/getting_started.html" rel="self">basic clojure syntax</a> (there is also a download link). Clojure is trivial to get running and you definitely want to play with it a little to understand the rest of this. The quick description of clojure is that it's a dialect of Lisp that runs on the JVM. It has support for immutable and persistent data-structures and a concurrent programming model.<br /><br />Today I'm going to start with some of the work I did to learn clojure through translating SICP lectures. In the first lecture, the first interesting program starts at 56:20 in this video:<br /><br /><embed style="width:400px; height:326px;" id="VideoPlayback" type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docId=5546836985338782440&hl=en" flashvars=""> </embed><br /><br />Starting there presumes you know some basic Lisp syntax. This is the program he eventually writes to calculate the square root (in Scheme):<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(define (improve guess x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(average guess (/ x guess)))<br /></span><span style="font:12px Courier, mono; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(define (good-enough? guess x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(< (abs (- (square guess) x)) .001))<br /></span><span style="font:12px Courier, mono; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(define (try guess x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(if (good-enough? guess x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">guess<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(try (improve guess x) x)))<br /></span><span style="font:12px Courier, mono; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(define (sqrt x) (try 1 x))</span><br /><br />I have left out implementations for square and average here. This code and the algorithm is explained in the video.  Here it is in clojure (I defined average and square -- you could just use Java, but I am trying to keep it all in clojure for now)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn sum ([] 0)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">([x] x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">([x & more] (+ x (apply sum more) )))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn average<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">([] 0)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">([x] x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">([x & more]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(/ (+ x (apply sum more)) (+ 1 (count more)))))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn abs [x] (if (< x 0) (- x) x))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn square [x] (* x x))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn improve [guess x]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(average guess (/ x guess)))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn good-enough? [guess x]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(< (abs (- (square guess) x)) 0.001))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn try-sqrt [guess x]<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(if (good-enough? guess x)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">guess<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(try-sqrt (improve guess x) x)))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(defn sqrt [x]  (try-sqrt 1 x))<br /><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">(prn (sqrt 9))<br /></span><br />If you take this and put it in a file named sqrt.clj, you can run it like this (after downloading clojure):<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">java -cp clojure.jar clojure.lang.Script sqrt.clj</span><br /><br />And it will print out:<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="font:12px Courier, mono; ">65537/21845</span><br /><br />Explanation of the differences between the two examples:<br /><ol class="arabic-numbers"><li>clojure uses defn to define functions and puts arguments in []</li><li>sum and average implementations show how clojure can overload on arity (number of arguments)</li><li>try is reserved for exception handling, so I renamed the try function to try-sqrt</li><li>the answer is in clojure's rational number format, since all of the computation was adding and averaging integers and rationals, the result is a rational number and clojure preserves that.</li></ol>Tomorrow, I'll improve this so to make it more generic.  A lot of what I used in this can is explained in the <a href="http://clojure.sourceforge.net/features/functional_programming.html" rel="self" title="Clojure Functional Programming">clojure Functional Programming support</a> page.]]></content:encoded></item><item><title>Book Review: Collective Intelligence&#x2c; Part I</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2008-01-16T18:38:24-05:00</dc:date><link>http://www.loufranco.com/blog/files/CollectiveIntelligencePart1.html#unique-entry-id-37</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/CollectiveIntelligencePart1.html#unique-entry-id-37</guid><content:encoded><![CDATA[<div class="image-right"><img class="imageStyle" alt="51AnWLR89xL._AA240_" src="http://www.loufranco.com/blog/files/page2_blog_entry37_1.jpg" width="240" height="240"/></div>I'm at about the halfway point in <a href="http://www.amazon.com/Programming-Collective-Intelligence-Building-Applications/dp/0596529325">Programming Collective Intelligence</a> by <a href="http://blog.kiwitobes.com/">Toby Segaran</a>, and even if the second half was blank, I'd be telling everyone to read this book. It's been a while since I've read a technical book this good.  It excels because of a combination of three factors:<br /><ol><li>Useful algorithms</li><li>Shown in real-life situations</li><li>With real data that you can get yourself</li></ol>The basic idea of the book is to show different ways of using user-generated datasets to extract information and make decisions. Each chapter tackles a different problem and shows a few ways to approach it.  All of the examples are in Python, but even if you don't know Python, you should be fine if you know any structured language. Practically every example either uses some dataset that he tells you how to get, or a public API that is free to access. <br /><br />This book is the first I've read that relies on the current maturity level of the web.  A few years ago, it wouldn't have been possible to provide so many relevant examples.  In a few years, the API's might be out-of-date -- but don't let that stop you -- the algorithms are timeless.<br /><br />The choice of Python is a good one for a few reasons.  Firstly, it's pretty clear to read even if you don't know it. Secondly, list-comprehensions are a pretty good way to think about data crunching (which these algorithms do a lot), and, finally, there are many freely available Python libraries to deal with the public APIs he uses.<br /><br />To give you an idea of Toby's approach, I'm going to run through my favorite chapter so far, the one on Optimization.  The quick description of the problem domain should be familiar to every programmer -- solve NP complete problems like the traveling salesperson.  Basically, Optimization techniques can be used in situations where (1) you can't analytically solve the problem (2) the solution set is too large to exhaustively search (3) you can express the cost of a possible solution such that better solutions have a lower cost than worse ones and (4) solutions that are "near" each other have similar values for cost.<br /><br />Toby's first example is how a family can choose flights so that they arrive at the same airport from all over the country at nearly the same time and depart for home a few days later at nearly the same time.  The cost function is a combination of the actual costs of the tickets and the difference in time between the earliest and latest flights. He goes on to provide a dataset of flights, describes setting up optimization problems in general, and shows the python code to implement the cost function. <br /><br />Then he introduces a few optimization algorithms, implements them, and discusses their relative strengths and weaknesses. The next section applies these techniques to real data on Kayak.com using the standard Python DOM parser, minidom. The final section shows how to apply these techniques to other problems like pairing students in a dorm and network visualization. Other chapters get a similarly exhaustive treatment.<br /><br />I really hope that this is the future of technical books.]]></content:encoded></item><item><title>Django&#x2c; WebFaction&#x2c; RapidWeaver and Christmas</title><dc:creator>Lou Franco</dc:creator><category>Personal</category><dc:date>2006-12-25T16:38:07-05:00</dc:date><link>http://www.loufranco.com/blog/files/DjangoWebFactionRapidWeaverXMas.html#unique-entry-id-35</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/DjangoWebFactionRapidWeaverXMas.html#unique-entry-id-35</guid><content:encoded><![CDATA[Atalasoft closes for the week between Christmas and New Year's, so I have time to catch up on some things I've been wanting to do -- namely move this site to <a href="http://www.webfaction.com?affiliate=loumf" rel="self">WebFaction</a>. I chose WebFaction once I decided that I wanted to learn Django (after reading this great <a href="http://jesusphreak.infogami.com/blog/why_django" rel="self">comparison of Django and Rails</a>). Following along the forums, there were more than a few good mentions of WebFaction as a good Django host.<br /><br />A couple of weeks into Django and a couple of days into WebFaction, so far, I'm pretty happy. It's Christmas today, so even though I had some questions for WebFaction, I really didn't expect them to get back to me -- so I was pretty happy that they do -- I guess I should expect 365 24x7 from an ISP, but I hadn't been getting it before.<br /><br />In addition to new hosting and a new webapp framework -- I've also settled on <a href="http://www.realmacsoftware.com/rapidweaver/" rel="self">RapidWeaver</a> for content management. I moved to Mac for home a couple of years ago, and I still hadn't found a good desktop CMS that was as good as CityDesk on the PC. RapidWeaver has beautiful themes built in, and a lot of the features that I've gotten used to.  The built-in blog is nice (would be nicer with an import from RSS), but it didn't take too long to transfer everything over.<br /><br />All of this work is to get this site going again.]]></content:encoded></item><item><title>API UI</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2006-03-15T12:44:16-05:00</dc:date><link>http://www.loufranco.com/blog/files/APIUI.html#unique-entry-id-34</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/APIUI.html#unique-entry-id-34</guid><content:encoded><![CDATA[I saw this article on <a href="http://www.reddit.com" rel="self">Reddit</a> that <a href="http://www.acmqueue.com/modules.php?name=Content&pa=showpage&pid=317&page=1" rel="self">applies principles from human-factors design to API design</a>. I think that's a great idea, but this suggestion sounds weird to me.<br /><blockquote><p>Now we could use progressive disclosure to help reduce the complexity of that JButton class: put the expert stuff in an object returned by a getExpertKnobs() method, and the graphics subsystem hooks in an object returned by a getIntegrationHooks() method, and you would be left with a button API that had just a handful of methods&mdash;the basic methods we all need.</p></blockquote> This brings the number of methods in a button from about 100 to about 10, which sounds great until you try to subclass. Overriding a method that's in the object returned by the getExpertKnobs method would be a little tricky. It's likely that you don't even know the real class of that object because those methods are likely to return references to interfaces, plus the component code is in charge of constructing the objects, so there would have to be a way plug into that too, so that your subclass is constructed. I agree that the interface would be much simpler for most users, but it is much more complex for subclassers.<br /><br />There's also the issue of what would be in the expertKnobs object. Some of the methods in JButton that would go in there actually come from JComponent or Component. In fact, as we progressively go down the class hierarchy, we are adding methods into the class that might belong together, which means that there is probably an expertKnobs class for each component class.&nbsp; But, the getExpertKnobs() method is probably introduced early in the hierarchy -- what does it return? Will I have to downcast to get to the button's expert knobs?<br /><br />I don't have a solution -- but these issues probably drove the design of JButton more than the idea that they just sloppily added a 100 methods without giving a thought to the complexity of the class.<br /><br />But the point is taken, and I like the idea of using hard won knowledge from other domains in software design.&nbsp;<br /><br />Another recent blog on this topic was Steve Hawley's <a href="http://atalasoft.com/cs/blogs/stevehawley/archive/2006/02/27/9590.aspx" rel="self">Principle of Least Astonishment</a><a href="http://atalasoft.com/cs/blogs/stevehawley/archive/2006/02/27/9590.aspx" rel="self">&nbsp;</a> essay -- the last topic, on layering APIs, has his approach to this problem.]]></content:encoded></item><item><title>UML Cheatsheet</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2006-02-25T12:39:40-05:00</dc:date><link>http://www.loufranco.com/blog/files/UMLCheatsheet.html#unique-entry-id-33</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/UMLCheatsheet.html#unique-entry-id-33</guid><content:encoded><![CDATA[Here is a download for a <a href="http://www.loufranco.com/blog/assets/cheatsheet.pdf" rel="self">UML Cheatsheet</a> I made for my UML presentation this week. It's released under this <a href="http://creativecommons.org/licenses/by-nc-sa/2.5/" rel="self">creative commons license</a>. When I'm done with the slides, I will post them here as well.<br /><br /><strong>Update</strong>: Here are the slides:<br /><div style="width:425px" id="__ss_4617855"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/loumf/introduction-to-uml-4617855" title="Introduction to UML">Introduction to UML</a></strong><object id="__sse4617855" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=umlintro05-100625185712-phpapp01&stripped_title=introduction-to-uml-4617855" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse4617855" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=umlintro05-100625185712-phpapp01&stripped_title=introduction-to-uml-4617855" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/loumf">Lou Franco</a>.</div></div>]]></content:encoded></item><item><title>WinFX Generation</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2006-02-18T12:36:37-05:00</dc:date><link>http://www.loufranco.com/blog/files/WinFX.html#unique-entry-id-32</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/WinFX.html#unique-entry-id-32</guid><content:encoded><![CDATA[Been looking around WinFX and specifically XAML recently. Not sure I think writing XML is a great way to write a GUI (but billions of web pages clearly prove me wrong). My first impression is that one of the benefits is going to be automated creation of XAML -- not from tools, but from our own programs.<br /><br />It's been 10 years since HTML was a household word and I still feel like it's easier to hand write it than use a WYSIWYG tool. I also never really liked using dialog editors. Even good ones like Delphi have too many limitations, especially when it comes to layout. So, I'm not expecting much from the tool support for XAML. But since it's just a text format, it should be pretty easy to generate from a simpler format (or from models). I'm looking forward to playing around with that idea.]]></content:encoded></item><item><title>Presentation Links</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2006-02-11T12:32:31-05:00</dc:date><link>http://www.loufranco.com/blog/files/PresentationLinks.html#unique-entry-id-31</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/PresentationLinks.html#unique-entry-id-31</guid><content:encoded><![CDATA[Here are some links I've collected on giving presentations. I have been revisiting them lately in preparation for my talk next month.<br /><ul><li>Kathy Sierra, in her Creating Passionate Users blog, thinks that <a href="http://headrush.typepad.com/creating_passionate_users/2005/06/kill_your_prese.html" rel="self">we shouldn't have slides</a>. She also has this <a href="http://headrush.typepad.com/creating_passionate_users/2006/01/crash_course_in.html" rel="self">crash course on learning theory</a> (with pictures and a workbook).&nbsp;</li>
<li>Seth Godin has a free-book called <a href="http://www.sethgodin.com/freeprize/reallybad.html" rel="self">Really Bad PowerPoint</a>. First tip: "No more than six words on a slide. EVER"</li>
<li>Guy Kawasaki has the <a href="http://blog.guykawasaki.com/2005/12/the_102030_rule.html" rel="self">10/20/30 rule of PowerPoint</a>.</li>
<li>The <a href="http://www.beyondbullets.com/" rel="self">Beyond Bullets</a> blog has great tips.</li>
<li>The Zen master of presentations, <a href="http://presentationzen.blogs.com/presentationzen/2005/11/the_zen_estheti.html" rel="self">Steve Jobs, vs. Bill Gates</a>.</li></ul>]]></content:encoded></item><item><title>Apple XCode CPlusTest Port</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2006-02-09T12:04:35-05:00</dc:date><link>http://www.loufranco.com/blog/files/AppleCppUnitPort.html#unique-entry-id-30</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/AppleCppUnitPort.html#unique-entry-id-30</guid><content:encoded><![CDATA[C++ (and Cocoa) unit testing is built into XCode on OSX. I am writing an application right now that I plan to port to Windows. When I wanted to see how portable my code was, I decided to get all of the unit tests passed on Windows.<br /><br />Unfortunately, XCode does not use CppUnit, which is already portable. <a href="http://www.loufranco.com/blog/assets/CPlusTest.zip" rel="self">Here is some code</a> I wrote that you can use to run your XCode generated unit tests on Windows.]]></content:encoded></item><item><title>UML Primer at WMass Dot Net Users Group</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>Western MA</category><dc:date>2006-02-09T12:01:16-05:00</dc:date><link>http://www.loufranco.com/blog/files/UMLatWMassDotNet.html#unique-entry-id-29</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/UMLatWMassDotNet.html#unique-entry-id-29</guid><content:encoded><![CDATA[I'll be giving the next presentation at the Western Mass Dot Net Users Group on the basics of UML.&nbsp;<a href="http://wmassdotnet.org/cs/blogs/events/archive/2006/02/09/38.aspx" rel="self">Details</a>:<br /><br /><strong>Presentation:<br /></strong>Get an introduction to the Unified Modeling Language. Learn the basics of Class, Sequence, and Use Case diagrams.&nbsp; The emphasis will be on UML sketching, but UML code generation will be discussed.<br /><br />This session will be platform independent.&nbsp; Please bring an open mind, your ideas, and experience to share with the group.&nbsp; Software developers, project managers, students and anyone interested in software development on any platform are encouraged to attend.<br /><br /><strong>Meeting Details:</strong><br />Tuesday, February 7 at 6:00 PM<br />Fazzi Associates, Inc.<br />243 King St. Suite 236, Northampton]]></content:encoded></item><item><title>Servware</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2006-02-06T11:58:36-05:00</dc:date><link>http://www.loufranco.com/blog/files/Servware.html#unique-entry-id-28</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/Servware.html#unique-entry-id-28</guid><content:encoded><![CDATA[Despite his rants against C++, <a href="http://opal.cabochon.com/~stevey/blog-rants/" rel="self">Stevey's Drunken Blog Rants</a>, is one of my favorite new blogs. Actually, since it hasn't been updated in about nine months, and was written mostly in 2004, it's not really new. It was rediscovered by social bookmarking sites (I found it on <a href="http://www.reddit.com/" rel="self">reddit.com</a>). I was reminded of it while thinking about resuscitating this site.<br /><br />There are a lot of great articles, but this one about <a href="http://opal.cabochon.com/~stevey/blog-rants/its-not-software.html" rel="self">server-side service software</a> is one of my favorites (given that I've spent a lot of time thinking about the subject). Another great article on this topic is Paul Graham's <em><a href="http://paulgraham.com/road.html" rel="self">The Other Road Ahead</a></em>.]]></content:encoded></item><item><title>Western Mass .Net Users Group</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><category>Western MA</category><dc:date>2006-02-06T11:54:20-05:00</dc:date><link>http://www.loufranco.com/blog/files/WMassDotNet.html#unique-entry-id-27</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/WMassDotNet.html#unique-entry-id-27</guid><content:encoded><![CDATA[The old .NET SAPs is rechristened under the name: <a href="http://wmassdotnet.org/" rel="self">Western Mass .NET Users Group</a><a href="http://wmassdotnet.org/" rel="self">&nbsp;</a><a href="http://wmassdotnet.org/" rel="self"> (and a spiffy new website)</a>. Tomorrow's meeting topic is XML.<br /><br />Speaking of XML, I saw this recently: <a href="http://www.tbray.org/ongoing/When/200x/2006/01/08/No-New-XML-Languages" rel="self">Don't Invent XML Languages</a> by Tim Bray. In addition to pointing to this <a href="http://xml.coverpages.org/xmlApplications.html" rel="self">great list of XML Languages</a>, he introduces "The Big Five" XML Languages and where they should be used.<br /><br /><blockquote><p>Suppose you&rsquo;ve got an application where a markup language would be handy, and you&rsquo;re wisely resisting the temptation to build your own. What are you going to do, then?<br/><br/>The smartest thing to do would be to find a way to use one of the perfectly good markup languages that have been designed and debugged and have validators and authoring software and parsers and generators and all that other good stuff. Here&rsquo;s a radical idea: don&rsquo;t even think of making your own language until you&rsquo;re sure that you can&rsquo;t do the job using one of the Big Five: XHTML, DocBook, ODF, UBL, and Atom.</p></blockquote>]]></content:encoded></item><item><title>The Chameleon Developer</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-03-14T11:50:12-05:00</dc:date><link>http://www.loufranco.com/blog/files/TheChameleonDeveloper.html#unique-entry-id-26</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/TheChameleonDeveloper.html#unique-entry-id-26</guid><content:encoded><![CDATA[<div class="image-right"><img class="imageStyle" alt="Chameleon camouflaged against some leaves" src="http://www.loufranco.com/blog/files/page2_blog_entry26_1.jpg" width="218" height="188"/></div><br />I was talking to a developer friend today about developers who don't&nbsp;get the importance of communication. Look through any want-ads for developers and right after the alphabet soup of technologies you have to know is the same requirement&mdash;must have &ldquo;excellent written and verbal communication skills&rdquo;. You'd be hard pressed to find a programmer job without those requirements.<br /><br />But, expressing yourself clearly is only half of communication. The more important aspect is listening to and understanding other people. This is what separates good and great developers. And the most important skill in understanding is empathy&mdash;not only understanding someone, but being able to&nbsp;be them.<br /><br />To be a successful developer, you have to learn more than just the software aspect of your business. Developers who understand this are more valuable and valued more. If you want to do this effectively, you have to think like a saleperson, a marketer, a CEO, your customers, the press, etc. You have to think like them because they aren't all going to try to think like you (but if they're going to try, by all means, help them).<br /><br />Another part of empathy is thinking about how they will interpret your words. For instance, avoid rhetorical tics like &ldquo;think about it&rdquo; and &ldquo;you're not seeing the big picture&rdquo;. Not only are they annoying, but it puts people on the defensive.<br /><br />If you understand&mdash;not only what someone is saying, but why&mdash;you'll have a much better chance of expressing yourself. So, the next time you have a communication gap with a non-developer, stop talking and ask yourself how much you even understand about them.]]></content:encoded></item><item><title>Software Addins as a Business</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-03-12T11:46:11-05:00</dc:date><link>http://www.loufranco.com/blog/files/SoftwareAddinsasaBusiness.html#unique-entry-id-25</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/SoftwareAddinsasaBusiness.html#unique-entry-id-25</guid><content:encoded><![CDATA[<div class="image-right"><a href="http://www.spheresoft.com/highlighter/" rel="self"><img class="imageStyle" alt="Animated demo of Highlighter" src="http://www.loufranco.com/blog/files/page2_blog_entry25_1.gif" width="280" height="200"/></a></div>I've written a couple of add-ins for CityDesk, and of course, it's tempting to think about trying to make some money off of them. I'm already a partner in another add-ins business (<a href="http://www.spheresoft.com/" rel="self">Spheresoft</a>, which makes MS Office addins -- check out <a href="http://www.spheresoft.com/highlighter/" rel="self">Highlighter</a> if you view realtime data in Excel), so I know a little about what goes into the development, support, marketing, sales, licensing, etc. of doing this kind of thing.<br /><br />Add-ins are a great business for small companies, because they are much easier to implement than a full-blown product and the software you are adding on to will help with marketing. Another add-in that Spheresoft will be publishing soon, <a href="http://www.spheresoft.com/modeler" rel="self">changes the nature of spreadsheet modeling</a>, but we'd never want to compete with Excel on thousands of other tiny features, so it makes more sense for this to be an add-in.<br /><br />But, with any business, you have to decide how much effort you are willing to put in and what you are expecting back. The market of people who have Office is huge and I have a reasonable expectation of making a good enough return on Office add-ins to warrant the time spent writing and supporting them.&nbsp;<br /><br />I'm not sure I can do the same for add-ins for Fogcreek products. I'm glad that people find them useful, and I do them because I need them as well. I would never make enough money to recoup support costs I would have to undertake if I charged for them.<br /><br />So, they will remain free and pretty much unsupported for now.]]></content:encoded></item><item><title>Code Generation from Requirements</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-03-12T11:24:42-05:00</dc:date><link>http://www.loufranco.com/blog/files/CodeGenerationfromRequire.html#unique-entry-id-24</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/CodeGenerationfromRequire.html#unique-entry-id-24</guid><content:encoded><![CDATA[This article on <a href="http://martinfowler.com/bliki/DomainSpecificLanguage.html" rel="self">Domain Specific Languages from Martin Fowler</a> got me thinking on code generation in general. A project I'm working on right now has many opportunities for generating code&mdash;not from a domain specific language, but from the requirements documentation and other source information.<br /><br />I am working on a project now with a very detailed requirements document. For instance, practically all of the strings shown to the user are in there. Since the project uses string resources, there's no reason to manually copy and paste&mdash;the string resource is easily generated from the document.<br /><br />The project also has a lot of images.&nbsp; And images are associated with each other (some images are the small version of another, or meant to be the same object but from another angle). Luckily, the artist used a directory and naming convention that makes these associations easy to figure out, and generate an XML resource descriptor and object building code from.<br /><br />Tying together this information (each image has a string descriptor) is also easy, given the detail in the document and the naming convention.<br /><br />Actual logical code generation is almost possible as well, as the project is a kind of complicated finite state machine. In this case the document doesn't go far enough to be a source. A Domain Specific Language might help here, and leaves me with source that might be able to be maintained more easily that a Java representation.<br /><br />This brings up a good lesson for those writing requirements, even if you don't know how to program. If you follow conventions closely, it might be a good starting point for generating code.]]></content:encoded></item><item><title>Furl</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-03-09T11:22:14-05:00</dc:date><link>http://www.loufranco.com/blog/files/Furl.html#unique-entry-id-23</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/Furl.html#unique-entry-id-23</guid><content:encoded><![CDATA[I've been playing around with the <a href="http://www.furl.net" rel="self">Furl Beta</a>. It's looking pretty good. Essentially, it's a personal online cache of web pages that you can view, search, and share. Better than bookmarking because you can search the contents of it later, and it's accessible from any browser. You can even provide RSS feeds to your Furl content.&nbsp; Collaborative research on the internet just got a whole lot easier.<br /><br />One drawback, there does not appear to be any way to make the cache private, so I can't possibly use it, because there is no way I want a public database of every site I find interesting or useful. I definitely would share some of it with some people, but totally public is not an option.<br /><br />Perhaps there will be a pay service for a private space.<br /><br /><strong>Update</strong>: My bad. Just mark the item private when you Furl it.&nbsp; Duh.&nbsp; Didn't see that on the Furl dialog and still don't see how to make a public item private (except to change its topic to personal, but then I lose the utility of topics). Anyway, now the biggest drawback is that the first dialog comes up at the wrong size and there is no scrollbar, so you can't see the buttons.]]></content:encoded></item><item><title>Informational Integrity</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-02-21T11:14:40-05:00</dc:date><link>http://www.loufranco.com/blog/files/InformationalIntegrity.html#unique-entry-id-22</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/InformationalIntegrity.html#unique-entry-id-22</guid><content:encoded><![CDATA[<blockquote><p>Any program that accepts user input will need to separate good input from bad, and to make sure little of the latter gets recorded.</p></blockquote> So begins the <a href="http://c2.com/ppr/checks.html" rel="self">CHECKS Pattern Language of Informational Integrity</a> by Ward Cunningham. I read this article years ago and loved it&mdash;mostly because it jibed with my experience for writing usable business software. The theme of the language is to make sure that data entered by the user is correct, and accomplishes this with various kinds of validation and data representation techniques.<br /><br />I find that two of the patterns are invaluable for usable user interfaces&mdash;<a href="http://c2.com/ppr/checks.html#4" rel="self">Echo Back</a> and <a href="http://c2.com/ppr/checks.html#5" rel="self">Visible Implication</a>. The section they appear in starts with: <blockquote><p>A person reaches through a program's interface to manipulate the domain model. Although the interface is itself a program (an interface model and graphical machinery), its purpose is to enable the direct manipulation of the domain model as transparently as possible. The user interface is programmed to create the illusion of control in the mind of the user. To this end it must provide sufficient clues of the model's state so that sensible operation is the norm. </p></blockquote>These ideas are so important to the usability of software and so difficult to implement in HTML based software, because there is little domain knowledge accessible from the client side. For instance, <strong>Echo Back </strong>requires that a field, once entered, is transformed into a domain object and injected into the model. It is then read back from the model and displayed as understood by the model. <strong>Visible Implication</strong> further requires that any cascading consequences are also displayed. This kind of interface is the norm in the Fat Client or Client-Server world, and mostly absent in the web-based software world. As a consequence, it is harder for users to enter data.<br /><br />We've all had the experience of filling out a huge form on a web page and submitting it, only to be told that we've made a mistake and have to go back. That's <a href="http://c2.com/ppr/checks.html#6" rel="self">Deferred Validation</a> used in isolation of the other patterns, and was never considered a good UI decision until the web made it commonplace. And yes, I know that you can get part of the way there with javascript, but only simple validations are possible. Imagine correcting a pay date in a maintainable and configurable way as described in the example for Echo Back.<br /><br />I appreciate the revolution that the web has brought us, but something better is needed for software with high usability or productivity requirements (as opposed to high learnability or deployability requirements).&nbsp;<a href="http://weblogs.java.net/pub/wlg/396" rel="self">Philip Brittan describes an architecture</a> we worked on that can recapture the connection between UI code and the domain model, while still maintaining the benefits of web based software.]]></content:encoded></item><item><title>HTML DBScript</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-02-19T21:53:57-05:00</dc:date><link>http://www.loufranco.com/blog/files/HTMLDBScript.html#unique-entry-id-21</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/HTMLDBScript.html#unique-entry-id-21</guid><content:encoded><![CDATA[If you want to add the results of Database queries to HTML files before they are published (and keep them as static pages), you can use my new utility, HTML DBScript. It will work on any HTML, but is designed to fit well with <a href="http://redirect.fogcreek.com/?id=greenwave&url=http://www.fogcreek.com/CityDesk" rel="self">CityDesk's</a> "Before Copy" publishing location feature.<br /><br />It's in Beta right now, but well tested and has decent error reporting. Let me know if you have any comments by using the <a href="../contactme/index.php" rel="self" title="Contact Me">Contact Page</a>.<br /><br /><strong>Update</strong>: v1.0 is released. FogCreek is featuring a link to it on their <a href="http://redirect.fogcreek.com/?id=greenwave&url=http%3A//www.fogcreek.com/CityDesk/news/entries/2004/February/20.html">CityDesk News Page</a>.]]></content:encoded></item><item><title>ArgoUML</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-02-16T21:48:48-05:00</dc:date><link>http://www.loufranco.com/blog/files/ArgoUML.html#unique-entry-id-20</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/ArgoUML.html#unique-entry-id-20</guid><content:encoded><![CDATA[I've been playing around with <a href="http://argouml.tigris.org/" rel="self">ArgoUML</a>, an open-source UML modeling and code generation program. So far, the major drawback for me is the non-standard UI elements because of Swing&mdash;I really hate Swing File dialogs&mdash;even the &ldquo;Windows&rdquo; look and feel ones.<br /><br />My first impressions are very good. I have spent seven years with Rational Rose and like it very much, but it is out of my price range right now. I haven't used any other products and I am only interested in packages with some kind of code generation and deep UML knowledge (that rules out generic drawing packages). And, price is an issue. So far, Argo meets all of my basic requirements.<br /><br />One of the features I think I will like is what they call cognitive support. It manifests itself in a list of suggestions about your model. For instance, in playing around, I have a class with no non-static members or associations. In the to-do list, I see a suggestion to make this a Singleton. Argo also helped me understand some of its conventions by suggesting names for the packages I made. In general, Argo understands UML, and does a great job of helping you create it.<br /><br />The code generation is in the early stages, and in inadequate for use on a project unless you are using an editor that will seamlessly fix the code into your standard tabbing style. Even when I use UML as a sketch, I like to generate the code as a sanity check to make sure the UML says what I think it says&mdash;it's good enough for that.<br /><br />Large multi-person projects might find the lack of external packages (packages each stored in their own file) a deal breaker. Rational has very good support for this, and it's essential when you try to use UML as a programming language, since having one big file becomes a impediment to collaborative development. This extends to property sets as well, which I don't see how to share between models.<br /><br />Here's my first model:<br /><p style="text-align:center;"><img class="imageStyle" alt="UML model of a bowling scorer" src="http://www.loufranco.com/blog/files/page2_blog_entry20_1.gif" width="485" height="266"/><br /><br /></p><p style="text-align:left;">Created to mimic the design in this <a href="http://www.loufranco.com/blog/files/DotNetSapsUnitTesting.html" rel="self" title="Blog:DotNetSaps: Unit Testing">NUnit presentation</a>.</p>]]></content:encoded></item><item><title>Who is Responsible for Usability?</title><dc:creator>Lou Franco</dc:creator><dc:subject>Blog</dc:subject><dc:date>2004-02-10T21:39:05-05:00</dc:date><link>http://www.loufranco.com/blog/files/WhoisResponsibleforUsabil.html#unique-entry-id-19</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/WhoisResponsibleforUsabil.html#unique-entry-id-19</guid><content:encoded><![CDATA[It's great that unit testing is getting a lot of attention. There are xUnit frameworks for every language, and secondary tools are emerging. It is also becoming common to designate some developers as &ldquo;in test&rdquo;, meaning that they develop software to test their organization's development projects. More importantly though, developers are thinking about testing, educating themselves, and taking responsibility. A similar movement needs to take place in software usability.<br /><br />A usability department is more rare than a QA department ever was. Most developers will never work with a usability expert, and even if they did, they still would have a lot of usability decisions to make. Like other aspects of software creation, developers need to learn the concepts of usability. But, unlike many aspects of development, usability is not clearly quantifiable or automatable. There are some rigorous methods, but usability knowledge is essentially a set of heuristics and the ability to imagine yourself as the user.<br /><div class="image-left"><a href="http://homepage.mac.com/bradster/iarchitect/tabs.htm" rel="self"><img class="imageStyle" alt="Bad UI with tabs on all four sides" src="http://www.loufranco.com/blog/files/page2_blog_entry19_1.gif" width="278" height="290"/></a></div><br />The heuristics can be learned either by example (see sidebar) or counter-example (like the picture to the left).&nbsp; But imagining yourself as the user is a little harder.<br /><br />You spend all day with the software you create. It is probably one of the most important things in your life&mdash;it pays for your food and rent. You know everything about it.<br /><br />Your users prefer not to even think about your software. They have tasks they are trying to accomplish (to earn money to buy food and pay the rent). Even vitally important software, like my web browser, my e-mail client or my compiler, are insignificant when compared to my family, my job, paying my bills, and having fun&mdash;and I would replace them in a second if they got in the way of those things. Keep that in mind.<br /><br />The only way to learn about your users is to watch them use your software in their environment, with their distractions. You must learn what they typically know, the words they use, the things they care about. If you are a developer, don't let yourself be shielded from the users. You need to meet them and hear what they have to say. You need to ask questions. And by &ldquo;users&rdquo;, I mean the people who use your software&mdash;not their bosses or their IT staff or your boss or a UI expert or a marketing guy or whoever. If you manage developers, put them in front of users.<br /><div class="image-right"><img class="imageStyle" alt="Trader in front of computer" src="http://www.loufranco.com/blog/files/page2_blog_entry19_2.jpg" width="230" height="125"/></div><br />I have learned more about financial trading software by sitting with traders than the entire time I spent writing it. There are idiosyncrasies that I would never know unless I watched them work (how little time they have to do a trade, how many hands they have free, the distractions, their patience level, their technical level, their vocabulary, etc), and I guarantee that your users are similarly unique.<br /><br />For further reading: Bruce Tognazzi's <em><a href="http://www.asktog.com/basics/firstPrinciples.html" rel="self">First Principles of Interaction Design</a></em>, Joel Spolsky's <em><a href="http://redirect.fogcreek.com/?id=greenwave&url=http%3A//www.joelonsoftware.com/uibook/chapters/fog0000000057.html" rel="self">UI Design for Programmers series</a></em>, Jakob Nielsen's <em><a href="http://www.useit.com/papers/heuristic/heuristic_list.html" rel="self">Ten Usability Heuristics</a></em>. Learn from the mistakes of others by looking at the original&nbsp;<a href="http://homepage.mac.com/bradster/iarchitect/tabs.htm" rel="self">User Interface Hall of Shame</a><a href="http://homepage.mac.com/bradster/iarchitect/tabs.htm" rel="self">&nbsp;</a> or this other one from&nbsp;<a href="http://pixelcentric.net/x-shame/">Pixelcentric</a>.]]></content:encoded></item><item><title>UML in an Agile World</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-02-07T21:35:25-05:00</dc:date><link>http://www.loufranco.com/blog/files/AgileUML.html#unique-entry-id-18</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/AgileUML.html#unique-entry-id-18</guid><content:encoded><![CDATA[Although UML is usually not associated with agile processes, there are two ways I think it can play a major role in an agile development project.<br /><br />The first is a full adoption of a UML toolset, including full round-tripping through the entire implementation. In this case, UML becomes part of your programming language. It maps very well onto the constructs of Object-Oriented implementation languages, and there is nothing about it that will stop you from doing all of the things you do in an agile process (Simple Design, Test First, etc.) The benefit is that you have a up-to-date UML document at the end of the implementation (why you might want this, I'll save for a future entry). I have done this with Rational Rose for C++ with great success, and if you want UML diagrams that actually match the implementation, this is the way to go.<br /><br />The other use is to not even attempt to keep UML documents consistent with the implementation as it progresses, and just use UML to convey design ideas. This is more precise than a text description, and certainly a good supplement to one. <em>Design Patterns</em> by the GoF is a good example of a book that uses UML to convey design ideas. Martin Fowler's <em>Patterns of Enterprise Application Architecture</em> uses it extensively as well, and he says this about the <a href="http://www.martinfowler.com/bliki/UmlAsSketch.html" rel="self">UML in his books</a>.<br /><blockquote><p>Most UML diagrams shown in books, such as mine, are sketches. Their emphasis is on selective communication rather than complete specification. Hence my sound-bite "comprehensiveness is the enemy of comprehensibility"</p></blockquote><br />Unless UML is the implementation language (where completeness is essential), then there is no need to include every detail in the drawing. In fact, inclusion communicates importance in this context.]]></content:encoded></item><item><title>Unit Testing Old Code</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-28T21:32:33-05:00</dc:date><link>http://www.loufranco.com/blog/files/UnitTestingOldCode.html#unique-entry-id-17</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/UnitTestingOldCode.html#unique-entry-id-17</guid><content:encoded><![CDATA[If you are new to unit testing, but the source base is old, the sheer size of code to test will seem daunting. Here are some strategies for adding unit testing to old code.<br /><ul><li>Test code before refactoring or optimizing &ndash; The purpose of refactoring and optimizing is to make the code do the exact same thing but in a different way. It is perfectly suited to being unit tested since tests you write at the beginning of the change need to pass at the end.&nbsp; And, the unit tests will let you make more aggressive changes.</li>
<li>Test code while learning what it does &ndash; When you're trying to learn a body of code, a unit test is a good way to check your assumptions about how the code works. This strategy also works well in training a new developer&mdash;explain the code by writing new tests for it together.</li>
<li>Before fixing a bug, write a failing test &ndash; This is the perfect time to add a test since reliably reproducing the bug is a good first step. The beauty of this is that now the bug won't return. </li></ul>
In general, I would not make a project out of writing unit tests for old code (except during the period where you are installing the xUnit framework and getting used to it). Unit testing works best when it isn't the end, but instead a means to accomplishing something else.]]></content:encoded></item><item><title>DotNetSaps: Unit Testing</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-26T21:20:43-05:00</dc:date><link>http://www.loufranco.com/blog/files/DotNetSapsUnitTesting.html#unique-entry-id-16</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/DotNetSapsUnitTesting.html#unique-entry-id-16</guid><content:encoded><![CDATA[It was my turn to present to the <a href="http://www.wmassdotnet.org/" rel="self">DotNetSaps</a>. Here are <a href="http://www.loufranco.com/blog/assets/unittest.zip" rel="self">the slides and code to score bowling games</a> that I wrote during the presentation.&nbsp; Get <a href="http://nunit.org/" rel="self">NUnit</a>, <a href="http://www.fitnesse.org/" rel="self">FitNesse</a> and look at&nbsp;<a href="http://www.xprogramming.com/" rel="self">XProgramming.com</a> for more information on unit testing.<br /><br /><strong>Note on the code:</strong> This code is not done. There are at least three bugs in it, but it passes all of the tests. This means that there are more tests to write.&nbsp; Here are some that would fail:<br /><br /><div style="border:1px solid"><span style="font-family:Courier"><strong>public void</strong> testNonStrikeAfterDoubles()<br/>
{<br/>
&nbsp;&nbsp;game.bowl(10);<br/>
&nbsp;&nbsp;game.bowl(10);<br/>
&nbsp;&nbsp;game.bowl(5);<br/>
&nbsp;&nbsp;game.bowl(5);<br/>
&nbsp;&nbsp;assertEquals(game.getScore(), 55);<br/>
}<br/>
<br/>
<strong>public void</strong> testSimpleEndOfGame()<br/>
{<br/>
&nbsp;&nbsp;<strong>for</strong> (<strong>int</strong> i = 0; i < 10; ++i) { <br/>
&nbsp;&nbsp;&nbsp;&nbsp;game.bowl(0); <br/>
&nbsp;&nbsp;&nbsp;&nbsp;game.bowl(0); <br/>
&nbsp;&nbsp;} <br/>
&nbsp;&nbsp;assert(game.getIsOver()); <br/>
} <br/>
<br/>
<strong>public void</strong> testEndOfGameStrikeInTenth() <br/>
{ <br/>
&nbsp;&nbsp;game = <strong>new</strong> BowlingGame(); <br/>
&nbsp;&nbsp;<strong>for</strong> (<strong>int</strong> i = 0; i < 10; ++i) { <br/>
&nbsp;&nbsp;&nbsp;&nbsp;game.bowl(10); <br/>
&nbsp;&nbsp;} <br/>
&nbsp;&nbsp;assert(!game.getIsOver()); <br/>
}<br/></span></div>
<br />Not to mention scoring the tenth frame correctly. Fixing those tests and finding others is left as an exercise to the reader.]]></content:encoded></item><item><title>Nielsen&#x27;s HomePage Usability Rules: A Self-Assessment</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-22T21:01:35-05:00</dc:date><link>http://www.loufranco.com/blog/files/NielsensRulesASelf-Assess.html#unique-entry-id-15</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/NielsensRulesASelf-Assess.html#unique-entry-id-15</guid><content:encoded><![CDATA[<div class="image-right"><img class="imageStyle" alt="Homepage Usability book cover" src="http://www.loufranco.com/blog/files/page2_blog_entry15_1.jpg" width="128" height="128"/></div>Jakob Nielsen has been supporting his book, <em><a href="http://www.useit.com/homepageusability/" rel="self">Homepage Usability: 50 Websites Deconstructed</a></em>, with a few of articles on homepage design. I took the opportunity to make some changes to my own site after reading them.<br /><br />The first article, <a href="http://www.useit.com/alertbox/20031222.html" rel="self">Top Ten Web Design Mistakes of 2003</a>, lists what's been annoying him recently. I did well on this one&mdash;I only needed to add some ALT text to my images (Tip #5 is&nbsp;<em>Overly detailed ALT Text</em>&mdash;oops, I actually didn't have any) and make pages stop linking to themselves (#10). The latter improvement is not directly supported in my CMS tool (CityDesk) and took a fair amount of scripting, but armed with CityDesk keywords and my <a href="../KeywordPickerforCityDesk.html" rel="self" title="Keyword Picker for CityDesk">keyword organizing utility</a>, I got it done.<br /><br />That article linked to <a href="http://www.useit.com/alertbox/20031110.html" rel="self">The Ten Most Violated Homepage Design Guidelines</a>. I didn't do too badly on that one either, but I decided to differently color visited links and make it more clear where you are on the site (#3). I rewrote my tag line to be more informative (#5) and made my <title> tags more descriptive. I was already following #2 (<em>Use a liquid layout that lets users adjust the homepage size</em>), since that's a pet-peeve of mine.<br />Finally, I read <a href="http://www.useit.com/alertbox/20020512.html" rel="self">Top Ten Guidelines for Homepage Usability</a>. By this point, most of the tips were redundant. I haven't added a search yet, but I'll do that soon.<br /><br />The book has over a hundred guidelines sure to improve any site.]]></content:encoded></item><item><title>The NeverLost UI&#x2014;Design for the Disengaged User</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-20T20:53:37-05:00</dc:date><link>http://www.loufranco.com/blog/files/NeverLostUI.html#unique-entry-id-14</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/NeverLostUI.html#unique-entry-id-14</guid><content:encoded><![CDATA[<div class="image-right"><img class="imageStyle" alt="Neverlost" src="http://www.loufranco.com/blog/files/page2_blog_entry14_1.jpg" width="89" height="186"/></div>Last week I had my first experience with a GPS based guidance system, the NeverLost from Hertz. I was struck by some of the good UI choices and want to highlight them here. For a more in-depth analysis, see <a href="http://filebox.vt.edu/users/eolsen/neverlost/neverlost.htm" rel="self">this evaluation</a>. I will limit this entry to my current blog topic of <a href="http://www.loufranco.com/blog/files/Usabilityvs.Learnability" rel="self" title="Blog:Usability vs. Learnability">usability vs. learnability</a><a href="http://www.loufranco.com/blog/files/Usabilityvs.Learnability" rel="self" title="Blog:Usability vs. Learnability">&nbsp;</a> as it applies to the disengaged user.<br /><br />The designers of NeverLost certainly had to design for both usability and learnability. Few will have the time or inclination to read the manual once they get to their rental car, and many will be first time or occasional users. More importantly though, the NeverLost must be easy to use. I'm sure the designers of NeverLost understood the possibility of their device contributing to an accident, and let that be the overriding concern in all of their choices. The NeverLost is a good example of designing for disengaged users, that is, users that are doing something else while using your software. The principles of the NeverLost design have wide applicability (e.g. software for call centers or traders).<br /><br />Here are some of the basic principles they have adhered to:<br /><ol><li>Constraining choices rather than interrupting on errors: A good choice in any application, the NeverLost takes it to an extreme. Typing is hard (you choose letters by navigating over a pick-list), so the search interface only shows letters that will actually return a result. So, for example, if you pick the letters &ldquo;H-O-L-I-D&rdquo; in the Yellow Pages search, only the letter &ldquo;A&rdquo; appears on the pick list, because&nbsp;the &ldquo;Holiday Inn&rdquo; is the only item in their list that starts with those letters. Searches never fail to return a result, and you can correct errors immediately. Of course, a keyboard or a touchscreen might have made this easier, but they would also add to the cost.</li>
<li>Speech rather than text: Essential for this kind of system since you really should not be looking at it while driving. </li>
<li>The display is easy to glance at: While driving, the display is simply the major routes with the current one highlighted and the car showing the driving direction.&nbsp; It's very easy to see that you are on the right track.&nbsp; All other information is via speech. </li>
<li>Anticipation rather than waiting for input:&nbsp; We made two deviations from the directions. The first was missing our exit, and the NeverLost immediately calculated a new route and let us know what it was doing. The second was getting off at an exit to make a rest-stop&mdash;in that case, the NeverLost let us get back to the route ourselves without recalculating. Both choices were exactly what we wanted, so we didn't need to fiddle with the interface.</li> 
<li>Mistakes are easy to correct: The NeverLost keeps a list of the destinations you have input and lets you easily go back to them. A&nbsp;Cancel button lets you back out of all choices. Having these features lets the NeverLost stay out of your way most of the time, because it knows that you can revert to an old state when you need to.</li></ol>All of these are good ideas for any interface, and if you imagine that your user is distracted, your user interfaces will be even easier to use when they aren't. Of course, a speech interface is not right for all applications, but sounds usually are, and can help to alert users when their attention is required.<br />When conducting usability tests, keep in mind the environment your users are in, and try to match it. For example, don't gather users to your pristine environment. Go to them if you want to see how they really use your software and the distractions they encounter.]]></content:encoded></item><item><title>Usable and Learnable</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-13T20:51:51-05:00</dc:date><link>http://www.loufranco.com/blog/files/UsableandLearnable.html#unique-entry-id-13</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/UsableandLearnable.html#unique-entry-id-13</guid><content:encoded><![CDATA[Usable interfaces are all about productivity for those that use your software every day. They feature a UI that anticipates you, but gets out of your way and ensures that your mistakes are recoverable.<br /><br />Novices require more hand-holding. They may either be new to the application and not yet a power-user, or they may be an occasional user, or they may be watching a demo. In each of these cases, the application must be easy to learn and understand.<br /><br />When you prepare your user profiles for a UI Design or a product requirements document, it may seem that these two user types are hopelessly irreconcilable, and sometimes you'll specify two completely separate UI's (e.g. wizards in addition to the &ldquo;normal&rdquo; UI). Sometimes this is appropriate, but on his blog, <a href="http://weblogs.java.net/blog/pbrittan/archive/2003/08/software_usabil.html" rel="self">Philip Brittan discusses a product</a> we worked on, where features supporting both types were implemented with the same UI.]]></content:encoded></item><item><title>Usability vs. Learnability</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-13T20:46:42-05:00</dc:date><link>http://www.loufranco.com/blog/files/Usabilityvs.Learnability#unique-entry-id-12</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/Usabilityvs.Learnability#unique-entry-id-12</guid><content:encoded><![CDATA[I just needed to look up something in <em>User Interface Design for Programmers</em> by <a href="http://redirect.fogcreek.com/?id=greenwave&url=http://www.joelonsoftware.com/uibook/chapters/fog0000000057.html" rel="self">Joel Spolsky</a> and I was reminded of a great chapter on usability testing (only in the print version). One of the insights is the difference between &ldquo;usability&rdquo; and &ldquo;learnability&rdquo;. He revisited it in <a href="http://redirect.fogcreek.com/?id=greenwave&url=http://www.joelonsoftware.com/articles/fog0000000008.html" rel="self">another post</a>.<br /><blockquote><p>For casual users, learnability and simplicity are more important than usability and power. In that sentence, by &ldquo;learnability,&rdquo; I mean, the ability for novices to figure out how to get tasks done rapidly. By &ldquo;usability,&rdquo; I mean only the ability to do tasks in a convenient and ergonomic way without making mistakes and without needing to do repetitive tasks. A data entry system that minimizes keystrokes by prefilling things and automatically jumping from field to field is more usable for experienced users, but it's harder to learn because it behaves unexpectedly to a novice.</p></blockquote>The book is worth picking up if you are planning a formal usability test, just to see what kind of things to look for, and what to expect to accomplish. Keep in mind, that if your testers are seeing the UI for the first time, you are testing learnability, not usability.]]></content:encoded></item><item><title>FitNesse and Requirements in XP</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-11T20:40:16-05:00</dc:date><link>http://www.loufranco.com/blog/files/FitNesseandRequirementsinX.html#unique-entry-id-11</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/FitNesseandRequirementsinX.html#unique-entry-id-11</guid><content:encoded><![CDATA[In XP, requirements gathering is an ongoing conversation validated with acceptance testing. It makes sense, therefore, that any document that results from gathering requirements be easy to edit and give explicit instructions for validation. <a href="http://fitnesse.org/" rel="self">FitNesse</a>&nbsp;takes this idea to the extreme by using a Wiki front-end to make the requirements document the living, growing entity it needs to be, and it builds in <a href="http://fit.c2.com/" rel="self">FIT</a> acceptance testing, so that tables representing acceptance tests can be added&nbsp;and run directly from the document.<br /><br />To use FitNesse, developers add Fixtures to their projects using the FIT framework. These Fixtures can be are added to FitNesse using path and fixture directives. Each page can embed an acceptance test using syntax like the following:<br /><br /><span style="font-family: Courier">|!-CalculatorColumnFixture-!|<br/>
|button|display()|<br/>
| |0|<br/>
|1|1|<br/>
|+|1|<br/>
|2|2|<br/>
|=|3|</span><br/>
<br />This example tests a calculator by pressing its buttons. CalculatorColumnFixture is a class extending ColumnFixture in FIT.&nbsp; It has a member variable called <strong>button</strong> and a method called <strong>display()</strong>.&nbsp; For each row,&nbsp;<strong>button</strong> is set to the value in the left column and the return value of <strong>display()</strong> is checked against the value in the right column. In addition to this table, any text describing the functionality of the calculator can appear on the page. Advanced Fixtures are available for more complex interfaces.<br /><br />The beauty of FitNesse is that it is implemented as a web-server that serves up the Wiki with the requirements documentation and acceptance tests. It adds FIT directives to the normal Wiki editing syntax and includes version tracking for each page.<br /><br />Combining the aspects of collaborative document growing and automated acceptance tests, FitNesse is a great addition to the requirements process.]]></content:encoded></item><item><title>Keyword Picker for CityDesk</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-09T19:10:30-05:00</dc:date><link>http://www.loufranco.com/blog/files/KeywordPickerforCityDesk.html#unique-entry-id-10</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/KeywordPickerforCityDesk.html#unique-entry-id-10</guid><content:encoded><![CDATA[I use <a href="http://redirect.fogcreek.com/?id=greenwave&url=http://www.fogcreek.com/CityDesk" rel="self">CityDesk</a> to manage this site. One of the features is that each page can be tagged with keywords. The problem is, however, that the keywords are typed into a TextBox, not chosen from a List. I am having problems remembering all of the keywords I have decided to use, but I want to be consistent, because I plan on making pages for each keyword when I have enough blog entries (to help organize the archive page).<br /><br />I wrote a small program to help me do this.&nbsp; If you have the same problem, check it out.<br /><strong><br />Update</strong>: Cool. Five minutes after posting this, it's already in <a href="http://tk-jk.net/city/Articles/fog0000000010.html" rel="self">TK's CityDesk Help Reference</a>&mdash;which, by the way, has some good stuff for CityDesk users.]]></content:encoded></item><item><title>FIT for Testing</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-08T19:00:04-05:00</dc:date><link>http://www.loufranco.com/blog/files/FITforTesting.html#unique-entry-id-9</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/FITforTesting.html#unique-entry-id-9</guid><content:encoded><![CDATA[Over at <a href="http://www.martinfowler.com/bliki/TestingLanguage.html" rel="self">Martin Fowler's blog</a>, I found a link to <a href="http://fit.c2.com/" rel="self">Framework for Integrated Test</a> (FIT) from Ward Cunningham. I'm just starting to read it now, but I wanted to pass it along because it looks pretty good. Fowler writes:<br /><blockquote><p>But I wonder if a language designed for programming is really the right language for writing tests. The point about tests is that they operate by example. They don't try to cover how to handle any value, instead they describe specific scenarios and responses. I wonder if this implies a different kind of programming language is required. Perhaps this is the truly startling innovation in FIT.</p></blockquote>More on this later.]]></content:encoded></item><item><title>Document Growing</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-07T18:55:46-05:00</dc:date><link>http://www.loufranco.com/blog/files/DocumentGrowing.html#unique-entry-id-8</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/DocumentGrowing.html#unique-entry-id-8</guid><content:encoded><![CDATA[If your documentation system is easy to use, add to and edit, you can grow your documentation.&nbsp;<a href="http://www.estherderby.com/weblog/archive/2004_01_01_archive.html#107333657533273894" rel="self">Esther Derby has an example</a>.&nbsp;<a href="http://www.loufranco.com/blog/files/FluidCommunication.html" rel="self" title="Blog:Fluid Communication">Wikis</a> are particularly suited to this style of collaborative document growing.<br /><br /><strong>Update</strong>: <a href="http://martinfowler.com/bliki/RefactoringMalapropism.html" rel="self">Martin Fowler</a> wants us to be more precise with the word &ldquo;refactoring&rdquo;. Since the above article uses it in precisely the way he's talking about changing, I thought I'd add this note.]]></content:encoded></item><item><title>Fluid Communication</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-07T18:44:53-05:00</dc:date><link>http://www.loufranco.com/blog/files/FluidCommunication.html#unique-entry-id-7</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/FluidCommunication.html#unique-entry-id-7</guid><content:encoded><![CDATA[Sharing information in your organization is much easier if you use some kind of knowledge base software. For large enterprises, there are plenty of choices, most aimed at the help desk or call center, but they might be overkill and expensive if all you are trying to do is make a central repository of the bits of information in the collective mind of your company. Here are three low-cost ideas for implementing a simple knowledge repository.<br /><ul><li><b>News Group Software</b> &mdash; &nbsp;There are plenty of easy to install and use newsgroup applications. I've had good experiences with <a href="http://www.snitz.net/" rel="self">Snitz</a>, which is free and full-featured.</li>
<ul><li><b>Advantages</b>: Familiar interface, every edit is marked with author, support for alerting via e-mail is common</li>
<li><b>Disadvantages</b>: Knowledge is in discussion/serial format, hard to edit old entries, linking to other entries can be hard, requires ability to install software on the server, may not support attachments</li></ul>
<li><b>Wiki Software</b>&nbsp;&mdash; A Wiki is a website where every page is editable by the reader. The best known public example is the <a href="http://en.wikipedia.org/" rel="self">WikiPedia</a>, but the concept started at the <a href="http://www.c2.com/cgi/wiki?WelcomeVisitors" rel="self">Portland Pattern Repository</a>. It's a powerful idea, but depending on the exact software you use, it can be hard for some people to use. Here's a <a href="http://www.c2.com/cgi/wiki?WikiWikiClones" rel="self">list of wiki implementations</a>.</li>
<ul><li><b>Advantages</b>: Everything is editable, linking is easy, free implementations are available, pro versions track users and edits</li>
<li><b>Disadvantages</b>: Can be hard to use, requires ability to install software on the server, may not support attachments</li></ul>
<li><b>Content Management Software</b> &mdash; CMS tools can be as expensive as KnowledgeBase tools, but for ease of use and quality of the resulting site, they cannot be beat. I use CityDesk for this site and others (Note: as of 2007, I use <a href="http://www.realmacsoftware.com/rapidweaver" rel="self">RapidWeaver</a>). It averages about $100 a user for contributors and $300 for the site designer, but for small sites, a free version is available.</li>
<ul><li><b>Advantages</b>: Complete control of resulting site, linking is easy, everything is editable, very easy to use, attachments usually supported</li>
<li><b>Disadvantage</b>: Must set up templates, edits not usually logged</li></ul></ul><br />For some knowledge bases, a combination of these ideas can work very well&mdash;a news group for requests and a Wiki or CMS for official information, or a Wiki for internal use and a CMS for customer facing pages that need to look pretty.]]></content:encoded></item><item><title>Book Review: VB for Testers</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-05T17:46:05-05:00</dc:date><link>http://www.loufranco.com/blog/files/BookReviewVBForTesters.html#unique-entry-id-6</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/BookReviewVBForTesters.html#unique-entry-id-6</guid><content:encoded><![CDATA[<div class="image-right"><img class="imageStyle" alt="Book cover of VB for Testers" src="http://www.loufranco.com/blog/files/page2_blog_entry6_1.jpg" width="126" height="160"/></div>I was somewhat skeptical about <em>Visual Basic for Testers</em> [<a href="http://www.amazon.com/exec/obidos/tg/detail/-/1893115534/qid=1073357500/sr=1-1/ref=sr_1_1/102-5298284-0307334" rel="self">amazon</a>] because I thought it was going to be focused on automated GUI testing. I have no interest in reinventing <a href="http://www.mercuryinteractive.com/products/winrunner/" rel="self">WinRunner</a> or <a href="http://www.automatedqa.com/products/tc.asp" rel="self">TestComplete</a> as a giant list of SendKeys calls. Luckily, neither did Mary Romero Sweeney. She concludes the first chapter with the advice that &ldquo;Visual Basic should not be considered a substitute for the major test tools but simply a powerful adjunct to them&rdquo;. Earlier in the chapter, in a section titled <strong>Automated Software Testing in the Real World</strong> (page 8), she justifies the use of VB and other general-purpose languages for testing with this:<br /><blockquote><p>Using Visual Basic and other programming languages on a test project are some of the real-world techniques we end up using when our high-priced automated testing tools just can't get to that important information. This is not meant as a criticism of the automated test tools on the market today [...] However, by default, these tools can't possibly keep up with every need on every test project. Most testing organizations find that at some point they need to resort to using programming-experienced personnel to write code to supplement their testing.</p></blockquote>I have to confess that had she not been clear about this goal, I may have abandoned the book here. Confident that this book was going to offer something to add to my arsenal of testing techniques, I read on.<br /><br />The next few chapters are an introduction to VB focusing on the features that a tester would be interested in (getting data from a database, automating a COM object, manipulating the registry). Experienced VB programmers will likely skip over these chapters. If you want to skim these chapters, I recommend hunting down the asides marked &ldquo;Tester's Tip&rdquo; and those set off with dotted lines and a bold centered title. Some of the latter of these are good software development process tips. Ms. Sweeney rightly realized that she was addressing beginning programmers and sought to instill good practice in them from the start. She offers tips on accessibility (p. 52), tab order (p. 54), setting up a directory structure (p. 62), and naming conventions (p. 77). These are all important concepts and it's never too early to learn them.<br /><br />It's obvious that Ms. Sweeney actually uses VB for testing, because the examples are suited to VB's strengths, not just a hodgepodge of VB features. She spends most of her time on database, COM, registry, file I/O and other Windows API features, revisiting them in later chapters. This is the gap between unit testing (which is best written in the same language of the application) and automated GUI testing (written using off-the-shelf tools). These features are hard to test with a recorder and often best tested in the language you expect your customers to use, which in many cases is VB. If your application exposes a COM interface, for instance, it would be foolish not to use VB.<br /><br />Chapter 10, <strong>Testing the Web with Visual Basic</strong>, begins with an explanation that there are tools (some free) for testing websites, but also that there is more you can do with VB. One useful example in this chapter is a testing web browser that exposes the internals of the site. I could see this being useful, for example, for verifying that specific headers are present without constantly viewing source. And since you use the IE control, you can be assured that the page will be rendered exactly as it would in IE. Taking the idea further, the browser could be a flight recorder for functional testing&mdash;logging exactly what you've done on a site, so that if you see a bug, it would be easy to reproduce.<br /><br />The one critique I have of the book is that while the examples are great for learning the features of VB, they are not really testing scripts. In real testing scripts, there would not be visual confirmation&mdash;testing scripts run best without a GUI or intervention from the user, only logging information when there is something wrong. The examples are visual because of the visual nature of VB development and the fact that when learning a new language, it's easier to understand if you can see what's going on.&nbsp;&nbsp;I would have liked to see the idea of self-verification explored more. That being said, Ms. Sweeney says in the introduction that this is not a software testing automation book or a VB manual&mdash;that it is enough of both to get started on using VB for automation, and readers are expected to be somewhat familiar with automation practice. She recommends <em>Software Test Automation</em> by Fewster and Graham [<a href="http://www.amazon.com/exec/obidos/tg/detail/-/0201331403/ref=sib_rdr_dp/104-1562018-1491922?%5Fencoding=UTF8&no=283155&me=ATVPDKIKX0DER&st=books" rel="self">amazon</a>] and&nbsp;<em>Automated Software Testing: Introduction, Management, and Performance</em> by Dustin, et al. [<a href="http://www.amazon.com/exec/obidos/tg/detail/-/0201432870/qid=1073401931/sr=1-1/ref=sr_1_1/104-1562018-1491922?v=glance&s=books" rel="self">amazon</a>] for learning automation practice.<br /><br />Also, realizing the need to at least mention .NET, this book tacks on two chapters from a VB.NET book. They are not specifically about testing and serve to introduce a VB programmer to the many differences in between VB and VB.NET. It is somewhat of an afterthought, and might be useful to get your feet wet, but I would have liked to see some of the &ldquo;Testing Tips&rdquo; or other asides from the earlier chapters.<br /><br />The book ends with advice directly from some professional test automators and genuinely useful appendices. Appendix D collects some interesting essays for further reading.<br /><br />If you are in test automation, and running up against the limitations of the available tools, this book is great for learning how to fill that gap. Also, any tester who is interested in learning how to program will find the advice invaluable and the examples relevant to their work. The fact that Ms. Sweeney and her contributors are professional test automators imparting hard-won advice makes this book all the more useful.]]></content:encoded></item><item><title>Using jUnit for Monitoring</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2004-01-01T17:42:36-05:00</dc:date><link>http://www.loufranco.com/blog/files/UsingjUnitforMonitoring.html#unique-entry-id-5</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/UsingjUnitforMonitoring.html#unique-entry-id-5</guid><content:encoded><![CDATA[Since jUnit (and the xUnit family) is just a verification mechanism, it's a natural fit for service monitoring.&nbsp;<a href="http://www.sys-con.com/story/?storyid=37797&DE=1" rel="self">This article from JDJ describes using jUnit and JMX to build a service monitoring framework</a>:<br /><blockquote><p>This article walks you through the process of setting up a basic service monitor and event handler for a common J2EE n-tier system. Developers of J2EE systems will be able to use JMX4ODP to create testing suites to help them develop more reliable systems. J2EE application administrators will be able to use JMX4ODP to simplify and regulate the management of deployed systems.</p></blockquote>Why jUnit?<br /><blockquote><p>JUnit bills itself as a regression-testing suite for code objects, but it's not much of a leap to see it as a tool for distributed system diagnostics. JUnit runs tests by instantiating objects, invoking their methods with known inputs, and checking the output against expected returns.The article is very Java and J2EE focused, but the concepts are applicable to any service monitoring project.</p></blockquote>]]></content:encoded></item><item><title>Source Control for One</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2003-12-31T17:37:37-05:00</dc:date><link>http://www.loufranco.com/blog/files/SourceControlforOne.html#unique-entry-id-4</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/SourceControlforOne.html#unique-entry-id-4</guid><content:encoded><![CDATA[Eric Sink, whose company, SourceGear, publishes a source control product called&nbsp;<a href="http://www.sourcegear.com/vault" rel="self">SourceGear Vault</a>, announced that they are now offering a single user license for $49.<br /><br />He has an excellent article about <a href="http://software.ericsink.com/20031103.html#10134" rel="self">why to use source control on projects with one developer</a> and a <a href="http://software.ericsink.com/20031104.html#10135" rel="self">follow up</a>.<br /><br />To his list of reasons, I'd add these:<br /><ul><li>It enables Daily Builds.&nbsp; You can't build on a clean machine from the source on your drive. You need there to be an official, working version of the source.</li>
<li>It enables bug fixes to released versions. Using labeling and branching features, you can fix a bug in a released version to a user without also giving them every change you've made since then. This is important no matter how many developers you have.</li>
<li>It enables binary search bug fixing. Outlined in this JoelOnSoftware article, it's simply a way of finding a bug by systematically trying each archived build until you find the one that introduced the bug.&nbsp; Then you check the log entries to see what you did.</li></ul>
Eric sells the benefits a little short, I think, but any company with one developer is unlikely to shell out a lot for source control, so the price is probably right, and there's always that hope for a second developer.]]></content:encoded></item><item><title>Unit Testing with NUnit</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2003-12-31T16:21:19-05:00</dc:date><link>http://www.loufranco.com/blog/files/UnitTestingwithNUnit.html#unique-entry-id-3</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/UnitTestingwithNUnit.html#unique-entry-id-3</guid><content:encoded><![CDATA[I'm preparing a presentation on unit testing in .NET (using <a href="http://www.nunit.org" rel="self">NUnit</a>). Unit Testing is generally non-implementation language specific. The original SmallTalk framework and the popular <a href="http://www.junit.org" rel="self">jUnit Framework</a> for Java have nearly identical designs. The same is true for CppUnit (for C++) and every other unit testing framework I've looked at. Since .NET languages support all of the language features necessary to implement this design, I assumed that it would be the same&mdash;and for NUnit 1.0, that was the case.<br /><br />NUnit 2.0 takes it further. The developers correctly realized that .NET offers some features that can automate some of the tasks in unit testing, and took advantage of them. This &ldquo;breaks&rdquo; consistency with other unit testing frameworks, but for a good reason, and it's close enough to the others to not be a big problem.<br /><br />The basic architecture of the xUnit Frameworks provides a base class called TestCase which you extend to contain the test methods. The framework requires you to write another class that builds a list of these classes into a TestSuite. In jUnit, this class typically looks like this:<br /><br /><span style="font-family:Courier"><b>import</b> junit.framework.*;<br/>
<br/>
<b>public class</b> AllTests<br/>
{<br/>
&nbsp;&nbsp;<b>public static</b> Test suite() {  <br/>
&nbsp;&nbsp;&nbsp;&nbsp;TestSuite suite = <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>new</b> TestSuite("All tests");<br/>
<br/>
&nbsp;&nbsp;&nbsp;&nbsp;suite.addTest(<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>new</b> TestSuite(ReaderTest.<b>class</b>)<br/>
&nbsp;&nbsp;&nbsp;&nbsp;);<br/>
<br/>		
&nbsp;&nbsp;&nbsp;&nbsp;suite.addTest(<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>new</b> TestSuite(CommandTest.<b>class</b>)<br/>
&nbsp;&nbsp;&nbsp;&nbsp;);<br/>
<br/>
&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b> suite;<br/>
&nbsp;&nbsp;}<br/>
}<br/></span><br /><br />Note that the method AllTests.suite() must be edited each time a test class is added. If you forget, you will get a false test success. If you're writing tests first, you will notice this immediately&mdash;but it would still be nice not to have to write or maintain this class. NUnit 2.0 uses custom attributes so that the framework can discover all Test classes and call them automatically, and takes care of this manual task. In NUnit, instead of extending a TestCase, you use a custom attribute to mark the class as a TestFixture and add test methods to it (either marked with the attribute Test or named with the prefix &ldquo;test&rdquo;).&nbsp; It looks like this:<br /><br /><span style="font-family:Courier"><b>namespace</b> NUnit.Tests<br/>
{<br/>
&nbsp;&nbsp;<b>using</b> System;<br/>
&nbsp;&nbsp;<b>using</b> NUnit.Framework;<br/>
<br/>  
&nbsp;&nbsp;[TestFixture]<br/>
&nbsp;&nbsp;<b>public class</b> SuccessTests<br/>
&nbsp;&nbsp;{<br/>
&nbsp;&nbsp;&nbsp;&nbsp;[Test] <b>public void</b> Add()<br/>
&nbsp;&nbsp;&nbsp;&nbsp;{ /* ... */ }<br/>
<br/>
&nbsp;&nbsp;&nbsp;&nbsp;<b>public void</b> TestSubtract()<br/>
&nbsp;&nbsp;&nbsp;&nbsp;{ /* ... */ }<br/>
&nbsp;&nbsp;}<br/>
}</span>
<br /><br />There is no need to write an AllTests class, as .NET has features that allows the framework to discover this class automatically and run it. Kent Beck calls this an &ldquo;idiomatic design&rdquo;, one that takes advantage of language features, instead of porting the design from a language with less features, and is a good lesson for any type of language port.]]></content:encoded></item><item><title>Getting Started with Extreme Programming</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2003-12-23T16:17:59-05:00</dc:date><link>http://www.loufranco.com/blog/files/GettingStartedwithExtreme.html#unique-entry-id-2</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/GettingStartedwithExtreme.html#unique-entry-id-2</guid><content:encoded><![CDATA[Extreme Programming combines several practices into a well-defined software process. The goal of XP is to deliver features to the end user as fast as possible. Some of the practices are focused on quality, some on maintaining releasability, some on development speed and some on planning.<br /><br />XP may seem daunting to you at first because it's probably very different from how you work now. It's also common for development teams to doubt the benefits of some of the practices and resist adopting them. Therefore, when getting started with XP, you will find it easier to migrate there in small changes, each one building upon the last and gaining confidence and trust in the process the whole way. If some of the practices aren't right for your organization, you can still benefit from the others.<br /><br />There are three XP practices which are easy to adopt and will provide immediate benefit. In addition, they don't rely on other practices.<br /><br />The first, <strong>Coding Standard</strong>, simply states that you should have a consistent naming and formatting convention for your code. Many organizations already do this and some languages (Java, Eiffel, C#) already have recommended coding standards. Your coding standard should not only be internally consistent, but also consistent with industry norms. This practice enables the <strong>Metaphor</strong> and <strong>Common Code Ownership</strong> practices.<br /><br />The next, <strong>Unit Testing</strong>, is far less commonly used in non-XP shops, but no other XP practice is as easy to adopt and has as much immediate benefit as it does. Even if you are skeptical of XP, I highly recommend that you try Unit Testing and I will be spending a lot of time in this blog discussing why. Unit Testing enables <strong>Refactoring</strong>, <strong>Simple Design</strong>, <strong>Common Code Ownership</strong>, <strong>Continuous Integration</strong>, and other good practices.<br /><br />Lastly, instituting <strong>Daily Builds</strong> will make your functional testing and deployment more consistent. This is also easy to adopt and has many obvious benefits. This practice enables <strong>Continuous Integration</strong>,<strong> Small Releases</strong>, and <strong>Customer Tests</strong> practices.<br /><br />XP practices work best when combined, but it's better to be successful at using some of them than fail when trying to use them all at once.<br /><br />Once you've mastered these, pick among the enabled practices to take your process further. Practices focused on getting code to users will be most beneficial (<strong>Continuous Integration</strong>, <strong>Simple Design</strong> and <strong>Small Releases</strong>).]]></content:encoded></item><item><title>Automated Software Process Checklist</title><dc:creator>Lou Franco</dc:creator><category>Software Development</category><dc:date>2003-12-23T16:13:12-05:00</dc:date><link>http://www.loufranco.com/blog/files/AutomatedSoftwareProcessC.html#unique-entry-id-1</link><guid isPermaLink="true">http://www.loufranco.com/blog/files/AutomatedSoftwareProcessC.html#unique-entry-id-1</guid><content:encoded><![CDATA[Here is a list of software processes that should be automated<br /><br />	1.	Source control<br />	2.	Bug tracking<br />	3.	Unit Testing<br />	4.	Daily Build and Test<br />	5.	Deployment<br />	6.	Functional Testing (Black box testing)<br />	7.	Source Code Generation (from other sources -- e.g. Databases)<br /><br />I'll be talking more about these soon.&nbsp; The order is determined by what will give you the most benefit for the least additional work.<br /><br />For some projects, it's just inexcusable to not have automated deployment, and it will make sense to tackle that first. For most projects, it's the development processes which are manual or semi-manual and need to be dealt with first.]]></content:encoded></item></channel>
</rss>