<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4892696525791628275</id><updated>2011-12-13T04:31:32.102-07:00</updated><category term='fonemonkey iphone testing'/><title type='text'>Big Gorilla - Stu Stern's Blog</title><subtitle type='html'>Thoughts about the art and business of programming</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>61</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-6058241816462407729</id><published>2011-12-09T12:16:00.002-07:00</published><updated>2011-12-09T12:21:12.002-07:00</updated><title type='text'>FoneMonkey for Android Q&amp;A</title><content type='html'>I'm interviewed about FoneMonkey for Android: &lt;a href="http://jaxenter.com/fonemonkey-for-android-q-a-39195.html" target="_blank" style="color: rgb(17, 85, 204); font-family: arial, sans-serif; font-size: 13px; text-align: -webkit-auto; background-color: rgba(255, 255, 255, 0.917969); "&gt;http://&lt;span class="il" style="background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(255, 255, 204); color: rgb(34, 34, 34); background-position: initial initial; background-repeat: initial initial; "&gt;jaxenter&lt;/span&gt;.com/&lt;wbr&gt;fonemonkey-for-android-q-a-&lt;wbr&gt;39195.html&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-6058241816462407729?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/6058241816462407729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=6058241816462407729' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6058241816462407729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6058241816462407729'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/12/fonemonkey-for-android-q.html' title='FoneMonkey for Android Q&amp;A'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/12820963202656470846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-8274240036875800197</id><published>2011-11-21T20:56:00.003-07:00</published><updated>2011-11-21T21:13:09.288-07:00</updated><title type='text'>FoneMonkey, Objective-C, and the Dark Arts</title><content type='html'>Dr. Dobbs just published &lt;a href="http://drdobbs.com/open-source/231903414"&gt;part 2 of my series&lt;/a&gt; on FoneMonkey for iOS. Part 2 gets deep into the very mysterious business of how we record and playback user interactions.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Not only does this article reveal the secrets to extending FoneMonkey, but it also reveals techniques for doing unholy things in Objective-C like replacing method implementations and grafting methods onto objects at runtime.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Java took them away, but Objective-C puts the guns and knives back into programming!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-8274240036875800197?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/8274240036875800197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=8274240036875800197' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8274240036875800197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8274240036875800197'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/11/fonemonkey-objective-c-and-dark-arts.html' title='FoneMonkey, Objective-C, and the Dark Arts'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/12820963202656470846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-4211772912274622309</id><published>2011-11-14T22:40:00.003-07:00</published><updated>2011-11-14T22:41:43.807-07:00</updated><title type='text'>FoneMonkey for Android has Landed!</title><content type='html'>Just pushed FoneMonkey for Android 0.6 Early Access out the door. You can download it &lt;a href="http://www.gorillalogic.com/fonemonkey4android"&gt;here&lt;/a&gt;. We'll be uploading documentation and sample projects over the next few days. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But now...sleep.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-4211772912274622309?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/4211772912274622309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=4211772912274622309' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4211772912274622309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4211772912274622309'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/11/fonemonkey-for-android-has-landed.html' title='FoneMonkey for Android has Landed!'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/12820963202656470846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-6804064831310905700</id><published>2011-11-09T08:28:00.003-07:00</published><updated>2011-11-09T08:37:29.725-07:00</updated><title type='text'>Adobe kills Flash</title><content type='html'>Given that mobile is the future (and the present), this news that &lt;a href="http://blogs.adobe.com/conversations/2011/11/flash-focus.html"&gt;Adobe is EOL'ing mobile Flash&lt;/a&gt; amounts to a death sentence for desktop Flash as well. It's sad (and perhaps disturbing) that a mature and powerful technology loved by so many was so easily killed off by the neighborhood bully (and everybody just stood by and watched).&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Time to learn to love JavaScript.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;        &lt;p class="p1"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class="p1"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class="p1"&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-6804064831310905700?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/6804064831310905700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=6804064831310905700' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6804064831310905700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6804064831310905700'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/11/adobe-kills-flash.html' title='Adobe kills Flash'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/12820963202656470846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-2689642122228048823</id><published>2011-10-25T11:37:00.002-06:00</published><updated>2011-10-25T11:41:48.618-06:00</updated><title type='text'>Dr. Dobbs meets the monkey</title><content type='html'>I think Dr. Dobb's was the first tech mag I ever read (back in the 80's!). The good doctor just published an &lt;a href="http://drdobbs.com/open-source/231901614"&gt;article I wrote&lt;/a&gt; about FoneMonkey. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-2689642122228048823?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/2689642122228048823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=2689642122228048823' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/2689642122228048823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/2689642122228048823'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/10/dr-dobbs-meets-monkey.html' title='Dr. Dobbs meets the monkey'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/12820963202656470846</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-8465161732610657629</id><published>2011-05-11T16:54:00.000-06:00</published><updated>2011-05-13T14:51:37.404-06:00</updated><title type='text'>We're the "E" in iOS: Open source projects fill Enterprise holes in Xcode</title><content type='html'>&lt;style&gt;@font-face {   font-family: "Cambria"; }p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0in 0in 10pt; font-size: 12pt; font-family: "Times New Roman"; }div.Section1 { page: Section1; }&lt;/style&gt;     &lt;p class="MsoNormal"&gt;A  long, long time ago, just as the internet bubble was really getting  going, many pundits were talking about “internet time” to describe the  radical time compression brought about by the web. Software release  cycles were suddenly occurring over periods of just a few months rather  than years, and technology platforms were similarly revving over just a  few years whereas previously it had literally taken decades for  enterprise IT to make any major changes in how they built software.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;If  internet time was fast, what are we to make of “mobile time”? The big  bang of mobile time, the release of the first iPhone, was just four  years ago. Enterprises certainly needed to move quickly to keep up with  internet time, but at roughly the same four-year mark, most enterprises  were doing little more than creating static websites. There has been no  comparable gestation period for mobile development since Apple was nice  enough to skip over infancy and adolescence and give birth on day one to  fully formed, mature applications employing radically new user  interfaces.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;While iPhone applications have  been pretty “magical” since day one, enterprise-class tool support for  iOS app development has been quite a bit slower in coming. It’s hard to  find many enterprise developers having anything nice to say about  Apple’s Xcode IDE, which is currently the only serious game in town for  developing iOS apps. Try the Google search &lt;i style=""&gt;Xcode +”piece of crap”&lt;/i&gt; and you’ll be treated to more than 40,000 results. There are of course many similar but more colorful searches you can try.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Back  in the days of internet time, Sun created a virtually unusable IDE  called Java Workshop. Fortunately for internet time, other companies  including IBM, Borland, and Symantec created competing IDE’s and Java  development has enjoyed robust tool support ever since. The closed  nature of iOS however has understandably dampened the enthusiasm anybody  outside of Apple might have for jumping into the nascent iOS  development ecosystem. After all, Apple can at any time change the iOS  platform in such a way as to make third-party tools incompatible,  similar to the way in which iTunes was continually revved to maintain  incompatibility with the Palm Pre mobile phone.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;So,  since the usual commercial suspects have too much business sense to  enter into the iOS development ecosystem, it’s left up to those of us  with little or no business sense – I am of course referring to open  source software developers – to fill the gap! &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-8465161732610657629?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/8465161732610657629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=8465161732610657629' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8465161732610657629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8465161732610657629'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/05/were-e-in-ios-open-source-projects-fill.html' title='We&apos;re the &quot;E&quot; in iOS: Open source projects fill Enterprise holes in Xcode'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-2242204895616312693</id><published>2011-04-04T08:24:00.002-06:00</published><updated>2011-04-04T08:26:51.068-06:00</updated><title type='text'>FoneMonkey 5, baby!</title><content type='html'>This morning at 7am we unleashed FoneMonkey 5, our first officially supported production release of our record/playback functional testing tool for native iOS apps on iPhone and iPad.&lt;br /&gt;&lt;br /&gt;FoneMonkey 5 is by far our most solid release yet. Go get it now at http://www.gorillalogic.com/fonemonkey!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-2242204895616312693?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/2242204895616312693/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=2242204895616312693' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/2242204895616312693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/2242204895616312693'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/04/fonemonkey-5-baby.html' title='FoneMonkey 5, baby!'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-3770809626423097283</id><published>2011-04-01T15:32:00.005-06:00</published><updated>2011-04-01T16:02:24.703-06:00</updated><title type='text'>My Podcast with Coté</title><content type='html'>Yesterday I had the pleasure of being a guest on &lt;a href="http://www.redmonk.com/cote/"&gt;RedMonk analyst Michael Coté's&lt;/a&gt;&lt;span style="text-decoration: underline;"&gt;&lt;/span&gt; "Make All" podcast. We discussed the evolution of software dev over the last 15 years, and talked about how native apps and client-side runtimes like Flash support the delivery of full-blown client-side user interfaces, which back in 1996 is what most of us expected from Java applets.&lt;br /&gt;&lt;br /&gt;Back then, it wasn't long before we woke up to the twin realities of browser compatibility and bandwidth constraints and were forced to shunt Java from the front- to the back-end of application development, and we spent several years dealing with the page-based hack that became known as MVC2.&lt;br /&gt;&lt;br /&gt;Plentiful bandwidth and a new generation of client-side technologies such as Flex, Silverlight, Android, and iOS are finally allowing us to build user interfaces in a much more direct, natural, and efficient fashion than the page-based MVC2 approach, and arguably, provide similar advantages over the the JavaScript-meets-DOM hack now known as AJAX.&lt;br /&gt;&lt;br /&gt;You can listen to my complete conversation with Michael &lt;a href="http://www.redmonk.com/cote/2011/04/01/applets-to-ajax-to-apps-with-stu-stern-of-gorilla-logic-make-all-016/"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-3770809626423097283?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/3770809626423097283/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=3770809626423097283' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3770809626423097283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3770809626423097283'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/04/my-podcast-with-cote.html' title='My Podcast with Coté'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-7629568539147779564</id><published>2011-03-31T13:26:00.002-06:00</published><updated>2011-03-31T13:30:11.436-06:00</updated><title type='text'>Gosling@Google</title><content type='html'>The web is abuzz today with speculation about just what James Gosling will be doing for his new employer, Google. My own two cents are included in this &lt;a href="http://adtmag.com/blogs/watersworks/2011/03/google-gosling-hire.aspx"&gt;post&lt;/a&gt; from John Waters at Application Development Trends.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-7629568539147779564?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/7629568539147779564/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=7629568539147779564' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7629568539147779564'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7629568539147779564'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/03/goslinggoogle.html' title='Gosling@Google'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-8549344487137650507</id><published>2011-03-04T21:14:00.001-07:00</published><updated>2011-03-04T21:14:51.218-07:00</updated><title type='text'>FoneMonkey 4.2c improves text input handling</title><content type='html'>&lt;p&gt;We very pleased to announce the availability of FoneMonkey 4.2c which  improves handling for UITextField and UITextView components.&lt;/p&gt; &lt;p&gt;4.2c provides robust handling of keyboard input, including recording  of the Return key, and fixes an issue where sometimes touch events that  ended field editing would be recorded prior to recording the text input  itself. On playback, FoneMonkey now triggers all appropriate delegate  methods and notifications.&lt;/p&gt; &lt;p&gt;We believe that keyboard-related input issues were the last major  problem facing us and 4.2c should reliably provide recording and  playback for virtually all common user interface gestures.&lt;/p&gt; &lt;p&gt;Script and generated code storage has been moved back to the base  Documents directory to make it easier to use iTunes to move scripts on  and off iPhone and iPad devices. FoneMonkey scripts are now suffixed  with .fm. You will need to rename any existing scripts.&lt;/p&gt; &lt;p&gt;FoneMonkey 4.2c is available for immediate download at  www.gorillalogic.com/fonemonkey. Thanks for the continued feedback. Your  input is the primary factor determining what we tackle next!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-8549344487137650507?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/8549344487137650507/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=8549344487137650507' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8549344487137650507'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8549344487137650507'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/03/fonemonkey-42c-improves-text-input.html' title='FoneMonkey 4.2c improves text input handling'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-600208461945572290</id><published>2011-02-08T10:53:00.000-07:00</published><updated>2011-02-08T10:54:12.811-07:00</updated><title type='text'>FoneMonkey 4.2 adds iOS UIAutomation Support</title><content type='html'>We're excited (especially since now we can finally get some sleep) to announce the availability of FoneMonkey 4.2, the latest incarnation of Gorilla Logic's free and open source functional testing tool for iOS apps on the iPhone and iPad.&lt;br /&gt;&lt;br /&gt;FoneMonkey 4.2 includes numerous bug fixes and adds several significant new features including:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Generation of ready-to-run OCUnit test scripts&lt;/span&gt; - Automatically convert "native" FoneMonkey test scripts to Objective-C code that can be extended with Objective-C control logic to add control flow or data-driving logic to your tests.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Generation of ready-to-run JavaScript-based tests for Apple's UIAutomation&lt;/span&gt; Framework - Automatically convert "native" FoneMonkey scripts to JavaScript code that can be run in Apple's &lt;a href="http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Built-InInstruments/Built-InInstruments.html#//apple_ref/doc/uid/TP40004652-CH6-SW75"&gt;Automation Instrument&lt;/a&gt;. You can uyse FoneMonkey to record &lt;a href="http://developer.apple.com/library/ios/#documentation/DeveloperTools/Reference/UIAutomationRef/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009771-CH1-SW1"&gt;UIAutomation&lt;/a&gt; scripts which allows for test scripts to be maintained in JavaScript rather than Objective-C. Since these UIAutomation scripts require no FoneMonkey libraries to run, they can be executed against "release" builds of your application.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Recording and Playback of Device Rotation&lt;/span&gt; - You can record and playback device rotations on the simulator or on devices.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;This release is a significant step forward in the maturing of the FoneMonkey project. Thanks to the members of the FoneMonkey community for providing the feedback and support essential to making FoneMonkey a continuing success.&lt;br /&gt;&lt;br /&gt;FoneMonkey 4.2 is available for download at http://www.gorillalogic.com/fonemonkey.&lt;br /&gt;&lt;br /&gt;Happy testing!&lt;br /&gt;&lt;br /&gt;-Stu&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-600208461945572290?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/600208461945572290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=600208461945572290' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/600208461945572290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/600208461945572290'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/02/fonemonkey-42-adds-ios-uiautomation.html' title='FoneMonkey 4.2 adds iOS UIAutomation Support'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-8301504889209199408</id><published>2011-01-18T14:16:00.004-07:00</published><updated>2011-01-18T14:35:36.165-07:00</updated><title type='text'>See FoneMonkey at iPhone DevCon!</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.iphonedevcon.com/"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 222px; height: 123px;" src="http://4.bp.blogspot.com/_hNEirhCE9Kw/TTYEMmld67I/AAAAAAAAALk/_KLeRn2Vq5w/s400/iphoneDevcon.jpg" alt="" id="BLOGGER_PHOTO_ID_5563639004225465266" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I'll be presenting &lt;strong style="font-style: italic;" class="sidebarheadpurple"&gt;Automating iOS User  Interface Testing with FoneMonkey &lt;/strong&gt;&lt;strong class="sidebarheadpurple"&gt;&lt;span style="font-weight: normal;"&gt;at iPhone/iPad DevCon East in April. &lt;a href="http://www.gorillalogic.com/fonemonkey"&gt;FoneMonkey&lt;/a&gt; is a free and open source, record/playback functional testing tool for native iPhone and iPad apps. If you're going to DevCon, come on by and check out the monkey!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/strong&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-8301504889209199408?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/8301504889209199408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=8301504889209199408' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8301504889209199408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8301504889209199408'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2011/01/see-fonemonkey-at-iphone-devcon.html' title='See FoneMonkey at iPhone DevCon!'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hNEirhCE9Kw/TTYEMmld67I/AAAAAAAAALk/_KLeRn2Vq5w/s72-c/iphoneDevcon.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-8534882881279370513</id><published>2010-12-16T16:12:00.003-07:00</published><updated>2010-12-16T17:06:18.301-07:00</updated><title type='text'>FlexMonkium 4.1.4 Released!</title><content type='html'>We are pleased to announce the newest version of FlexMonkium, Gorilla Logic's plugin that adds Flex recording and playback capabilities to the Selenium web testing framework. FlexMonkium  4.1.4, available for download from www.gorillalogic.com/flexmonkey.&lt;br /&gt;&lt;br /&gt;FlexMonkium 4.1.4 includes some important enhancements, bug fixes and usability features including:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Support for running FlexMonkey tests in Internet Explorer with Selenium-RC. Previous versions of FlexMonkium only supported Firefox.&lt;/li&gt;&lt;li&gt;Bug fixes for the getFlexMonkeyValue command, which now reliably retrieves values from properties and table cells.&lt;/li&gt;&lt;li&gt;Commands can now be made to wait for a component to appear before executing. For example, a command for clicking on a button will wait for the button to appear before attempting to click it.&lt;/li&gt;&lt;li&gt;Ability to verify (or retrieve) values for property path expressions. For example, you can verify the number of rows in a DataGrid with the path expression "dataProvider.length".&lt;/li&gt;&lt;li&gt;By default, all commands and verifies are now recorded as "WaitFor..." commands, which eliminates the need in most cases to slow or pause script execution to give components time to appear on the display.&lt;/li&gt;&lt;li&gt;The XML recorded by Selenium-IDE for FlexMonkey commands has been simplified to make reading and editing easier.&lt;/li&gt;&lt;/ul&gt;FlexMonkium 4.1.4 is the successor to FlexMonkium 1.1. We changed the version numbering so that it syncs up with FlexMonkey version numbering (which we in turn changed last year to sync up with Flex version numbering).&lt;br /&gt;&lt;br /&gt;To upgrade to FlexMokium 4.1.4, install the new console and download the new zip file. Upgrade the Firefox plugin by opening flexmonkium.xpi in Firefox. You will need to compile your app with the latest automation_monkey swc file. You will additionally need to use the new version of user-extensions.js with Selenium-RC.&lt;br /&gt;&lt;br /&gt;Happy testing!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-8534882881279370513?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/8534882881279370513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=8534882881279370513' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8534882881279370513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8534882881279370513'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/12/flexmonkium-414-released.html' title='FlexMonkium 4.1.4 Released!'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-8423888104421599981</id><published>2010-11-18T16:32:00.003-07:00</published><updated>2010-11-18T16:34:28.193-07:00</updated><title type='text'>Great In-Depth Guide to FlexMonkey</title><content type='html'>Jon Rose has just published an extensive guide explaining the finer points of using FlexMonkey. You can check it out &lt;a href="http://www.infoq.com/articles/flexmonkey-deep-dive"&gt;here&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-8423888104421599981?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/8423888104421599981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=8423888104421599981' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8423888104421599981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8423888104421599981'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/11/great-in-depth-guide-to-flexmonkey.html' title='Great In-Depth Guide to FlexMonkey'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-1333144538421302983</id><published>2010-11-08T22:17:00.002-07:00</published><updated>2010-11-08T22:21:28.012-07:00</updated><title type='text'>New FoneMonkey for iOS Release!</title><content type='html'>We've just released the latest version of FoneMonkey, our free and open source functional testing tool for iOS applications on the iPhone, iPad, and iPod Touch.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can find it at http://www.gorillalogic.com/fonemonkey.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Happy testing!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-1333144538421302983?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/1333144538421302983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=1333144538421302983' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/1333144538421302983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/1333144538421302983'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/11/new-fonemonkey-for-ios-release.html' title='New FoneMonkey for iOS Release!'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-7118349708628744665</id><published>2010-11-04T20:39:00.002-06:00</published><updated>2010-11-04T20:42:36.684-06:00</updated><title type='text'>See FlexMonkey at Flex Camp Wall Street</title><content type='html'>I'll be presenting a session on &lt;a href="http://www.gorillalogic.com/flexmonkey"&gt;FlexMonkey&lt;/a&gt; at &lt;a href="http://www.flexcampwallstreet.com/"&gt;Flex Camp Wall Street&lt;/a&gt; on November 15th in New York. Come on by to see the latest version of our open source Flex testing tool and let us know what you'd like to see it do in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-7118349708628744665?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/7118349708628744665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=7118349708628744665' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7118349708628744665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7118349708628744665'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/11/see-flexmonkey-at-flex-camp-wall-street.html' title='See FlexMonkey at Flex Camp Wall Street'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-6221252609432120896</id><published>2010-11-01T19:56:00.003-06:00</published><updated>2010-11-01T20:00:44.389-06:00</updated><title type='text'>See FoneMonkey at 360|iDev</title><content type='html'>I'll be presenting a session on our open source &lt;a href="http://www.gorillalogic.com/fonemonkey"&gt;FoneMonkey&lt;/a&gt; testing tool for iOS applications at next week's &lt;a href="http://www.360idev.com/"&gt;360|iDev&lt;/a&gt; conference in Austin, TX.&lt;br /&gt;&lt;br /&gt;If you're going to be at the conference, come on by to see how to get the most out of FoneMonkey, and let me know what you'd like to see in future releases.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-6221252609432120896?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/6221252609432120896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=6221252609432120896' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6221252609432120896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6221252609432120896'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/11/see-fonemonkey-at-360idev.html' title='See FoneMonkey at 360|iDev'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-3678668133567877636</id><published>2010-06-09T12:06:00.002-06:00</published><updated>2010-06-09T14:55:24.682-06:00</updated><title type='text'>FlexMonkium is here!</title><content type='html'>We are very excited today to announce the availability of FlexMonkium, a plugin that adds FlexMonkey recording and playback to Selenium, the popular, open source, web testing framework.&lt;br /&gt;&lt;br /&gt;FlexMonkium provides for the testing of hybrid applications consisting of both Flex and HTML components by seamlessly interleaving the recording and playback of Flex and HTML interactions. Recorded tests can be output as JUnit-based scripts that can be extended with Java-based testing logic, and that can be run from build scripts and continuous integration processes.&lt;br /&gt;&lt;br /&gt;You can download FlexMonkium from http://www.gorillalogic.com/flexmonkium.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-3678668133567877636?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/3678668133567877636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=3678668133567877636' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3678668133567877636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3678668133567877636'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/06/flexmonkium-is-here.html' title='FlexMonkium is here!'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-4745201483414821615</id><published>2010-06-05T11:19:00.003-06:00</published><updated>2010-06-05T11:24:19.599-06:00</updated><title type='text'>FoneMonkey - A Closer Look (Clever Tester Managazine)</title><content type='html'>Recently I was interviewed by Clever Tester about FoneMonkey. You can check it out &lt;a href="http://www.clevertester.com/articles/gorilla_logic_introduces_fonemonkey_a_closer_look.html"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-4745201483414821615?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/4745201483414821615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=4745201483414821615' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4745201483414821615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4745201483414821615'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/06/recently-i-was-interviewed-by.html' title='FoneMonkey - A Closer Look (Clever Tester Managazine)'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-5357929329201543996</id><published>2010-06-05T11:14:00.002-06:00</published><updated>2010-06-05T11:25:10.118-06:00</updated><title type='text'>FlexMonkey 4 and FlexMonkium (DZone)</title><content type='html'>I was recently interviewed by DZone about FlexMonkey 4 and FlexMonkium. You can check it out &lt;a href="http://css.dzone.com/articles/flexmonkey-4-and-flexmonkium"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-5357929329201543996?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/5357929329201543996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=5357929329201543996' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5357929329201543996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5357929329201543996'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/06/dzone-flexmonkey-4-and-flexmonkium.html' title='FlexMonkey 4 and FlexMonkium (DZone)'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-4457450614197678463</id><published>2010-05-25T11:30:00.004-06:00</published><updated>2010-05-25T11:33:04.648-06:00</updated><title type='text'>Flex Developer's Journal: Functional testing of Flex RIA with FlexMonkey 4</title><content type='html'>I was recently interviewed by Yakov Fain, editor of Flex Developer's Journal. You can check it out &lt;a href="http://flex.sys-con.com/node/1408137"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-4457450614197678463?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/4457450614197678463/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=4457450614197678463' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4457450614197678463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4457450614197678463'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/05/flex-developers-journal-functional.html' title='Flex Developer&apos;s Journal: Functional testing of Flex RIA with FlexMonkey 4'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-7188784244399566678</id><published>2010-05-15T16:20:00.005-06:00</published><updated>2010-05-15T19:08:11.380-06:00</updated><title type='text'>FlexMonkium: Get ready for the 119th element!</title><content type='html'>FlexMonkium, the Selenium Plugin that adds FlexMonkey recording and playback to Selenium-IDE and Selenium-RC, is undergoing final testing and packaging in preparation for its forthcoming release.&lt;br /&gt;&lt;br /&gt;In this pair of videos smuggled from Gorilla Logic labs, deep beneath the surface of the Earth, we see FlexMonkium interleaving Flex with HTML recording and playback, and generated JUnit test scripts being run with Selenium-RC.&lt;br /&gt;&lt;br /&gt;&lt;object id="scPlayer" height="480" width="640"&gt; &lt;param name="movie" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/8504d67b-9dd1-41f1-8295-11948bfa81e2/mp4h264player.swf"&gt; &lt;param name="quality" value="high"&gt; &lt;param name="bgcolor" value="#FFFFFF"&gt; &lt;param name="flashVars" value="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/8504d67b-9dd1-41f1-8295-11948bfa81e2/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/8504d67b-9dd1-41f1-8295-11948bfa81e2/FlexMonkium%20Plugin%20Part%201.mp4"&gt; &lt;param name="allowFullScreen" value="true"&gt; &lt;param name="scale" value="showall"&gt; &lt;param name="allowScriptAccess" value="always"&gt; &lt;param name="base" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/8504d67b-9dd1-41f1-8295-11948bfa81e2/"&gt;  &lt;embed src="http://content.screencast.com/users/StuStern/folders/Camtasia/media/8504d67b-9dd1-41f1-8295-11948bfa81e2/mp4h264player.swf" quality="high" bgcolor="#FFFFFF" type="application/x-shockwave-flash" allowscriptaccess="always" flashvars="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/8504d67b-9dd1-41f1-8295-11948bfa81e2/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/8504d67b-9dd1-41f1-8295-11948bfa81e2/FlexMonkium%20Plugin%20Part%201.mp4" allowfullscreen="true" base="http://content.screencast.com/users/StuStern/folders/Camtasia/media/8504d67b-9dd1-41f1-8295-11948bfa81e2/" scale="showall" height="480" width="640"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;object id="scPlayer" height="480" width="640"&gt; &lt;param name="movie" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/2d1a708d-ec9b-46c4-9b79-f1fdb0d43f00/mp4h264player.swf"&gt; &lt;param name="quality" value="high"&gt; &lt;param name="bgcolor" value="#FFFFFF"&gt; &lt;param name="flashVars" value="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/2d1a708d-ec9b-46c4-9b79-f1fdb0d43f00/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/2d1a708d-ec9b-46c4-9b79-f1fdb0d43f00/FlexMonkium%20Plugin%20Part%202.mp4"&gt; &lt;param name="allowFullScreen" value="true"&gt; &lt;param name="scale" value="showall"&gt; &lt;param name="allowScriptAccess" value="always"&gt; &lt;param name="base" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/2d1a708d-ec9b-46c4-9b79-f1fdb0d43f00/"&gt;  &lt;embed src="http://content.screencast.com/users/StuStern/folders/Camtasia/media/2d1a708d-ec9b-46c4-9b79-f1fdb0d43f00/mp4h264player.swf" quality="high" bgcolor="#FFFFFF" type="application/x-shockwave-flash" allowscriptaccess="always" flashvars="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/2d1a708d-ec9b-46c4-9b79-f1fdb0d43f00/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/2d1a708d-ec9b-46c4-9b79-f1fdb0d43f00/FlexMonkium%20Plugin%20Part%202.mp4" allowfullscreen="true" base="http://content.screencast.com/users/StuStern/folders/Camtasia/media/2d1a708d-ec9b-46c4-9b79-f1fdb0d43f00/" scale="showall" height="480" width="640"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-7188784244399566678?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/7188784244399566678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=7188784244399566678' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7188784244399566678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7188784244399566678'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/05/flexmonkium-119th-element-available-for.html' title='FlexMonkium: Get ready for the 119th element!'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-4852810186685125123</id><published>2010-05-05T17:41:00.003-06:00</published><updated>2010-05-05T17:51:43.910-06:00</updated><title type='text'>FlexMonkey 4 is here!</title><content type='html'>We just posted the new installer and accessories zip to &lt;a href="http://www.gorillalogic.com/flexmonkey"&gt;FlexMonkey Project Home&lt;/a&gt;. Getting FlexMonkey to work with Flex 4 proved to be a bit more work than we'd anticipated but ultimately we got everything working and the result is a solid release that includes support for all Spark components.&lt;br /&gt;&lt;br /&gt;Happily, we now return our attention back to FlexMonkium, our FlexMonkey/Selenium bridge, which is rapidly nearing it's first public release!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-4852810186685125123?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/4852810186685125123/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=4852810186685125123' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4852810186685125123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4852810186685125123'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/05/flexmonkey-4-is-here.html' title='FlexMonkey 4 is here!'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-5293839320705779116</id><published>2010-04-18T21:29:00.002-06:00</published><updated>2010-04-18T21:33:15.922-06:00</updated><title type='text'>FlexMonkey 4 is coming!</title><content type='html'>We've just completed testing and anticipate releasing FlexMonkey for Flex 4 before the end of April!&lt;br /&gt;&lt;br /&gt;This upcoming release, which we think we're going to call "FlexMonkey 4", works perfectly with Flex 4 and handles all of the new Spark components.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-5293839320705779116?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/5293839320705779116/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=5293839320705779116' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5293839320705779116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5293839320705779116'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/04/flexmonkey-4-is-coming.html' title='FlexMonkey 4 is coming!'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-5171865690290124990</id><published>2010-04-04T21:18:00.003-06:00</published><updated>2010-04-04T21:25:59.960-06:00</updated><title type='text'>FoneMonkey 0.7.2 Released</title><content type='html'>Thanks to the continuing feedback from our rapidly growing community of FoneMonkey users, we've been able to identify and fix several issues and bring you FoneMonkey 0.7.2, available now at FoneMonkey &lt;a href="http://www.gorillalogic.com/fonemonkey"&gt;Project Home&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This release fixes various bugs including problems with keyboard and scroll recording.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-5171865690290124990?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/5171865690290124990/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=5171865690290124990' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5171865690290124990'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5171865690290124990'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/04/fonemonkey-072-released.html' title='FoneMonkey 0.7.2 Released'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-1016517797124382563</id><published>2010-03-16T21:15:00.001-06:00</published><updated>2010-03-16T21:21:34.146-06:00</updated><title type='text'>FoneMonkey 0.7.1 Released</title><content type='html'>Thanks to the intrepid souls who have taken the plunge into the first ever public release of FoneMonkey, we got some great feedback from 0.7 users and have just posted a new release, 0.7.1, with several important bug fixes and feature enhancements, notably:&lt;br /&gt;&lt;br /&gt;Enhancements:&lt;br /&gt;&lt;br /&gt;* WaitFor command - You can cause script execution to wait for views to be created or property values to be set&lt;br /&gt;* "Popup Dialog" handling - You can now script UIAlertViews and UIAlertSheets.&lt;br /&gt;* Better control event handling for UITextFields.&lt;br /&gt;&lt;br /&gt;Bug fixes:&lt;br /&gt;&lt;br /&gt;* OCUnit runner crash&lt;br /&gt;* UINavigationBar rightItem playback&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;FoneMonkey 0.7.1 can be downloaded from FoneMonkey &lt;a href="http://www.gorillalogic.com/fonemonkey"&gt;Project Home&lt;/a&gt;. We can understand if you considered 0.7 to be too early a release to try, but surely you'll feel differently about 0.7.1, which includes not one, but two, decimal points.&lt;br /&gt;&lt;br /&gt;In all honesty, FoneMonkey, while not yet bug free, is quite stable and will definitely make your life better, at least in terms of iPhone testing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-1016517797124382563?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/1016517797124382563/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=1016517797124382563' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/1016517797124382563'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/1016517797124382563'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/03/fonemonkey-071-released.html' title='FoneMonkey 0.7.1 Released'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-4457549910288069287</id><published>2010-02-28T12:03:00.000-07:00</published><updated>2010-02-28T12:41:45.541-07:00</updated><title type='text'>Selenium Assertions and waitFors in FlexMonkium</title><content type='html'>In our &lt;a href="http://stu-stern.blogspot.com/2010/02/flexmonkium-movie.html"&gt;previous video&lt;/a&gt;, we saw recording and playback of Flex interactions interleaved with browser interactions within a single &lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt; script. Today's video shows how we can execute &lt;a href="http://www.gorillalogic.com/flexmonkey"&gt;FlexMonkey&lt;/a&gt; Verify commands as &lt;span style="font-style: italic;"&gt;assertions&lt;/span&gt; or &lt;span style="font-style: italic;"&gt;waitFor&lt;/span&gt; predicates within a Selenium script.&lt;br /&gt;&lt;br /&gt;The video shows a simply script being played back at slow speed. When we then try to play the same script back at fast speed, it fails because the script navigates to the page containing a Flex app, but then attempts to interact with it before the app has finished loading.&lt;br /&gt;&lt;br /&gt;What we would like to do is have a way to tell Selenium to wait for some condition that signals the app has finished loading. One way to do this is to have Selenium wait for the appearance of a component within the application's window. We interactively create a FlexMonkey Verify command that tests whether the name field has a blank value. Notice that when we create this command, it is also "recorded" by the Selenium IDE as an assertion, &lt;span style="font-style: italic;"&gt;assertFlexVerify&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;This assertion will fail if it is executed before the swf has finished loading. However, we can ask Selenium to wait for the condition to become true by changing the assertFlexVerify command to be a &lt;span style="font-style: italic;"&gt;waitForFlexVerify&lt;/span&gt; instead. Now, when we run the script, it waits for the swf to load before continuing, and then successfullly plays the rest of the script at high speed. We can of course use a similar technique to have a Selenium script wait for other Flex application events, such as data being returned from a query to be displayed in a table.&lt;br /&gt;&lt;br /&gt;&lt;object id="scPlayer" width="640" height="480"&gt; &lt;param name="movie" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/e40edae0-d987-4095-afd8-b418a8e67938/mp4h264player.swf"&gt;&lt;/param&gt; &lt;param name="quality" value="high"&gt;&lt;/param&gt; &lt;param name="bgcolor" value="#FFFFFF"&gt;&lt;/param&gt; &lt;param name="flashVars" value="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/e40edae0-d987-4095-afd8-b418a8e67938/FirstFrame.jpg&amp;containerwidth=640&amp;containerheight=480&amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/e40edae0-d987-4095-afd8-b418a8e67938/FoneMonkey%20Assertions%20and%20WaitFors.mp4"&gt;&lt;/param&gt; &lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt; &lt;param name="scale" value="showall"&gt;&lt;/param&gt; &lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt; &lt;param name="base" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/e40edae0-d987-4095-afd8-b418a8e67938/"&gt;&lt;/param&gt; &lt;embed src="http://content.screencast.com/users/StuStern/folders/Camtasia/media/e40edae0-d987-4095-afd8-b418a8e67938/mp4h264player.swf" quality="high" bgcolor="#FFFFFF" width="640" height="480" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/e40edae0-d987-4095-afd8-b418a8e67938/FirstFrame.jpg&amp;containerwidth=640&amp;containerheight=480&amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/e40edae0-d987-4095-afd8-b418a8e67938/FoneMonkey%20Assertions%20and%20WaitFors.mp4" allowFullScreen="true" base="http://content.screencast.com/users/StuStern/folders/Camtasia/media/e40edae0-d987-4095-afd8-b418a8e67938/" scale="showall"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;br /&gt;&lt;br /&gt;As you can see, we have all the major mechanisms necessary to very clean integration of FlexMonkey and Selenium. There is some trivial syntactic sugar we will likely sprinkle on what the video shows here, and we've still got some code clean up to do before we'll be ready to release, but we believe all the hard problems have been solved so it won't be much longer before FlexMonkium, the FlexMonkey Plug-In for Selenium, is publicly available!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-4457549910288069287?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/4457549910288069287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=4457549910288069287' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4457549910288069287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4457549910288069287'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/02/selenium-assertions-and-waitfors-in.html' title='Selenium Assertions and waitFors in FlexMonkium'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-1996482298652641233</id><published>2010-02-27T21:52:00.001-07:00</published><updated>2010-02-27T23:22:57.098-07:00</updated><title type='text'>FlexMonkium: The Movie</title><content type='html'>Once again, we bring you a video smuggled at great risk from &lt;a href="http://www.gorillalogic.com/"&gt;Gorilla Logic&lt;/a&gt; Labs, deep beneath the surface of the Earth.&lt;br /&gt;&lt;br /&gt;Last week, on this very blog, the world first learned of &lt;a href="http://stu-stern.blogspot.com/2010/02/flexmonkium-flexmonkeyselenium-bridge.html"&gt;FlexMonkium&lt;/a&gt;, the &lt;a href="http://gorillalogic.com/flexmonkey"&gt;FlexMonkey&lt;/a&gt; plug-in for &lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt;. Now, we are pleased to present this exclusive video of FlexMonkium in action, allowing Selenium IDE to record both browser and Flex application interactions within a single Selenium script.&lt;br /&gt;&lt;br /&gt;Although the recorded scenario is seemingly simple, it is actually quite wonderful. Selenium IDE begins recording on a plain html page, and continues recording as we navigate to a page containing a Flex application, and Flex application interactions are recorded to the script. Recording continues as we hit an html link ("Back") outside the Flex application in the browser page. For good measure, we continue recording as we navigate again to the page with the Flex app for further interaction, and then navigate back to the plain html page. All Flex and browser interactions have been recorded to a single Selenium script!&lt;br /&gt;&lt;br /&gt;And of course, playback works as well.&lt;br /&gt;&lt;br /&gt;&lt;object id="scPlayer" width="640" height="480"&gt; &lt;param name="movie" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/fb862764-6784-4370-ba91-753c624f4a33/mp4h264player.swf"&gt; &lt;param name="quality" value="high"&gt; &lt;param name="bgcolor" value="#FFFFFF"&gt; &lt;param name="flashVars" value="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/fb862764-6784-4370-ba91-753c624f4a33/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/fb862764-6784-4370-ba91-753c624f4a33/FlexMonkium%20The%20Movie.mp4"&gt; &lt;param name="allowFullScreen" value="true"&gt; &lt;param name="scale" value="showall"&gt; &lt;param name="allowScriptAccess" value="always"&gt; &lt;param name="base" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/fb862764-6784-4370-ba91-753c624f4a33/"&gt; &lt;embed src="http://content.screencast.com/users/StuStern/folders/Camtasia/media/fb862764-6784-4370-ba91-753c624f4a33/mp4h264player.swf" quality="high" bgcolor="#FFFFFF" type="application/x-shockwave-flash" allowscriptaccess="always" flashvars="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/fb862764-6784-4370-ba91-753c624f4a33/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/fb862764-6784-4370-ba91-753c624f4a33/FlexMonkium%20The%20Movie.mp4" allowfullscreen="true" base="http://content.screencast.com/users/StuStern/folders/Camtasia/media/fb862764-6784-4370-ba91-753c624f4a33/" scale="showall" width="640" height="480"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;br /&gt;&lt;br /&gt;Just a few more weeks and we'll be ready to release FlexMonkum! If you're interested in early access, please &lt;a href="http://gorillalogic.com/who-we-are/contact"&gt;let us know&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-1996482298652641233?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/1996482298652641233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=1996482298652641233' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/1996482298652641233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/1996482298652641233'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/02/flexmonkium-movie.html' title='FlexMonkium: The Movie'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-6059062120367690856</id><published>2010-02-23T21:32:00.000-07:00</published><updated>2010-02-23T21:36:46.809-07:00</updated><title type='text'>We've released FoneMonkey, our record/play functional tester for iPhone</title><content type='html'>We officially launched the FoneMonkey open source project today at &lt;a href="http://www.gorillalogic.com/fonemonkey"&gt;http://www.gorillalogic.com/fonemonkey&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If you've been following my recent posts, you know that FoneMonkey is the world's first record/playback functional testing tool for the iPhone. FoneMonkey records user interactions with the iPhone, and replays them while verifying that actual results match expected ones.&lt;br /&gt;&lt;br /&gt;Key FoneMonkey features:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;High fidelity &lt;span style="font-weight: bold;"&gt;recording and playback of most iPhone gestures&lt;/span&gt; including touches, drags, and shakes.&lt;/li&gt;&lt;li&gt;I&lt;span style="font-weight: bold;"&gt;ntegrated script editor and test runner&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Recording and playback on both the &lt;span style="font-weight: bold;"&gt;simulator and actual iPhone&lt;/span&gt; device.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Extensible framework&lt;/span&gt; can be customized to provide specialized command recording and playback for custom components.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Simple Objective-API&lt;/span&gt; can be used to run FoneMonkey scripts using &lt;span style="font-weight: bold;"&gt;OCUnit&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;With complete source, downloads, documentation, video tutorials, and a user forum available now at &lt;a href="http://www.gorillalogic.com/fonemonkey"&gt;FoneMonkey Home&lt;/a&gt;, we are fully ready to monkey!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-6059062120367690856?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/6059062120367690856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=6059062120367690856' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6059062120367690856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6059062120367690856'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/02/weve-released-fonemonkey-our-recordplay.html' title='We&apos;ve released FoneMonkey, our record/play functional tester for iPhone'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-1746554762584707351</id><published>2010-02-22T17:00:00.000-07:00</published><updated>2010-02-22T18:01:19.900-07:00</updated><title type='text'>FlexMonkium: FlexMonkey/Selenium Bridge</title><content type='html'>Hey, all you Selenium people out there, get ready to monkey!&lt;br /&gt;&lt;br /&gt;We've been getting a lot of requests about integrating &lt;a href="http://www.gorillalogic.com/flexmonkey"&gt;FlexMonkey&lt;/a&gt; with &lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt; to provide testing of "hybrid" test scenarios involving both Flex and non-Flex web apps. It is of course common to embed Flex applications within web pages that also contain non-Flex, HTML components, and the combined Flex and non-Flex pieces together produce a single user experience and workflow. Ideally, such hybrid user interface scenarios could be automated within a single test case. In fact, many times the functional dependencies between Flex and non-Flex components make it impossible to test one without the other.&lt;br /&gt;&lt;br /&gt;While we've been hearing about many efforts to combine FlexMonkey with Selenium to provide for such hybrid testing, we're not aware of anything having yet been made publicly available, and having just completed development of &lt;a href="http://www.gorillalogic.com/fonemonkey"&gt;FoneMonkey&lt;/a&gt; (which we're officially announcing tomorrow), and FlexMonkey 1.0GA (which we're releasing in about a week), we've had some time to take a look ourselves at how we might go about integrating Selenium with The Monkey.&lt;br /&gt;&lt;br /&gt;After exploring various permutations, we hit upon a very robust approach through which we  "slave" FlexMonkey recording and playback beneath Selenium. We have created a bridge, which we are provisionally calling &lt;span style="font-style: italic;"&gt;FlexMonkium&lt;/span&gt;, that forwards FlexMonkey commands to Selenium during recording, and forwards FlexMonkey commands from Selenium to FlexMonkey during playback. Such FlexMonkey recording and playback is seamlessly interleaved with native Selenium recording and playback to easily produce hybrid testing scenarios. For example, in a single recording session you can click on HTML components and Flex components, even across multiple browser pages, with the resulting FlexMonkey and Selenium commands being recorded into a single Selenium script which (with the aid of the FlexMonkium bridge) can then be played back with any Selenium runner.&lt;br /&gt;&lt;br /&gt;We are fairly confident we'll have something ready for early access in a matter of weeks! If you'd like to get your hands on FlexMonkium as soon as possible, contact us &lt;a href="http://gorillalogic.com/who-we-are/contact"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-1746554762584707351?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/1746554762584707351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=1746554762584707351' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/1746554762584707351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/1746554762584707351'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/02/flexmonkium-flexmonkeyselenium-bridge.html' title='FlexMonkium: FlexMonkey/Selenium Bridge'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-7880267958836896190</id><published>2010-02-10T18:41:00.000-07:00</published><updated>2010-02-10T18:50:29.662-07:00</updated><title type='text'>FoneMonkey is In the Launch Tube</title><content type='html'>Although we're not officially launching for another week or so, the &lt;span style="font-weight: bold;"&gt;FoneMonkey&lt;/span&gt; project site is now live at &lt;a href="http://www.gorillalogic.com/fonemonkey"&gt;http://www.gorillalogic.com/fonemonkey&lt;/a&gt;. We've published the source, binaries, and complete documentation. The issue management system and discussion board are also open for business.&lt;br /&gt;&lt;br /&gt;iPhone developers of the world, get ready to monkey!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-7880267958836896190?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/7880267958836896190/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=7880267958836896190' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7880267958836896190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7880267958836896190'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/02/fonemonkey-is-in-launch-tube.html' title='FoneMonkey is In the Launch Tube'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-364146247457647604</id><published>2010-02-06T16:29:00.000-07:00</published><updated>2010-02-06T16:56:34.271-07:00</updated><title type='text'>Drupal Page Editor Bookmarklet</title><content type='html'>We're in the process of putting gorillalogic.com under the &lt;a href="http://drupal.org/"&gt;Drupal&lt;/a&gt; content management system. I find Drupal's admin interface to be unbelievably annoying. What I really want to be able to do is navigate gorillalogic.com in my browser, and have a button I can hit to open the current page in the Drupal editor.&lt;br /&gt;&lt;br /&gt;So, I created a &lt;a href="http://en.wikipedia.org/wiki/Bookmarklet"&gt;bookmarklet&lt;/a&gt; for this purpose. Drag the link below to your browser's bookmark bar. When you're browsing a Drupal-managed site, click the bookmark to open the current page in the Drupal editor (assuming of course you have editing privilege for the page).&lt;br /&gt;&lt;br /&gt;&lt;a href='javascript:%20function%20getNodeNumberFor(obj)%20{%20%20%20%20%20%20if%20(%20obj.id%20&amp;&amp;%20obj.id.indexOf("node-")%20==%200)%20{%20%20%20%20%20%20%20%20return%20(obj.id.split("node-"))[1];%20%20%20%20%20};%20%20%20%20%20for%20(%20var%20i%20=%200;%20i%20!=%20obj.childNodes.length;%20i++%20)%20{%20%20%20%20%20%20%20%20%20var%20number%20=%20getNodeNumberFor(%20obj.childNodes[i]%20);%20%20%20%20%20%20%20%20%20if%20(number%20!=%20null)%20{%20return%20number;%20%20%20%20%20%20%20%20%20};%20%20%20%20%20%20%20%20%20%20};%20%20%20%20%20return%20null;%20};%20var%20nodeNumber%20=%20getNodeNumberFor(document.body);%20window.location="/node/"+nodeNumber+"/edit?destination=admin%2Fcontent%2Fnode";'&gt;DrupEdit&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-364146247457647604?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/364146247457647604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=364146247457647604' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/364146247457647604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/364146247457647604'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/02/drupal-page-editor-bookmarklet.html' title='Drupal Page Editor Bookmarklet'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-3232815657969713065</id><published>2010-02-03T12:25:00.001-07:00</published><updated>2010-02-03T12:52:07.104-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fonemonkey iphone testing'/><title type='text'>Using FoneMonkey With OCUnit</title><content type='html'>&lt;span style="font-weight: bold;"&gt;FoneMonkey&lt;/span&gt;, the world's first functional testing automation tool for the iPhone, now provides direct support for running FoneMonkey scripts from &lt;span style="font-weight: bold;"&gt;OCUnit&lt;/span&gt; test suites.&lt;br /&gt;&lt;br /&gt;You can download the latest version of FoneMonkey &lt;a href="http://stu-stern.blogspot.com/2009/12/fonemonkey-download.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;div class="section-1"&gt;                 &lt;div class="section-2"&gt;                &lt;div id="node-125" class="section-3"&gt;   &lt;h1 class="book-heading"&gt;Running Under OCUnit&lt;/h1&gt;   &lt;p&gt;&lt;a href="http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/135-Unit_Testing_Applications/unit_testing_applications.html#//apple_ref/doc/uid/TP40007959-CH20-SW3"&gt;&lt;strong&gt;OCUnit&lt;/strong&gt;&lt;/a&gt; (also known as &lt;strong&gt;SenTestingKit) &lt;/strong&gt;is a unit testing framework  for Objective-C that's bundled with the XCode IDE. As a member of the &lt;a href="http://en.wikipedia.org/wiki/XUnit"&gt;xUnit&lt;/a&gt; family of testing frameworks, OCUnit is similar to other popular frameworks such as JUnit (for Java), and FlexUnit (for Adobe Flex).&lt;/p&gt; &lt;p&gt;Using OCUnit, you can combine FoneMonkey- and non-FoneMonkey-based tests into comprehensive test suites that can be invoked interactively, as well as from build scripts, and from &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;continuous integration&lt;/a&gt; frameworks such as &lt;a href="http://blog.jayway.com/2010/01/31/continuos-integration-for-xcode-projects/"&gt;Hudson&lt;/a&gt; or &lt;a href="http://blog.jeffreyfredrick.com/2008/11/27/continuous-integration-for-iphonexcode-projects/"&gt;Cruise Control.&lt;/a&gt; It is also possible to combine OCUnit tests with non-OCUnit (for example, JUnit) tests, and combine the output so as to provide considated test reporting across all front- and back-end components of your application.&lt;/p&gt; &lt;p&gt;Please note that to run FoneMonkey with OCUnit, you should &lt;strong&gt;not&lt;/strong&gt; create a &lt;strong&gt;testing bundle&lt;/strong&gt;. Instead, you use the &lt;strong&gt;FoneMonkeyOCUnit&lt;/strong&gt; plug-in to launch your OCUnit tests cases, as described later in this section.&lt;/p&gt;   &lt;div id="node-126" class="section-4"&gt;   &lt;h1 class="book-heading"&gt;Adding OCUnit to Your Project&lt;/h1&gt;   &lt;p&gt;You add OCUnit to your project much in the same way you add any framework.&lt;/p&gt; &lt;ul&gt;&lt;li&gt;Right click on the target that includes FoneMonkey, and select &lt;strong&gt;Get Info &lt;/strong&gt;from the menu. The &lt;strong&gt;Target Info&lt;/strong&gt; dialog will be displayed.&lt;/li&gt;&lt;li&gt;Add a new entry to the &lt;strong&gt;Linked Libraries&lt;/strong&gt; by clicking the add (&lt;strong&gt;+&lt;/strong&gt;) button at the bottom of the dialog window. A selection dialog will open.&lt;/li&gt;&lt;li&gt;Click the &lt;strong&gt;Add Other...&lt;/strong&gt; button. A file selection dialog will open.&lt;/li&gt;&lt;li&gt;Navigate to the  &lt;strong&gt;/Developer/Library/Frameworks&lt;/strong&gt; folder. Select &lt;strong&gt;SenTestingKit.framework&lt;/strong&gt;.&lt;/li&gt;&lt;li&gt;Click the &lt;strong&gt;Add&lt;/strong&gt; button.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt; &lt;/p&gt;   &lt;/div&gt; &lt;div id="node-127" class="section-4"&gt;   &lt;h1 class="book-heading"&gt;Adding the FoneMonkeyOCUnit Plug-In&lt;/h1&gt;   &lt;p&gt;The FoneMonkey distribution includes &lt;strong&gt;libFoneMonkeyOCUnit.a&lt;/strong&gt; which is a static library that extends FoneMonkey with an OCUnit test launcher.&lt;/p&gt; &lt;ul&gt;&lt;li&gt;To add the library to your project, right-click on your FoneMonkey testing target and select &lt;strong&gt;Get Info&lt;/strong&gt;. The &lt;strong&gt;Target Info&lt;/strong&gt; dialog will be displayed.&lt;/li&gt;&lt;li&gt; &lt;p&gt;On the Build Tab, scroll down to the &lt;strong&gt;Linking&lt;/strong&gt; section. Add &lt;strong&gt;-lFoneMonkeyOCUnit&lt;/strong&gt; to &lt;strong&gt;Other Linker Flags&lt;/strong&gt; so that it now should look something like this:&lt;/p&gt; &lt;pre&gt;-ObjC -all_load -lFoneMonkey &lt;strong&gt;-lFoneMonkeyOCUnit &lt;/strong&gt;&lt;/pre&gt;&lt;p&gt; &lt;/p&gt; &lt;/li&gt;&lt;/ul&gt; &lt;p&gt; &lt;/p&gt;   &lt;/div&gt; &lt;div id="node-128" class="section-4"&gt;   &lt;h1 class="book-heading"&gt;Writing a Test Case&lt;/h1&gt;   &lt;p&gt;You write your test cases for FoneMonkey in the same way you write any OCUnit test. To create a test case, simply subclass SenTestCase and use &lt;a href="http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/905-A-Unit-Test_Result_Macro_Reference/unit-test_results.html#//apple_ref/doc/uid/TP40007959-CH21-SW2"&gt;&lt;strong&gt;STAssertions&lt;/strong&gt;&lt;/a&gt; to test for expected results. For more information on OCUnit (SenTestingKit), see &lt;a href="http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/135-Unit_Testing_Applications/unit_testing_applications.html#//apple_ref/doc/uid/TP40007959-CH20-SW3"&gt;Apple's Documentation&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Using the &lt;strong&gt;FoneMonkey API&lt;/strong&gt;, you can run FoneMonkey commands from within your test case, and you use OCUnit Let's look at an example:&lt;/p&gt; &lt;hr /&gt; &lt;pre&gt;#import &lt;sentestingkit h=""&gt;&lt;br /&gt;#import &lt;uikit h=""&gt;&lt;br /&gt;&lt;/uikit&gt;&lt;/sentestingkit&gt;&lt;/pre&gt;&lt;pre&gt;#import "FoneMonkey.h"&lt;br /&gt;&lt;br /&gt;@interface SampleTest : SenTestCase&lt;br /&gt;&lt;br /&gt;- (void) testSample;&lt;br /&gt;&lt;br /&gt;@end&lt;br /&gt;&lt;br /&gt;@implementation SampleTest&lt;br /&gt;&lt;br /&gt;- (void) testSample {&lt;br /&gt;  NSString* lastResult = [[FoneMonkey sharedMonkey] playAndWait:@"Test1"];&lt;br /&gt;  STAssertNil(lastResult, lastResult);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@end&lt;/pre&gt;&lt;hr /&gt; &lt;p&gt;You run a FoneMonkey script from a test case by calling runScript:(NSString*)script, where script is the name of a  FoneMonkey script stored in your application's&lt;a href="http://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/FilesandNetworking/FilesandNetworking.html"&gt; Documents directory&lt;/a&gt;. runScript: returns nil if the script runs successfully. For example, in the script above we call:&lt;/p&gt; &lt;pre&gt;    NSString* lastResult = [[FoneMonkey sharedMonkey] runScript:@"Test1"];&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;If the script fails for any reason, runScript: returns the message generated from a failed Verify command, or other error message. You need to explicitly add an assertion to test for a non-nil result, and display the returned message if it's non-nil as follows:&lt;/p&gt; &lt;p&gt;    STAssertNil(lastResult, lastResult);&lt;/p&gt; &lt;p&gt;You can of course do more in your test case than simply run a script and test its result. You can include addition programming logic and assertions, and run multiple scripts.&lt;/p&gt; &lt;p&gt;Using the FoneMonkey API, It is also possible to build scripts programatically at run time, rather than running a script previously saved.&lt;/p&gt; &lt;p&gt; &lt;/p&gt;   &lt;/div&gt; &lt;div id="node-129" class="section-4"&gt;   &lt;h1 class="book-heading"&gt;Running OCUnit Tests&lt;/h1&gt;   &lt;p&gt;When you link your application with FoneMonkey and FoneMonkeyOCUnit, FoneMonkey will by default run all SenTestCase subclasses, and OCUnit output will be written to the console. &lt;/p&gt; &lt;p&gt;If you would like to exit your application after the OCUnit tests have run, set &lt;strong&gt;FM_ENABLE_AUTOEXIT &lt;/strong&gt; the environment variable.&lt;/p&gt; &lt;p&gt;You can disable the running of OCUnit tests upon FoneMonkey start up by setting the &lt;strong&gt;FM_DISABLE_AUTOSTART&lt;/strong&gt; environment variable. Omitting the &lt;strong&gt;-lFoneMonkeyOCUnit linker&lt;/strong&gt; flag will also disable the running of any OCUnit tests at startup.&lt;/p&gt;   &lt;/div&gt; &lt;/div&gt;     &lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-3232815657969713065?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/3232815657969713065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=3232815657969713065' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3232815657969713065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3232815657969713065'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/02/using-fonemonkey-with-ocunit.html' title='Using FoneMonkey With OCUnit'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-988788317622000814</id><published>2010-01-24T19:45:00.000-07:00</published><updated>2010-01-24T19:46:53.206-07:00</updated><title type='text'>Using the FoneMonkey Console</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;Creating and Editing Scripts with the FoneMonkey Console&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When you launch an application that has been linked with FoneMonkey (see Setup Guide), the FoneMonkey Console is displayed on top of the application’s window.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hNEirhCE9Kw/S1zjXyhcz1I/AAAAAAAAAHY/KykJi07SZlE/s1600-h/fonemonkey7.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_hNEirhCE9Kw/S1zjXyhcz1I/AAAAAAAAAHY/KykJi07SZlE/s400/fonemonkey7.png" alt="" id="BLOGGER_PHOTO_ID_5430465248540544850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To begin recording, touch the &lt;span style="font-weight: bold;"&gt;Record&lt;/span&gt; button. The FoneMonkey console will hide and you can manually test your application. As you interact with it, FoneMonkey records FoneMonkey commands corresponding to each user interface gesture.&lt;br /&gt;&lt;br /&gt;If you stop interacting with the application for longer than the timeout interval (by default, 2.5 seconds), the FoneMonkey console will reappear on top of your application window.&lt;br /&gt;If you are not yet done recording, click any where over the application to hide the FoneMonkey console and resume recording.&lt;br /&gt;&lt;br /&gt;Touching the &lt;span style="font-weight: bold;"&gt;Pause&lt;/span&gt; button hides the FoneMonkey window and lets you interact with your application without recording. The console will reappear after the timeout interval. Touch anywhere on your application to re-hide the console and continue without recording.&lt;br /&gt;Touch the More button to view the list of recorded commands.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hNEirhCE9Kw/S1zjsVDd31I/AAAAAAAAAHg/k1EGpxey6V4/s1600-h/fonemonkey8.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hNEirhCE9Kw/S1zjsVDd31I/AAAAAAAAAHg/k1EGpxey6V4/s400/fonemonkey8.png" alt="" id="BLOGGER_PHOTO_ID_5430465601407410002" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Commands are displayed in the &lt;span style="font-weight: bold;"&gt;Command List&lt;/span&gt; table. The &lt;span style="font-weight: bold;"&gt;Timeout&lt;/span&gt; slider can be used to set the timeout interval anywhere from 2 to 10 seconds. If the console is reappearing more quickly than you want it to while the console is recording or paused, make the timeout longer.&lt;br /&gt;&lt;br /&gt;Touch the &lt;span style="font-weight: bold;"&gt;Play&lt;/span&gt; button to begin playback. The console hides and FoneMonkey executes each command in sequence, generating user interface actions corresponding to each command.&lt;br /&gt;By default, FoneMonkey pauses .5 seconds between commands. Sometimes you may need FoneMonkey to wait additional time at certain points in a script. For example, a command might need to wait until an animation finishes running. Use &lt;span style="font-weight: bold;"&gt;Pause&lt;/span&gt; commands (see command reference) to insert pauses between commands during playback.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Editing Recorded Commands&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To edit a recorded command, touch the &lt;span style="font-weight: bold;"&gt;Edit&lt;/span&gt; button on the row in the command list to be edited. The Command Editor will be displayed.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hNEirhCE9Kw/S10ECNq1SGI/AAAAAAAAAIA/4n92D3-nqOE/s1600-h/fonemonkey11.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hNEirhCE9Kw/S10ECNq1SGI/AAAAAAAAAIA/4n92D3-nqOE/s400/fonemonkey11.png" alt="" id="BLOGGER_PHOTO_ID_5430501161754249314" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Using the command editor, you can change the &lt;span style="font-style: italic;"&gt;Command&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;Component Class&lt;/span&gt;, Monkey ID, or any of the associated parameters. When you’re finished editing, touch the &lt;span style="font-weight: bold;"&gt;Done&lt;/span&gt; button.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Inserting and Deleting Commands&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Commands can be inserted and deleted using the Insert and Delete toolbar buttons, which display the Insert or Delete buttons in each row of the displayed script.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hNEirhCE9Kw/S1zrxRGVudI/AAAAAAAAAHw/fTyJYLGlHSc/s1600-h/fonemonkey9.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hNEirhCE9Kw/S1zrxRGVudI/AAAAAAAAAHw/fTyJYLGlHSc/s400/fonemonkey9.png" alt="" id="BLOGGER_PHOTO_ID_5430474482338085330" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Saving a Script&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To save a script, touch the &lt;span style="font-weight: bold;"&gt;Save&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;Script&lt;/span&gt; button. The &lt;span style="font-weight: bold;"&gt;Save Script&lt;/span&gt; dialog will be displayed.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hNEirhCE9Kw/S10CMbKLjZI/AAAAAAAAAH4/A9hAZRelXtI/s1600-h/fonemonkey10.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_hNEirhCE9Kw/S10CMbKLjZI/AAAAAAAAAH4/A9hAZRelXtI/s400/fonemonkey10.png" alt="" id="BLOGGER_PHOTO_ID_5430499138150829458" border="0" /&gt;&lt;/a&gt;Enter a name for the script and hit the &lt;span style="font-weight: bold;"&gt;Save&lt;/span&gt; button. Scripts are saved in the application's &lt;a href="http://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/FilesandNetworking/FilesandNetworking.html"&gt;&lt;span style="font-weight: bold;"&gt;Documents directory&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Running a Saved Script&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To run a saved script, touch the &lt;span style="font-weight: bold;"&gt;Open Script&lt;/span&gt; button. The &lt;span style="font-weight: bold;"&gt;Saved Script List&lt;/span&gt; will open displaying all saved scripts.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hNEirhCE9Kw/S10Eh1Dmr_I/AAAAAAAAAIQ/cT_ho-PmAhM/s1600-h/fonemonkey12.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hNEirhCE9Kw/S10Eh1Dmr_I/AAAAAAAAAIQ/cT_ho-PmAhM/s400/fonemonkey12.png" alt="" id="BLOGGER_PHOTO_ID_5430501704903077874" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;To open a script, touch its name in the list. The script will open in the console and can be played and edited.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Recording a New Script&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To clear the currently opened script and begin creating a new one, click the &lt;span style="font-weight: bold;"&gt;Open Script&lt;/span&gt; button and then touch the &lt;span style="font-weight: bold;"&gt;New&lt;/span&gt; button displayed above the &lt;span style="font-weight: bold;"&gt;Saved Script List&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Deleting a Saved Script&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To delete a saved script, touch the &lt;span style="font-weight: bold;"&gt;Open Script&lt;/span&gt; button and then click the &lt;span style="font-weight: bold;"&gt;Edit&lt;/span&gt; button displayed above the &lt;span style="font-weight: bold;"&gt;Saved Script List&lt;/span&gt;. You may then delete a saved script by touching the associated &lt;span style="font-weight: bold;"&gt;Delete&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;Icon&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-988788317622000814?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/988788317622000814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=988788317622000814' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/988788317622000814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/988788317622000814'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/01/using-fonemonkey-console.html' title='Using the FoneMonkey Console'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_hNEirhCE9Kw/S1zjXyhcz1I/AAAAAAAAAHY/KykJi07SZlE/s72-c/fonemonkey7.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-2261127405036861978</id><published>2010-01-22T21:27:00.000-07:00</published><updated>2010-01-24T17:08:13.109-07:00</updated><title type='text'>Working with FoneMonkey Command Scripts</title><content type='html'>FoneMonkey plays FoneMonkey &lt;span style="font-weight: bold;"&gt;commands&lt;/span&gt;. For each kind of user interface action there is a corresponding command. Some examples of commands are &lt;span style="font-weight: bold;"&gt;Touch&lt;/span&gt;, &lt;span style="font-weight: bold;"&gt;Scroll&lt;/span&gt;, and &lt;span style="font-weight: bold;"&gt;Shake&lt;/span&gt;. (See the FoneMonkey Command Reference for a complete list).&lt;br /&gt;&lt;br /&gt;User interface actions are directed to components. For example, you &lt;span style="font-style: italic;"&gt;Touch&lt;/span&gt; a &lt;span style="font-style: italic;"&gt;UIButton&lt;/span&gt;, or &lt;span style="font-style: italic;"&gt;Scroll&lt;/span&gt; a &lt;span style="font-style: italic;"&gt;UITableView &lt;/span&gt;&lt;span&gt;to &lt;span style="font-style: italic;"&gt;Row 5&lt;/span&gt;&lt;/span&gt;. FlexMonkey commands identify the action to be performed, and the component to receive the action. Components are identified by a combination of their Object-C class name (or superclass name) and a string identifier called a &lt;span style="font-weight: bold;"&gt;monkeyID&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;All commands are written as:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;CommandName&lt;/span&gt; &lt;span style="font-style: italic;"&gt;ComponentType&lt;/span&gt; &lt;span style="font-style: italic;"&gt;"MonkeyID"&lt;/span&gt; &lt;span style="font-style: italic;"&gt;Parameters, ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;where&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;CommandName &lt;/span&gt;identifies the command to be executed.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;ComponentType&lt;/span&gt; is the Objective-C class name of the component to receive the command. If componentType is omitted, it defaults to UIView (ie, any component).&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"MonkeyID&lt;/span&gt;" is a quoted string that uniquely identifies which instance of the component's class should receive the command. If there is only one instance of a particular type, monkeyID may be omitted.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Parameters, ....&lt;/span&gt; are zero or more command-specific parameter values in CSV format.&lt;br /&gt;&lt;br /&gt;By overriding recording and playback methods, it's easy to add your own commands to FoneMonkey or customize existing commands. See the FoneMonkey Extension Guide for more information.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Some Command Examples&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Touch the "Done" button:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Touch UIButton "Done"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Touch the  PaintingView at coordinate (25, 75):&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Touch PaintingView 25, 75&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Enter text into the "FirstName" field:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;InputText UITextField "FirstName" fred&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Identifying Components by ClassName and MonkeyID&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As mentioned above, commands correspond to user interface actions, and actions are directed to components. For example, a command might specify to &lt;span style="font-style: italic;"&gt;Touch&lt;/span&gt; a &lt;span style="font-style: italic;"&gt;UIButton&lt;/span&gt;. If there is only one UIButton on the screen, FoneMonkey knows which button the command is referring to. If there are multiple buttons, however, we must tell FoneMonkey which one to use. In addition to  the component's Objective-C classname, and a unique identifier called a &lt;span style="font-weight: bold;"&gt;monkeyID&lt;/span&gt; that's generated by FoneMonkey extensions for various UIKit classes. For any command, you can specify just a className or a monkeyID, or you can specify both.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Component Identification Examples&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-style: italic;"&gt;If there are multiple buttons on the screen:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Touch UIButton "Done"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;If there is just one button on the screen:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;Touch UIButton&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;If threre is just one button on the screen with a monkeyID of "Done":&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Understanding MonkeyID's&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;FoneMonkey's UIView extensions provide the default monkeyID for all components. By default, the monkeyID of a component is the value of its &lt;span style="font-weight: bold;"&gt;accessbilityLabel&lt;/span&gt; property, if one exists, its &lt;span style="font-weight: bold;"&gt;tag&lt;/span&gt; property if it's non-zero, and otherwise FoneMonkey generates a unique identifier as explained below. Many component types provide specialized monkeyID's. For example, UIButton returns its &lt;span style="font-weight: bold;"&gt;titleLabel.text&lt;/span&gt; as its monkeyID, UITextField returns its &lt;span style="font-weight: bold;"&gt;placeholder&lt;/span&gt; value.&lt;br /&gt;&lt;br /&gt;See the FoneMonkey Command Reference for a description of the monkeyID's returned by each component type.&lt;br /&gt;&lt;br /&gt;If a component provides no monkeyID, FoneMoney generates an identifier by assigning an ordinal to each instance of each class on the screen FoneMonkey generated monkeyID's are prefix with a #-sign.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Examples of Generated MonkeyID's&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Touch the first button:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Touch UIButton #0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Touch the second button:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Touch UIButton #1&lt;span style="font-family:times new roman;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Validating Tests with the Verify Command&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You insert &lt;span style="font-weight: bold;"&gt;Verify &lt;/span&gt;&lt;/span&gt;commands into your script to validate during playback that actual results match expected ones. The Verify command has the following syntax:&lt;br /&gt;&lt;br /&gt;Verify &lt;span style="font-style: italic;"&gt;ClassName&lt;/span&gt; &lt;span style="font-style: italic;"&gt;"monkeyID"&lt;/span&gt; &lt;span style="font-style: italic;"&gt;propertyPath,&lt;/span&gt; &lt;span style="font-style: italic;"&gt;expectedValue&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As with all FoneMonkey commands, you can specify either ClassName or monkeyID or both to identify the component.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;propertyPath&lt;/span&gt; is any valid &lt;a href="http://developer.apple.com/mac/library/documentation/cocoa/conceptual/KeyValueCoding/Concepts/BasicPrinciples.html"&gt;key path&lt;/a&gt; to a property.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;expectedValue&lt;/span&gt; is the expected value of the property identified by the propertyPath.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Verify Command Examples&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Check that the last name label is "Smith"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Verify UILable "Last Name" text, Smith&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Check that the button says "Hello"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Verify UIButton titleLabel.text, Hello&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If a verify command fails, a message is displayed in the FoneMonkey Command List.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Inserting Pauses into a Script&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;By default, FoneMonkey pauses .5 seconds between commands during playback. Sometimes you may need a longer delay between commands, for example if an animation needs to finish running before a component is displayed.&lt;br /&gt;&lt;br /&gt;You can insert pause commands to allow additional time between the execution of commands. It has the following syntax:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Pause milliseconds&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;where milliseconds is the number of milliseconds to pause before executing the next command.&lt;br /&gt;&lt;br /&gt;The Pause command ignores class name and monkey ID, if any are supplied.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Pause Example&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Pause for 1 second:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Pause 1000&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-2261127405036861978?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/2261127405036861978/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=2261127405036861978' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/2261127405036861978'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/2261127405036861978'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/01/working-with-fonemonkey-command-scripts.html' title='Working with FoneMonkey Command Scripts'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-8939055910604227822</id><published>2010-01-21T20:50:00.000-07:00</published><updated>2010-01-21T21:14:23.592-07:00</updated><title type='text'>FoneMonkey: New Fat Library</title><content type='html'>Thanks to some helpful advice from Victor Costan about &lt;a href="http://blog.costan.us/2009/12/fat-iphone-static-libraries-device-and.html"&gt;building fat libraries&lt;/a&gt;, the latest FoneMonkey library can be used to build applications for both the iPhone device and simulator. The fat library contains code for both arm7 (iPhone) and i386 (simulator) architectures, so you can reference the same library binary from either your simulator of device builds. Note that the linker will strip out unreferenced code so the convenience of the single library does not come at the expensive of a bloated application binary.&lt;br /&gt;&lt;br /&gt;The download is available &lt;a href="http://stu-stern.blogspot.com/2009/12/fonemonkey-download.html"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-8939055910604227822?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/8939055910604227822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=8939055910604227822' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8939055910604227822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8939055910604227822'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/01/fonemonkey-new-fat-library.html' title='FoneMonkey: New Fat Library'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-7003213086738063071</id><published>2010-01-16T14:55:00.000-07:00</published><updated>2010-01-16T15:10:49.281-07:00</updated><title type='text'>FoneMonkey: The Update</title><content type='html'>This release of &lt;a href="http://stu-stern.blogspot.com/2009/12/fonemonkey-open-source-testing-tool-for.html"&gt;FoneMonkey&lt;/a&gt;, the world's first and only free and open source testing automation tool for the iPhone, fixes various bugs, adds support for additional Cocoa Touch components, and can be run on an actual iPhone device in addition to the simulator.&lt;br /&gt;&lt;br /&gt;The latest FoneMonkey download and release instructions can be found &lt;a href="http://stu-stern.blogspot.com/2009/12/fonemonkey-download.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;We expect to have the official FoneMonkey project site online later this month!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-7003213086738063071?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/7003213086738063071/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=7003213086738063071' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7003213086738063071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7003213086738063071'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2010/01/fonemonkey-update.html' title='FoneMonkey: The Update'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-6030025612681876274</id><published>2009-12-29T16:33:00.000-07:00</published><updated>2010-02-03T12:51:01.749-07:00</updated><title type='text'>FoneMonkey: The Download</title><content type='html'>Tonight I am releasing FoneMonkey into the wild. Without further ado, here it is:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.screencast.com/t/MmU0ZmRlOTg" com="" t="" ndcxzti0odk=""&gt;FoneMonkey.zip&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The iPhone does not yet allow installation of user-defined frameworks, so FoneMonkey is disbributed as a static library along with the image files and nibs required by the FoneMonkey user interface. FoneMonkey.zip contians libFoneMonkey.a as well as a bunch of png and xib files.&lt;br /&gt;&lt;br /&gt;The zip file does not include the FoneMonkey source code, which we'll be releasing when we officially launch the FoneMonkey open source project in mid-January, 2010 (ie, just a few weeks from now!). At that time we'll be going live with a community forum as well. Until then, please post questions or comments to this blog.&lt;br /&gt;&lt;br /&gt;To get started using FoneMonkey, download the zip file and extract the FoneMonkey distribution folder. Then follow the instructions below.&lt;br /&gt;&lt;br /&gt;Happy testing! We look forward to your feedback!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;Testing an iPhone application with FoneMonkey&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In order to test an iPhone application with FoneMonkey, you must first link FoneMonkey with your application as shown in the 2-minute video below. Step-by-step textual instructions are also provided &lt;a href="http://www.blogger.com/post-edit.g?blogID=4892696525791628275&amp;amp;postID=6030025612681876274#instructions"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;You might need to view the video in a &lt;a href="http://www.screencast.com/t/MjA5OWE4Mz"&gt;new window&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;object width="640" height="480"&gt; &lt;param name="movie" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/6cbb3305-c30c-4322-ac52-aca776486d7e/mp4h264player.swf"&gt; &lt;param name="quality" value="high"&gt; &lt;param name="bgcolor" value="#FFFFFF"&gt; &lt;param name="flashVars" value="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/6cbb3305-c30c-4322-ac52-aca776486d7e/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/6cbb3305-c30c-4322-ac52-aca776486d7e/FoneMonkey%20Setup.mp4"&gt; &lt;param name="allowFullScreen" value="true"&gt; &lt;param name="scale" value="showall"&gt; &lt;param name="allowScriptAccess" value="always"&gt; &lt;param name="base" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/6cbb3305-c30c-4322-ac52-aca776486d7e/"&gt;  &lt;embed src="http://content.screencast.com/users/StuStern/folders/Camtasia/media/6cbb3305-c30c-4322-ac52-aca776486d7e/mp4h264player.swf" quality="high" bgcolor="#FFFFFF" type="application/x-shockwave-flash" allowscriptaccess="always" flashvars="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/6cbb3305-c30c-4322-ac52-aca776486d7e/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/6cbb3305-c30c-4322-ac52-aca776486d7e/FoneMonkey%20Setup.mp4" allowfullscreen="true" base="http://content.screencast.com/users/StuStern/folders/Camtasia/media/6cbb3305-c30c-4322-ac52-aca776486d7e/" scale="showall" width="640" height="480"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="instructions"&gt;&lt;/a&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Open your application's project in xcode.&lt;/li&gt;&lt;li&gt;Duplicate your application's build target by right-clicking on it and selecting &lt;span style="font-weight: bold;"&gt;Duplicate&lt;/span&gt; from the  menu. A new target will be created called &lt;span style="font-style: italic;"&gt;YourApp copy&lt;/span&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Rename &lt;span style="font-style: italic;"&gt;YourApp copy&lt;/span&gt; to something like &lt;span style="font-style: italic;"&gt;YourAppTest&lt;/span&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Add the downloaded &lt;span style="font-weight: bold;"&gt;FoneMonkey&lt;/span&gt; folder to your project by right-clicking on the project and selecting &lt;span style="font-weight: bold;"&gt;Add &gt; Existing Files...&lt;/span&gt; from the menu. Navigate to the FoneMonkey folder, select it, and click the &lt;span style="font-weight: bold;"&gt;Add&lt;/span&gt; button.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;When the dialog box appears, select the &lt;span style="font-weight: bold;"&gt;Recursively create groups for any added folders&lt;/span&gt; option.&lt;/li&gt;&lt;li&gt;In the &lt;span style="font-weight: bold;"&gt;Add to Targets&lt;/span&gt; box, &lt;span style="font-style: italic; font-weight: bold;"&gt;de&lt;/span&gt;select &lt;span style="font-style: italic;"&gt;YourApp&lt;/span&gt; and select &lt;span style="font-style: italic;"&gt;YourAppTest&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Click &lt;span style="font-weight: bold;"&gt;Add&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Right-click on the &lt;span style="font-style: italic;"&gt;YourAppTest&lt;/span&gt; build target and select &lt;span style="font-weight: bold;"&gt;Get Info&lt;/span&gt; from the menu.&lt;/li&gt;&lt;li&gt;On the &lt;span style="font-weight: bold;"&gt;General&lt;/span&gt; tab, delete libFoneMonkey.a from the &lt;span style="font-weight: bold;"&gt;Linked Libraries&lt;/span&gt;. You will need to add CoreGraphics.framework and QuartzCore.framework to the &lt;span style="font-weight: bold;"&gt;Linked Libraries&lt;/span&gt; list they aren't already there.&lt;/li&gt;&lt;li&gt;On the &lt;span style="font-weight: bold;"&gt;Build&lt;/span&gt; tab, scroll down to the &lt;span style="font-weight: bold;"&gt;Linking&lt;/span&gt; section and click on the&lt;span style="font-weight: bold;"&gt; Other Linker Flags &lt;/span&gt;setting. When the dialog box appears, enter:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;-ObjC -lFoneMonkey -LFoneMonkey/lib -all_load&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Dismiss the project Info window.&lt;/li&gt;&lt;li&gt;Right-click on &lt;span style="font-style: italic;"&gt;YourAppTest&lt;/span&gt; build target and select &lt;span style="font-weight: bold;"&gt;Clean&lt;/span&gt; from the menu.&lt;/li&gt;&lt;li&gt;Right-click on &lt;span style="font-style: italic;"&gt;YourAppTest&lt;/span&gt; build target again and select &lt;span style="font-weight: bold;"&gt;Build and Debug&lt;/span&gt; from the menu.&lt;/li&gt;&lt;li&gt;Your application should start in the simulator. Immediately after it displays, the FoneMonkey console should drop down over it.&lt;/li&gt;&lt;li&gt;See &lt;a href="http://stu-stern.blogspot.com/2009/12/fonemonkey-open-source-testing-tool-for.html#UsingFoneMonkey"&gt;this post&lt;/a&gt; for more info about recording and playing back tests with FoneMonkey.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-6030025612681876274?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/6030025612681876274/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=6030025612681876274' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6030025612681876274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6030025612681876274'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/12/fonemonkey-download.html' title='FoneMonkey: The Download'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-8453528804527033504</id><published>2009-12-16T22:21:00.000-07:00</published><updated>2009-12-29T20:31:05.851-07:00</updated><title type='text'>FoneMonkey: The Movie</title><content type='html'>In this video, recently smuggled from &lt;a href="http://www.gorillalogic.com/"&gt;Gorilla Logic&lt;/a&gt; labs deep beneath the surface of the Earth, we see the revolutionary new open source, iPhone application testing tool &lt;span style="font-weight: bold;"&gt;FoneMonkey&lt;/span&gt; recording and playing back interactions with an application that was cobbled together from Apple's UICatalog and GLPaint sample applications (which together are comprised of most of the iPhone SDK UI Components).&lt;br /&gt;&lt;br /&gt;The video demonstrates &lt;span style="font-weight: bold;"&gt;FoneMonkey&lt;/span&gt; recording and playing back various actions including button touches, table scrolling and selection, switches, sliders, text entry, tab selection, finger dragging (in this case, painting), and even phone shaking (which is the gesture that causes GLPaint to erase the current painting).&lt;br /&gt;&lt;br /&gt;You might need to view this video in a &lt;a href="http://www.screencast.com/t/YTZiZWFl"&gt;new window&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;object width="640" height="480"&gt; &lt;param name="movie" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/141b991d-24da-4f66-abfa-9b81fc03f1b1/mp4h264player.swf"&gt; &lt;param name="quality" value="high"&gt; &lt;param name="bgcolor" value="#FFFFFF"&gt; &lt;param name="flashVars" value="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/141b991d-24da-4f66-abfa-9b81fc03f1b1/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/141b991d-24da-4f66-abfa-9b81fc03f1b1/FoneMonkey%20UICatalog%20Demo.mp4"&gt; &lt;param name="allowFullScreen" value="true"&gt; &lt;param name="scale" value="showall"&gt; &lt;param name="allowScriptAccess" value="always"&gt; &lt;param name="base" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/141b991d-24da-4f66-abfa-9b81fc03f1b1/"&gt; &lt;embed src="http://content.screencast.com/users/StuStern/folders/Camtasia/media/141b991d-24da-4f66-abfa-9b81fc03f1b1/mp4h264player.swf" quality="high" bgcolor="#FFFFFF" type="application/x-shockwave-flash" allowscriptaccess="always" flashvars="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/141b991d-24da-4f66-abfa-9b81fc03f1b1/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/141b991d-24da-4f66-abfa-9b81fc03f1b1/FoneMonkey%20UICatalog%20Demo.mp4" allowfullscreen="true" base="http://content.screencast.com/users/StuStern/folders/Camtasia/media/141b991d-24da-4f66-abfa-9b81fc03f1b1/" scale="showall" width="640" height="480"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;br /&gt;&lt;br /&gt;As you can see, the monkey can really dance. I hope to post the library binary and installation instructions within the next few days.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-8453528804527033504?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/8453528804527033504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=8453528804527033504' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8453528804527033504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8453528804527033504'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/12/fonemonkey-movie.html' title='FoneMonkey: The Movie'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-7047232170303857818</id><published>2009-12-13T18:35:00.000-07:00</published><updated>2009-12-29T20:34:29.123-07:00</updated><title type='text'>FoneMonkey: Open Source, Testing Tool for iPhone Applications</title><content type='html'>This blog post is the first announcement to the world of &lt;span style="font-weight: bold;"&gt;FoneMonkey&lt;/span&gt;, an open source iPhone testing tool that I've been developing for the last several months. FoneMonkey automates iPhone application testing by recording and playing back user interactions, and verifying the results. FoneMonkey was inspired by &lt;a href="http://flexmonkey.gorillalogic.com/"&gt;FlexMonkey&lt;/a&gt;, the open source Flex testing tool I wrote a little more than a year ago, and which has subsequently been significantly enhanced by my colleagues at Gorilla Logic, especially Eric Owens. Today FlexMonkey has more than 4,000 registered users and an active community.&lt;br /&gt;&lt;br /&gt;We plan to release FoneMonkey source and binaries (with attendant fanfare) in early January. Here's a sneak preview of what's coming.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Some Technical Background&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;FoneMonkey has been more challenging than FlexMonkey to create because the &lt;span style="font-weight: bold;"&gt;iPhone SDK, &lt;/span&gt;&lt;span&gt;unlike the &lt;span style="font-weight: bold;"&gt;Flex SDK&lt;/span&gt;,&lt;/span&gt; provides no &lt;span style="font-weight: bold;"&gt;Automation API&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;. Before I could develop FoneMonkey, I had to develop an automation framework. The resulting &lt;span style="font-weight: bold;"&gt;FoneMonkey API&lt;/span&gt; is simple, extensible and initially supports nearly all native iPhone (ie, Cocoa Touch) components.&lt;br /&gt;&lt;br /&gt;Like FlexMonkey, FoneMonkey is designed to be used by both programmers and QA testers. Rather than simply recording and playing back low-level events, FoneMonkey records "semantic" events. In other words, FoneMonkey doesn't record that &lt;span style="font-style: italic;"&gt;you touched a pixel at coordinate (125, 210)&lt;/span&gt;, but instead records that &lt;span style="font-style: italic;"&gt;you selected table row 5&lt;/span&gt;. The resulting scripts are relatively forgiving with respect to cosmetic UI changes. They can also be composed from scratch by directly specifying sequences of commands. (FoneMonkey Command Guide coming soon....).&lt;br /&gt;&lt;br /&gt;Each FoneMonkey command is composed of a command name, a component identifier, and a set of command-specific arguments. For example:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Touch UIButton Send&lt;/span&gt; (touches the UIButton labeled "Send")&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;InputText UITextField, your name, Fred&lt;/span&gt; (types "Fred" into the UITextField with a field prompt of "your name")&lt;br /&gt;&lt;br /&gt;The Flex Automation API provides an &lt;span style="font-weight: bold;"&gt;AutomatDelegate&lt;/span&gt; corresponding to each Flex &lt;span style="font-weight: bold;"&gt;UIComponent&lt;/span&gt;, and a delegate instance is created for each UIComponent instance created at run-time. Automation delegates subscribe to their component counterparts for all UI events, and translate these low-level keyboard and mouse events into high-level component events. FoneMonkey uses a logically similar mechanism, but is instead implemented with Objective-C categories that extend UI component classes with record and playback logic.&lt;br /&gt;&lt;br /&gt;While recording, the FoneMonkey framework monitors all UI events and forwards them to the FoneMonkey category methods that provide recording for each component class. During playback, FoneMonkey sends each command to the playback methods also provided by the class's FoneMonkey extension category.&lt;br /&gt;&lt;br /&gt;The FoneMonkey framework provides categories that record and play back events for instances of the UIView class and all UIView subclasses. It is straightforward to create a category for any custom UI class that requires custom recording and playback logic, or to further enhance the recording and playback logic provided out of the box by the FoneMonkey framework. (FoneMonkey Extension Guide coming soon....)&lt;br /&gt;&lt;br /&gt;&lt;a name="UsingFoneMonkey"&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Using FoneMonkey&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To test an application, you simply statically link it with the FoneMonkey library. (FoneMonkey Setup Guide coming soon....) Upon starting your application, the FoneMonkey Console "drops down" over your application window, displaying the recording and playback controls at the bottom of the screen.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hNEirhCE9Kw/Sya-sbUERLI/AAAAAAAAAFI/6_duVEZb9c4/s1600-h/fonemonkey1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: left; cursor: pointer; width: 208px; height: 400px;" src="http://2.bp.blogspot.com/_hNEirhCE9Kw/Sya-sbUERLI/AAAAAAAAAFI/6_duVEZb9c4/s400/fonemonkey1.png" alt="" id="BLOGGER_PHOTO_ID_5415225272415044786" border="0" /&gt;&lt;/a&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;The Elements&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; application&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hNEirhCE9Kw/Sya_HZwNtUI/AAAAAAAAAFQ/3IDVV8j7Y6U/s1600-h/fonemonkey2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: right; cursor: pointer; width: 208px; height: 400px;" src="http://3.bp.blogspot.com/_hNEirhCE9Kw/Sya_HZwNtUI/AAAAAAAAAFQ/3IDVV8j7Y6U/s400/fonemonkey2.png" alt="" id="BLOGGER_PHOTO_ID_5415225735852700994" border="0" /&gt;&lt;/a&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;The Elements&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; application with FoneMonkey controls (at the bottom).&lt;/span&gt; &lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The video below shows FoneMonkey being used to test Apple's "The Elements" sample application.&lt;br /&gt;&lt;br /&gt;In the video, we touch the record button to hide the FoneMonkey Console and begin recording our interactions with "The Elements" application. FoneMonkey monitors for periods of inactivity and drops back down over the application if we stop interacting with it for more than the current inactivity timeout setting (by default, 2.5 seconds). Touching the play button replays the recorded script.&lt;br /&gt;&lt;br /&gt;You might need to view this video in a &lt;a href="http://www.screencast.com/t/NjMwYTA0Y2Y"&gt;new window&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;object width="640" height="480"&gt; &lt;param name="movie" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/72f58c6d-ea79-44cc-9b46-d5874c432f7d/mp4h264player.swf"&gt; &lt;param name="quality" value="high"&gt; &lt;param name="bgcolor" value="#FFFFFF"&gt; &lt;param name="flashVars" value="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/72f58c6d-ea79-44cc-9b46-d5874c432f7d/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/72f58c6d-ea79-44cc-9b46-d5874c432f7d/FoneMonkey%20Record%20and%20Playback.mp4"&gt; &lt;param name="allowFullScreen" value="true"&gt; &lt;param name="scale" value="showall"&gt; &lt;param name="allowScriptAccess" value="always"&gt; &lt;param name="base" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/72f58c6d-ea79-44cc-9b46-d5874c432f7d/"&gt; &lt;embed src="http://content.screencast.com/users/StuStern/folders/Camtasia/media/72f58c6d-ea79-44cc-9b46-d5874c432f7d/mp4h264player.swf" quality="high" bgcolor="#FFFFFF" type="application/x-shockwave-flash" allowscriptaccess="always" flashvars="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/72f58c6d-ea79-44cc-9b46-d5874c432f7d/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/72f58c6d-ea79-44cc-9b46-d5874c432f7d/FoneMonkey%20Record%20and%20Playback.mp4" allowfullscreen="true" base="http://content.screencast.com/users/StuStern/folders/Camtasia/media/72f58c6d-ea79-44cc-9b46-d5874c432f7d/" scale="showall" width="640" height="480"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;br /&gt;FoneMonkey provides the ability to edit scripts and save them for later replaying.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hNEirhCE9Kw/SybC9Lu9tQI/AAAAAAAAAFY/yu70w9pTABU/s1600-h/fonemonkey3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 208px; height: 400px;" src="http://2.bp.blogspot.com/_hNEirhCE9Kw/SybC9Lu9tQI/AAAAAAAAAFY/yu70w9pTABU/s400/fonemonkey3.png" alt="" id="BLOGGER_PHOTO_ID_5415229958337180930" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;The FoneMonkey script editor&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;You can add &lt;span style="font-weight: bold;"&gt;Verify&lt;/span&gt; commands to a script to test the values UI component properties or the values of associated object properties (ie, you can use a &lt;a href="http://developer.apple.com/mac/library/documentation/cocoa/conceptual/KeyValueCoding/Concepts/BasicPrinciples.html#//apple_ref/doc/uid/20002170"&gt;key-value encoded key path&lt;/a&gt;) . In The Elements sample application, a custom class called &lt;span style="font-style: italic;"&gt;AtomicElementView&lt;/span&gt; is used to display data for the currently selected element. The &lt;span style="font-style: italic;"&gt;AtomicElementView&lt;/span&gt; has a property called &lt;span style="font-style: italic;"&gt;element&lt;/span&gt; that references an instance of the &lt;span style="font-style: italic;"&gt;AtomicElement&lt;/span&gt; class, which in turn as a property called &lt;span style="font-style: italic;"&gt;name&lt;/span&gt;. In the Verify command below, we test that the current &lt;span style="font-style: italic;"&gt;AtomicElementView&lt;/span&gt;'s &lt;span style="font-style: italic;"&gt;element.name&lt;/span&gt; has a value of "Lead".&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hNEirhCE9Kw/SybHneDzD1I/AAAAAAAAAFg/N2Uf28Iqk0E/s1600-h/fonemonkey4.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 208px; height: 400px;" src="http://1.bp.blogspot.com/_hNEirhCE9Kw/SybHneDzD1I/AAAAAAAAAFg/N2Uf28Iqk0E/s400/fonemonkey4.png" alt="" id="BLOGGER_PHOTO_ID_5415235082857418578" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;Adding a Verify command to a script&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hNEirhCE9Kw/SybLDQhItZI/AAAAAAAAAFo/fCyRP9zagWo/s1600-h/fonemonkey5.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 208px; height: 400px;" src="http://2.bp.blogspot.com/_hNEirhCE9Kw/SybLDQhItZI/AAAAAAAAAFo/fCyRP9zagWo/s400/fonemonkey5.png" alt="" id="BLOGGER_PHOTO_ID_5415238858793596306" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;Script results with failed Verify (in red)&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;The next video shows how to edit a script, add a verify command, save the modified script, and then replay it.&lt;br /&gt;&lt;br /&gt;You might need to view this video in a &lt;a href="http://www.screencast.com/t/Mjg5N2Ux"&gt;new window&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;object width="640" height="480"&gt; &lt;param name="movie" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/dc0700d1-2a27-4851-9b69-54d14a1fbef9/mp4h264player.swf"&gt; &lt;param name="quality" value="high"&gt; &lt;param name="bgcolor" value="#FFFFFF"&gt; &lt;param name="flashVars" value="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/dc0700d1-2a27-4851-9b69-54d14a1fbef9/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/dc0700d1-2a27-4851-9b69-54d14a1fbef9/FoneMonkey%20Script%20Edit%20and%20Save.mp4"&gt; &lt;param name="allowFullScreen" value="true"&gt; &lt;param name="scale" value="showall"&gt; &lt;param name="allowScriptAccess" value="always"&gt; &lt;param name="base" value="http://content.screencast.com/users/StuStern/folders/Camtasia/media/dc0700d1-2a27-4851-9b69-54d14a1fbef9/"&gt; &lt;embed src="http://content.screencast.com/users/StuStern/folders/Camtasia/media/dc0700d1-2a27-4851-9b69-54d14a1fbef9/mp4h264player.swf" quality="high" bgcolor="#FFFFFF" type="application/x-shockwave-flash" allowscriptaccess="always" flashvars="thumb=http://content.screencast.com/users/StuStern/folders/Camtasia/media/dc0700d1-2a27-4851-9b69-54d14a1fbef9/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=480&amp;amp;content=http://content.screencast.com/users/StuStern/folders/Camtasia/media/dc0700d1-2a27-4851-9b69-54d14a1fbef9/FoneMonkey%20Script%20Edit%20and%20Save.mp4" allowfullscreen="true" base="http://content.screencast.com/users/StuStern/folders/Camtasia/media/dc0700d1-2a27-4851-9b69-54d14a1fbef9/" scale="showall" width="640" height="480"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;Over the next several weeks I'll be continuing to update the doc in preparation for our putative January launch. Stay tuned.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-7047232170303857818?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/7047232170303857818/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=7047232170303857818' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7047232170303857818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7047232170303857818'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/12/fonemonkey-open-source-testing-tool-for.html' title='FoneMonkey: Open Source, Testing Tool for iPhone Applications'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_hNEirhCE9Kw/Sya-sbUERLI/AAAAAAAAAFI/6_duVEZb9c4/s72-c/fonemonkey1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-3715586188893681216</id><published>2009-10-31T11:23:00.000-06:00</published><updated>2009-10-31T11:37:34.530-06:00</updated><title type='text'>Gorilla Logic gets kosher-er</title><content type='html'>Since ICAAN has approved &lt;a href="http://tech.yahoo.com/news/ap/20091030/ap_on_hi_te/as_tec_internet_names_10"&gt;hebrew domain names,&lt;/a&gt; I think we need to register  gorillalogic.&lt;span style="font-style: italic; font-weight: bold;"&gt;ch&lt;/span&gt;om.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-3715586188893681216?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/3715586188893681216/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=3715586188893681216' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3715586188893681216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3715586188893681216'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/10/gorilla-logic-gets-kosher-er.html' title='Gorilla Logic gets kosher-er'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-5024419411532526834</id><published>2009-08-17T17:15:00.000-06:00</published><updated>2009-08-17T17:19:02.004-06:00</updated><title type='text'>FlexMonkey 1.0 Beta 2 and the FlexMonkey User Guide are here!</title><content type='html'>Announcing the immediate availability of FlexMonkey 1.0 Beta 2! After the very successful Beta 1 launch last month, we are pleased to bring you Beta 2. Since Beta 1 had very frew issues, Beta 2 is much more of an enhancement than a bug-fix release.&lt;br /&gt;&lt;br /&gt;Most notably, Beta 2 introduces "MonkeyLink", which allows you to link FlexMonkey directly into your target SWF. If you have had any problems dynamically loading your application through the FlexMonkey Console or the MonkeyAgent, you can now instead compile MonkeyLink into your application SWF, and then launch your application directly. Using MonkeyLink, you can test virtually any Flex or AIR application. Dynamic SWF loading with the Console or the MonkeyAgent are of course still supported so you also continue to have the option of testing SWFs without having to first recompile them.&lt;br /&gt;&lt;br /&gt;Download FlexMonkey 1.0 Beta 2 now at &lt;a href="http://flexmonkey.gorillalogic.com/gl/stuff.flexmonkey.download.html"&gt;http://flexmonkey.gorillalogic.com/gl/stuff.flexmonkey.download.html&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;The long-awaited FlexMonkey User Guide is available at &lt;a href="http://flexmonkey.gorillalogic.com/gl/flexmonkey/FlexMonkeyUserGuideR1b2.pdf"&gt;http://flexmonkey.gorillalogic.com/gl/flexmonkey/FlexMonkeyUserGuideR1b2.pdf&lt;/a&gt;! Weighing in at nearly 60 pages, the FlexMonkey User Guide is like having your very own Eric Owens!&lt;br /&gt;&lt;br /&gt;Happy testing!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-5024419411532526834?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/5024419411532526834/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=5024419411532526834' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5024419411532526834'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5024419411532526834'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/08/flexmonkey-10-beta-2-and-flexmonkey.html' title='FlexMonkey 1.0 Beta 2 and the FlexMonkey User Guide are here!'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-14773547087863209</id><published>2009-07-16T14:27:00.000-06:00</published><updated>2009-07-16T21:13:44.547-06:00</updated><title type='text'>Who you calling ugly?</title><content type='html'>As mentioned in my previous post, the web has been abuzz over FlexMonkey this week. I noticed that artima.com was referencing us and so I clicked on over to see &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=262876"&gt;what they had to say&lt;/a&gt;. Here's the quote from Bruce Eckel:&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;Looking closer to home, Jon Rose at &lt;a class="reference" href="http://www.gorillalogic.com/"&gt;Gorilla Logic&lt;/a&gt; has just released &lt;a class="reference" href="http://flexmonkey.gorillalogic.com/gl/stuff.flexmonkey.html"&gt;Flex Monkey&lt;/a&gt;, a free tool to automatically test your Flex UIs. I've known Jon through various events so decided to look at the site. As with many sites, it contains a fair amount of cleverness but no clear statement of what they are about. However, among the slogans I found one that I thought had promise: "The answer is not more monkeys." It's succinct, catchy, and on the right track, because it's suggesting that more things should be automated (and Flex Monkey is an example of that kind of automation). Alas, the rest of the site doesn't give me a clear idea of what they do.&lt;/blockquote&gt;Now I've done some hanging with Bruce and he's someone I like and respect, so I talked to our graphic designers and had them make some changes to our home page.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.gorillalogic.com/"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 238px;" src="http://1.bp.blogspot.com/_hNEirhCE9Kw/Sl_l5NAvdiI/AAAAAAAAAE4/Dydt6s1opmQ/s400/gldotcom.jpg" alt="" id="BLOGGER_PHOTO_ID_5359254852502255138" border="0" /&gt;&lt;/a&gt;Before&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.gorillalogic.com/"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 238px;" src="http://4.bp.blogspot.com/_hNEirhCE9Kw/Sl_meOg22pI/AAAAAAAAAFA/tcTTFBAv_v0/s400/after.jpg" alt="" id="BLOGGER_PHOTO_ID_5359255488560552594" border="0" /&gt;&lt;/a&gt;After&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;In all seriousness, we do appreciate any and all feedback on the site (and we do really like Bruce).&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-14773547087863209?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/14773547087863209/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=14773547087863209' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/14773547087863209'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/14773547087863209'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/07/who-you-calling-ugly.html' title='Who you calling ugly?'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_hNEirhCE9Kw/Sl_l5NAvdiI/AAAAAAAAAE4/Dydt6s1opmQ/s72-c/gldotcom.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-8106505480339404873</id><published>2009-07-16T13:09:00.000-06:00</published><updated>2009-07-20T10:52:52.277-06:00</updated><title type='text'>Meet the Monkey</title><content type='html'>We're gratified by all the buzz being generating around FlexMonkey in the wake of our 1.0 release this week. A search for FlexMonkey +testing on google returns more than 12,000 links.&lt;br /&gt;&lt;br /&gt;My own article, which gives an overview of FlexMonkey's advanced features and discusses user interface testing more generally, was published today on InfoQ at &lt;a href="http://www.infoq.com/articles/flexmonkey-ui-unit-testing"&gt;http://www.infoq.com/articles/flexmonkey-ui-unit-testing&lt;/a&gt;. Eric Owens, our lead developer on the FlexMonkey project published an intro article on Adobe Devcenter at&lt;a href="http://www.adobe.com/devnet/flex/articles/flexmonkey.html"&gt; http://www.adobe.com/devnet/flex/articles/flexmonkey.html&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If you haven't already, please take a minute to meet the monkey and let us know what you think!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-8106505480339404873?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/8106505480339404873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=8106505480339404873' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8106505480339404873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8106505480339404873'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/07/meet-monkey.html' title='Meet the Monkey'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-8643943460238507134</id><published>2009-07-14T14:06:00.000-06:00</published><updated>2009-07-14T14:26:21.667-06:00</updated><title type='text'>The monkey has landed!</title><content type='html'>FlexMonkey 1.0 is here! After nearly nine months of gestation we've delivered what is undoubtedly the premier record/playback testing automation tool for Adobe Flex and AIR applications. And it's free!&lt;br /&gt;&lt;br /&gt;For the thousands of folks who are already using FlexMonkey 0.8, FlexMonkey 1.0 brings significant new functionality including a completely revamped user interface which makes it much easier to record and playback tests. We've also added the ability to take snapshots of portions of the screen or of property values to be verified during playback. In addition to testing Flex apps, FlexMonkey 1.0 for the first time provides direct support for testing AIR apps. The FlexMonkey Console is now itself an AIR app, but can launch standalone as well as browser-based SWFs for testing.&lt;br /&gt;&lt;p&gt;Please let us show you our monkey at &lt;a href="http://flexmonkey.gorillalogic.com/"&gt;http://flexmonkey.gorillalogic.com&lt;/a&gt;! You can also check out Gorilla Logic's Flex service offerings at &lt;a href="http://www.gorillalogic.com/what.development.services.flex.html"&gt;http://www.gorillalogic.com/what.development.services.flex.html&lt;/a&gt;.&lt;br /&gt;&lt;a href="http://www.gorillalogic.com/what.development.services.flex.html"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-8643943460238507134?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/8643943460238507134/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=8643943460238507134' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8643943460238507134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8643943460238507134'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/07/monkey-has-landed.html' title='The monkey has landed!'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-3233979382046420281</id><published>2009-06-01T16:08:00.000-06:00</published><updated>2009-06-01T16:09:46.942-06:00</updated><title type='text'>In a Perfect World....</title><content type='html'>In a perfect world, we could focus solely on implementing functional requirements and not have to do anything explicitly to deal with non-functional constraints such as keeping shared resources from becoming bottlenecks or contending with bandwidth limitations. It can be instructive to consider what an application would look like if there were no physical constraints. Imagine if we lived in a world with infinite memory, infinite processing capacity, unlimited bandwidth, zero down-time, and interesting television shows (Imagine really hard). In such a world, queries are blindingly fast , there is no limit to how often we interact with the back-end, and we can can constantly exchange enormous amounts of data if we need to. With such a platform, we are free to develop our application without any consideration of physical constraints. Each view can refresh the data it is displaying nearly instantaneously, and we can immediately transmit changes to the back-end, and immediately receive notifications of any errors encountered.&lt;br /&gt;&lt;br /&gt;In such an environment, the need for a great many design constraints is removed, although not completely eliminated. Even with physical constraints removed, logical constraints remain. Still, removing the physical constraints certainly simplifies software construction by removing the need to manage limited resources efficiently. Of course, in the real world of enterprise applications, there is no such environment, but not every physical or logical constraint is an issue for every application. Low volume applications or those with very small and simple data requirements can often behave almost as if they were executing in the (near-)perfect world. Consider for example an application that allows a user to update their name, address, and credit card information. As soon as the user logs in, you can easily retrieve such a small volume of data immediately, and you wouldn't have to contend with the user's name and address being changed by someone else simulataneously. You can then allow the user to update any of the returned data, updating their name and address, deleting some credit cards and adding others. If there are few simultaneous users, we can transmit each change immediately to the server where we immediately run required edit checks against it and report any errors encountered back to the client for communication to the user via the UI. Such an approach allows us to write an application in what is arguably the most “natural” way, ie, the simplest way. Physical constraints, on the other hand, force us to commit "unnatural acts", ie, they force us to write code that is more complex than it needs to be from a purely logical perspective.&lt;br /&gt;&lt;br /&gt;With RIA's, there are a few physical constraints which are fundamental at this point in time. The client application is a separate process (on a unique platform), and all communication with the server-side must be accomplished by messaging. It is this constraint, more than anything else, that distinguishes ERIA architecture from web applications, two-tier client server applications, or one-tier local applications. And speaking of one-tier applications, it is worth noting that virtually no enterprise application allows for the data to be persisted entirely on the client box. It is virtually always the case that we cannot rely on the client itself for safe storage of business records, and there are typically large amounts of non-client-specific data (such as a product catalog) that are usually too large to make client-side distribution practical.&lt;br /&gt;&lt;br /&gt;Another constraint is the almost universal requirement that persistence be provided by a non-object-oriented datastore, typically a relational database. There is of course a fundamental impedance mismatch between object- and a relational-centric data structures that is at the heart of many unnatural programming acts, and although there have been many variations on “object databases” over the years, relational databases continue to dominate for good reasons we’ll explore in some depth another time. In a perfect world, queries would return graphs of objects rather than lists of rows. Fortunately, persistence management frameworks such as Hibernate automate a good deal of the acrobatics involved in object-relational mapping, but unfortunately are not (yet?) fully transparent to the application developer, requiring varying amounts of explicit coding.&lt;br /&gt;&lt;br /&gt;Coding in the real world requires more effort than coding in the perfect world because we need to add code to work around physical constraints. It would seem to be self-evident that since it takes more effort to add more code, you should only do so when there is an actual requirement to do so. In other words, the default architecture for any ERIA is essentially the simple one described above. We retrieve all the data up-front. Operate on the data as necessary. And send edits to the back-end as they occur. In pondering each of the questions posed above, the default answer in each case is this straight-forward, perfect world architecture since it requires the least effort to build. In each case however it is also necessary to consider how physical constraints can force the undertaking of more complicated strategies, but again, it should be emphasized that in the absence of any such physical constraints, the simplicity of the perfect world approach is the way to go.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-3233979382046420281?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/3233979382046420281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=3233979382046420281' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3233979382046420281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3233979382046420281'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/06/in-perfect-world.html' title='In a Perfect World....'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-6801690839620999820</id><published>2009-02-17T21:22:00.000-07:00</published><updated>2009-02-20T15:40:51.040-07:00</updated><title type='text'>What is an architecture and why do you want one?</title><content type='html'>An architecture is essentially a set of design constraints imposed on an IT development project. You want one because unconstrained design leads to impedance mismatches among the various pieces of a system due to logical or physical incompatibilities among software components developed by different team members or third parties. The result is software that takes longer or costs more to build, or is more expensive to operate once it's deployed.&lt;br /&gt;&lt;br /&gt;Impedance mismatches can manifest in a variety of ways.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;     Model - Multiple, possibly inconsistent object definitions for the same logical entity   &lt;/li&gt;&lt;li&gt;     API - Incompatible arguments or return results required or produced by libraries   &lt;/li&gt;&lt;li&gt;     Performance - Inability of data sources to provide data as fast as required   &lt;/li&gt;&lt;li&gt;     Locks - Contention resulting from different components having different expectations for how resources should be shared   &lt;/li&gt;&lt;li&gt;     Transactions - Improperly serialized updates resulting in data being lost or overwritten with stale values   &lt;/li&gt;&lt;li&gt;     Responsibility - Functionality needlessly duplicated or incorrectly assumed to be provided elsewhere   &lt;/li&gt;&lt;li&gt;     Recovery - Components in the event of failure not coordinating properly to minimize downtime or data loss   &lt;/li&gt;&lt;li&gt;     Operational - Software too difficult to modify in response to anticipated future needs   &lt;/li&gt;&lt;/ul&gt; An architecture is sufficiently defined when you can turn a developer loose on developing some piece of functionality and if he or she obeys all the established design constraints, there is a minimal possibility of creating software that produces any of the above problems. If you're conceptually bothered by being constrained, preferring instead to program in wide open spaces with the wind blowing in your hair, perhaps you would prefer to instead think of architecture a form of freedom -- the &lt;i&gt;freedom from choice&lt;/i&gt;. Once defined, an architecture frees developers from having to make (possibly incompatible) choices for how to implement an application's functionality, and instead devote most of their time to implementing functional requirements while minimizing the time spent hacking together glue to integrate with the rest of the team's code.&lt;br /&gt;&lt;br /&gt;Here's a very high-level breakdown of a typical ERIA:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_hNEirhCE9Kw/SZ7ptSSdTNI/AAAAAAAAAEY/BFM0uXRIQI4/s1600-h/simplified.jpg"&gt;&lt;img alt="" id="BLOGGER_PHOTO_ID_5304934375301663954" src="http://3.bp.blogspot.com/_hNEirhCE9Kw/SZ7ptSSdTNI/AAAAAAAAAEY/BFM0uXRIQI4/s400/simplified.jpg" style="margin: 0px auto 10px; display: block; text-align: center; width: 400px; height: 94px;" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:130%;"&gt;&lt;b&gt;BackendService&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In any non-trivial enterprise application development project, multiple developers will be working in tandem, and in an RIA project where the client and server platforms do not even use the same programming language, it is natural that developers will be divided into front-end and back-end teams. In order to reduce dependencies between client and server code development and allow the teams to work in relative independence on their respective components, it makes sense to explicitly define an API that will provide the linkage between the client and server code.&lt;br /&gt;&lt;br /&gt;The BackendService is typically implemented using a webservice-type container, for example Tomcat and associated plugins, which provides a framework for authorizing users, managing session data, and communicating over web protocols such as REST, SOAP, or AMF.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;b&gt;UserSession&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As with most traditional web applications, we require a container that maintains &lt;i&gt;session state &lt;/i&gt;for each logged in user. Unless application users are anonymous, the session state will at a minimum contain user identity information required for access control. For many applications, code can be simplified by maintaining other session-specific information on the server, such as for example the current contents of the user's shopping cart.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;b&gt;UserIdentity&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In most applications, we require user identity information in order to be able to complete requests received from a client. For example, when a user requests information for "my account", the server must need to somehow know which account to access. It is typically not an option to supply the account number for example as part of the request, since the client could be running a hacked application that allows the user to specify an arbitrary account number. When the user authenticates with the server, the server must associate the authorized user's identity with the session, and check each subsequent request against the that identity information in order to perform the requisite access control.&lt;br /&gt;&lt;br /&gt;UserIdentity is typically implemented with role-based security frameworks such as &lt;i&gt;JEE security&lt;/i&gt; implementations riding on &lt;i&gt;LDAP&lt;/i&gt; or some other user directory store.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;b&gt;DomainObject&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;   &lt;b&gt;DomainObjects&lt;/b&gt; are instances of classes that directly model some aspect of our problem domain, such as &lt;i&gt;Customers&lt;/i&gt;, &lt;i&gt;Invoices&lt;/i&gt;, and &lt;i&gt;Products&lt;/i&gt;. These objects are mostly created from input received from the client, or by being retrieved from a database or some external source, and additionally provide the non-UI-specific logic comprising our application.[Mention DDD?]&lt;/p&gt; &lt;span style="font-size:130%;"&gt;&lt;/span&gt;&lt;br /&gt;If we do our jobs right, most of the custom code we write on the backend will be domain-specific, having delegated most of the non-domain-specific plumbing to third-party frameworks. &lt;p&gt;   &lt;span style="font-size:130%;"&gt;&lt;/span&gt; &lt;/p&gt; &lt;span style="font-size:130%;"&gt; &lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;b&gt;PersistenceManager&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt; &lt;p&gt;   &lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;/span&gt;&lt;/span&gt;The PersistenceManager caches previously retrieved data and collects updates triggered by the client until such time as a logical transaction is completed and can be committed to a database or external system. &lt;span style="font-size:100%;"&gt;For relational databases, the PersistenceManager is typically implemented with a framework such as &lt;i&gt;Hibernate&lt;/i&gt;. [Link to hibernate definition?]&lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;/span&gt;&lt;/span&gt; &lt;/p&gt; &lt;p&gt;   &lt;span style="font-size:130%;"&gt;&lt;/span&gt; &lt;/p&gt; &lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;b&gt;BackEndServiceAPI&lt;br /&gt;&lt;/b&gt;&lt;span style="font-size:100%;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Clients access the BackEndService via a library that provides a client-code-friendly interface. This BackEndServiceAPI is often no more than a wrapper that exposes the BackEndService interface in the client's native language, and does little more than marshal arguments as necessary to call whatever remoting framework is being used for backend communication, and set up whatever callbacks are needed in cases where results are returned asynchronously.&lt;br /&gt;&lt;br /&gt;The BackEndServiceAPI would usually be defined as an interface for which a mock implementation can be used as a stand-in so that the front-end team has the option of proceeding with development ahead of the back-end implementation being complete.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;b&gt;DomainDTO&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In a typical RIA, we cannot actually return full-blown objects from the server to the client or vice versa. Instead, we can only transmit an object's primitive property values. For example, if the client requests a particular Customer, the server does not return an actual instance of a DomainObject, but instead returns a set of values such as name, address, and account number. While its possible to construct an actual DomainObject instance from these returned values, it is often unnecessary since an RIA in many cases is merely providing for the display and editing of such primitive values, delegating any requisite business logic back to the server-based DomainObjects. DomainDTO's are objects that provide holders for these values, but don't necessarily provide any "behavior" in the form of methods on the objects. It is of course also common to selectively replicate some DomainObject logic on the client, especially simple field edits, and in some cases we might even replicate complex logic on the client, so we're using the term DTO loosely here. [Link to DTO definition?]&lt;br /&gt;&lt;br /&gt;[Diagram showing a DomainObject vs corresponding DomainDTO?]&lt;br /&gt;&lt;h2&gt;CacheManager&lt;/h2&gt; With a thin client, client-side state does not usually consist of anymore than the contents of some html form or table. Each new view usually requires a round-trip to the server to retrieve both the definition of the view (ie, an html page), and the data presented within it. Even just changing the sort sequence of the rows in a table require re-retrieving a fully formatted table of data from a server. One of the big advantages in an RIA is that we can provide a much more interactive and responsive user experience by not requiring the constant back-and-forth of data and markup with the server. Instead we can retrieve (possibly large amounts of) data just once, display it in a variety of ways, allow the user to edit it, and send updates to the server only after a transaction is logically complete.&lt;br /&gt;&lt;br /&gt;The CacheManager keeps track of what we've already retrieved from the server so that we don't incur unnecessary overhead of re-retrieving the same data, and tracks what objects are changed ("dirty") and require transmission back to the server. The sophistication of CacheManagers can vary greatly from one application to another, consisting of little more than hash tables of objects by type [Include a simple diagram of this?], or as much as client-side relational databases.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ViewComponent&lt;/h2&gt; The view components are the widgets that provide for the display and editing data, usually DomainDTO's retrieved from the local cache. By ViewComponents, we don't mean low-level UI components like buttons and textfields, but semantically rich composite components such as for example a Customer Creation Form or an Order History Table.&lt;br /&gt;&lt;h2&gt;EventBus&lt;/h2&gt; RIA platforms are event-driven user interface frameworks where ViewComponents emit and respond to asynchronous notifications such as "User Wants to Quit" or "User Has Updated His Credit Card Info". While such event-driven models are ideally suited to coordinating the asynchronous update and display of data across possibly multiple views, event-driven programs can degenerate into a tangle of interdependencies among components dispatching and listening for each other's events. An EventBus organizes event handling around a hub-and-spoke where events are logically broadcast throughout the application. In this way, brittle point-to-point connections are replaced by a robust, centralized switchboard for application events.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Application&lt;/h2&gt; The Application is "everything else". It's the code necessary to integrate the BackEndAPI, the ViewComponents, and the CacheManager into the functioning whole experienced by the user. The Application for example binds particular views to particular DTO's, and invokes particular BackEndAPI methods in response to user interactions.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Can I just go build my application now?&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;Having dilligently studied the above description, you may be chomping at the bit to put the above principles to work and begin building your next RIA. Unfortunately, the above is not the answer. It only frames the questions more clearly. Chiefly:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;     Whether to locate logic on the client or server?   &lt;/li&gt;&lt;li&gt;     How much data to cache locally on the client?   &lt;/li&gt;&lt;li&gt;     When should data be transmitted from the client to the server?   &lt;/li&gt;&lt;li&gt;     When should data be persisted to a database?   &lt;/li&gt;&lt;li&gt;     How should view components be made aware of updates to what is being displayed?   &lt;/li&gt;&lt;li&gt;     What is the right level of granularity for remote operations?   &lt;/li&gt;&lt;/ul&gt;What's that you say? You came here for answers? Fear not. All will be revealed. But not this afternoon....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-6801690839620999820?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/6801690839620999820/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=6801690839620999820' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6801690839620999820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6801690839620999820'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/02/what-is-architecture-and-why-do-we-want.html' title='What is an architecture and why do you want one?'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_hNEirhCE9Kw/SZ7ptSSdTNI/AAAAAAAAAEY/BFM0uXRIQI4/s72-c/simplified.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-6147987757112308</id><published>2009-01-27T19:57:00.000-07:00</published><updated>2009-02-05T20:48:53.294-07:00</updated><title type='text'>The Year of Coding Dangerously</title><content type='html'>You've got an appointment set up with your customer at a lunch place down by the water. You get there early, sit down at a booth and check the place out. There's a beautiful woman sitting at a table near the door, watching a tiny movie on her iPhone. You think, where have I seen her before? Is she from a rival consulting outfit? Could it be you're being followed? No, no, you think. Just paranoia. On the road too long.&lt;br /&gt;&lt;br /&gt;Your customer arrives and sits down heavily on the other side of the table. He pushes a sky blue folder toward you and orders a patty melt. Inside you find a PowerPoint deck and flip through it, amazed that people still use such cheesy clipart. After a minute you look up, and trying to control your voice manage to say, "We can't do it in time." You reach for a cigarette but then realize you don't smoke. So instead you pick up a french fry.&lt;br /&gt;&lt;br /&gt;Your customer gets an impatient look on his face and says, "Look, negotiations broke down in Helsinki. It was bad. They quit the consortium. They're not going with the standard. We've gotta do it their way. How bad could their proprietary stuff really be?".&lt;br /&gt;&lt;br /&gt;Just then, an explosion rips through the building. You find yourself lying face up in the parking lot just as a helicopter lands and two guys wearing flak jackets with your company's logo jump out and pull you inside. As you fly off, you see the entire island  being consumed in a volcanic eruption and sinking slowly into the sea. Just before you pass out again you think, next time I gotta get a local gig.&lt;br /&gt;&lt;br /&gt;I'm sure we've all had experiences like this one. As application developers, we live in a world of excitement, intrigue and suspense. Yes, danger lurks around every turn. Sometimes it arrives with a whisper. A never-before-seen error message appears on a console, or a process turns up dead. Other times it comes with a bang. A load balancer goes beserk and the Big Board in the call center lights up like a pinball machine. The lives of thousands of active sessions hang by a thread. Your cell phone rings. The president needs an update....&lt;br /&gt;&lt;br /&gt;As asserted in our last post, architecture can be seen as a a set of implementation constraints selected to mitigate risk. There are other ways to think about architecture, but this definition works well in that it emphasizes the "why" rather than the "what" of architecture. By focusing on the "why", we can better determine the "how much" and define no more architecture than necessary to deal with the risk profile of a particular project.&lt;br /&gt;&lt;br /&gt;Architecture alone is of course insufficient for mitigating every kind of risk we might encounter on a project. We also need things like legal contracts, customer expectation management, and adequate QA testing, to name a few. Most of those other things are not, strictly speaking, technical risks, and so are not typically the province of application developers, being handled instead by people like lawyers, project managers, and that really annoying guy in the purchasing department.&lt;br /&gt;&lt;br /&gt;In defining an Enterprise RIA Architecture, we will begin by identifying the most common risks faced by most development efforts and define our architecture in the context of providing mitigation strategies for those risks.&lt;br /&gt;&lt;br /&gt;To be clear, what we mean by "Enterprise RIA" (ERIA) is any application in which a rich client user interface accesses a set of back-end services to execute transactions. ERIA's are characterized much more by this back-end interaction requirement than by any particular attributes of the user interface itself. Because the user interface of an ERIA can vary so dramatically from application to appllication, there's not much we'll say about the architecture of the presentation portion of an application, which might consist of anything from simple forms to sophisticated 3D aimations. We are much more concerned with how the presentation portion handles information and transactions in concert with back-end systems, where the back-end systems are information- or transaction-centric.&lt;br /&gt;&lt;br /&gt;What, you may wonder, makes back-end interaction in an RIA fundamentally different from good-old-fashioned J2EE architecture? The answer is that in a typical J2EE application, virtually all the logic lives in the back-end. Yes, we can use JavaScript to execute logic on the client platform directly, but since, by definition, non-RIA applications provide non-rich UI functionality, that logic is typically limited and simple.&lt;br /&gt;&lt;br /&gt;In an RIA, however, we are building full-blown client-side applications with client-side logic that can be quite complex. RIA clients tend to be highly stateful, oftentimes maintaining relatively large amounts of data client-side that create unique problems around synchronization with back-end systems of record. As we shall see, such front-end to back-end state synchronization is one of the major technical requirements that drive many of our architectural decisions.&lt;br /&gt;&lt;br /&gt;In our next installment, we'll look more closely at the risks confronting most ERIA projects. Until then, watch your back-end and for godsakes make sure you're not being followed by agents of rival consulting outfits....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-6147987757112308?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/6147987757112308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=6147987757112308' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6147987757112308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6147987757112308'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/01/year-of-coding-dangerously.html' title='The Year of Coding Dangerously'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-8418910306281563013</id><published>2009-01-21T20:50:00.001-07:00</published><updated>2009-01-21T21:17:21.399-07:00</updated><title type='text'>Architecture, smarchitecture.</title><content type='html'>Now begins our discussion of Rich Internet Application Architecture. This is a work in progress, which is to say that what is below is really a draft of a post, but we're exposing the salami-making process to invite collaboration from our friends and lovers.&lt;br /&gt;&lt;br /&gt;The first thing we need to discuss is what we mean by "architecture", since this is surely an overloaded term in our industry. It seems to mostly say something about how a system's functionality (domain-specific and otherwise) is partitioned both logically and physically across application code, software platforms, and physical hosts. For the purposes of this discussion we'll define architecture as &lt;span style="font-style: italic;"&gt;any set of implementation constraints imposed on a team during some project.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;By this definition, a project without a pre-defined architecture is one in which their might be a "design", for example consisting of major classes and how they interact with each other, and choices about what platforms things will run on, but beyond that it is left up to each developer to determine how to implement each piece of functionality assigned to their work queue. We say that the project has no &lt;span style="font-style: italic;"&gt;pre-defined&lt;/span&gt; architecture because one will almost inevitably "emerge" as various mechanisms and partitioning strategies get worked out and discussed among the team, and people naturally clone already working code when they need to do something similar. It could be argued that the resulting "architecture"  is one that is tightly adapted to meet the actual (emerging) needs for one, rather than something possibly over-engineered beyond what we find is really needed after we've been coding on the project for a while.&lt;br /&gt;&lt;br /&gt;Of course the real choice is not a binary one between having a pre-defined architecture and not having one. We can rigorously define some aspects of a system's architecture while letting other aspects emerge. But that still leaves the question: "How much architecture do we need?"&lt;br /&gt;&lt;br /&gt;I propose that the answer to that question should be "Just enough to mitigate risk" and in summary will close with the proposition that:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;A system's architecture definition should consist of the &lt;span&gt;minimal&lt;/span&gt; set of implementation constraints needed to mitigate implementation risks.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;In our next installment, we'll discuss the most commons risks confronting Enterprise RIA system implementations.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-8418910306281563013?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/8418910306281563013/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=8418910306281563013' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8418910306281563013'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/8418910306281563013'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/01/architecture-smarchitecture.html' title='Architecture, smarchitecture.'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-2515935932541386597</id><published>2009-01-15T15:45:00.001-07:00</published><updated>2009-01-19T16:22:01.770-07:00</updated><title type='text'>A sketch of a Rich Internet Application Architecture</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hNEirhCE9Kw/SXULEwVAo1I/AAAAAAAAAC4/gOU_Cdvf8nQ/s1600-h/RiaArch.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 184px;" src="http://3.bp.blogspot.com/_hNEirhCE9Kw/SXULEwVAo1I/AAAAAAAAAC4/gOU_Cdvf8nQ/s400/RiaArch.jpg" alt="" id="BLOGGER_PHOTO_ID_5293149113364292434" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hNEirhCE9Kw/SW-8u4jsQEI/AAAAAAAAACo/JtozUv4P95s/s1600-h/RiaArch.jpg"&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-2515935932541386597?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/2515935932541386597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=2515935932541386597' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/2515935932541386597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/2515935932541386597'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/01/sketch-of-rich-internet-application.html' title='A sketch of a Rich Internet Application Architecture'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_hNEirhCE9Kw/SXULEwVAo1I/AAAAAAAAAC4/gOU_Cdvf8nQ/s72-c/RiaArch.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-6447869147336335054</id><published>2009-01-14T11:41:00.000-07:00</published><updated>2009-01-14T16:23:43.146-07:00</updated><title type='text'>Just another code-slinging CEO</title><content type='html'>I am a fossil, or more accurately, I should say that I'm a fossil record. Or perhaps the better metaphor would be that I'm like one of those ice cores geologists drill from the depths of the Arctic.  If you were to sink a drill deep into my head (and I know many of my former colleagues would like to), you would find evidence of the many fads, trends, and revolutions that have constantly reshaped corporate IT over the past 30 years recorded in my brain like the stratified deposits within an ice core. By examining such ice cores, geologists arrive at a deeper understanding of our planet, and by examining the ice core in my brain, I will endeavor for us to arrive at a deeper understanding of Planet IT. I have not only been present for the many tectonic shifts that periodically rock our industry, I have usually been standing directly on the fault line, intimately involved as a leader, manager, and practitioner of application development.&lt;br /&gt;&lt;br /&gt;I want to emphasize the "practioner" part of what I just said. Years ago, my colleagues and I would tell each other (half-) jokingly, "Don't trust anybody who doesn't log on". This was shorthand for our belief (which I still hold) that anybody who no longer understands the technology is inherently ineffective in directing IT initiatives. This does not mean that management needs to write code, but management does need to understand a fairly large body of key technical principles since these significantly impact the planning and execution of any IT project.&lt;br /&gt;&lt;br /&gt;I myself have continued to write code in spite of having spent many years in fairly senior management positions (at Sun, for example, I managed 300 people). Hopefully as I delve into the subtleties of Rich Internet Application Architecture in the following series of posts, you will trust that my views are derived not just from a consideration of battles viewed from the safety of an underground bunker back at central command, but also while engaged in fierce trench warfare myself.&lt;br /&gt;&lt;br /&gt;This experience, coupled with the ice core in my brain that informs my views with a deep (and painful) appreciation of all that has gone (wrong) before hopefully convinces you that my insights are more valuable than what you would find in a random blog post. (And yes, I realize that this is itself a random blog post and my last comment was a referential recursion of sorts that probably blew the stack of several unsuspecting readers).&lt;br /&gt;&lt;br /&gt;In any event, I do hope you'll join me in my next few posts for an exploration of Rich Internet Application Architecture (I hesitate to call this RIAA since it's the RIAA that sues people for downloading Britney Spears singles), but before we begin, let's all go write some code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-6447869147336335054?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/6447869147336335054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=6447869147336335054' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6447869147336335054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6447869147336335054'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/01/just-another-code-slinging-ceo.html' title='Just another code-slinging CEO'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-4079348633791313157</id><published>2009-01-08T21:12:00.001-07:00</published><updated>2009-01-08T21:37:36.182-07:00</updated><title type='text'>The Tower of Babbage</title><content type='html'>In this &lt;a href="http://ectropic.com/wordpress/2009/01/06/the-art-of-software-providing-value-by-focusing-on-the-core-domain/"&gt;post&lt;/a&gt; about an Eric Evans presentation, Jon Rose mentions how Eric needed to clarify that the intention is not for Ubiquitous Languages to be enterprise-wide. UL's are established across project teams, not organizations. I was initially surprised that such a clarification would be necessary since this seems obvious, but then I remembered life in the late eighties....&lt;br /&gt;&lt;br /&gt;Love Shack was a smash hit and Enterprise Data Models were all the rage.&lt;br /&gt;&lt;br /&gt;Much like the Arthur Clarke science fiction &lt;a href="http://en.wikipedia.org/wiki/The_Nine_Billion_Names_of_God"&gt;story&lt;/a&gt; in which a monastery of monks fulfills the purpose of the universe by recording with a computer every known name of God (when they were finished "&lt;i&gt;overhead, without any fuss, the stars were going out"&lt;/i&gt;), the idea was that if we could just catalog EVERY data entity, attribute, and association across the ENTIRE enterprise, then surely we would come to know our domain, our applications, our users, indeed our very inner souls better, and thus build better software faster since all of the various warring factions in IT would finally speak the one, true tongue.&lt;br /&gt;&lt;br /&gt;At my company, PaineWebber, several monkish DBA's undertook this task for several years, compiling an ever growing glossary of ever greater weight and size. One night in a dream (or perhaps it was after a series of lunches with a leggy sales rep) our CIO realized he could accelerate our rendevous with destiny by buying somebody else's financial services datamodel. And so it was that for the low, low price of $1.5 million, we purchased a great many binders from First Boston containing a great multitude of boxes and lines.&lt;br /&gt;&lt;br /&gt;From time to time, developers would come to seek the truth of the binders. Like astrologers poring over charts of the stars, they would look for signs in the many boxes and lines, looking for clues to unlock the secrets of their particular problem domain. But, alas, while many of the boxes and lines bore striking resemblances to actual people, places, and things from the known world, there would also be striking differences from the reality they knew, and in any case, the detail of the models was simply too overwhelming -- or perhaps it was just too magnificent.&lt;br /&gt;&lt;br /&gt;And so we went on as before, speaking our own local dialects and doing our best to communicate with neighboring tribes, using extract files like smoke signals, reeking with the smell of EBCDIC.&lt;br /&gt;&lt;br /&gt;At least the stars didn't wink out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-4079348633791313157?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/4079348633791313157/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=4079348633791313157' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4079348633791313157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4079348633791313157'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2009/01/tower-of-babbage.html' title='The Tower of Babbage'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-3032290785289410323</id><published>2008-12-11T15:15:00.000-07:00</published><updated>2008-12-11T15:22:39.256-07:00</updated><title type='text'>Moe, Larry, and Curly Braces</title><content type='html'>We've thus far discussed several of the primary pillars of Precision Modeling -- &lt;a href="http://stu-stern.blogspot.com/2008/11/lets-not-get-physical.html"&gt;derivation expressions&lt;/a&gt;, &lt;a href="http://stu-stern.blogspot.com/2008/12/conditional-love.html"&gt;conditional expressions&lt;/a&gt;, &lt;a href="http://stu-stern.blogspot.com/2008/12/axis-of-e-ville.html"&gt;query expressions&lt;/a&gt;, and &lt;a href="http://stu-stern.blogspot.com/2008/12/enemy-of-my-enemy-is-my-customer.html"&gt;derived associations&lt;/a&gt; -- and we've used these to help out our hypothetical (and some might say homicidal) customer, arms4less.com ("where you can get regime change for small change!"). We've been specifying the business rule stating that customers' can pay a surcharge to prevent their enemies from purchasing any of the same weapons they're purchasing themselves. We did this by creating a &lt;em&gt;&lt;strong&gt;derived association&lt;/strong&gt;&lt;/em&gt;, &lt;em&gt;enemyProducts, &lt;/em&gt;that contains the list of all products we are unable to sell to a particular customer, because they have already been purchased by enemies of the customer who have opted to pay the surcharge:&lt;br /&gt;&lt;p align="left"&gt;&lt;code&gt;/enemyProducts : Product = enemies.orders.items[isExclusive].product&lt;/code&gt;&lt;/p&gt;&lt;br /&gt;Now we just need to somehow use this association to prevent a customer from actually buying any of these &lt;em&gt;enemyProducts&lt;/em&gt;. As with the many wonders of Precision Modeling we've previously discussed, we can specify such a requirement precisely and concisely (Hey, that rhymes. Our marketing people will be so pleased.) via a little Gorilla UML.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hNEirhCE9Kw/SUGR8Q9p73I/AAAAAAAAACg/afjU0ssg4XU/s1600-h/figure8.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 338px; height: 400px;" src="http://2.bp.blogspot.com/_hNEirhCE9Kw/SUGR8Q9p73I/AAAAAAAAACg/afjU0ssg4XU/s400/figure8.jpg" alt="" id="BLOGGER_PHOTO_ID_5278660702786678642" border="0" /&gt;&lt;/a&gt; Notice the &lt;em&gt;&lt;strong&gt;constraint expression &lt;/strong&gt;&lt;/em&gt;we've attached to &lt;strong&gt;OrderItem&lt;/strong&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;{not product in order.customer.enemyProducts}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;In UML, constraints are specified inside curly braces (many have postulated this proves once and for all that Grady Booch is a die-hard Three Stooges fan). Because this constraint is attached to &lt;strong&gt;OrderItem&lt;/strong&gt;, it is specifying that any &lt;em&gt;product&lt;/em&gt; associated with an &lt;strong&gt;OrderItem&lt;/strong&gt; cannot also be included in the list of the &lt;em&gt;order&lt;/em&gt;'s &lt;em&gt;customer&lt;/em&gt;'s &lt;em&gt;enemyProduct&lt;/em&gt;'s list.&lt;br /&gt;&lt;br /&gt;Our SME, Sarge, inquires as to how we plan to enforce this constraint? "If it gets violated, there needs to be -- you know -- consquences." We ensure him that we will be sure to thoroughly test our implementation of this constraint to ensure that the software indeed enforces it. Sarge sighs wistully as he removes his hand from a bulge beneath his flack jacket.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-3032290785289410323?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/3032290785289410323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=3032290785289410323' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3032290785289410323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/3032290785289410323'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2008/12/weve-thus-far-discussed-several-of.html' title='Moe, Larry, and Curly Braces'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_hNEirhCE9Kw/SUGR8Q9p73I/AAAAAAAAACg/afjU0ssg4XU/s72-c/figure8.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-4341274504432360322</id><published>2008-12-04T13:01:00.000-07:00</published><updated>2008-12-04T13:19:13.614-07:00</updated><title type='text'>The enemy of my enemy is my customer</title><content type='html'>If you're new here, this post is part of a more-or-less continuous train-of-thought that begins &lt;a href="http://stu-stern.blogspot.com/2008/11/too-much-religion.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Today we continue looking at &lt;a href="http://stu-stern.blogspot.com/2008/12/axis-of-e-ville.html"&gt;query expressions&lt;/a&gt;, which I introduced with much hullabaloo last time,  but have thus far only given you the smallest taste. The glutinous among you are surely clamoring for more. So let's eat. But please stop using that use case diagram as a napkin. (Javadoc is much more absorbent).&lt;br /&gt;&lt;br /&gt;Sarge has for the first time invited us to the headquarters of Arms4Less.com. After our blindfolds have been removed and our hands untied, we find ourselves seated around a large conference table in a windowless room. Charts around the wall show sales projections and troop strength estimates for the various markets Arms4Less is targeting over the next twelve months.&lt;br /&gt;&lt;br /&gt;Last time we looked at how we can derive a value (isTrusted) using a query expression. Let's consider another such example. Sarge explains to us that Arms4Less prides itself on its high ethical standards. "Like if we sell a particular model of tank to one guy, for a small surcharge of 10%, we won't sell the same kinda tank to any of his enemies." We consider this requirement and realize that we need to prevent a customer from ordering any product that has been previously ordered by any of the customer's enemies. Now many of you are probably wonder how the heck we can express something like this on a lowly class diagram. Doesn't this require a more procedurally-oriented specification? Something with a little more get-up-and-go than a class diagram? Class diagrams just lay there, you say. We need something that moves, don't we?&lt;br /&gt;&lt;br /&gt;Ha! I laugh at you (with all due respect of course). Do you think I would have wasted this much time blogging about this crap if we could go no further? Consider our latest version of the precision model, below:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hNEirhCE9Kw/STg3lT2nd_I/AAAAAAAAACI/eXDfqA8P57Y/s1600-h/figure5.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 397px;" src="http://3.bp.blogspot.com/_hNEirhCE9Kw/STg3lT2nd_I/AAAAAAAAACI/eXDfqA8P57Y/s400/figure5.jpg" alt="" id="BLOGGER_PHOTO_ID_5276028077588576242" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We have added a new association, &lt;em&gt;enemies&lt;/em&gt;, to keep track of a customer's enemies, and we have added a &lt;em&gt;&lt;strong&gt;derived association&lt;/strong&gt;&lt;/em&gt; called &lt;em&gt;enemyProducts &lt;/em&gt;that references all the products purchased by a customer's enemies. Let me clarify a few things about "derived associations". First, you may be scratching your head about why we're calling &lt;em&gt;enemyProducts&lt;/em&gt; an association at all, since it's not represented by a line on our class diagram. Notice however the type of the &lt;em&gt;enemyProducts&lt;/em&gt; attribute. It's a &lt;strong&gt;Product&lt;/strong&gt;. (In fact, as we'll discuss another time, it's a list of &lt;strong&gt;Product&lt;/strong&gt;s.)&lt;br /&gt;&lt;br /&gt;There are multiple ways of representing associations in UML. For example, the following two representations are virtually equivalent.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hNEirhCE9Kw/STg4DWrhNDI/AAAAAAAAACY/7kxcTxj-ugU/s1600-h/figure7.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: right; cursor: pointer; width: 127px; height: 86px;" src="http://1.bp.blogspot.com/_hNEirhCE9Kw/STg4DWrhNDI/AAAAAAAAACY/7kxcTxj-ugU/s400/figure7.jpg" alt="" id="BLOGGER_PHOTO_ID_5276028593743410226" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hNEirhCE9Kw/STg32lSOyqI/AAAAAAAAACQ/7w3xKoPBu98/s1600-h/figure6.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: left; cursor: pointer; width: 288px; height: 77px;" src="http://3.bp.blogspot.com/_hNEirhCE9Kw/STg32lSOyqI/AAAAAAAAACQ/7w3xKoPBu98/s400/figure6.jpg" alt="" id="BLOGGER_PHOTO_ID_5276028374325578402" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;On top, we see that the &lt;strong&gt;Employee&lt;/strong&gt; has a &lt;strong&gt;BattleInjury&lt;/strong&gt; reference called &lt;em&gt;injuries&lt;/em&gt;. We see exactly the same thing with the &lt;strong&gt;Employee&lt;/strong&gt; representation on the bottom, which contains a &lt;strong&gt;BattleInjury&lt;/strong&gt; reference as well. The only difference is the notation being used. On the top we depict the reference with a composite association named &lt;em&gt;injuries&lt;/em&gt;, whereas on the bottom, we decpict the reference with a nested attribute, also called &lt;em&gt;injuries&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;A &lt;strong&gt;&lt;em&gt;derived association&lt;/em&gt;&lt;/strong&gt; then is simply a derived attribute whose formula evaluates to a list of entities of some type. Let's look at the derivation expression for &lt;em&gt;enemyProducts&lt;/em&gt;:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;enemies.orders.items[isExclusive].product &lt;/em&gt;&lt;br /&gt;&lt;br /&gt;In evaluating the value of this expression for a particular customer, we navigate through the customer's associated &lt;em&gt;enemies&lt;/em&gt;, to their &lt;em&gt;orders&lt;/em&gt; and then to the order's associated &lt;em&gt;items&lt;/em&gt;. We then subset (query) the orders to select out those for which enemies have opted for an exclusive deal, and then we navigate from this resulting set to their associated products. The resulting list of products are the ones that we can't sell to the Customer.&lt;br /&gt;&lt;br /&gt;The astute reader (or at least most who weren't out drinking last night) will have noticed we're essentially navigating multiple paths in parallel when we navigate &lt;em&gt;enemies.orders.items&lt;/em&gt; since a customer can have many enemies, each in turn having many orders, and each of those orders having many items. The expression "unions" the results of navigating these parallel paths.&lt;br /&gt;&lt;br /&gt;Now, you may recall earlier in this tirade we talked about the importance of precision. In fact, recall that all these techniques we're using comprise a methodology called Precision Modeling. You can rest assured that I'm not just whipping out arbitrary syntax for each of the formulas we've used. All of them are expressed with a formal expression language that are part of what we call &lt;em&gt;&lt;strong&gt;Gorilla UML (GUML)&lt;/strong&gt;&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;strong&gt;GUML&lt;/strong&gt;&lt;/em&gt; not only has formal syntax definition. It executes! (Sarge says, "Cool! I execute too!") More on execution later. In our next little visit together, we'll actually look at using GUML to specify &lt;strong&gt;&lt;em&gt;constraints&lt;/em&gt;&lt;/strong&gt;. Using constraints we can complete our specification of Sarge's business rule preventing a product being sold to a customer's enemies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-4341274504432360322?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/4341274504432360322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=4341274504432360322' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4341274504432360322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4341274504432360322'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2008/12/enemy-of-my-enemy-is-my-customer.html' title='The enemy of my enemy is my customer'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_hNEirhCE9Kw/STg3lT2nd_I/AAAAAAAAACI/eXDfqA8P57Y/s72-c/figure5.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-5110872622589230947</id><published>2008-12-02T13:40:00.000-07:00</published><updated>2008-12-02T13:50:02.315-07:00</updated><title type='text'>The Axis of e-Ville</title><content type='html'>Having looked at how we can use derived and conditional expressions in our class diagrams, we are now ready to consider a construct so powerful that I shudder to think of what could happen if Iran, North Korea, or Microsoft should get hold of it. In fact, I'm taking a huge risk in revealing it here today. If this is my last post, it's a good bet that I'm in the hands of foreign agents trying to force me into assisting with a diabolical plot involving germs, radiation, and Tomcat 5.5.&lt;br /&gt;&lt;br /&gt;Yes, today you are ready to learn about (cue some suitably momentous music) query expressions! Wait! Where are you going? Come back. I'm tellin' ya. Query expressions are some serious mojo!&lt;br /&gt;&lt;br /&gt;Let us feel their power together by returning again to our consideration of the Arms4Less online superstore ("where you don't need to spend a lot to destroy a lot"). Sarge explains to us that they don't sell to just anybody. "For the really good stuff, you gotta be somebody we trust -- either somebody we know, or a friend of at least two people we know." We easily capture this notion of who's trusted as follows.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hNEirhCE9Kw/STWeMY3rjmI/AAAAAAAAACA/GUQUU0T9ch8/s1600-h/figure4.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 351px; height: 400px;" src="http://4.bp.blogspot.com/_hNEirhCE9Kw/STWeMY3rjmI/AAAAAAAAACA/GUQUU0T9ch8/s400/figure4.jpg" alt="" id="BLOGGER_PHOTO_ID_5275296474206015074" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We add a &lt;strong&gt;Customer&lt;/strong&gt; entity with an association, &lt;em&gt;friends&lt;/em&gt;, referencing customers who are a customer's friends. We give &lt;strong&gt;Customer&lt;/strong&gt; a boolean attribute, &lt;em&gt;isSomebodyWeKnow&lt;/em&gt;, and as well as a derived attribute, &lt;em&gt;isTrusted&lt;/em&gt;. The value of isTrusted is derived from the expression:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;isSomebodyWeKnow or #friends[isSomebodyWeKnow]  &gt;= 2&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;The []-brackets enclose a selection expression. &lt;em&gt;friends[isSomebodyWeKnow] &lt;/em&gt;selects all of the friends of some customer where &lt;em&gt;isSomebodyWeKnow&lt;/em&gt; is true.  The #-sign is a shorthand for "count". So, we can see that &lt;em&gt;isTrusted&lt;/em&gt; will evaluate to true if the customer is somebody we know or if they have at least 2 friends we know.&lt;br /&gt;&lt;br /&gt;When next we meet, we'll delve into the notion of query expressions more fully. In the meantime, beware of North Koreans toting pirated UML editors....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-5110872622589230947?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/5110872622589230947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=5110872622589230947' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5110872622589230947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5110872622589230947'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2008/12/axis-of-e-ville.html' title='The Axis of e-Ville'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hNEirhCE9Kw/STWeMY3rjmI/AAAAAAAAACA/GUQUU0T9ch8/s72-c/figure4.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-4774651076829551791</id><published>2008-12-01T19:35:00.000-07:00</published><updated>2008-12-01T19:45:29.697-07:00</updated><title type='text'>Conditional Love</title><content type='html'>Let's consider some other amusing things we can do with class diagrams. With a little tape, some string, and a pair of scissors, we can of course convert most class diagrams into a ceremonial tribal mask or a pirate hat. Another fun thing we can do is derive attribute values using conditional expressions.&lt;br /&gt;&lt;br /&gt;Let's return to our example of the Arms4Less online superstore. We're having lunch with our SME, Sarge, and he's just finished telling us a funny story about a coup he helped stage a few years back. "So Johnny turns to me and says, whadaya mean, where's the king? Who do we got tied up in the back of your car?" We laugh appreciatively, and then turn the conversation back to the requirements for the store. Sarge explains how they want to offer various sales incentives, "like 20% off for quantities over 50". We can easily modify our model to reflect this  requirement, by adding a new derived attribute called &lt;em&gt;discount&lt;/em&gt; to &lt;strong&gt;OrderItem&lt;/strong&gt;, and then modifying the derivation expression on &lt;em&gt;total&lt;/em&gt; to reflect any discounting to be applied. We must also add the necessary non-derived attributes, &lt;em&gt;discountQty&lt;/em&gt; and &lt;em&gt;discount,&lt;/em&gt; to the &lt;strong&gt;Product&lt;/strong&gt;, as shown.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hNEirhCE9Kw/STSg1qWaQUI/AAAAAAAAAB4/Tp9wQt4kJM8/s1600-h/figure3.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 358px;" src="http://3.bp.blogspot.com/_hNEirhCE9Kw/STSg1qWaQUI/AAAAAAAAAB4/Tp9wQt4kJM8/s400/figure3.jpg" alt="" id="BLOGGER_PHOTO_ID_5275017907319488834" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Hopefully, you are beginning to see how much more you could be getting out of your class diagrams if you would just spend a little more time drawing pictures and a little less time writing code. I know how that can be tough with all the pressure you're getting from religious eXtremists, but as we shall soon see, Precision Requirements Modeling fits very nicely into an Agile approach that even the religious right can love.&lt;br /&gt;&lt;br /&gt;In our next installment we'll really get this party started when we consider how to derive values from query expressions. I know the anticipation will be killing you between now and then, and I'd love to show you right now, but I gotta go write some code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-4774651076829551791?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/4774651076829551791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=4774651076829551791' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4774651076829551791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/4774651076829551791'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2008/12/conditional-love.html' title='Conditional Love'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_hNEirhCE9Kw/STSg1qWaQUI/AAAAAAAAAB4/Tp9wQt4kJM8/s72-c/figure3.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-6503882253515032684</id><published>2008-11-18T20:24:00.000-07:00</published><updated>2008-11-18T20:41:04.342-07:00</updated><title type='text'>Let's not get physical</title><content type='html'>In my last post, I promised to reveal how class diagrams can be your secret weapon in the war against imprecise requirements. How can this be, you wonder? Sure, class diagrams capture entities, attributes, and associations, but they're completely incapable of expressing the hopes, fears, aspirations and unwarranted hostility of my end users. Surely we need all the subtlety and nuance of natural language to fully capture the essence of what we're being required to build? Surely we need to capture requirements using the flowing prose of use cases?&lt;br /&gt;&lt;br /&gt;As we've &lt;a href="http://stu-stern.blogspot.com/2008/11/just-what-we-need-more-lawyers.html"&gt;discussed&lt;/a&gt;, precision is certainly something to be aspired to in requirements specifications, and yet, the legal profession provides compelling testimony to the horrible things that happen to beautiful prose when we impose precision upon it. Let's begin to consider some other things we can express clearly, unambiguously, and some might say beautifully, via everybody's favorite UML diagram.&lt;br /&gt;&lt;br /&gt;Suppose we've been asked to build an online storefront offering stolen military hardware at low-low prices. The company, Arms4Less, was founded by several retired mercenaries now holed up somewhere in Honduras. Our primary contact is this crusty old guy we know only as "Sarge". The first thing he says the system needs to do is "store orders for stuff."&lt;br /&gt;&lt;br /&gt;"You know", he says, "we sell stuff. Hand grenades, bazookas, napalm cannisters, that kinda thing. We'll need the usual shopping cart deal, letting customers tell us how much of each product they want." We sketch out the diagram below.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hNEirhCE9Kw/SSOJqiec4NI/AAAAAAAAABg/ArhzgoWzcM0/s1600-h/figure1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 134px; height: 343px;" src="http://4.bp.blogspot.com/_hNEirhCE9Kw/SSOJqiec4NI/AAAAAAAAABg/ArhzgoWzcM0/s400/figure1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5270207352855650514" /&gt;&lt;/a&gt;As you would expect, an &lt;strong&gt;Order&lt;/strong&gt; consists of 1 or more (1..*) &lt;em&gt;items,&lt;/em&gt; and each &lt;strong&gt;OrderItem&lt;/strong&gt; specifies the &lt;em&gt;quantity&lt;/em&gt; of some &lt;em&gt;product&lt;/em&gt; being ordered. Each &lt;strong&gt;Product&lt;/strong&gt; has a &lt;em&gt;price&lt;/em&gt;. Now, hopefully you're regarding this model and saying, "Yeah? So? Why am I wasting time reading this stupid guy's blog when I could be learning Spring?" In a moment we'll make this model a lot more interesting. The diamond, by the way, signifies a "composite" relationship between an &lt;strong&gt;Order&lt;/strong&gt; and its &lt;em&gt;items&lt;/em&gt;, which essentially means that if we delete an Order, all of its items will get deleted too. (You would of course know what the diamond means if you'd been paying attention instead of doing email in that UML course your boss sent you to.)  If the other symbols being used here are mysterious to you, go hang out with &lt;a href="http://www.agilemodeling.com/artifacts/classDiagram.htm"&gt;Ambler&lt;/a&gt; and come back when you're done.&lt;br /&gt;&lt;br /&gt;A tremendously useful, but largely underused (Ambler's overview doesn't even mention them), facility of class diagrams is the specification of "derived" attributes. Derived attribute values are - uh - derived. That is, their values don't need to be stored since they can be completely determined from other data values. For example, Sarge explains that we need to total up each order and make the customer's got enough dough to cover it. "We do this for the customer's own protection", Sarge explains. "You don't wanna know what's gotta happen if the guy can't pay us." And indeed, we really don't wanna know until a later iteration.  So, we add 2 derived attributes to the model to deal with the order total.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hNEirhCE9Kw/SSOKQnRP-_I/AAAAAAAAABo/1yeD3iXJZic/s1600-h/figure2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 202px; height: 343px;" src="http://3.bp.blogspot.com/_hNEirhCE9Kw/SSOKQnRP-_I/AAAAAAAAABo/1yeD3iXJZic/s400/figure2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5270208006977485810" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We've added a &lt;em&gt;total&lt;/em&gt; attribute to both the &lt;strong&gt;Order&lt;/strong&gt; and the &lt;strong&gt;OrderItem&lt;/strong&gt; entities. Note that each has a leading slash, which means "derived" in UML. The &lt;strong&gt;OrderLine&lt;/strong&gt; total is, not surprisingly, derived by multiplying the &lt;em&gt;quantity&lt;/em&gt; by the &lt;em&gt;price&lt;/em&gt; of the associated &lt;em&gt;product&lt;/em&gt; (quantity*product.price). The &lt;strong&gt;Order&lt;/strong&gt; &lt;em&gt;total&lt;/em&gt; is the sum of the &lt;em&gt;total&lt;/em&gt;s of its &lt;em&gt;items&lt;/em&gt; (sum(items.total)). We mentioned earlier that derived attributes don't need to be stored, and indeed you can see how we can simply calculate these attributes' values on the fly. Certainly, however, there are situations in which we store derived attributes if, for example, they're too expensive to calculate dynamically. Such a decision however is purely an implementation choice. Logically, these attributes are derived.† This is all about what the system must do, not how it will do it. So let's keep our functional requirements logical. As Sarge might say, "You don't wanna get physical with me unless you're good and ready, computer boy."&lt;br /&gt;&lt;br /&gt;Now, you're probably still a little underwhelmed by all this. But as we'll see in our next episode, we've only just scratched the surface of the expressive power of the friendly, little class diagram.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-6503882253515032684?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/6503882253515032684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=6503882253515032684' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6503882253515032684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6503882253515032684'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2008/11/lets-not-get-physical.html' title='Let&apos;s not get physical'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hNEirhCE9Kw/SSOJqiec4NI/AAAAAAAAABg/ArhzgoWzcM0/s72-c/figure1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-2422398266543851484</id><published>2008-11-17T10:52:00.000-07:00</published><updated>2008-11-17T10:56:30.356-07:00</updated><title type='text'>Real programmers don't eat diagrams</title><content type='html'>Yesterday I discussed how we developers routinely deal with imprecise requirements and while most of us find this to be annoying from time to time, overall we don't consider this a Big Problem. Or perhaps many of us do recognize this as a Big Problem, but have resigned ourselves to its seeming intractability. In any event, we can all agree that if it were possible for us to unambiguously "encode" requirements precisely, and could do this economically, it would surely be better than the current, preferred practice of getting a "pretty good idea" of what some business guy needs, code it up, and then sit down with the guy to see what we got wrong,  and come away with a "pretty gooder idea" than we had previously. And then repeating this process over and over again until we get it right or until it's time to go live.&lt;br /&gt;&lt;br /&gt;Most development projects begin with a fuzzy expression of requirements as articulated via some combination of text, pictures, and threatening emails by some end users, and end with a concrete expression of requirements as expressed in code and entreaties for forgiveness by programmers. As we discussed, there is currently no widely recognized middle ground between the fuzziness of warm, friendly natural language-based requirements specs, and  cold, hard code. As a result, developers are left to interpret the fuzzy as their first step toward implementing a solution. Precision Requirements Modeling (PRM) is a set of techniques for transforming fuzzy requirements into a "code-ready" requirements specification. PRM allows requirements to be expressed with the precision of code, without getting bogged down in requirements details. Perhaps most tantalizingly, PRM specifications are themselves executable, which means we can let end users test drive a specification prior to developers becoming lost within the dense tangle of the implementation jungle, where they become increasingly isolated from civilization as they fashion primitive tools and frameworks, and engage in pitched warfare with competing tribes using .NET.&lt;br /&gt;&lt;br /&gt;PRM begins with good-old-fashioned domain modeling. Virtually all O-O developers engage in some level of domain modeling whether they realize it or not. Every time you specify a class that represents a business concept, you're engaging in domain modeling. Even the staunchest of anti-modeling activists can often be caught in moments of weakness drawing UML-ish boxes and lines on a whiteboard. Anybody who has worked on anything but the most trivial of applications has come to recognize the usefulness of UML class diagrams or, at a minimum, entity relationship diagrams as a way of allowing members of a team to get a shared understanding of the major abstractions or data representations being used and how they relate to one another. Of course, you can always just fire up a debugger and trace through your buddy's code, but most of us would prefer a less - uh - extreme approach to integrating the disparate pieces of an implementation.&lt;br /&gt;&lt;br /&gt;Class diagrams and ERDs are some of the best ways of communicating among a team an application's entities, their attributes, and their relationships to each other. In terms of attributes, most developers specify no more than names and types of what will be persisted. But as we shall soon see, class diagrams have the potential of communicating so much more if we would just let them. How well do you really know class diagrams? Sure you draw them occasionally. Sometimes you may even bring them to lunch with your colleagues. But if you would just get to really know them, you would see that they're among your best friends.&lt;br /&gt;&lt;br /&gt;In our next installment, we'll get better acquainted with some class diagrams and see how, with some minor extensions, they can be used to unambiguously specify large portions of any requirements specification, and bridge the gap between warm, fuzzy business people and cold, hard programmers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-2422398266543851484?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/2422398266543851484/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=2422398266543851484' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/2422398266543851484'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/2422398266543851484'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2008/11/real-programmers-dont-eat-diagrams.html' title='Real programmers don&apos;t eat diagrams'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-5605528517904013760</id><published>2008-11-16T15:00:00.000-07:00</published><updated>2008-11-16T15:05:57.731-07:00</updated><title type='text'>Just what we need -- more lawyers</title><content type='html'>One of the things you gotta love about "agile" is the name. Is it ever bad to be "agile"? Is there a good alternative (other than synonyms) for "agility"? Here at Gorilla Logic, we've devised what we modestly consider a breakthrough approach to requirements definition. "Precision Requirements Modeling" is the best our marketing department has been able to come up with as the moniker for this new approach. Although mind-numbingly accurate in its characterization, the name lacks a certain zing. Perhaps "Naked Precision Requirements Modeling" would be better.&lt;br /&gt;&lt;br /&gt;While all developers want to be rich, thin, agile, and left alone, the same cannot be said of their wanting to be "precise". This is a curious thing when you consider that programming of course is nothing if not "precise". Code specifies precisely what the system will do. For the time being at least, computers don't have the ability to ponder a set of instructions and decide how best to carry them out. Programming code is literal, bereft of simile, metaphor, and clever double entendres. Functional requirements on the other hand are captured as natural language either because they're being written by non-programmers, or because they need to be reviewed and approved by non-programmers. Natural language tends to be pretty imprecise. (That's why we need programming languages.) Our industry has thus become accustomed to routinely working with imprecise requirements specifications.&lt;br /&gt;&lt;br /&gt;Now some will argue that natural language can be quite precise. Aren't legal contracts shining examples of precise, natural language? Perhaps the world needs more lawyers. On the other hand, legal contracts tend to be fairly unintelligible to non-lawyers, and although I can't prove this, I will assert that most lawyers would make crummy programmers. Since non-lawyers are going to be writing the code, we probably need something other than legalese to communicate requirements.&lt;br /&gt;&lt;br /&gt;Some will say, "aha"! This is precisely why striving for precision in requirements is a waste of time. "Those wacky business people can't possibly know if they want something or not until they see it running on their own desktops anyway". To a large extent this is of course true, but the number of cycles required to get things accepted by an end user will surely be reduced in direct proportion to how well we can understand the requirements prior to writing each round of code. Many theologians will say that although better requirements will reduce the cycles, they don't necessarily reduce the overall effort, since we're just substituting time spent requirements writing for time spent coding (and wouldn't you rather be writing code right now?). In fact, given what we've discussed about the imprecise nature of natural language, aren't we just better off capturing the requirements as code rather than trying to turn a requirements specification into a legal contract?&lt;br /&gt;&lt;br /&gt;Perhaps. But this argument ignores the fact that when we code, we deal with far more than functional requirements. As much as 80% of code can be concerned with implementation details as opposed to business logic. (Actually, I just totally made up this statistic, but if you write code, I'm sure you'll agree that a very large proportion of code is solely concerned with plumbing).  So the problem is that when we run off and code up a set of loosely defined requirements, we spend a whole lot of time dealing with implementation details that along with the business logic will need to be redone if our interpretation of those requirements is somehow incorrect.&lt;br /&gt;&lt;br /&gt;Ah, but isn't this what "refactoring" is all about? The answer to that question is "no". Refactoring is about cleaning up an implementation. It's about avoiding over-engineering by just writing the damn code, and then restructuring that code when it becomes unwieldy, rather than building elaborate frameworks before we truly understand what our implementation requires. "Requirements refactoring" is a euphemism for getting things wrong. When we need to "refactor code" to reflect a requirements "clarification", we are simply rewriting code that was written to do something nobody actually wanted.&lt;br /&gt;&lt;br /&gt;If there were only some way to "code" requirements without having to deal with implementation details. Then, we could indeed use code as our medium for capturing precise requirements, without wasting a lot of time on unneeded implementation should those requirements prove inaccurate. Hmmm, if only there were some way to capture requirements as code without implementation details.... Oh, that's right. There is a way. And coincidentally, it's what we've been working on for the last six years here at GL.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-5605528517904013760?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/5605528517904013760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=5605528517904013760' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5605528517904013760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/5605528517904013760'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2008/11/just-what-we-need-more-lawyers.html' title='Just what we need -- more lawyers'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-6009529878531971516</id><published>2008-11-06T20:42:00.000-07:00</published><updated>2008-11-06T20:45:58.922-07:00</updated><title type='text'>Searching for love in all the wrong use cases</title><content type='html'>Having &lt;a href="/2008/11/too-much-religion.html"&gt;established&lt;/a&gt; (ie, forcefully asserted) that it is generally Bad to engage in ritualistic development practices, but Good to adhere to a particular practice when it's well-suited to surmounting some challenge, let's consider the first snarling beast that leaps out to menace most young, impressionable development projects before they've even secured funding -- requirements definition.&lt;br /&gt;&lt;br /&gt;Functional requirements are strange and mysterious things. Many programmers have never actually seen any, relying instead on rumor, innuendo or hearsay to guide their development objectives. For many, functional requirements are the only things keeping programming from being their dream vocation. Programming after all is, at its best, a beautifully artistic endeavor wherein we devise clever structures to manage the complexity of some problem, and transform chaos into order. Implementation "elegance" is regarded as  one of the highest achievements we can attain as developers. As each new project begins, we think wistfully of the various forms of abstraction and all the intricate frameworks we have mastered over the years, and consider how, armed with the depth of our experience, this project will surely be different from our past ones. This time we'll build the thing Right, methodically assembling a great edifice from a series of simple building blocks. Each will be as cohesive as the nucleus of an atom, but as loosely coupled from one another as the grains of sand along the seashore. You kick off your shoes, and wander along the beach, smelling the salt air and thinking about that time under the boardwalk -- then, suddenly, a subject matter expert comes marching down the beach with several unruly business owners in tow, and all hell breaks loose.&lt;br /&gt;&lt;br /&gt;Real-world requirements are seldom elegant. On the contrary, they tend to be maddeningly messy. For many applications, the hand-waving of some business stakeholder-guy can be sufficient for reaching an understanding of what needs to be built. But, alas, the majority of applications we build are far more "interesting" than these. Confronted by the terrifying unknown of some obscure workflow that has evolved over millions of years and countless mergers and acquisitions, many developers immediately fall back on their religious texts for guidance and comfort against the onrushing horror. They begin frantically writing user stories, drawing anatomically inaccurate stick figures, and in the dark of the night wondering why the gods of order and logic have forsaken them despite their best attempts to follow the good and righteous path documented and indexed in their most venerated religous text (second edition, totally updated with a new preface by the author).&lt;br /&gt;&lt;br /&gt;Why must it be so? Why do business requirements, which on the surface seem so simple compared to the complexity of the software platforms we, as accomplished software developers, whip into submission almost every day, so often defy our best efforts to wrestle them to the ground though we pelt them with CRC cards and lock them in use cases? Is there no way to reduce the arbitrary tangle of business rules to some elegant expression of the problem that can return us to our idyllic afternoon at the seaside?&lt;br /&gt;&lt;br /&gt;Grab a towel and some sunscreen and allow me to introduce you to Precision Requirements Modeling.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-6009529878531971516?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/6009529878531971516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=6009529878531971516' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6009529878531971516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/6009529878531971516'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2008/11/searching-for-love-in-all-wrong-use.html' title='Searching for love in all the wrong use cases'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4892696525791628275.post-7298595447000236066</id><published>2008-11-04T16:44:00.000-07:00</published><updated>2008-11-06T20:15:35.775-07:00</updated><title type='text'>Too Much Religion</title><content type='html'>Programmers are a religious sort, unquestioningly engaging in ritualistic practices pronounced as "good" by the industry's high priests, and likewise shunning those practices branded as blasphemous. Everyone knows for example that mixing business logic with user interface code will damn your soul to Hell for all of eternity. Likewise, engaging in waterfall development leads to nowhere but poverty and pestilence.  And each time you use dependency injection, an angel gets his wings.&lt;br /&gt;&lt;br /&gt;The religious tenets of our industry of course have mostly arisen from hard-learned lessons about what seems to generally work and what seems generally not to. Still, it is clearly the case that there is no single path to project nirvana. Every development initiative grapples with a unique variety of technical, political, and sociological challenges. Some projects even succeed. It is of course natural that people examine the practices used by the really successful ones, and strive to emulate them to maximize their own chances for salvation.&lt;br /&gt;&lt;br /&gt;Successful software development, alas, cannot be achieved by blindly following the prescriptions laid down in some sacred textbook or blog posting. The sacred texts do indeed provide valuable techniques discovered only after the spilling of vast amounts of blood by our ancestors who came down out of their mainframes to spread out across the network, converting green screens to rich clients, and procedures to objects. So, let us embrace the tools and techniques, but let us also recognize that the reason software projects fail is that there is no "Way" that one can simply follow to guarantee success.&lt;br /&gt;&lt;br /&gt;Software development projects present us with a series of challenges. Each of those challenges can generally be addressed with some established set of tools and techniques. When we complete a successful project we are typically tempted to look back on the steps we took along the way and announce to our colleagues, "Ah, yes, truly we have found The Way. Let The Way be written down so that it be made repeatably so, and we can look forward to nothing but happy days for ourselves, our managers, and our manager's managers." And yet we then see others try to follow The Way, only to find misery, chaos, and even death. Okay, maybe not death.&lt;br /&gt;&lt;br /&gt;So are we condemned then to roll the dice each time we undertake a new development initiative? I don't think so. But the solution is not religion. The solution is in learning a few highly useful techniques, but rather than applying them ritualistically, we should instead learn to assess the particular challenges presented at a particular juncture of a particular project, and to select among and adapt the various techniques to the challenge at hand.&lt;br /&gt;&lt;br /&gt;The Way does not exist. This is The Only Way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4892696525791628275-7298595447000236066?l=stu-stern.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stu-stern.blogspot.com/feeds/7298595447000236066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4892696525791628275&amp;postID=7298595447000236066' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7298595447000236066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4892696525791628275/posts/default/7298595447000236066'/><link rel='alternate' type='text/html' href='http://stu-stern.blogspot.com/2008/11/too-much-religion.html' title='Too Much Religion'/><author><name>Stu Stern</name><uri>http://www.blogger.com/profile/06705405325556429179</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/_hNEirhCE9Kw/TH64jXWkvAI/AAAAAAAAAKg/o09JLKUy0kQ/S220/stu+head+shot.jpg'/></author><thr:total>0</thr:total></entry></feed>
