<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0" xml:base="http://www.esjewett.com">
<channel>
 <title>esjewett.com</title>
 <link>http://www.esjewett.com</link>
 <description />
 <language>en</language>
<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://www.esjewett.com/rss.xml" type="application/rss+xml" /><feedburner:emailServiceId>esjewett</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Fwww.esjewett.com%2Frss.xml" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Fwww.esjewett.com%2Frss.xml" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Fwww.esjewett.com%2Frss.xml" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://www.esjewett.com/rss.xml" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Fwww.esjewett.com%2Frss.xml" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Fwww.esjewett.com%2Frss.xml" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Fwww.esjewett.com%2Frss.xml" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
 <title>Introducing jsglue</title>
 <link>http://feedproxy.google.com/~r/esjewett/~3/LYr5cl___0Q/introducing-jsglue</link>
 <description>&lt;p&gt;Last weekend I pushed out the very first version of something I'm calling jsglue to Github. It now lives here: &lt;a title="http://github.com/esjewett/jsglue/tree/master" href="http://github.com/esjewett/jsglue/tree/master"&gt;http://github.com/esjewett/jsglue/tree/master&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;jsglue is in essence a framework for implementing web-connective applications a la Yahoo! Pipes and Tarpipe. Currently it is at best a compliment to those programs and at worst totally useless. In the future I would like to see it or something like it become an alternative to these tools, for a few reasons that I'll eventually get into in later posts.&lt;/p&gt;
&lt;p&gt;jsglue does three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It allows you to register a handler to a path.
&lt;ul&gt;
&lt;li&gt;The handler consists of a path and two pieces of javascript - one that constructs a response to a request sent to that path, and one that constructs one request (and in the future multiple requests, optionally) to another URL.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It accepts HTTP requests to paths with registered handlers.
&lt;ul&gt;
&lt;li&gt;When this happens, it creates a response using the handler javascript for this purpose, and it adds a job to a stack that will be processed later.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It provides a program that can be run periodically to process the stack of jobs that has built up, sending off new requests as specified by the javascript in the handler associated with each job.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That's it.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Why do I care?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Well, hopefully that will become clear of its own accord. But the key is that the full contents of the original request are exposed to the javascript processing script that constructs the new request. As such, you can do pretty much any kind of processing you like within this handler code, which is user-defined.&lt;/p&gt;
&lt;p&gt;So why do you care? Let me count the ways:&lt;/p&gt;
&lt;p&gt;1. Receive a request in JSON and spit it back out multi-part form-encoded (in fact, right now this is pretty much the only thing you can do). Ever tried to connect up Yahoo! Pipes with Tarpipe? It doesn't work. With this, it can.&lt;/p&gt;
&lt;p&gt;2. &lt;a title="Webhooks" href="http://timothyfitz.wordpress.com/2009/02/09/what-webhooks-are-and-why-you-should-care/"&gt;Webhooks&lt;/a&gt; are great. Webhooks are the facility to have a web application issue an HTTP request to an arbitrary URL when some event happens in the web application. That sounds boring, but it's actually awesome. Webhooks are great, except that no one speaks the same language so every webhook-based solution is bespoke. Bespoke is great in a suit or a coffee mug, but it's bad in web infrastructure. Yahoo! Pipes can't understand webhook calls. Tarpipe usually can't understand them. Most other web applications can't understand them. There needs to be some sort of middle-person.&lt;/p&gt;
&lt;p&gt;3. If I'm going to run a ton of my personal data through some middleman web application, you should have the option of running that web application yourself. I'm not saying you will, but I think it would be nice if you could.&lt;/p&gt;
&lt;p&gt;Okay, 3 ways is enough for now. We'll get to more later.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Why do you *not* care?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Well, there are lots of reasons for that too.&lt;/p&gt;
&lt;p&gt;1. This is dorky. No, there is not a UI. No, it doesn't do much of interest. It's an infrastructure prototype more than anything else. The idea is really that we need infrastructure for building applications that can do this sort of thing. I don't have a lot of time to spare, so I'm willing to just put a framework out there, and maybe a REST-only web-application if I can get the components running on a hosting service (harder than it sounds). I'll leave it to someone else to put the UI on top of it. I'm not convinced that the "pipe" metaphor is correct (I'm partial to "tubes" myself), but I don't have a better idea, so someone else will have to have that idea.&lt;/p&gt;
&lt;p&gt;2. This code sucks. Yes it does. I urge you to fork it, improve it, or throw up your hands in disgust and start over. I just want something that does this. I don't really care if it's written by me.&lt;/p&gt;
&lt;p&gt;3. There's no way this execution model will fly on a public site, and no one is going to run this on their own server. This is sort a feature of this design that allows your users to execute arbitrary javascript on your server. As such, I think this will primarily find use on private servers, or as a back-end engine for a public site where the inputs are carefully cleansed. Not a recipe for ultra-popularity, I'll grant. But that's not really the point either.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;So what's it made out of?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Currently, there are only four main ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title="Ruby" href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt; is the implementation language. It's role in jsglue is to serve as duct-tape for the other components.
&lt;/li&gt;
&lt;li&gt;&lt;a title="Datamapper" href="http://datamapper.org/"&gt;Datamapper&lt;/a&gt; is the database interface, allowing you to use pretty much any supported database (I'm using SQLite at the moment).
&lt;/li&gt;
&lt;li&gt;&lt;a title="Sinatra" href="http://www.sinatrarb.com/"&gt;Sinatra&lt;/a&gt; for the HTTP web-service interfaces. These interfaces are pretty much a direct mapping onto the database. (REST-ful? Maybe.) (Incidentally, how is it that a minuscule Ruby web-framework beats out FRANK SINATRA in the Google rankings?)
&lt;/li&gt;
&lt;li&gt;&lt;a title="Johnson" href="http://github.com/jbarnette/johnson/tree/master"&gt;Johnson&lt;/a&gt; for the Javascript processing.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That's it. It's a couple hundred lines of code. I haven't really counted, or put it on Ohloh.com for that matter, but it can't be more than that. It's got some unit tests. It's going to be changing quickly as I make it more multi-purpose.&lt;/p&gt;
&lt;p&gt;I'll document and post examples as they become available.&lt;/p&gt;

&lt;!--
&lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"&gt;
&lt;rdf:Description rdf:about="http://www.esjewett.com/blog/introducing-jsglue" dc:identifier="http://www.esjewett.com/blog/introducing-jsglue" dc:title="Introducing jsglue" trackback:ping="http://www.esjewett.com/trackback/41" /&gt;
&lt;/rdf:RDF&gt;
--&gt;
&lt;div id="trackback-url"&gt;&lt;div class="box"&gt;

  &lt;h2&gt;Trackback URL for this post:&lt;/h2&gt;

  &lt;div class="content"&gt;http://www.esjewett.com/trackback/41&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=LYr5cl___0Q:lQv34DRXxFs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=LYr5cl___0Q:lQv34DRXxFs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=LYr5cl___0Q:lQv34DRXxFs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=LYr5cl___0Q:lQv34DRXxFs:SSaB9coO5pA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=LYr5cl___0Q:lQv34DRXxFs:SSaB9coO5pA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/esjewett/~4/LYr5cl___0Q" height="1" width="1"/&gt;</description>
 <category domain="http://www.esjewett.com/tag/javascript">javascript</category>
 <category domain="http://www.esjewett.com/tag/johnson">johnson</category>
 <category domain="http://www.esjewett.com/tag/jsglue">jsglue</category>
 <category domain="http://www.esjewett.com/tag/pipes">pipes</category>
 <category domain="http://www.esjewett.com/tag/ruby">ruby</category>
 <category domain="http://www.esjewett.com/tag/sinatra">sinatra</category>
 <category domain="http://www.esjewett.com/tag/tarpipe">tarpipe</category>
 <pubDate>Wed, 06 May 2009 23:03:01 +0000</pubDate>
 <dc:creator>esjewett</dc:creator>
 <guid isPermaLink="false">41 at http://www.esjewett.com</guid>
<feedburner:origLink>http://www.esjewett.com/blog/introducing-jsglue</feedburner:origLink></item>
<item>
 <title>A tour of testing with an SAP focus (in the end)</title>
 <link>http://feedproxy.google.com/~r/esjewett/~3/GuNMY0dU6AQ/a-tour-of-testing-with-an-sap-focus-in-the-end</link>
 <description>&lt;p&gt;As might have been assumed from the my post on &lt;a href="http://www.esjewett.com/blog/automated-testing-in-sap-systems"&gt;automated testing in SAP systems&lt;/a&gt; a couple months ago, I've been delving into testing in the SAP landscape. I'm beginning to put together a series of presentations and workshops on the subject, the first of which I was delighted to deliver last week.&lt;/p&gt;
&lt;p&gt;Being the first in the series, this presentation focuses on an overview of the leading edge of the field. It would be nice to be able to emulate the sort of testing techniques we can use in Ruby in SAP BI and EPM application development. Nice, but not necessarily realistic. I can dream!&lt;/p&gt;
&lt;div style="width:425px;text-align:left" id="__ss_1352251"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/esjewett/testing-sap-modern-methodology?type=powerpoint" title="Testing Sap: Modern Methodology"&gt;Testing Sap: Modern Methodology&lt;/a&gt;
&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=testingsap-modernmethodology-forpublicdistribution-090427112037-phpapp01&amp;rel=0&amp;stripped_title=testing-sap-modern-methodology" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=testingsap-modernmethodology-forpublicdistribution-090427112037-phpapp01&amp;rel=0&amp;stripped_title=testing-sap-modern-methodology" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/esjewett"&gt;Ethan Jewett&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;

&lt;!--
&lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"&gt;
&lt;rdf:Description rdf:about="http://www.esjewett.com/blog/a-tour-of-testing-with-an-sap-focus-in-the-end" dc:identifier="http://www.esjewett.com/blog/a-tour-of-testing-with-an-sap-focus-in-the-end" dc:title="A tour of testing with an SAP focus (in the end)" trackback:ping="http://www.esjewett.com/trackback/40" /&gt;
&lt;/rdf:RDF&gt;
--&gt;
&lt;div id="trackback-url"&gt;&lt;div class="box"&gt;

  &lt;h2&gt;Trackback URL for this post:&lt;/h2&gt;

  &lt;div class="content"&gt;http://www.esjewett.com/trackback/40&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=GuNMY0dU6AQ:HoaoVVEWIVA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=GuNMY0dU6AQ:HoaoVVEWIVA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=GuNMY0dU6AQ:HoaoVVEWIVA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=GuNMY0dU6AQ:HoaoVVEWIVA:SSaB9coO5pA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=GuNMY0dU6AQ:HoaoVVEWIVA:SSaB9coO5pA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/esjewett/~4/GuNMY0dU6AQ" height="1" width="1"/&gt;</description>
 <category domain="http://www.esjewett.com/tag/agile">agile</category>
 <category domain="http://www.esjewett.com/tag/bdd">bdd</category>
 <category domain="http://www.esjewett.com/tag/cucumber">cucumber</category>
 <category domain="http://www.esjewett.com/tag/enterprise">enterprise</category>
 <category domain="http://www.esjewett.com/tag/open">open</category>
 <category domain="http://www.esjewett.com/tag/rspec">rspec</category>
 <category domain="http://www.esjewett.com/tag/ruby">ruby</category>
 <category domain="http://www.esjewett.com/tag/sap">sap</category>
 <category domain="http://www.esjewett.com/tag/tdd">tdd</category>
 <category domain="http://www.esjewett.com/tag/testing">testing</category>
 <pubDate>Tue, 28 Apr 2009 02:43:16 +0000</pubDate>
 <dc:creator>esjewett</dc:creator>
 <guid isPermaLink="false">40 at http://www.esjewett.com</guid>
<feedburner:origLink>http://www.esjewett.com/blog/a-tour-of-testing-with-an-sap-focus-in-the-end</feedburner:origLink></item>
<item>
 <title>How to get Johnson built</title>
 <link>http://feedproxy.google.com/~r/esjewett/~3/x14ajT3JrGo/how-to-get-johnson-built</link>
 <description>&lt;p&gt;&lt;a href="http://github.com/jbarnette/johnson/tree/master"&gt;Johnson&lt;/a&gt; is a Ruby wrapper of the SpiderMonkey JavaScript interpreter. In practice, this means you can use Johnson to evaluate JavaScript statements within a Ruby program.&lt;/p&gt;
&lt;p&gt;It works really nicely, but there is no released gem and building the development gem is a bit of a headache.  The instructions in the readme at the Johnson Github site appear simple but have several prerequisites that must be fulfilled before the whole process works.  Here's what I did on Leopard.  I'll try recreating on Windows tomorrow.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;
[sudo] gem sources -a &lt;a href="http://gems.github.com" title="http://gems.github.com"&gt;http://gems.github.com&lt;/a&gt;&lt;br /&gt;
[sudo] gem install jbarnette-johnson
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Multiple errors occur - if you see gems missing (like hoe, for example) then install them.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;
[sudo] gem install jbarnette-johnson
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Errors occur, probably due to a failure to compile the native gem.  Usually something about a missing rake/extensiontask.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;
[sudo] gem install rake-compiler&lt;br /&gt;
[sudo] gem install jbarnette-johnson
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Yet another error occurs - a missing Manifest.txt file.  Download from Github at &lt;a href="http://github.com/jbarnette/johnson/tree/master"&gt;http://github.com/jbarnette/johnson/tree/master&lt;/a&gt; and put it into the directory in the error message.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;
[sudo] gem install jbarnette-johnson
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;p&gt;[Apr. 4, 2009 - Fixed typo, changing "rake-compile" to "rake-compiler"]&lt;/p&gt;

&lt;!--
&lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"&gt;
&lt;rdf:Description rdf:about="http://www.esjewett.com/blog/how-to-get-johnson-built" dc:identifier="http://www.esjewett.com/blog/how-to-get-johnson-built" dc:title="How to get Johnson built" trackback:ping="http://www.esjewett.com/trackback/39" /&gt;
&lt;/rdf:RDF&gt;
--&gt;
&lt;div id="trackback-url"&gt;&lt;div class="box"&gt;

  &lt;h2&gt;Trackback URL for this post:&lt;/h2&gt;

  &lt;div class="content"&gt;http://www.esjewett.com/trackback/39&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=x14ajT3JrGo:CSaiZOKVmZ8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=x14ajT3JrGo:CSaiZOKVmZ8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=x14ajT3JrGo:CSaiZOKVmZ8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=x14ajT3JrGo:CSaiZOKVmZ8:SSaB9coO5pA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=x14ajT3JrGo:CSaiZOKVmZ8:SSaB9coO5pA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/esjewett/~4/x14ajT3JrGo" height="1" width="1"/&gt;</description>
 <category domain="http://www.esjewett.com/tag/javascript">javascript</category>
 <category domain="http://www.esjewett.com/tag/johnson">johnson</category>
 <category domain="http://www.esjewett.com/tag/ruby">ruby</category>
 <pubDate>Fri, 03 Apr 2009 02:38:05 +0000</pubDate>
 <dc:creator>esjewett</dc:creator>
 <guid isPermaLink="false">39 at http://www.esjewett.com</guid>
<feedburner:origLink>http://www.esjewett.com/blog/how-to-get-johnson-built</feedburner:origLink></item>
<item>
 <title>OAuth Q&amp;A Part 2</title>
 <link>http://feedproxy.google.com/~r/esjewett/~3/1N1rX2k-5wU/oauth-qa-part-2</link>
 <description>&lt;p&gt;This the continuation of my ongoing OAuth Q&amp;amp;A, now with fewer links and more editorial commentary. See &lt;a title="Part 1" href="http://www.esjewett.com/blog/oauth-qa-part-1"&gt;Part 1&lt;/a&gt;  as well.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;If I have access to an authorized token and the consumer key and secret, I can make "authorized" API requests galore. So OAuth is no more secure than the username/password pattern.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;That's not a question. Way to start off part 2 with a big fail!&lt;/p&gt;
&lt;p&gt;[Ed. - Ahem . . . You're asking the questions as well as answering them.]&lt;/p&gt;
&lt;p&gt;[Me - I deny that. But okay, let's try again at a real answer.]&lt;/p&gt;
&lt;p&gt;This is only partly correct.&lt;/p&gt;
&lt;p&gt;First, OAuth provides the a pattern for providers to scope access much more granularly than when a single username/password pair gives total access to an app. For example, most OAuth providers do not allow access to administrative functions when authorizing with an OAuth token, so a rogue client cannot change a user's password. Because of this, the user's access to the app can be guaranteed and damage can be limited to the scope of access granted to the client.&lt;/p&gt;
&lt;p&gt;Second, because the user's access can be guaranteed and because client access can be managed at the level of the token, authorization for a given token can be revoked in a self-service manner. The scenario here is that a user grants access to a malicious app that vandalizes the account. The user realizes this, logs in to the provider, revokes the consumer's access, and repairs (hopefully) the damage. Because the malicious consumer cannot change the password on the account, the provider does not have to become involved in the initial response to the vandalism. Follow-on activities that the provider may need to become involved in (like account restoration or consumer key revocation) still exist, but the need for instantaneous response is lowered.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Hey, you just said "consumer key revocation", but back in Part 1 you said that the provider can't assume a consumer key uniquely identifies a particular class of consumers. What gives?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;It is correct that the provider can't make this assumption based on the OAuth specification. However, the provider can impose requirements around the consumer key on consumer developers, and the provider can reserve the right to revoke a consumer key for whatever reason they choose. This could be required in the case of denial of service attacks or malicious consumers using a particular key. Providers should work closely with consumer developers to clearly lay out what actions the provider will take in these cases and what options consumer developers have.&lt;/p&gt;
&lt;p&gt;Providers should recognize that the case of desktop and web apps are significantly different in the case of key revocation and they should plan accordingly. In the case of web apps, it should be relatively easy to replace a compromised consumer key and secret. In the case of desktop apps, the consumer developer may face the task of updating thousands or millions of installed applications in the case of a key revocation.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Let's assume that a user has installed a malicious desktop app that wants to use the API of my web app. What's the point of requiring OAuth, since this malicious desktop app already owns the user's system and will have access to anything the user types?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;I'm not sure where this assumption comes from. Well, let me amend that. I know exactly where this assumption comes from, but it is still incorrect. Let me assure the reader that there are many platforms where the installation of a malicious application does not translate into ownership of the host system. The reader will find this sort of behavior in any properly configured Unix-like operating system including Linux, on the iPhone, in any modern browser, in Mac OS X, and even in some locked down versions of the Windows operating system.&lt;/p&gt;
&lt;p&gt;On these platforms, even if the user is tricked into installing a malicious client or going to a malicious website, the user may still be careful to verify that they are only entering their password into the real site of the provider. There are a lot of options for verifying this, but the best way is for the user to make sure that he or she always enters there password into their provider's site using a modern browser with anti-phishing technology and using an https connection.&lt;/p&gt;

&lt;!--
&lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"&gt;
&lt;rdf:Description rdf:about="http://www.esjewett.com/blog/oauth-qa-part-2" dc:identifier="http://www.esjewett.com/blog/oauth-qa-part-2" dc:title="OAuth Q&amp;amp;A Part 2" trackback:ping="http://www.esjewett.com/trackback/38" /&gt;
&lt;/rdf:RDF&gt;
--&gt;
&lt;div id="trackback-url"&gt;&lt;div class="box"&gt;

  &lt;h2&gt;Trackback URL for this post:&lt;/h2&gt;

  &lt;div class="content"&gt;http://www.esjewett.com/trackback/38&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=1N1rX2k-5wU:XbQ7H6MMjZU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=1N1rX2k-5wU:XbQ7H6MMjZU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=1N1rX2k-5wU:XbQ7H6MMjZU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=1N1rX2k-5wU:XbQ7H6MMjZU:SSaB9coO5pA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=1N1rX2k-5wU:XbQ7H6MMjZU:SSaB9coO5pA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/esjewett/~4/1N1rX2k-5wU" height="1" width="1"/&gt;</description>
 <category domain="http://www.esjewett.com/tag/api">api</category>
 <category domain="http://www.esjewett.com/tag/oauth">OAuth</category>
 <category domain="http://www.esjewett.com/tag/security">security</category>
 <pubDate>Thu, 26 Mar 2009 23:08:52 +0000</pubDate>
 <dc:creator>esjewett</dc:creator>
 <guid isPermaLink="false">38 at http://www.esjewett.com</guid>
<feedburner:origLink>http://www.esjewett.com/blog/oauth-qa-part-2</feedburner:origLink></item>
<item>
 <title>Background processing in Web Dynpro for ABAP</title>
 <link>http://feedproxy.google.com/~r/esjewett/~3/58St8a_etFI/background-processing-in-web-dynpro-for-abap</link>
 <description>&lt;p&gt;This week I was writing a Web Dynpro ABAP interface for a long-running process. In general it is probably not a good idea from a performance perspective to run intensive processes synchronously in the context of a Web Dynpro view. It's also a really bad idea because it makes the user wait for the process to finish. If the process runs longer than the server's time-out setting then you get a nasty error message.&lt;/p&gt;
&lt;p&gt;I knew that there was a way to handle this in ABAP, but I don't really live in the language, so it took me a little while to figure it out.&amp;nbsp; Here's the skinny:&lt;/p&gt;
&lt;p&gt;The answer is to write a function module to carry out the processing for you. Enable the function module for RFC (and by extension, set all of the parameters to "Pass by value"). You then call the function module from a Web Dynpro controller method in the background. This registers the function module for execution as an RFC function call in the background.&lt;/p&gt;
&lt;p&gt;Once you've done all of your "CALL FUNCTION xxxxx IN BACKGROUND TASK." statements, use the "COMMIT WORK." command to trigger the execution of these functions. You end up with a code snippet that looks something like:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;call function zsample_function in background task&lt;br /&gt;
*&amp;nbsp; exporting&lt;br /&gt;
*&amp;nbsp;&amp;nbsp;&amp;nbsp; parameter =&lt;br /&gt;
*&amp;nbsp; importing&lt;br /&gt;
*&amp;nbsp;&amp;nbsp;&amp;nbsp; ret =&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; .&lt;/p&gt;
&lt;p&gt;commit work.
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Now your function will start running and control will be returned to the user in the Web Dynpro UI.&lt;/p&gt;
&lt;p&gt;One important thing to remember is that this method provides no feedback to the user by default. Usually it will be a good idea to at least return a message explaining that the task has been started. If possible further feedback should be provided for long-running jobs. I was able to do this by querying a status table that my job populated, but other options are available.&lt;/p&gt;
&lt;p&gt;Help documentation - &lt;a title="http://help.sap.com/saphelp_nw70ehp1/helpdata/en/8f/53b67ad30be445b0ccc968d69bc6ff/frameset.htm" href="http://help.sap.com/saphelp_nw70ehp1/helpdata/en/8f/53b67ad30be445b0ccc968d69bc6ff/frameset.htm"&gt;http://help.sap.com/saphelp_nw70ehp1/helpdata/en/8f/53b67ad30be445b0ccc968d69bc6ff/frameset.htm&lt;/a&gt;&lt;/p&gt;

&lt;!--
&lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"&gt;
&lt;rdf:Description rdf:about="http://www.esjewett.com/blog/background-processing-in-web-dynpro-for-abap" dc:identifier="http://www.esjewett.com/blog/background-processing-in-web-dynpro-for-abap" dc:title="Background processing in Web Dynpro for ABAP" trackback:ping="http://www.esjewett.com/trackback/37" /&gt;
&lt;/rdf:RDF&gt;
--&gt;
&lt;div id="trackback-url"&gt;&lt;div class="box"&gt;

  &lt;h2&gt;Trackback URL for this post:&lt;/h2&gt;

  &lt;div class="content"&gt;http://www.esjewett.com/trackback/37&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=58St8a_etFI:xS4fayVT8WY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=58St8a_etFI:xS4fayVT8WY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=58St8a_etFI:xS4fayVT8WY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=58St8a_etFI:xS4fayVT8WY:SSaB9coO5pA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=58St8a_etFI:xS4fayVT8WY:SSaB9coO5pA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/esjewett/~4/58St8a_etFI" height="1" width="1"/&gt;</description>
 <category domain="http://www.esjewett.com/tag/abap">abap</category>
 <category domain="http://www.esjewett.com/tag/programming">programming</category>
 <category domain="http://www.esjewett.com/tag/sap">sap</category>
 <pubDate>Fri, 13 Mar 2009 22:47:56 +0000</pubDate>
 <dc:creator>esjewett</dc:creator>
 <guid isPermaLink="false">37 at http://www.esjewett.com</guid>
<feedburner:origLink>http://www.esjewett.com/blog/background-processing-in-web-dynpro-for-abap</feedburner:origLink></item>
<item>
 <title>OAuth Q&amp;A - Part 1</title>
 <link>http://feedproxy.google.com/~r/esjewett/~3/E15v1s4Feg8/oauth-qa-part-1</link>
 <description>&lt;h3&gt;OAuth Q&amp;amp;A - Part 1&lt;/h3&gt;
&lt;p&gt;I've been seeing a lot of misinformation about OAuth in discussions lately. Mostly, this is because there has been a lot of activity around OAuth due to the announcement that the Twitter API will be supporting OAuth and eventually (probably, and less officially) moving to OAuth-only authentication and dropping support for basic auth entirely. Generally this misinformation is rebutted somewhere else on the web but it can be somewhat inconvenient to track down all of the call-and-response blog postings on the topic.&lt;/p&gt;
&lt;p&gt;As such, I thought an &lt;a href="http://redmonk.com/sogrady/" title="O'Grady"&gt;O'Grady&lt;/a&gt;-style Q&amp;amp;A might be in order, based on my notes and recollections. Said Q&amp;amp;A turned out to be a little longer than expected, so I'm doing it in a number of parts that will be determined by the cessation of misinformation or the end of my attention span, whichever comes first. If there are any inaccuracies included in these posts that I become aware of (On the web? About OAuth? From a non-expert? Impossible!), I'll post corrections inline.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;What was OAuth designed to do?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;OAuth was designed to do delegated authorization, which is a fancy way of saying that it was designed to ensure that a user will never have to give the password for a service to any entity other than the service provider. If the user wishes to use an application that is not the provider itself in order to access the provider (for example, using &lt;a href="http://www.twhirl.org/" title="Twhirl"&gt;Twhirl&lt;/a&gt;  to access Twitter, or Plaxo to access your Google contacts), then that application can use OAuth to request authorization, which is then granted in a transaction that occurs directly between the user and the provider and does not involve giving the password to the application.&lt;/p&gt;
&lt;p&gt;You can read lots about it on the &lt;a href="http://oauth.net/" title="OAuth site"&gt;OAuth site&lt;/a&gt;, the &lt;a href="http://wiki.oauth.net/" title="OAuth wiki"&gt;OAuth wiki&lt;/a&gt;, the &lt;a href="http://groups.google.com/group/oauth/topics?hl=en&amp;amp;pli=1" title="OAuth mailing list"&gt;OAuth mailing list&lt;/a&gt;, on &lt;a href="http://www.hueniverse.com/" title="Eran Hammer-Lahav's site"&gt;Eran Hammer-Lahav's site&lt;/a&gt;, and the &lt;a href="https://sites.google.com/site/oauthgoog/" title="Google identity and authorization site"&gt;Google identity and authorization site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;OAuth doesn't work in desktop applications because there is no way to protect the consumer key or secret, so there's no point in using it here, right?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;No, OAuth does what it was designed to do just fine in desktop apps.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;But doesn't OAuth rely on a consumer secret and key to identify applications that are allowed to access protected resources and services? How do I protect that in a desktop application?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://oauth.net/core/1.0#anchor4" title="OAuth neither requires nor assumes that the consumer key and secret are hidden from other apps"&gt;OAuth neither requires nor assumes that the consumer key and secret are hidden from other apps&lt;/a&gt;  (though there are some nice payoffs if you can manage this). The consumer secret is simply not sent over the wire. Providers should not assume that consumer keys or secrets identify specific consumers or classes of consumers. Note that this may require providers to treat desktop consumers differently than web apps where requests come from a single IP address and the consumer has more control over the key than is the case with desktop apps.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;My company has a web app and we also provide a desktop client. Because we provide the client, we can just use username/password authentication in the client and that's safe, right?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;No, and there are two reasons for this. First, doing this teaches your users that responding to the &lt;a href="http://adactio.com/journal/1357" title="password anti-pattern"&gt;password anti-pattern&lt;/a&gt;  is acceptable behavior and makes your users more susceptible to malicious API clients that ask for their password. Second, this client behavior necessarily results in the user's password being stored by the client in a recoverable format, which is a significant security risk.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;OAuth is really just a standard for token negotiation and request signing. My application already generates API access tokens and I have a scheme for sending the token along with the request, so why do I need OAuth?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;The most important reason is that there are a lot of things that can go wrong with API access tokens, especially when used over an insecure transport (http instead of https). Using a public, peer-reviewed standard lets you rest easy knowing that lots of experienced thought has gone into avoiding security issues.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Well, okay, but I've actually got the best security minds in the business working on my access token scheme, so I'm pretty comfortable there. What are the other reasons?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;The next biggest reason is interoperability. There are lots of OAuth [client libraries] that make it relatively easy to inter-operate with systems that use OAuth as their auth delegation protocol. For example, &lt;a href="http://incubator.apache.org/shindig/" title="Shindig"&gt;Shindig&lt;/a&gt;  (&lt;a href="http://www.opensocial.org/" title="OpenSocial"&gt;OpenSocial&lt;/a&gt;, &lt;a href="http://code.google.com/apis/gadgets/docs/overview.html" title="Google Gadgets"&gt;Google Gadgets&lt;/a&gt;, iGoogle, etc.) has built in support for OAuth API access for gadgets running on the platform. I expect that within a year there will be at least one web "glue" application (like &lt;a href="http://pipes.yahoo.com/pipes/" title="Yahoo! Pipes"&gt;Yahoo! Pipes&lt;/a&gt;, or &lt;a href="http://tarpipe.com/" title="Tarpipe"&gt;Tarpipe&lt;/a&gt;) that will support reads from and writes to arbitrary OAuth endpoints. If you use a custom scheme, you will miss out on this interoperability.&lt;/p&gt;

&lt;!--
&lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"&gt;
&lt;rdf:Description rdf:about="http://www.esjewett.com/blog/oauth-qa-part-1" dc:identifier="http://www.esjewett.com/blog/oauth-qa-part-1" dc:title="OAuth Q&amp;amp;A - Part 1" trackback:ping="http://www.esjewett.com/trackback/36" /&gt;
&lt;/rdf:RDF&gt;
--&gt;
&lt;div id="trackback-url"&gt;&lt;div class="box"&gt;

  &lt;h2&gt;Trackback URL for this post:&lt;/h2&gt;

  &lt;div class="content"&gt;http://www.esjewett.com/trackback/36&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=E15v1s4Feg8:8hk_z5Lrmko:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=E15v1s4Feg8:8hk_z5Lrmko:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=E15v1s4Feg8:8hk_z5Lrmko:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/esjewett?a=E15v1s4Feg8:8hk_z5Lrmko:SSaB9coO5pA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/esjewett?i=E15v1s4Feg8:8hk_z5Lrmko:SSaB9coO5pA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/esjewett/~4/E15v1s4Feg8" height="1" width="1"/&gt;</description>
 <category domain="http://www.esjewett.com/tag/api">api</category>
 <category domain="http://www.esjewett.com/tag/oauth">OAuth</category>
 <category domain="http://www.esjewett.com/tag/security">security</category>
 <category domain="http://www.esjewett.com/tag/user-interface">user interface</category>
 <pubDate>Sun, 01 Mar 2009 00:58:01 +0000</pubDate>
 <dc:creator>esjewett</dc:creator>
 <guid isPermaLink="false">36 at http://www.esjewett.com</guid>
<feedburner:origLink>http://www.esjewett.com/blog/oauth-qa-part-1</feedburner:origLink></item>
<item>
 <title>Twitter -&gt; Pipes -&gt; ESME</title>
 <link>http://feedproxy.google.com/~r/esjewett/~3/Bf9iuOTFlGo/twitter-pipes-esme</link>
 <description>&lt;p&gt;This is a quick how-to, showing how to route your Twitter feed through Yahoo! Pipes to filter and cleanse it, then consume it using ESME actions.&lt;/p&gt;
&lt;p&gt;I've created a parametrized Yahoo! Pipe &lt;a href="http://pipes.yahoo.com/pipes/pipe.info?_id=fJZ29qrr3RGjLPJI6icw5g"&gt;here&lt;/a&gt; where you can input your Twitter username and get back a feed of all mentions of "ESME", "esme", or "Esme" from your Twitter timeline.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.esjewett.com/files/2009-02-22_1552.png" alt="Pipe with input for Twitter username" \ /&gt;&lt;/p&gt;
&lt;p&gt;(Pipe address: &lt;a href="http://pipes.yahoo.com/pipes/pipe.info?_id=fJZ29qrr3RGjLPJI6icw5g"&gt;http://pipes.yahoo.com/pipes/pipe.info?_id=fJZ29qrr3RGjLPJI6icw5g&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Once the "Run Pipe" button is pressed, the filtered time-line displays.  I've also removed the username from the beginning of the Tweets, for better display in ESME.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.esjewett.com/files/2009-02-22_1553.png" width="500px" alt="Pipe after running" \ /&gt;&lt;/p&gt;
&lt;p&gt;Feel free to use this pipe with your username, or "Clone" it and modify it as you like.  The structure of the Pipe as it is now is available as an image &lt;a href="http://www.esjewett.com/files/2009-02-22_1553-1.png"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once the pipe has been run, it is possible to retrieve the output as an RSS feed.  Copy the link for the RSS feed for this pipe, as we will need to consume it using an ESME action.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.esjewett.com/files/2009-02-22_1555.png" alt="Copying the link for the RSS feed of the pipe" \ /&gt;&lt;/p&gt;
&lt;p&gt;Now navigate to your ESME server.  We need to use a relatively recent version of ESME, specifically a version including the recently merged actions branch.  I'm using &lt;a href="http://esmecloudserverapache.dickhirsch.staxapps.net/"&gt;http://esmecloudserverapache.dickhirsch.staxapps.net/&lt;/a&gt; in this example.&lt;/p&gt;
&lt;p&gt;Log in to the ESME server and create a new action.  Fill in the action name as desired.  For the test, use the "every N mins" test.  I'm chosen 5 minutes as my interval, which means that the pipe feed will be queried every 5 mins for new entries.&lt;/p&gt;
&lt;p&gt;For the Action, use the rss: action type, followed directly (no space) by the URL of the Pipes RSS feed that we copied earlier.  Your action form should look like this.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.esjewett.com/files/2009-02-22_1556.png" alt="ESME action form filled in with Yahoo! Pipe information" \ /&gt;&lt;/p&gt;
&lt;p&gt;Click the "Add" button and your recent Tweets containing the word "ESME" will start showing up on the ESME server.  One neat aspect of this is that any hashtags (#esme for example) in your Twitter updates will be converted to ESME tags automatically.&lt;/p&gt;
&lt;p&gt;This only works for public Twitter updates, as Yahoo! Pipes doesn't support authentication for feeds.  You could query your private Twitter feed directly from the ESME server, embedding your Twitter username and password in the URL, but I strongly recommend against this as your username and password will be stored in the ESME server database, which you do not control.&lt;/p&gt;

&lt;!--
&lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"&gt;
&lt;rdf:Description rdf:about="http://www.esjewett.com/blog/twitter-pipes-esme" dc:identifier="http://www.esjewett.com/blog/twitter-pipes-esme" dc:title="Twitter -&amp;gt; Pipes -&amp;gt; ESME" trackback:ping="http://www.esjewett.com/trackback/35" /&gt;
&lt;/rdf:RDF&gt;
--&gt;
&lt;div id="trackback-url"&gt;&lt;div class="box"&gt;

  &lt;h2&gt;Trackback URL for this post:&lt;/h2&gt;

  &lt;div class="content"&gt;http://www.esjewett.com/trackback/35&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/esjewett?a=KroDEKgK"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/esjewett?a=4dEsJUw0"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?i=4dEsJUw0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/esjewett?a=QnMl5URu"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?i=QnMl5URu" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/esjewett/~4/Bf9iuOTFlGo" height="1" width="1"/&gt;</description>
 <category domain="http://www.esjewett.com/tag/esme">esme</category>
 <category domain="http://www.esjewett.com/tag/feeds">feeds</category>
 <category domain="http://www.esjewett.com/tag/interop">interop</category>
 <category domain="http://www.esjewett.com/tag/pipes">pipes</category>
 <category domain="http://www.esjewett.com/tag/twitter">twitter</category>
 <category domain="http://www.esjewett.com/tag/yahoo">yahoo</category>
 <pubDate>Sun, 22 Feb 2009 22:19:24 +0000</pubDate>
 <dc:creator>esjewett</dc:creator>
 <guid isPermaLink="false">35 at http://www.esjewett.com</guid>
<feedburner:origLink>http://www.esjewett.com/blog/twitter-pipes-esme</feedburner:origLink></item>
<item>
 <title>A RESTful ESME API</title>
 <link>http://feedproxy.google.com/~r/esjewett/~3/YBgbOQ977FA/a-restful-esme-api</link>
 <description>&lt;p&gt;The Enterprise Social Messaging Experiment (ESME) project grew out of a collaboration in the SAP world and is now a &lt;a title="project in the Apache Incubator" href="http://incubator.apache.org/esme/" id="piu9"&gt;project in the Apache Incubator&lt;/a&gt;. The project itself is an interesting and inspiring demonstration of the organizing power of so-called web 2.0 tools, which allowed the project to go from an idea to an Incubator project in about half a year through the efforts of a wide-spread group of individuals, many of whom have never met. I've been on the sidelines of the project, looking on, but I've been fascinated by some conversations that have taken place around the API.&lt;/p&gt;
&lt;p&gt;The ESME API is often described as a "REST" API or a "RESTful" API. "REST" refers to the design principle of Representational State Transfer. Wikipedia has a good &lt;a title="overview" href="http://en.wikipedia.org/wiki/Representational_State_Transfer" id="j30o"&gt;overview&lt;/a&gt;. REST is often seen as an alternative to RPC APIs, or "Remote Procedure Call" APIs. At root, the difference as described by Wikipedia is that RPC is about telling an application to do something while REST is about changing the state of the resources of an application.&lt;/p&gt;
&lt;p&gt;The upshot is that RPC can be thought of as interfacing in verbs, while REST can be thought of as interfacing in nouns. To grossly oversimplify, let's pretend that I'm updating my location in the application &lt;a href="http://www.foobar.com/" title="http://www.foobar.com/"&gt;http://www.foobar.com/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In RPC I would do something like&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;POST HTTP request http://www.foobar.com/api/update_location?lat=1234&amp;amp;long=5678&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;In the context of a REST API, I would do something like&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;PUT or POST HTTP request http://www.foobar.com/location?lat=1234&amp;amp;long=5678&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;A subtle distinction to be sure, but let's look at the difference. In the RPC version, we see the verb in the URI. There is a separate URI for every possible action we might want to take with regards to a location (update_location, get_location, create_location, delete_location). In a REST API, the resources of the program are addressed directly (that is, we send the request to the same URI that we would use to display our location in a web browser), and the "verb" that we want to apply to the resource is embedded in the HTTP request. REST is a very HTTP-oriented design approach, but it is an approach that makes sense because HTTP is a protocol for handling resources. The Wikipedia page has more on this, and may very well contradict me, as I am by no means an API expert!&lt;/p&gt;
&lt;p&gt;To get to the point, what would an ESME REST API look like? Let's first look at the current ESME API, which is described as "REST", but which I think we can safely conclude is actually RPC.&lt;/p&gt;
&lt;p&gt;&lt;a title="http://code.google.com/p/esmeproject/wiki/REST_API_Documantation" href="http://code.google.com/p/esmeproject/wiki/REST_API_Documantation" id="gzr-"&gt;http://code.google.com/p/esmeproject/wiki/REST_API_Documantation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Note how each API command is a verb. This is the hallmark of an RPC API. (ESME is part of a tradition here. The &lt;a title="Twitter &amp;quot;REST&amp;quot; API" href="http://apiwiki.twitter.com/REST+API+Documentation" id="ahs."&gt;Twitter "REST" API&lt;/a&gt;  is also primarily written in an RPC style, where the verb is part of the path of URI and is not assumed based on the HTTP method. The Twitter API does assume that a GET HTTP request maps to a read except when they have also have a specific "show" verb, but now I'm just nit picking.)&lt;/p&gt;
&lt;p&gt;There is nothing wrong with this, and RPC is actually more in line with enterprise API design standards than a REST API, but I'd like to get at what a real ESME REST api would look like. I provide here the current ESME API method along with the REST equivalent that comes to mind.&lt;/p&gt;
&lt;p&gt;I'm listing arguments here as URL-encoded, but they could easily be form-encoded, XML, JSON or all of the above. On the REST side, where a portion of the URL is in all caps, this would be substituted by the unique ID of that particular resource. This is, of course, not a well-thought-out proposal, but rather a suggestion to illustrate what a more RESTful API might look like.&lt;/p&gt;
&lt;table border="1" cellpadding="1" cellspacing="0" width="100%"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;h3&gt;Current (RPC)&lt;/h3&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;h3&gt;REST&lt;/h3&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET /api/status&lt;/td&gt;
&lt;td&gt;GET api/sessions&lt;br /&gt;
(It might make sense for this to return only the current session, but in theory it would return all sessions that the current session is allowed to access, so for an administrator, it might return all open sessions. An individual session would be accessed at GET api/sessions/SESSIONID.)&lt;br /&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST /api/login&lt;br /&gt;
token=API_TOKEN&lt;/td&gt;
&lt;td&gt;POST api/sessions?token=API_TOKEN
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET /api/logout&lt;/td&gt;
&lt;td&gt;DELETE api/sessions/SESSIONID or&lt;br /&gt;
DELETE api/sessions?session=SESSIONID&lt;br /&gt;
(get SESSIONID from api/sessions)
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET /api/get_msgs&lt;/td&gt;
&lt;td&gt;GET api/users/USERID/messages&lt;br /&gt;
(get USERID from api/session)
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET /api/wait_for_msgs&lt;/td&gt;
&lt;td&gt;GET api/users/USERID/messages (long-poll?)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;td valign="top"&gt;GET api/messages/MESSAGEID&lt;br /&gt;
Gets a particular message.
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST /api/send_msg&lt;br /&gt;
message=messagebody&lt;br /&gt;
via=client&lt;br /&gt;
tags=tags&lt;br /&gt;
metadata=XML_data&lt;br /&gt;
replyto=message_id&lt;/td&gt;
&lt;td&gt;POST api/messages?message=MESSAGE_BODY&amp;amp;via=CLIENT&amp;amp;tags=TAGS&amp;amp;metadata=XML&amp;amp;replyto=MESSAGEID
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;td valign="top"&gt;PUT api/messages/MESSAGEID (payload the same as POST)
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;td valign="top"&gt;DELETE api/messages/MESSAGEID
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET /api/get_following&lt;/td&gt;
&lt;td&gt;GET api/users/USERID/followees&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET /api/get_followers&lt;/td&gt;
&lt;td&gt;GET api/users/USERID/followers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST /api/follow&lt;br /&gt;
user=id_of_user&lt;/td&gt;
&lt;td&gt;POST api/users/USERID/followees/USERID2 or&lt;br /&gt;
POST api/users/USERID/followees?user=USERID2
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST /api/unfollow&lt;br /&gt;
user=id_of_user&lt;/td&gt;
&lt;td&gt;DELETE api/users/USERID/followees/USERID2 or&lt;br /&gt;
DELETE api/users/USERID/followees?user=USERID2
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET /api/all_users&lt;/td&gt;
&lt;td&gt;GET api/users
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET /api/get_tagcloud&lt;br /&gt;
numTags=optional_no_of_tags&lt;/td&gt;
&lt;td&gt;GET api/tags&lt;br /&gt;
(This doesn't really seem like an appropriate API method. It should really return all of the tags, or user-specific tags (GET api/tags/USERID) and let the front-end decide what to do with it.)
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET /api/get_tracking&lt;/td&gt;
&lt;td&gt;GET api/users/USERID/tracks
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST /api/add_tracking&lt;br /&gt;
track=text&lt;/td&gt;
&lt;td&gt;POST api/users/USERID/tracks?track=TEXT_TO_TRACK
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST /api/remove_tracking&lt;br /&gt;
trackid=id_of_tracking_item&lt;/td&gt;
&lt;td&gt;DELETE api/users/USERID/tracks/TRACKID
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET /api/get_conversation&lt;br /&gt;
conversationid=Conversation_id&lt;/td&gt;
&lt;td&gt;GET api/conversations/CONVERSATIONID
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET /api/get_actions&lt;/td&gt;
&lt;td&gt;GET api/users/USERID/actions&lt;br /&gt;
(Actions probably don't make sense outside of the context of a specific user.)
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST /api/add_action&lt;br /&gt;
name=name&lt;br /&gt;
test=trigger&lt;br /&gt;
action=action&lt;/td&gt;
&lt;td&gt;POST api/users/USERID/actions?name=NAME&amp;amp;test=TEST&amp;amp;action=ACTION
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a name="Enable_Action"&gt;&lt;/a&gt;POST /api/enable_action&lt;br /&gt;
id=action_id&lt;br /&gt;
enabled=true|false&lt;/td&gt;
&lt;td&gt;PUT api/users/USERID/actions/ACTIONID?enabled=true|false&lt;br /&gt;
(This is actually a general outlet to update any attribute of an action, including whether or not it is enabled.)
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST /api/delete_action&lt;br /&gt;
actionid=action_id&lt;/td&gt;
&lt;td&gt;DELETE api/users/USERID/actions/ACTIONID
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;One point to note is that most HTTP clients do not currently support&lt;br /&gt;
the "PUT" or "DELETE" methods, so these have to be simulated&lt;br /&gt;
through POST methods with an extra parameter. I think that because of the close mapping to resource verbs, is worth using these methods in&lt;br /&gt;
the specification and defining the simulation method for the entire API&lt;br /&gt;
separately.&lt;/p&gt;
&lt;p&gt;The above is based on a rough object hierarchy as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ESME API instance (api/)
&lt;ul&gt;
&lt;li&gt;Sessions (api/sessions)&lt;/li&gt;
&lt;li&gt;Users (api/users)
&lt;ul&gt;
&lt;li&gt;Messages posted by a user (api/users/USERID/messages)&lt;/li&gt;
&lt;li&gt;Users followed by a user (api/users/USERID/followees)&lt;/li&gt;
&lt;li&gt;Users following a user (api/users/USERID/followers)&lt;/li&gt;
&lt;li&gt;Trackers belonging to a user (api/users/USERID/tracks)&lt;/li&gt;
&lt;li&gt;Actions belonging to a user (api/users/USERID/actions)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Messages (api/messages)&lt;/li&gt;
&lt;li&gt;Tags (api/tags)&lt;/li&gt;
&lt;li&gt;Conversations (api/conversations)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these bullets represents a set of objects. The resource representing an individual object lives at api/objects/OBJECTID. For example, api/sessions/SESSIONID. As much as is reasonable, one would expect to be able to GET (read), POST (create), PUT (update/amend), or DELETE (delete) any individual member of each of these object sets. Going through each of these objects to ask what it would mean to create, read, update, or delete that object may reveal holes in the existing API, some of which I have filled in above.&lt;/p&gt;

&lt;!--
&lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"&gt;
&lt;rdf:Description rdf:about="http://www.esjewett.com/blog/a-restful-esme-api" dc:identifier="http://www.esjewett.com/blog/a-restful-esme-api" dc:title="A RESTful ESME API" trackback:ping="http://www.esjewett.com/trackback/34" /&gt;
&lt;/rdf:RDF&gt;
--&gt;
&lt;div id="trackback-url"&gt;&lt;div class="box"&gt;

  &lt;h2&gt;Trackback URL for this post:&lt;/h2&gt;

  &lt;div class="content"&gt;http://www.esjewett.com/trackback/34&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/esjewett?a=0mRcNZUe"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/esjewett?a=m9Ljlcu2"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?i=m9Ljlcu2" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/esjewett?a=8SKvpP0H"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?i=8SKvpP0H" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/esjewett/~4/YBgbOQ977FA" height="1" width="1"/&gt;</description>
 <category domain="http://www.esjewett.com/tag/api">api</category>
 <category domain="http://www.esjewett.com/tag/esme">esme</category>
 <category domain="http://www.esjewett.com/tag/rest">rest</category>
 <category domain="http://www.esjewett.com/tag/twitter">twitter</category>
 <pubDate>Sun, 15 Feb 2009 05:20:39 +0000</pubDate>
 <dc:creator>esjewett</dc:creator>
 <guid isPermaLink="false">34 at http://www.esjewett.com</guid>
<feedburner:origLink>http://www.esjewett.com/blog/a-restful-esme-api</feedburner:origLink></item>
<item>
 <title>Automated testing in SAP systems</title>
 <link>http://feedproxy.google.com/~r/esjewett/~3/EmwwKL9Vwdc/automated-testing-in-sap-systems</link>
 <description>&lt;p&gt;This is another in my series of notes to myself that might somehow come in handy to others, so I'll post them to the blog. This is more of a brainstorm than anything else, but some thought has gone into this area. In terms of actual testing going on in the SAP world, it probably displays my ignorance more than anything, but I'd love to be corrected. If you aren't interested in SAP or in testing methodology, then I recommend you stop reading now!&lt;/p&gt;
&lt;p&gt;Based on what I've seen in my admittedly shortish time in the SAP world, the state of automated testing is sadly lacking. This is not to say that the facilities for testing don't exist, but perhaps that they are not adequately ergonomic or well understood. The result is that most implementations don't have a mature testing automation strategy, which is a key component of a modern approach to software development.&lt;/p&gt;
&lt;h3&gt;Unit testing&lt;/h3&gt;
&lt;p&gt;In the unit test arena we're doing alright as we have most of the standard Java capabilities on the Java development side and we have ABAP Unit on the ABAP side of the house. Though, I'll note that you've got to be a bit careful in designing your ABAP Unit tests to handle more than one failure per execution. There also isn't much of a facility for handling alternative testing strategies such as specification derived tests or behavioral testing. Part of this is due to the limitations of ABAP as a (mostly) statically typed, strictly object-oriented language. Part of this inflexibility is simply due to the fact that the necessary facilities have not been developed.&lt;/p&gt;
&lt;p&gt;I'll also note that while Java isn't my cup of tea, apparently setting up automated unit testing using JUnit on the Java side of the SAP world isn't straightforward. The SDN blog &lt;a href="https://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/wlg/12625" title="&amp;quot;Test-driven development with Composite Application Framework (CE 7.1)&amp;quot;"&gt;"Test-driven development with Composite Application Framework (CE 7.1)"&lt;/a&gt;looks like a decent overview of the process of getting JUnit testing set up.&lt;/p&gt;
&lt;p&gt;With SAP's focus on positioning itself as a full-featured development platform for the enterprise and the growth of agile, modern development methodologies in the enterprise, I'm surprised that unit testing and test-driven development aren't getting more attention from SAP as an integral part of the application lifecycle.&lt;/p&gt;
&lt;h3&gt;Performance&lt;/h3&gt;
&lt;p&gt;In the performance testing area a lot of work has been done to work out transactional systems under load. However, I'd argue that we need to understand the limits of this sort of testing. Usually it is focused on a single transaction or report, which is fine for testing the maximum performance of that piece of the system, but the tester must have a significant knowledge of the underlying architecture of the system in order to really test for table write contention or the performance of specialized processing logic under load.&lt;/p&gt;
&lt;p&gt;Performance testing gets really worthwhile only when the level of knowledge of the system architecture reaches a level where a significant number of these trouble spots can be identified and tested under load in a test environment. As it happens, we're mostly doing this type of testing in production in the SAP world, which is the situation we are ostensibly trying to avoid by doing "performance testing" in a pre-production test system.&lt;/p&gt;
&lt;p&gt;Jonathon Kohl &lt;a href="http://www.kohl.ca/blog/archives/000202.html" title="writes knowledgeably"&gt;writes knowledgeably&lt;/a&gt; of some of the complexities inherent in performance testing. I think we would be wise to admit the limits of performance testing in an environment as complex as most SAP implementations. This is not to say that we shouldn't do it, but simple load testing isn't getting us very far and we might be better served by focusing on replicating real system use or focusing on a more &lt;a title="exploratory" href="http://en.wikipedia.org/wiki/Exploratory_testing"&gt;exploratory&lt;/a&gt; version of performance testing.&lt;/p&gt;
&lt;h3&gt;Functional/Behavior&lt;/h3&gt;
&lt;p&gt;Up until this point we've had cursory automated testing occurring in most implementations. But when we get to functional testing things start to fall apart. There is a lot of potential contention over the right place to interface into the application to do functional testing. Most MVC frameworks provide an interface into the controller level to mock view requests and model contents. Some believe that the view/interface level is a good place for this kind of testing, which makes a certain amount of sense if the framework doesn't have a clear delineation between the user interface and the application logic or won't commit to the delineation that exists.&lt;/p&gt;
&lt;p&gt;The options for functional testing in delivered SAP systems are pretty much eCATT or an external testing tool that hooks in at the UI or API level. eCATT is not an ideal functional testing tool on some reads of "proper" functional testing but should be usable. I'll be looking into some eCATT good practices and testing strategies in a future article. There are also some options from vendors like &lt;a title="Mercury (now HP)" href="https://h10078.www1.hp.com/cda/hpms/display/main/hpms_content.jsp?zn=bto&amp;amp;cp=1-11-127-24_4000_100__"&gt;Mercury (now HP)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It should be possible to hack together a working external automated functional testing system for your organization's SAP landscape and chosen development method, but it would be expensive to maintain across significant upgrades. For example the recent Netweaver 7.0 enhancement package 1 upgrade would probably break most browser driven testing of WebDynPro ABAP/Java applications because of the shift from full server round-trips to a more AJAX-y user interface programming approach. Multiple levels of abstraction in the test harness would be necessary to limit breakage to predictable and manageable layers of the testing stack.&lt;/p&gt;
&lt;p&gt;I still think it is worthwhile to pursue this strategy if the built-in support for functional testing from SAP does not satisfy the needs of an organization. The automated approach done well can provide for better coverage, accuracy, and speed, while saving a bunch of un-fulfilling person-hours spent manually exercising a system while struggling to stay awake. There may be room for a vendor to build up and maintain standard APIs across versions of SAP systems and I'm sure that vendors like Mercury are working on this, at least in transactional systems. Heck, there may be room for an open source project to do the same using a browser driver like WATIR. Hmmmm...&lt;/p&gt;
&lt;p&gt;BI and performance management applications still seem to be pretty much an open field here.&lt;/p&gt;
&lt;h3&gt;Why automation&lt;/h3&gt;
&lt;p&gt;The real power of automated functional testing starts to show up when we consider doing things that we basically don't do in SAP projects. Coupled with an automated system build process (yes, we probably need to talk about this too), automated test suites allow for&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full nightly functional regression tests&lt;/li&gt;
&lt;li&gt;Running the full test suite on a contemplated change or note application&lt;/li&gt;
&lt;li&gt;Full regression testing after upgrading&lt;/li&gt;
&lt;li&gt;Behavior driven development (BDD) or business applications, where the specs are the business requirements&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Continuous integration for every level of the development and maintenance landscape&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The potential gains in productivity and reductions in risk that can be gleaned from engaging in a disciplined testing methodology (be it focused on coverage, TDD, BDD, etc) appear large. Certainly worth more thought and study.&lt;/p&gt;

&lt;!--
&lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"&gt;
&lt;rdf:Description rdf:about="http://www.esjewett.com/blog/automated-testing-in-sap-systems" dc:identifier="http://www.esjewett.com/blog/automated-testing-in-sap-systems" dc:title="Automated testing in SAP systems" trackback:ping="http://www.esjewett.com/trackback/33" /&gt;
&lt;/rdf:RDF&gt;
--&gt;
&lt;div id="trackback-url"&gt;&lt;div class="box"&gt;

  &lt;h2&gt;Trackback URL for this post:&lt;/h2&gt;

  &lt;div class="content"&gt;http://www.esjewett.com/trackback/33&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/esjewett?a=6cRU9Tgg"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/esjewett?a=UHT24XsC"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?i=UHT24XsC" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/esjewett?a=pSDEW8xU"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?i=pSDEW8xU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/esjewett/~4/EmwwKL9Vwdc" height="1" width="1"/&gt;</description>
 <category domain="http://www.esjewett.com/tag/automation">automation</category>
 <category domain="http://www.esjewett.com/tag/enterprise">enterprise</category>
 <category domain="http://www.esjewett.com/tag/performance">performance</category>
 <category domain="http://www.esjewett.com/tag/sap">sap</category>
 <category domain="http://www.esjewett.com/tag/testing">testing</category>
 <category domain="http://www.esjewett.com/tag/watir">watir</category>
 <pubDate>Fri, 30 Jan 2009 19:55:14 +0000</pubDate>
 <dc:creator>esjewett</dc:creator>
 <guid isPermaLink="false">33 at http://www.esjewett.com</guid>
<feedburner:origLink>http://www.esjewett.com/blog/automated-testing-in-sap-systems</feedburner:origLink></item>
<item>
 <title>Workflow change costs estimation</title>
 <link>http://feedproxy.google.com/~r/esjewett/~3/6hAsRpeCERM/workflow-change-costs-estimation</link>
 <description>&lt;p&gt;&lt;cite&gt;Originally posted as a &lt;a href="http://www.inquisitr.com/15368/so-you-want-to-trust-your-workflow-to-the-web-good-luck-with-than-plan/#comment-5267284"&gt;comment&lt;/a&gt; by &lt;a href="http://disqus.com/people/esjewett/"&gt;esjewett&lt;/a&gt; on &lt;a href="http://www.inquisitr.com"&gt;The Inquisitr&lt;/a&gt; using &lt;a href="http://disqus.com"&gt;Disqus&lt;/a&gt;.&lt;/cite&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;These are excellent points, but it only gets at half of the equation.  As I see it, the two main questions when working on my personal workflow are effectiveness and flexibility.  My impression is that when people are thinking about their workflows there is far too much emphasis on the stability of the platform (which is your point, and a good one) because of an inflated estimate of the costs associated with a workflow change.&lt;br /&gt;&lt;br /&gt;The basic question is this: Is a change to my workflow that takes X hours to execute worthwhile?&lt;br /&gt;&lt;br /&gt;The way a lot of people think about this question is by asking "Do I have X hours to spend on this or would I rather spend it on something else?"&lt;br /&gt;&lt;br /&gt;The question people should be asking contains another variable - the number of hours they will save overall through this change.  Let's call this number of hours "Y".  The question is: "Do I have X-Y hours to spend on this or would I rather spend it on something else?"  When the number of hours saved (Y) becomes greater than the switching cost (X), the cost associated with a workflow change becomes negative.&lt;br /&gt;&lt;br /&gt;I actually switch tools quite often, so my estimate of the total productivity gain for a given tool is necessarily limited by a short time horizon and my tolerance for switching costs should be correspondingly lower, but I still find that a switch is of tools is justified for a pretty small daily productivity gain (even 5 minutes saved per day makes a tool a clear winner).&lt;br /&gt;&lt;br /&gt;If Google Reader shut down tomorrow and I had to switch to a different feed reader, would I come out ahead in productivity over the last year or two as compared to the next best solution? I have no doubt in my mind that I would.  As such, I have no problem "entrusting" this part of my workflow to the web, as long as the switching costs (X) are less than the productivity gain.&lt;br /&gt;&lt;br /&gt;I find that the "web-iness" of a tool doesn't factor much in the estimate of switching costs.  The OPML export from Google Reader happens to make the switching cost very low, which makes my decision to use Google Reader very easy.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Original article: &lt;a href="http://www.inquisitr.com/15368/so-you-want-to-trust-your-workflow-to-the-web-good-luck-with-than-plan/"&gt;http://www.inquisitr.com/15368/so-you-want-to-trust-your-workflow-to-the-web-good-luck-with-than-plan/&lt;/a&gt;.&lt;/p&gt;

&lt;!--
&lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"&gt;
&lt;rdf:Description rdf:about="http://www.esjewett.com/blog/workflow-change-costs-estimation" dc:identifier="http://www.esjewett.com/blog/workflow-change-costs-estimation" dc:title="Workflow change costs estimation" trackback:ping="http://www.esjewett.com/trackback/32" /&gt;
&lt;/rdf:RDF&gt;
--&gt;
&lt;div id="trackback-url"&gt;&lt;div class="box"&gt;

  &lt;h2&gt;Trackback URL for this post:&lt;/h2&gt;

  &lt;div class="content"&gt;http://www.esjewett.com/trackback/32&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/esjewett?a=5kwR6QiA"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/esjewett?a=X1pOTmJM"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?i=X1pOTmJM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/esjewett?a=cucgC4h4"&gt;&lt;img src="http://feeds.feedburner.com/~f/esjewett?i=cucgC4h4" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/esjewett/~4/6hAsRpeCERM" height="1" width="1"/&gt;</description>
 <category domain="http://www.esjewett.com/tag/cloud">cloud</category>
 <category domain="http://www.esjewett.com/tag/feeds">feeds</category>
 <category domain="http://www.esjewett.com/tag/performance">performance</category>
 <category domain="http://www.esjewett.com/tag/productivity">productivity</category>
 <category domain="http://www.esjewett.com/tag/workflow">workflow</category>
 <pubDate>Sun, 18 Jan 2009 16:43:17 +0000</pubDate>
 <dc:creator>esjewett</dc:creator>
 <guid isPermaLink="false">32 at http://www.esjewett.com</guid>
<feedburner:origLink>http://www.esjewett.com/blog/workflow-change-costs-estimation</feedburner:origLink></item>
</channel>
</rss>
