<?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-2934352534884921566</id><updated>2011-08-15T14:57:13.385-07:00</updated><category term='Haskell'/><category term='Java JFace'/><category term='values'/><category term='interior design'/><category term='RCP'/><category term='agile'/><category term='documentation'/><category term='Scrum'/><category term='JDT'/><category term='Eclipse IDE'/><category term='philosophy'/><category term='Java'/><category term='conferences'/><category term='Refactoring'/><category term='Usus'/><title type='text'>The Examined Code</title><subtitle type='html'>Reflections on programming and technology</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-7753740192792847195</id><published>2010-09-30T04:45:00.000-07:00</published><updated>2010-09-30T13:10:07.558-07:00</updated><title type='text'>Automatic test suites in Usus 0.6</title><content type='html'>&lt;div style="font-family: Verdana,sans-serif;"&gt;For those of you who were at the &lt;a href="http://wiki.eclipse.org/EclipseTestingDay2010"&gt;Eclipse Testing Day&lt;/a&gt;, listening to the talk &lt;a href="http://marcphilipp.tumblr.com/"&gt;Marc&lt;/a&gt; and I gave about test suites in the Eclipse IDE: the new &lt;a href="http://projectusus.org/"&gt;Usus&lt;/a&gt; feature we described is now released. It's part of Usus 0.6. If you already have Usus 0.6, you can install it separately from the Usus update site at &lt;code&gt;http://projectusus.googlecode.com/svn/updates&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Here's what it does:&lt;br /&gt;&lt;br /&gt;Just as you can simply right-click any Java project in the workspace and run all JUnit tests contained in it, you can now select &lt;i&gt;&lt;b&gt;any two or more&lt;/b&gt;&lt;/i&gt; projects and run all &lt;i&gt;their&lt;/i&gt; tests as well. The only condition is that there is at least one project somewhere in the workspace that is a common dependency root of both (or all) selected projects, i.e. a project that depends, directly or indirectly, on both (or all of them). There is normally at least one such project, namely the one where you'd put your AllTests suite. Only of course with this new feature in Usus, you don't need an AllTests suite any more :-) &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_BynttqNlK3w/TKTcydhFGzI/AAAAAAAAARw/xNlkfY-l3hk/s1600/MultiProject.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="175" src="http://2.bp.blogspot.com/_BynttqNlK3w/TKTcydhFGzI/AAAAAAAAARw/xNlkfY-l3hk/s320/MultiProject.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;(A couple of remarks: If you select two projects where one of them depends on the other,&amp;nbsp; directly or indirectly, there is no need for an additional project that acts as common dependency root. The depending project itself can play this role.&lt;br /&gt;&lt;br /&gt;A Java project in the workspace 'depends' on another project when it has that project on its Java Build Path, as a required project. Among other things, this includes plug-in projects that are declared as required plug-ins when you do Eclipse plug-in development. Thus, if you do plug-in development, you can use this feature on any two plug-in projects as long as they are in the same dependency tree.)&lt;br /&gt;&lt;br /&gt;There's a second interesting new thing you can do with JUnit test suites in Usus 0.6. You can also select a &lt;i&gt;&lt;b&gt;single&lt;/b&gt;&lt;/i&gt; Java project, and choose &lt;code&gt;Run As... All Tests Suite (JUnit)&lt;/code&gt;. Usus will then collect all JUnit tests in that project and all its dependencies, i.e. walk the entire dependency tree&lt;br /&gt;and create a test suite from all tests found.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_BynttqNlK3w/TKTuaXHg_UI/AAAAAAAAAR0/npyjumoer2w/s1600/AllTests.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="231" src="http://3.bp.blogspot.com/_BynttqNlK3w/TKTuaXHg_UI/AAAAAAAAAR0/npyjumoer2w/s320/AllTests.png" width="320" /&gt;&lt;/a&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/2934352534884921566-7753740192792847195?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/7753740192792847195/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/09/automatic-test-suites-in-usus-06.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/7753740192792847195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/7753740192792847195'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/09/automatic-test-suites-in-usus-06.html' title='Automatic test suites in Usus 0.6'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_BynttqNlK3w/TKTcydhFGzI/AAAAAAAAARw/xNlkfY-l3hk/s72-c/MultiProject.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-2820255402794175340</id><published>2010-07-30T23:50:00.000-07:00</published><updated>2010-07-31T00:03:18.277-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Usus'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Speaking at the Eclipse Testing Day</title><content type='html'>My colleage at andrena, and fellow blogger over at &lt;a href="http://marcphilipp.tumblr.com/"&gt;Crafting Code&lt;/a&gt;, Marc and I will give a talk at the &lt;a href="http://wiki.eclipse.org/EclipseTestingDay2010"&gt;Eclipse Testing Day&lt;/a&gt; in Darmstadt on Sep 8th. Here's the abstract:&lt;br /&gt;&lt;blockquote&gt;In software projects with sizeable code bases maintaining the suite  of all unit tests regularly becomes an issue: developers want to be able  to execute the entire collection of tests with a single command, but an  AllTests suite that lists the test cases explicitly must be kept  manually, which is inefficient and error-prone.  &lt;br /&gt;The well-known &lt;a href="http://johanneslink.net/projects/cpsuite.jsp"&gt;ClasspathSuite&lt;/a&gt; solves this problem elegantly,  but it has its weaknesses, too: it becomes slow on large workspaces and  executes static code blocks in all classes when loading and analyzing  them, which can cause unexpected effects and in some cases make the  tests fail.  &lt;br /&gt;The Eclipse IDE allows to run all tests in a single Java project  or source folder directly from the context menu, but doesn't extend this  functionality to the entire workspace. (For good reasons, as we will  explain in the talk.) There are approaches to mitigate this issue (e.g. &lt;a href="http://marketplace.eclipse.org/content/run-all-tests"&gt;this Plug-in&lt;/a&gt;), but they have their own shortcomings. Still, they clearly show the  need for a solution in this area.  &lt;br /&gt;After discussing the current status of test suite management in  Eclipse, we introduce a new approach to address these issues; we'll also  demonstrate a prototypical implementation which we are currently  developing at &lt;a href="http://projectusus.org/"&gt;Project Usus&lt;/a&gt;.  &lt;/blockquote&gt;&amp;nbsp;(If you want to join us at the Testing Day, here's the &lt;a href="http://eclipsetestingday2010.eventbrite.com/"&gt;registration link&lt;/a&gt; :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2934352534884921566-2820255402794175340?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/2820255402794175340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/07/speaking-at-eclipse-testing-day.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/2820255402794175340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/2820255402794175340'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/07/speaking-at-eclipse-testing-day.html' title='Speaking at the Eclipse Testing Day'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-6216062979337527816</id><published>2010-05-17T15:27:00.000-07:00</published><updated>2010-07-31T00:03:52.392-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RCP'/><title type='text'>How to code with a hedge trimmer</title><content type='html'>Something you do often in an Eclipse RCP application (because it's a &lt;i&gt;client&lt;/i&gt; in some client-server-architecture) is to access a server and do something with a model object. &lt;br /&gt;&lt;br /&gt;For instance, you may have a table view that shows a list of customers, represented by objects of type &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Customer&lt;/span&gt;. (Ok, I know it's a lame example.You're invited to use your imagination, if you'd like to see something more colorful ;-)&lt;br /&gt;&lt;br /&gt;One of the tasks then is to load all customers from the server and put them as input on the table view. Thus your code would look something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; CustomerService service = getCustomerService();&lt;br /&gt;&amp;nbsp; List&amp;lt;Customer&amp;gt; customers = service.loadAllCustomers();&lt;br /&gt;&amp;nbsp; customersTableViewer.setInput( customers );&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;Code growing out of proportion...&amp;nbsp; &lt;/h4&gt;Of course, it's never quite that easy. Normally, a service call is a long-running operation, so the least you can do is to show a busy indicator to the user. But that requires that you put your code in a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Runnable&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; class LoadAllCustomers implements Runnable {&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private List&amp;lt;Customer&amp;gt; serverAccessResult;&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void run() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CustomerService service = getCustomerService();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; serverAccessResult = service.loadAllCustomers();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;Customer&amp;gt; getServerAccessResult() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return serverAccessResult;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; }&lt;/pre&gt;&lt;br /&gt;and then you can say:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; LoadAllCustomers op = new LoadAllCustomers();&lt;br /&gt;&amp;nbsp; BusyIndicator.showWhile( op );&lt;br /&gt;&amp;nbsp; customersTableViewer.setInput( op.getServerAccessResult() );&lt;/pre&gt;&lt;br /&gt;(Of course, you could do that in an anonymous implementation of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Runnable&lt;/span&gt;, but bear with me for a moment, you'll see I've used a slightly more elaborate way for didactic reasons ;-)&lt;br /&gt;&lt;br /&gt;Sometimes, however, you may expect the server call to run even longer, and therefore you want to shift it into the background entirely, so that the user can continue working until the server access results have arrived:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; class LoadAllCustomers extends Job {&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private List&amp;lt;Customer&amp;gt; serverAccessResult;&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; LoadAllCustomers() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; super( "Loading customer data" );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public IStatus run( IProgressMonitor monitor ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CustomerService service = getCustomerService();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; serverAccessResult = service.loadAllCustomers();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  return Status.OK_STATUS;&lt;br /&gt;    }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;Customer&amp;gt; getServerAccessResult() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return serverAccessResult;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; }&lt;/pre&gt;&lt;br /&gt;and then:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; Job job = new LoadAllCustomers();&lt;br /&gt;&amp;nbsp; job.schedule();&lt;/pre&gt;&lt;br /&gt;... ah, just a second. What now? We could wait for the job to finish by calling &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;join()&lt;/span&gt;, but what use would that be? That would destroy the point of putting something into a background job, wouldn't it? So we need a job-changed listener here:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; LoadAllCustomers op = new LoadAllCustomers();&lt;br /&gt;&amp;nbsp; op.addJobChangeListener( new JobChangeAdapter() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void done( IJobChangeEvent event ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; LoadAllCustomers loaderJob = ( LoadAllCustomers )event.getJob();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; customersTableViewer.setInput( loaderJob.getServerAccessResult() );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; } );&lt;br /&gt;&amp;nbsp; op.schedule();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Looks good? No, still no joy: this listener will be called from a thread outside the UI thread, and this will cause an invalid thread access. So this is getting more complicated-looking by the minute:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; LoadAllCustomers op = new LoadAllCustomers();&lt;br /&gt;&amp;nbsp; op.addJobChangeListener( new IJobChangeListener() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void done( IJobChangeEvent event ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; LoadAllCustomers loaderJob = ( LoadAllCustomers )event.getJob();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Display.getDefault().asyncExec( new Runnable() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void run() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; customersTableViewer.setInput( loaderJob.getServerAccessResult() );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; } );&lt;br /&gt;&amp;nbsp; op.schedule();&lt;/pre&gt;&lt;br /&gt;(Of course, not to mention any error handling you also might want to do.)&lt;br /&gt;&lt;br /&gt;To summarize: you basically have the same one or two lines of code, but you sometimes need them as a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Runnable&lt;/span&gt;, sometimes you need them as a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Job&lt;/span&gt;, and you may or may not have to put the follow-up operation in the UI thread. &lt;br /&gt;&lt;br /&gt;&lt;h4&gt;... and cutting it back&lt;/h4&gt;Here's how I like to organize this a little.&lt;br /&gt;&lt;br /&gt;First step: put the server access code for loading all customers and the follow-up code in their own classes.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; class LoadAllCustomers extends Job implements Runnable {&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private List&amp;lt;Customer&amp;gt; serverAccessResult;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; LoadAllCustomers() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; super( "Loading customer data" );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public IStatus run( IProgressMonitor monitor ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; run();&amp;nbsp;&lt;br /&gt;&amp;nbsp;     return Status.OK_STATUS;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void run() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CustomerService service = getCustomerService();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; serverAccessResult = service.loadAllCustomers();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; List getServerAccessResult() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return serverAccessResult;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; class SetInputAfterJobDone extends JobChangeAdapter {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private final Viewer viewer;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SetInputAfterJobDone( Viewer viewer ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.viewer = viewer;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void done( IJobChangeEvent event ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; LoadAllCustomers loaderJob = ( LoadAllCustomers )event.getJob();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; setInputInUIThread( loaderJob.getServerAccessResult() );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private void setInputInUIThread( Object input ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Display.getDefault().asyncExec( new Runnable() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void run() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; viewer.setInput( input );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp; &lt;br /&gt;&amp;nbsp; }&lt;/pre&gt;&lt;br /&gt;(You can see now what I meant by 'didactic reason' a few lines above.)&lt;br /&gt;&lt;br /&gt;You can now use your server access code both as &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Runnable&lt;/span&gt; or as &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Job&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; LoadAllCustomers op = new LoadAllCustomers();&lt;br /&gt;&amp;nbsp; BusyIndicator.showWhile( op );&lt;br /&gt;&amp;nbsp; customersTableViewer.setInput( op.getServerAccessResult() );&lt;/pre&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; LoadAllCustomers op = new LoadAllCustomers();&lt;br /&gt;&amp;nbsp; op.addJobChangeListener( new SetInputAfterJobDone( customersTableViewer ) );&lt;br /&gt;&amp;nbsp; op.schedule();&lt;/pre&gt;&lt;br /&gt;Second, I generally allow a follow-up behavior, if we're running as a job, by adding this method to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;LoadAllCustomers&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; public Job andThen( IJobChangeListener followUpBehavior ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; addJobChangeListener( followUpBehavior );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return this;&lt;br /&gt;&amp;nbsp; }&lt;/pre&gt;&lt;br /&gt;&amp;nbsp; So that I can write more compactly:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; new LoadAllCustomers().andThen( new SetInputAfterJobDone( customersTableViewer ) ).schedule();&lt;/pre&gt;&lt;br /&gt;Finally, pull up some of the common stuff in the server access code, so that you can re-use it for all other sorts of server accesses (like saving customers, querying customer details, and so on):&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; public abstract class ServerAccess&amp;lt;T&amp;gt; extends Job implements Runnable {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private T serverAccessResult;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public ServerAccess( String name ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; super( name );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected IStatus run( IProgressMonitor monitor ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; run();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return Status.OK_STATUS;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public T getServerAccessResult() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return serverAccessResult;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public ServerAccess&amp;lt;T&amp;gt; andThen( IJobChangeListener followUpBehavior ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; addJobChangeListener( followUpBehavior );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return this;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected void setServerAccessResult( T computationResult ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.serverAccessResult = computationResult;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; }&lt;/pre&gt;&lt;br /&gt;Subclasses then merely have to implement the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;run()&lt;/span&gt; method with their own server access logic, and set the result. That should usually be a one-liner, and as you've seen, using these server access objects also normally is. (Correspondingly, generalize &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SetInputAfterJobDone&lt;/span&gt; so that it can cope with &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ServerAccess&lt;/span&gt; objects instead of simple &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Job&lt;/span&gt;s).&lt;br /&gt;&lt;br /&gt;So, here's one exercise left for the interested reader:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&amp;nbsp; new TryItInYourNext( project ).andThen( new GoAndHaveSome( coffee ) ).schedule();&lt;/pre&gt;&lt;br /&gt;Tell me how it worked :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2934352534884921566-6216062979337527816?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/6216062979337527816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/05/how-to-code-with-hedge-trimmer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/6216062979337527816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/6216062979337527816'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/05/how-to-code-with-hedge-trimmer.html' title='How to code with a hedge trimmer'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-3106337488659764857</id><published>2010-05-17T04:10:00.000-07:00</published><updated>2010-05-17T04:10:44.241-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interior design'/><title type='text'>Keep the bar green to keep the code clean II</title><content type='html'>&lt;a href="http://1.bp.blogspot.com/_BynttqNlK3w/S_Ejz0E2akI/AAAAAAAAAQ8/PlV4rtANfNU/s1600/green-bar2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_BynttqNlK3w/S_Ejz0E2akI/AAAAAAAAAQ8/PlV4rtANfNU/s320/green-bar2.jpg" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2934352534884921566-3106337488659764857?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/3106337488659764857/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/05/keep-bar-green-to-keep-code-clean-ii.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/3106337488659764857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/3106337488659764857'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/05/keep-bar-green-to-keep-code-clean-ii.html' title='Keep the bar green to keep the code clean II'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_BynttqNlK3w/S_Ejz0E2akI/AAAAAAAAAQ8/PlV4rtANfNU/s72-c/green-bar2.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-7670451989332217025</id><published>2010-05-13T11:34:00.000-07:00</published><updated>2010-05-13T12:18:55.337-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java JFace'/><title type='text'>Extracting something from a selection</title><content type='html'>&lt;span style="font-family:arial;"&gt;That's a somewhat tedious task in JFace programming: you receive an object that represents the selection on a tree or table viewer; the selection object is of type &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;ISelection&lt;/span&gt;&lt;span style="font-family:arial;"&gt; (a JFace interface), but that means it &lt;/span&gt;&lt;span style="font-style: italic;font-family:arial;" &gt;could&lt;/span&gt;&lt;span style="font-family:arial;"&gt; be either an &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;IStructuredSelection&lt;/span&gt;&lt;span style="font-family:arial;"&gt; (one or more elements from a tree, table or list) or an &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;ITextSelection&lt;/span&gt;&lt;span style="font-family:arial;"&gt; (some text marked in a text editor); thus you need to check the subtype of &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;ISelection&lt;/span&gt;&lt;span style="font-family:arial;"&gt; first, then you have to check whether the selection is empty, then you can get the first element (for it might be a multi-selection, too), then you have to cast that into the correct type. All in all, you often end up with something long-winded like this:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;selectionService.addPostSelectionListener( new ISelectionListener() {&lt;br /&gt;  public void selectionChanged( IWorkbenchPart part, ISelection selection ) {&lt;br /&gt;    if( selection instanceof IStructuredSelection &amp;amp;&amp;amp; !selection.isEmpty() ) {&lt;br /&gt;      IStructuredSelection strusel = (IStructuredSelection)selection;&lt;br /&gt;      Object element = strusel.getFirstElement();&lt;br /&gt;      if( element instanceof MyCoolType ) {&lt;br /&gt;        MyCoolType coolThing = (MyCoolType)element;&lt;br /&gt;        // ... and now we finally can do something with the cool thing&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;} );&lt;br /&gt;&lt;/pre&gt;And you think: oh well, shouldn't this be a little easier to do?&lt;br /&gt;&lt;br /&gt;You are right to ask that question. Here's one way to do it a little more elegantly:&lt;br /&gt;&lt;pre class="brush: java"&gt;public void selectionChanged( IWorkbenchPart part, ISelection selection ) {&lt;br /&gt;  MyCoolType coolThing = new ElementFrom( selection ).as( MyCoolType.class );&lt;br /&gt;  // ... now do something with coolThing already&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;And this would be the implementation of the &lt;code&gt;ElementFrom&lt;/code&gt; utility:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;/** Extract the first element (if any) from a JFace selection, in a type-safe&lt;br /&gt;  * manner.&lt;br /&gt;  */&lt;br /&gt;public class ElementFrom {&lt;br /&gt;&lt;br /&gt;  private final ISelection selection;&lt;br /&gt;&lt;br /&gt;  /** constructs a new extraction operation.&lt;br /&gt;   *&lt;br /&gt;   * @param selection a JFace selection object from which to extract the&lt;br /&gt;   * selected element. Can be &lt;code&gt;null&lt;/code&gt;, in which case this extraction&lt;br /&gt;   * operation yields &lt;code&gt;null&lt;/code&gt;.&lt;br /&gt;   */&lt;br /&gt;  public ElementFrom( ISelection selection ) {&lt;br /&gt;    this.selection = selection;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /** retrieves the extracted element typed as specified.&lt;br /&gt;   *&lt;br /&gt;   * @param cls the class representing the expected type of the extracted element.&lt;br /&gt;   *            Must not be &lt;code&gt;null&lt;/code&gt;. &lt;br /&gt;   * @param &lt;t&gt; the expected type of the extracted element.&lt;br /&gt;   * @return    the element under the expected type, or &lt;code&gt;null&lt;/code&gt;&lt;br /&gt;   */&lt;br /&gt;  public &lt;t&gt; T as( Class&lt;t&gt; cls ) {&lt;br /&gt;    return extractElement( cls );&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private &lt;t&gt; T extractElement( Class&lt;t&gt; cls ) {&lt;br /&gt;    T result = null;&lt;br /&gt;    if( selectionIsGood() ) {&lt;br /&gt;      IStructuredSelection strusel = (IStructuredSelection)selection;&lt;br /&gt;      Object element = strusel.getFirstElement();&lt;br /&gt;      if( elementTypeIsGood( element, cls ) ) {&lt;br /&gt;        result = cls.cast( element );&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return result;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private &lt;t&gt; boolean elementTypeIsGood( Object element, Class&lt;t&gt; cls ) {&lt;br /&gt;    return cls.isAssignableFrom( element.getClass() );&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private boolean selectionIsGood() {&lt;br /&gt;    return selection instanceof IStructuredSelection &amp;amp;&amp;amp; !selection.isEmpty();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Have fun :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2934352534884921566-7670451989332217025?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/7670451989332217025/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/05/extracting-something-from-selection.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/7670451989332217025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/7670451989332217025'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/05/extracting-something-from-selection.html' title='Extracting something from a selection'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-5190329613420539135</id><published>2010-05-05T12:51:00.000-07:00</published><updated>2010-05-05T14:00:52.591-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse IDE'/><category scheme='http://www.blogger.com/atom/ns#' term='Usus'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Usus 0.4 preview build available</title><content type='html'>Just a brief update about what's going on at the Usus front: there is a new preview build of Usus available at &lt;a href="http://projectusus.org/"&gt;projectusus.org&lt;/a&gt; — you can get it as usual from the update site (look &lt;a href="http://code.google.com/p/projectusus/wiki/InstallationInstructions"&gt;here&lt;/a&gt; for install instructions). This one includes now improved ACD computation and packages in cycles as a new metric.&lt;br /&gt;&lt;br /&gt;In other news, today &lt;a href="http://it-republik.de/konferenzen/jax2010/speaker/#4941"&gt;Nicole&lt;/a&gt; and &lt;a href="http://it-republik.de/konferenzen/jax2010/speaker/#4942"&gt;Andreas&lt;/a&gt; gave a &lt;a href="http://it-republik.de/konferenzen/ext_scripts/v2/php/sessions-popup.php?module=jax2010&amp;amp;id=13829"&gt;talk&lt;/a&gt; about Usus at the 'Eclipse Tools Day' track at JAX 2010, the big Java Enterprise conference in Wiesbaden. If you were there, you've seen the new version first-hand :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2934352534884921566-5190329613420539135?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/5190329613420539135/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/05/usus-04-preview-build-available.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/5190329613420539135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/5190329613420539135'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/05/usus-04-preview-build-available.html' title='Usus 0.4 preview build available'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-7281616202053985061</id><published>2010-04-01T15:33:00.000-07:00</published><updated>2010-04-01T15:35:28.391-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Scrum'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Ken Schwaber at the Entwicklertag in Karlsruhe, June 21st-25th</title><content type='html'>There will be quite some highlight at the Entwicklertag this year with Ken Schwaber's keynote, panel discussions and &lt;i&gt;Scrum in Depth&lt;/i&gt; course:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.andrena.de/ken-schwaber-kommt"&gt;http://www.andrena.de/ken-schwaber-kommt&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Don't be late to register (and stay tuned, there will be more Entwicklertag news soon :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2934352534884921566-7281616202053985061?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/7281616202053985061/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/04/ken-schwaber-at-entwicklertag-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/7281616202053985061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/7281616202053985061'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/04/ken-schwaber-at-entwicklertag-in.html' title='Ken Schwaber at the Entwicklertag in Karlsruhe, June 21st-25th'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-6510946032708828228</id><published>2010-03-01T03:25:00.000-08:00</published><updated>2010-03-01T13:31:10.645-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='documentation'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='values'/><title type='text'>Documentation and the philosophical distinction between memory and reminiscence</title><content type='html'>The title of this blog, and the 'About' text about the parallels between life in general and coding specifically, aren't just meant as a feuilletonistic nicety. Over the past years I have reflected occasionally about both my job as a software programmer and development coach, and about philosophy (especially ancient ethics); and I've noticed connections between these two fields again and again. So my goals for this blog include exploring those parallels; today I want to try and get started with one such exploration. I'll introduce you to a thought I recently came across, and then link it with the analogies I see in our profession.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1)&lt;/b&gt; At her thoughtful and scientifically well-informed &lt;a href="http://mnemosynosis.livejournal.com/"&gt;blog on the philosophy of memory&lt;/a&gt;, Susannah Kate Devitt writes: "I'm fascinated by the degree of information we record about our lives today and the issues around what use such records will play in our lives at a later stage of life. Perhaps we spend too much time documenting our lives and not enough time improving our abilities to live them."[1]&lt;br /&gt;&lt;br /&gt;The line of thought that leads to this general statement is about the distinction between memory and reminiscence, as it is made in ancient philosophy. &lt;font style="font-weight: bold; font-style: italic;"&gt;Memory&lt;/font&gt;, on the one hand, is seen as a mental function that is useful in gaining &lt;i&gt;knowledge&lt;/i&gt;: it enables you to think independently, to understand complex arguments and examine them for their truth or falsity, and to teach your insights successfully to others. &lt;font style="font-weight: bold; font-style: italic;"&gt;Reminiscence&lt;/font&gt;, on the other hand, is a mere replay of something you've experienced, and there is nothing really to gain from it — it's good for some amusement at best.&lt;br /&gt;&lt;br /&gt;One notable thing about the distinction between memory and reminiscence is that it isn't just descriptive: it's not only that a difference is made between two functions of the mind; they are not simply neutrally described as we find them in people. On the contrary, there is a &lt;font style="font-style: italic;"&gt;normative dimension&lt;/font&gt; here. The two functions are examined with respect to their &lt;i&gt;value&lt;/i&gt;. It is made very clear that striving for knowledge is a good thing for us, while indulging in reminiscence isn't what a well-oriented person would sensibly do with her time.[2]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2)&lt;/b&gt; Let's now turn to the question of 'documenting our lives' and 'our abilities to live them' in the quote above. It is an important element of ancient ethics that your ability to live your life generally improves with the skills and knowledge that you gain from exercising your rational capacities: you become more successful by using reason and good sense. The two functions discussed here are then easily classified: memory would help you in living your life well, while reminiscence doesn't repay the time you're investing in it. (In fact, that is what &lt;i&gt;makes&lt;/i&gt; them good or bad respectively.) Apply this to our habit of recording experiences in our lives: the mere documentation of what happened, the heaping of images, audio and video clips, status updates, tweets and diggs (and what have you), won't contribute much to the success of your life, because they have no potential for growth and development — they're mere pictures, they're mirroring what happens in your life, but nothing substantial can be built on them. Real memory is about &lt;i&gt;insight&lt;/i&gt; into what happened as much as it is about re-presenting it; it's about learning from it, it connects your present actions, thoughts and feelings with those past experiences. And we are perhaps not putting much effort  into that.&lt;br /&gt;&lt;br /&gt;Once more, stating this isn't just about describing what happens. It is evaluative: that means it's about finding out what's good and what's bad to do — or, to put it less dramatically, it's about deciding what to do with your time, how to invest it wisely.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3)&lt;/b&gt; I've elaborated this line of thought in the hope that it makes some intuitive sense to you; it may seem rather 'philosophical' at first glance. And of course, that's exactly what it is. But that doesn't make it irrelevant; it also doesn't make it a topic that we may only think about in moments of reflection (which some people seem to picture as relaxed and calm situations involving an armchair and a bottle of wine). On the contrary, thinking about these things is perhaps the single most important activity there is in our lives. (I'm not going to argue for this claim here; it would take way too much space. But think about it for a moment: if you don't reflect about these topics, how would you know that you're investing your time well, the time of that single life that you've got? Are you steering &lt;i&gt;your own&lt;/i&gt; course or are you merely on automatic pilot, as programmed by your environment, your childhood experiences, the suggestions you receive from the media, and other such influences?)&lt;br /&gt;&lt;br /&gt;But my goal is to draw some connections between these reflections and similar issues we find in software projects. Let's change over into that area now.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4)&lt;/b&gt; In the quote I gave above, the word that captured my attention was of course 'documenting'. If you have spent some time in a software project, that is a topic you will likely have come across; and probably you have encountered a good deal of controversy around it. Documentation has been an undue favorite with many managers and process designers in the past, and there has been a powerful counter-movement in the agile community, which even made it a core value of its practice that "working software is more valuable than comprehensive documentation."[3]&lt;br /&gt;&lt;br /&gt;(However, notice that this is about &lt;i&gt;business value&lt;/i&gt;; you have to read it this way: "For our customers, we believe that working software has a higher business value than extensive documentation". So there is a slightly different concept of value involved here than the one I've used above in section 1).)&lt;br /&gt;&lt;br /&gt;Before I start outlining a parallel between the philosophical distinctions in memory and the area of software documentation, I want to put aside some uses of 'documentation' in that area which I don't have in mind here. One is &lt;i&gt;&lt;b&gt;user documentation&lt;/b&gt;&lt;/i&gt;: the audience for that sort of documentation is end users who work with some released version of a software product, and obviously they have to be taught how to use it. Then there is &lt;i&gt;&lt;b&gt;tracking and reporting&lt;/b&gt;&lt;/i&gt;: as in any other sort of project, software projects need to display, both for people inside the project team and for stakeholders outside it, what the current status is and how the reality of the situation compares to what was planned. Furthermore, information is collected about changes made in technical detail, mostly by means of &lt;b&gt;&lt;i&gt;revision control&lt;/i&gt;&lt;/b&gt; tools: this might be called a form of documentation (in management speak, it is sometimes said that "it is documented who made which change, when, and for what purpose"), but mostly it is merely a kind of backing up snapshots in order to be able to roll back to them when it turns out that some change wasn't a good idea. If used in the latter way, it is a pragmatic tool to support daily work; if used in the former way, it turns into a control instrument typically employed for putting blame somewhere (or for pre-empting blame).&lt;br /&gt;&lt;br /&gt;In contrast to these, the concept of documentation that I have primarily in mind here is &lt;i&gt;technical documentation&lt;/i&gt;, as it is for example introduced in the &lt;a href="http://en.wikipedia.org/wiki/Software_documentation#Technical_documentation"&gt;Wikipedia article on software documentation&lt;/a&gt;: "When creating software, code alone is insufficient. There must be some text along with it to describe various aspects of its intended operation."&lt;br /&gt;&lt;br /&gt;We have to unpack this claim first before we can discuss it.&lt;br /&gt;&lt;br /&gt;When developers are working on a software product, i.e. when they extend its functionality (or implement it in the first place), fix program errors or clean up its internal structure (a process known as 'refactoring'), they know how to deal with the source code: they know which passages to look at, they know which consequences a change in the code may have, and so on. Thus in an ongoing software project, besides the code itself there is vital information sedimented in the skills and knowledge of the developers. That is why it would not do to replace these people with others (even if equally educated), at least not without allowing for a period of orientation and training. When the Wikipedia article claims that the actual code alone is not enough, it is that extra information which it refers to. However, instead of directly talking about it as &lt;i&gt;skills and knowledge&lt;/i&gt; (something that would be attributed to people), it assumes that it can be codified, just as the source code is, in additional &lt;i&gt;text&lt;/i&gt; (i.e. it assumes that there is a largely context-independent format, perhaps prose or one of various visualization formats, which can capture this sort of knowledge). More precisely, then, the claim of the Wikipedia article, when made fully explicit, is something like this:&lt;br /&gt;&lt;pre&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;&lt;font style="font-weight: bold;"&gt;i)&lt;/font&gt; Software creation requires both&lt;br /&gt; &lt;font style="font-weight: bold;"&gt;a)&lt;/font&gt; code&lt;br /&gt; &lt;font style="font-weight: bold;"&gt;b)&lt;/font&gt; skills and knowledge with the developers who &lt;br /&gt;    create and work with the code.&lt;br /&gt;&lt;font style="font-weight: bold;"&gt;ii)&lt;/font&gt; These skills and knowledge can be codified &lt;br /&gt;    in text.&lt;br /&gt;&lt;font style="font-weight: bold;"&gt;iii)&lt;/font&gt; It is not only possible, but also necessary&lt;br /&gt;     for software creation to codify these skills and knowledge &lt;br /&gt;     in text.&lt;br /&gt;&lt;font style="font-weight: bold;"&gt;Therefore:&lt;/font&gt; "When creating software, code alone &lt;br /&gt;          is insufficient.&lt;br /&gt;          There must be some text along with it [...]".&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;It is not obvious why we should accept premises ii) and iii), though. (Not obvious, at any rate, from the cited Wikipedia article; and to be sure, both these premises are contentious, to say the least, in recent discussions. It's not my goal in this article to argue for or against them. But it should be clear already from my formulation that they are not self-evident once made explicit; it would take some argument to make them acceptable, and thus make the overall claim sustainable.)[4]&lt;br /&gt;&lt;br /&gt;Technical documentation, in the discussed sense, is an attempt to externalize the competence of the developers currently working on the code. It takes many forms, including code annotations (e.g. in the well-known doxygen or javadoc formats), class design or control flow diagrams, verbal descriptions of module responsibilities, explanations of intentions behind design and architecture decisions, and more. The objective is to record something that is present in skills and knowledge, in order to re-use those records, later on, with the purpose of re-instating such skills and knowledge.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;5)&lt;/b&gt; We are now in a position to see the connection between this and the philosophical distinction made earlier. We might say that documentation is for a software product what memory is for people; and our ability to carry out software projects depends on skills and knowledge in a similar way as our ability to live our lives well does. (Although obviously we're talking about two different sets of skills and knowledge here &amp;mdash; I'm just pointing out an analogy.) But from the philosophical discussion above we can learn that there are two different sorts of recording the past: one that has a constructive role in our personal development and therefore contributes to our ability to live our lives well, and one that is just a waste of time and energy. In the discussion above, these were called 'memory' and 'reminiscence' respectively.&lt;br /&gt;&lt;br /&gt;If we read 'documentation' for 'reminiscence', we might rewrite the quote I gave above, with respect to software development: "There's such a high amount of information we record about our product; and so much discussion about the use such records will play in our work at a later time. Perhaps we spend too much time documenting our software and not enough time improving our abilities to work with it." Have you ever had a thought like this in one of the projects you were working in?&lt;br /&gt;&lt;br /&gt;Just as genuine memory builds the knowledge required to live your life successfully, and reminiscence doesn't do that for you, there are also two ways of preserving technical information in the software world: one that builds the knowledge and competence required to work successfully on your software, and one that doesn't. Consequently, it's not enough to just write down what you know somehow: you have to find a better way than that. That way will certainly have to do with building skills and gathering insight about what you're doing (and how well it works); it won't be easily externalized or formalized, however. In other words, it won't resemble 'documentation', it will rather be like a constant learning process, an&lt;br /&gt;exercise in self-examination. &lt;br /&gt;&lt;br /&gt;In contrast with the attitude from the agile movement that I quoted above, however, this insight doesn't stem from the goal of maximizing business value. It comes from a totally different way of looking at things, one that connects with more fundamental principles.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;6)&lt;/b&gt; Sometimes things that look alike are really different; by bringing conceptual distinctions to the fore, philosophy can teach us to see the differences, and that's especially important if the things in question aren't simply different in themselves, but also have different &lt;i&gt;values&lt;/i&gt;, that is, if they are more or less good or bad for us. Insofar as philosophy helps us to make the necessary distinctions, it improves our abilities to deal with things, and be more successful &amp;mdash; be it in living our lives in general, or simply in a more restricted field, such as developing software. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font style="font-weight: bold;"&gt;References&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;[1] &lt;a href="http://mnemosynosis.livejournal.com/28724.html"&gt;http://mnemosynosis.livejournal.com/28724.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;[2] The text quoted by Devitt is Plato's &lt;i&gt;Phaedrus&lt;/i&gt;, at 274c-275b; Plato makes this contrast rather sharply and is more severe than most other ancient authors. The harsh judgment isn't restricted to ancient writing, though. It can equally be found in contemporary aesthetics. For instance, there is a similarly decided, and judgmental, formulation of an analogous point in Roger Scruton's &lt;i&gt;Beauty&lt;/i&gt;, in the section about fantasy vs. imagination. See Scruton, &lt;i&gt;Beauty&lt;/i&gt;, Oxford UP, 2009,  ch. 5 on 'Artistic Beauty'.&lt;br /&gt;&lt;br /&gt;[3] As expressed in the Agile Manifesto; &lt;a href="http://agilemanifesto.org/"&gt;http://agilemanifesto.org&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;[4] The Wikipedia article emphatically notes several times how important it is to have technical documentation in the discussed sense; however, insisting that something is in your view important is not the same as demonstrating that it is true.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2934352534884921566-6510946032708828228?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/6510946032708828228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/03/documentation-and-philosophical.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/6510946032708828228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/6510946032708828228'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/03/documentation-and-philosophical.html' title='Documentation and the philosophical distinction between memory and reminiscence'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-8055710722847346383</id><published>2010-02-24T11:21:00.000-08:00</published><updated>2010-02-24T11:23:55.227-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interior design'/><title type='text'>Keep the bar green to keep the code clean</title><content type='html'>&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_BynttqNlK3w/S4V8aoWFXwI/AAAAAAAAAQI/9jB2d7_reTc/s1600-h/green-bar.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 303px; height: 238px;" src="http://3.bp.blogspot.com/_BynttqNlK3w/S4V8aoWFXwI/AAAAAAAAAQI/9jB2d7_reTc/s320/green-bar.jpg" alt="" id="BLOGGER_PHOTO_ID_5441892521695600386" border="0" /&gt;&lt;/a&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/2934352534884921566-8055710722847346383?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/8055710722847346383/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/02/keep-bar-green-to-keep-code-clean.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/8055710722847346383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/8055710722847346383'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/02/keep-bar-green-to-keep-code-clean.html' title='Keep the bar green to keep the code clean'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_BynttqNlK3w/S4V8aoWFXwI/AAAAAAAAAQI/9jB2d7_reTc/s72-c/green-bar.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-8937903453131264863</id><published>2010-02-15T04:37:00.000-08:00</published><updated>2010-02-15T12:34:53.442-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JDT'/><category scheme='http://www.blogger.com/atom/ns#' term='Refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse IDE'/><category scheme='http://www.blogger.com/atom/ns#' term='Usus'/><title type='text'>A rose by any other name...</title><content type='html'>Some years ago when I &lt;a href="http://www.eclipse.org/articles/Article-LTK/ltk.html"&gt;wrote about Eclipse's APIs for supporting automated refactorings&lt;/a&gt;, it wasn't all too convenient to drive an existing JDT refactoring from your own plug-in. For instance, if you had an &lt;span style="font-family:courier new;"&gt;IField&lt;/span&gt; or an &lt;span style="font-family:courier new;"&gt;IMethod&lt;/span&gt; in your hands (one of JDT's Java language model objects), you couldn't simply call some API methods to rename that thing (field or method). You had to write quite a bit of code, and it was still difficult to avoid Eclipse presenting your refactoring in the standard wizard dialog. A few days ago I was playing around with a new fun feature in Usus (I'm not telling what it is :-) — and I found it much more convenient to do such a thing nowadays.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;How you do it&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;The central object that represents a refactoring procedure is the Language Toolkit's &lt;span style="font-family:courier new;"&gt;Refactoring&lt;/span&gt; (unsurprisingly). If you want to use an existing automated refactoring, such as &lt;span style="font-weight: bold; font-style: italic;"&gt;Rename field&lt;/span&gt; or &lt;span style="font-weight: bold; font-style: italic;"&gt;Extract method&lt;/span&gt; from the JDT pool, your first step is to retrieve an object that conforms to the &lt;span style="font-family:courier new;"&gt;Refactoring&lt;/span&gt; contract.&lt;br /&gt;&lt;br /&gt;You get one of these guys from the refactoring core plugin: first, add a plug-in dependency to &lt;span style="font-family:courier new;"&gt;org.eclipse.ltk.core.refactoring&lt;/span&gt;. You can then call the static factory method &lt;span style="font-family:courier new;"&gt;RefactoringCore.getRefactoringContribution( String id )&lt;/span&gt;in order to retrieve a refactoring contribution, i.e. an automated refactoring that was contributed from some plug-in via an extension in the &lt;span style="font-family:courier new;"&gt;plugin.xml&lt;/span&gt;. For this you need to know the ID of that refactoring contribution. In the case of the JDT refactorings, use the constants in &lt;span style="font-family:courier new;"&gt;IJavaRefactorings&lt;/span&gt; (add a dependency to &lt;span style="font-family:courier new;"&gt;org.eclipse.jdt.core.manipulation&lt;/span&gt;). You can now feed the refactoring contribution with the parameters it needs; in the case of a &lt;span style="font-weight: bold; font-style: italic;"&gt;Rename Method &lt;/span&gt;refactoring, for instance, that would be the &lt;span style="font-family:courier new;"&gt;IMethod&lt;/span&gt; object that represents the method we want to rename, and the new name we to give to it. Having done that, we can ask the contribution to create the &lt;span style="font-family:courier new;"&gt;Refactoring&lt;/span&gt; object for us. In sum, you'd do something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-size:78%;"&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="font-weight: bold;"&gt;private&lt;/span&gt; Refactoring mkRefactoring( RefactoringStatus status, IMethod methodToRename, String newName ) &lt;span style="font-weight: bold;"&gt;throws&lt;/span&gt; CoreException {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        RenameJavaElementDescriptor desc = loadDescriptor();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        desc.setJavaElement( methodToRename );&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        desc.setNewName( newName );&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;return&lt;/span&gt; desc.createRefactoring( status );&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="font-weight: bold;"&gt;private&lt;/span&gt; RenameJavaElementDescriptor loadDescriptor() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        String id = IJavaRefactorings.RENAME_METHOD;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        RefactoringContribution contrib = RefactoringCore.getRefactoringContribution( id );&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;return&lt;/span&gt; (RenameJavaElementDescriptor)contrib.createDescriptor();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see, I'm passing a &lt;span style="font-family:courier new;"&gt;RefactoringStatus&lt;/span&gt; object into the creation operation. That object will contain the result of the creation (which might be an &lt;span style="font-family:courier new;"&gt;OK&lt;/span&gt; or some error status).&lt;br /&gt;&lt;br /&gt;Once you are in possession of a refactoring object, you might run in it the standard refactoring dialog (in order to be nice to the user and present them with a preview and the cancel option), or you could extract the &lt;span style="font-family:courier new;"&gt;Change&lt;/span&gt; objects from it and just ask them to perform their work. All in all, a quick test drive of a Rename Method refactoring might be something along these lines:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-size:78%;"&gt;&lt;span style="font-family:courier new;"&gt;            RefactoringStatus status = &lt;span style="font-weight: bold;"&gt;new&lt;/span&gt; RefactoringStatus();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            Refactoring refactoring = mkRefactoring( status, methodToRename, newName );&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            &lt;span style="font-weight: bold;"&gt;if&lt;/span&gt;( status.isOK() ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                &lt;span style="font-weight: bold;"&gt;if&lt;/span&gt;( refactoring.checkAllConditions( nullMonitor() ).isOK() ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                    Change change = refactoring.createChange( nullMonitor() );&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                    change.perform( nullMonitor() );&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            }&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 51, 0);"&gt;    // ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;    private IProgressMonitor nullMonitor() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        return new NullProgressMonitor();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;A word to the wise&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Obviously, there are many aspects you want to consider if you try this in production code (are there editors open which you'll want to save? what about undo operations? do you want to support the local history? ...). You might want to look at the JDT code more in depth in order to find out how to handle these things. (That's something I didn't because I merely wanted to play around with them.) Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2934352534884921566-8937903453131264863?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/8937903453131264863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/02/rose-by-any-other-name.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/8937903453131264863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/8937903453131264863'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/02/rose-by-any-other-name.html' title='A rose by any other name...'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-7160733949850087972</id><published>2010-02-08T14:29:00.000-08:00</published><updated>2010-02-08T15:45:01.105-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Usus'/><title type='text'>Elegantification is possible even in Java</title><content type='html'>Sometimes it's the small things that make you smile. (That's so. Sometimes at least ;-)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;The unfavorable situation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the &lt;a href="http://projectusus.org/"&gt;Usus&lt;/a&gt; UI, we have several tables displaying code proportions information, and in order to simplify the code that configures such a table, we have a common &lt;span style="font-family:courier new;"&gt;TreeViewer&lt;/span&gt; that reads column information from an enum, where each of the enum's elements represents a table column and its meta data, such as the header string, the column weight and the text alignment in the column's cells. Thus, the table description for the Usus Cockpit view looked like this:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:78%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span&gt;&lt;pre&gt;&lt;span style="font-weight: bold;"&gt;enum&lt;/span&gt; CockpitColumnDesc &lt;span style="font-weight: bold;"&gt;implements&lt;/span&gt; IColumnDesc&lt;codeproportion&gt; {&lt;/codeproportion&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    INDICATOR( &lt;span style="color: rgb(102, 51, 0);"&gt;"Indicator"&lt;/span&gt;, LEFT, 56, &lt;span style="font-weight: bold;"&gt;true&lt;/span&gt; ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;public&lt;/span&gt; String getLabel( CodeProportion element ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            &lt;span style="font-weight: bold;"&gt;return&lt;/span&gt; element.getMetric().getLabel();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    },&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    SQI( &lt;span style="color: rgb(102, 51, 0);"&gt;"SQI"&lt;/span&gt;, 10, &lt;span style="font-weight: bold;"&gt;false&lt;/span&gt; ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;public&lt;/span&gt; String getLabel( CodeProportion element ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 51, 0);font-family:courier new;" &gt;            &lt;/span&gt;&lt;span style="color: rgb(0, 51, 0);"&gt;// ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    },&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 51, 0);font-family:courier new;" &gt;    // ... more enum fields&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="font-weight: bold;"&gt;private final&lt;/span&gt; String headLabel;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="font-weight: bold;"&gt;private final int&lt;/span&gt; weight;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="font-weight: bold;"&gt;private final boolean&lt;/span&gt; hasImage;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    CockpitColumnDesc( String headLabel, ColumnAlignment align, &lt;span style="font-weight: bold;"&gt;int&lt;/span&gt; weight, &lt;span style="font-weight: bold;"&gt;boolean&lt;/span&gt; hasImage ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;this&lt;/span&gt;.headLabel = headLabel;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;this&lt;/span&gt;.align = align;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;this&lt;/span&gt;.weight = weight;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;this&lt;/span&gt;.hasImage = hasImage;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    CockpitColumnDesc( String headLabel, &lt;span style="font-weight: bold;"&gt;int&lt;/span&gt; weight, &lt;span style="font-weight: bold;"&gt;boolean&lt;/span&gt; hasImage ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;this&lt;/span&gt;( headLabel, RIGHT, weight, hasImage );&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="font-weight: bold;"&gt;public int&lt;/span&gt; getWeight() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;return&lt;/span&gt; weight;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="font-weight: bold;"&gt;public&lt;/span&gt; String getHeadLabel() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;return&lt;/span&gt; headLabel;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 51, 0);font-family:courier new;" &gt;    // ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;/blockquote&gt;Now, having about a dozen or so column description enums like this, it became a little unwieldy to add more column information (such as the alignment, i.e. LEFT, RIGHT or CENTER). Each of the enums needed another field that kept the alignment, a getter and another constructor if a sensible default value was to apply. In other words, in order to add alignment information, we still had to write a bunch of code lines into each of the enums (that is, a bunch of code lines that was practically identical for each of them). That looked unelegant to me. The elegant solution was to use a custom annotation type.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Making it look nicer&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Annotations are normally used to attach meta data to language elements (classes, methods, fields), so that development tools can read them and do something sensible with the information. For instance, the well-known &lt;span style="font-family:courier new;"&gt;@SuppressWarnings&lt;/span&gt; annotation, when put above a method declaration, tells the Java compiler to shup up about some thing it might have complained about otherwise. (And gentle reader, you won't be surprised that this feature is misused every so often...)&lt;br /&gt;&lt;br /&gt;On the other hand, you can make annotation information available at runtime, and read it via reflection mechanisms. Let's say you declare a new annotation type:&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:78%;"  &gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style=";font-family:courier new;font-size:78%;"  &gt;&lt;pre&gt;&lt;pre&gt;@Target( value = { ElementType.FIELD } )&lt;br /&gt;@Retention( RetentionPolicy.RUNTIME )&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;public @interface&lt;/span&gt; UsusTreeColumn {&lt;br /&gt;String header() &lt;span style="font-weight: bold;"&gt;default&lt;/span&gt; &lt;span style="color: rgb(102, 51, 0);"&gt;""&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 51, 0);"&gt;   // column weight (percentage of overall width in the table that this column takes)&lt;/span&gt;&lt;br /&gt;int weight() &lt;span style="font-weight: bold;"&gt;default&lt;/span&gt; 5;&lt;br /&gt;&lt;br /&gt;ColumnAlignment align() &lt;span style="font-weight: bold;"&gt;default&lt;/span&gt; ColumnAlignment.LEFT;&lt;br /&gt;&lt;br /&gt;}&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/blockquote&gt;The bit about the &lt;span style="font-family:courier new;"&gt;RetentionPolicy&lt;/span&gt; tells the compiler to include the annotation information in the compiled code, so that it can be loaded at runtime. If someone uses your annotation like so:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:78%;"&gt;&lt;span style="font-family:courier new;"&gt;    &lt;pre&gt;@UsusTreeColumn( header =&lt;span style="color: rgb(102, 51, 0);"&gt; "SQI"&lt;/span&gt;, align = RIGHT, weight = 10 )&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    SQI( &lt;span style="font-weight: bold;"&gt;false&lt;/span&gt; ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;public&lt;/span&gt; String getLabel( CodeProportion element ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 51, 0);font-family:courier new;" &gt;            // ...&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-size:100%;"&gt;you can reach the info in the annotation this way:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;/span&gt;&lt;span style=";font-family:courier new;font-size:78%;"  &gt;&lt;pre&gt;        &lt;span style="font-weight: bold;"&gt;try&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            Field field = loadField( &lt;/span&gt;&lt;span style="color: rgb(102, 51, 0);font-family:courier new;" &gt;"SQI"&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; );&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;for&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;( Annotation annotation : field.getAnnotations() ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                &lt;span style="font-weight: bold;"&gt;if&lt;/span&gt;( annotation &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;instanceof&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; UsusTreeColumn ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                    UsusTreeColumn column = (UsusTreeColumn)annotation;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                    String header = column.header();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                    &lt;/span&gt;&lt;span style="color: rgb(0, 51, 0);font-family:courier new;" &gt;// ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        } &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;catch&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;( NoSuchFieldException nosufex ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 51, 0);font-family:courier new;" &gt;           // ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 51, 0);font-family:courier new;" &gt;    &lt;span style="color: rgb(0, 51, 0);"&gt;// ...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="font-weight: bold;"&gt;private&lt;/span&gt; Field loadField() &lt;span style="font-weight: bold;"&gt;throws&lt;/span&gt; NoSuchFieldException {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        Class enumClass = columnDescEnumValue.getClass();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;if&lt;/span&gt;( enumClass.isAnonymousClass() ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            enumClass = enumClass.getEnclosingClass();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;return&lt;/span&gt; enumClass.getDeclaredField( columnDescEnumValue.toString() );&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;&lt;br /&gt;&lt;/span&gt;Basically, you have to find the language element (in this case a field from the enum type) that has the annotation attached to it, and then &lt;span style="font-family:courier new;"&gt;getAnnotations()&lt;/span&gt; from it. The way you find it is via reflection as usual. Once you have the annotation, you can cast it to the interface type you declared (in this case &lt;span style="font-family:courier new;"&gt;UsusTreeColumn&lt;/span&gt;) and simply use it like any other Java object. In essence, that is what our tree viewer now does. The enums, on the other hand, look compact and much more readable:&lt;span style="font-weight: bold;font-family:courier new;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:78%;"  &gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;&lt;span&gt;&lt;pre&gt;&lt;span style="font-weight: bold;"&gt;enum&lt;/span&gt; CockpitColumnDesc &lt;span style="font-weight: bold;"&gt;implements&lt;/span&gt; IColumnDesc&lt;codeproportion&gt; {&lt;/codeproportion&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    @UsusTreeColumn( header = &lt;span style="color: rgb(102, 51, 0);"&gt;"Indicator"&lt;/span&gt;, weight = 56 )&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    INDICATOR( &lt;span style="font-weight: bold;"&gt;true&lt;/span&gt; ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;public&lt;/span&gt; String getLabel( CodeProportion element ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            &lt;span style="font-weight: bold;"&gt;return&lt;/span&gt; element.getMetric().getLabel();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    },&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    @UsusTreeColumn( header = &lt;span style="color: rgb(102, 51, 0);"&gt;"SQI"&lt;/span&gt;, align = RIGHT, weight = 10 )&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    SQI( &lt;span style="font-weight: bold;"&gt;false&lt;/span&gt; ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;public&lt;/span&gt; String getLabel( CodeProportion element ) {&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: rgb(0, 51, 0);"&gt; // ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 51, 0);"&gt;    // ...&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="font-weight: bold;"&gt;private final boolean&lt;/span&gt; hasImage;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    CockpitColumnDesc( &lt;span style="font-weight: bold;"&gt;boolean&lt;/span&gt; hasImage ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;this&lt;/span&gt;.hasImage = hasImage;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;boolean&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;hasImage() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;span style="font-weight: bold;"&gt;return&lt;/span&gt; hasImage;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;Most of the information is compressed in the annotations, though it is still well compiler-checked; and sensible defaults can be used, so that we can leave out parameters in the annotations if we like. (The code for all the enums that describe columns in the Usus UI is now less than half that it was before. Not that code size reduction is everything that matters — but since the new code brings the same information in a much more compact notation, it's really more readable now.)&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2934352534884921566-7160733949850087972?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/7160733949850087972/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/02/elegantification-is-possible-even-in.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/7160733949850087972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/7160733949850087972'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/02/elegantification-is-possible-even-in.html' title='Elegantification is possible even in Java'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-7812163032351882493</id><published>2010-01-29T06:54:00.000-08:00</published><updated>2010-01-30T07:16:13.399-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse IDE'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>Getting started with Haskell in Eclipse</title><content type='html'>If you just want to play around with Haskell a little, you can quickly get started by just installing &lt;a href="http://haskell.org/ghc" target="_blank"&gt;GHC&lt;/a&gt; and using a basic text editor. But what if you, like me, tend to put everything neatly into some Eclipse workspace? Well, here's what you need.&lt;p&gt;(I'm describing this for the Mac. Windows users will need some imagination ;-)&lt;/p&gt;&lt;h4&gt;Install the Haskell Platform&lt;/h4&gt;First, you need the basic Haskell platform, consisting of GHC, the Haskell compiler, and the standard libraries. You can download the platform from &lt;a href="http://hackage.haskell.org/platform/" target="_blank"&gt;http://hackage.haskell.org/platform/&lt;/a&gt; It comes with a neat installer and brings pretty much everything required to get started.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_BynttqNlK3w/S2RLODK7xiI/AAAAAAAAANw/c7f8ujEb3lQ/s1600-h/haskell-platform.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 467px; height: 247px;" src="http://2.bp.blogspot.com/_BynttqNlK3w/S2RLODK7xiI/AAAAAAAAANw/c7f8ujEb3lQ/s320/haskell-platform.jpg" alt="" id="BLOGGER_PHOTO_ID_5432549755257079330" border="0" /&gt;&lt;/a&gt;&lt;h4&gt;Get the Eclipse Plug-In&lt;/h4&gt;&lt;p&gt;&lt;a href="http://eclipsefp.sf.net/" target="_blank"&gt;EclipseFP&lt;/a&gt;, the plug-in that provides Haskell development support in Eclipse, can be installed from its &lt;strong&gt;update site at http://eclipsefp.sf.net/updates&lt;/strong&gt;. Choose version &lt;strong&gt;1.109.0&lt;/strong&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_BynttqNlK3w/S2RMNGcTnaI/AAAAAAAAAN4/M488QWQMnV4/s1600-h/eclipsefp.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 279px;" src="http://2.bp.blogspot.com/_BynttqNlK3w/S2RMNGcTnaI/AAAAAAAAAN4/M488QWQMnV4/s320/eclipsefp.jpg" alt="" id="BLOGGER_PHOTO_ID_5432550838467009954" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;(Sentimental note: EclipseFP is already a seasoned project, and I'm delighted to see that it is still alive and kicking. After &lt;a href="http://eclipsefp.wordpress.com/" target="_blank"&gt;Thomas ten Cate&lt;/a&gt; worked on it during a Google SoC project last year, it has been maintained and advanced now for some time by J.P. Moresmau. And there's some cool stuff in it now indeed :-)&lt;/p&gt;&lt;br /&gt;&lt;h4&gt;Build the scion server&lt;/h4&gt;&lt;p&gt;In order to function properly, EclipseFP requires an installation of &lt;a href="http://code.google.com/p/scion-lib/" target="_blank"&gt;Scion&lt;/a&gt; on your computer. Scion is a Haskell library that provides common functionality for Haskell development tools and is used in a number of editors and IDEs. &lt;/p&gt;&lt;p&gt;This is the part where it gets interesting, since you have to build scion from source. (EclipseFP needs some of its features that are not yet in the officially released version.) Here's how you do it:&lt;/p&gt;&lt;span style="font-family:courier new;"&gt;Seneca:~ leif$ ghc --version&lt;/span&gt; &lt;span style="font-family:courier new;"&gt;&lt;br /&gt;The Glorious Glasgow Haskell Compilation System, version 6.10.4&lt;/span&gt; &lt;span style="font-family:courier new;"&gt;Seneca:~ leif$ git clone git://github.com/JPMoresmau/scion.git&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;[skipping output]&lt;/span&gt; &lt;span style="font-family:courier new;"&gt;&lt;br /&gt;Seneca:~ leif$ cd scion/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Seneca:scion leif$ cabal install&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;[skipping output]&lt;/span&gt; &lt;span style="font-family:courier new;"&gt;&lt;br /&gt;Seneca:scion leif$ &lt;/span&gt;&lt;p&gt;You need &lt;a href="http://git-scm.com/" target="_blank"&gt;git&lt;/a&gt; (the distributed source control system) to get a copy (a 'clone' in git speak) of the scion repository. Then you run Cabal (the common Haskell build tool) to compile and register scion. The commands I've pasted above should to the trick for you.&lt;/p&gt;&lt;br /&gt;&lt;h4&gt;Tell EclipseFP where to find the scion server&lt;/h4&gt;&lt;p&gt;Finally, the Eclipse plug-in has to know where to find the executable of the scion server. Run Eclipse and open the Preferences at Haskell &gt; Scion. Click 'Autodetect'. For me, this resulted in EclipseFP locating the server executable correctly and putting it into the text field.&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_BynttqNlK3w/S2RMcKLp7XI/AAAAAAAAAOA/k-Zf-p2D45U/s1600-h/EclipseFP-scion-prefs.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 241px;" src="http://4.bp.blogspot.com/_BynttqNlK3w/S2RMcKLp7XI/AAAAAAAAAOA/k-Zf-p2D45U/s320/EclipseFP-scion-prefs.jpg" alt="" id="BLOGGER_PHOTO_ID_5432551097168948594" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;You can verify that EclipseFP works correctly by simply creating a new Haskell project in the workspace. The wizard conveniently generates a 'Hello world'-like program with a Main module. Open it in the editor: if you see an outline, and if you get syntax errors when you type in some bogus code, then you know that EclipseFP has everything it needs.&lt;/p&gt;&lt;p&gt;That's it — have fun :-)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2934352534884921566-7812163032351882493?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/7812163032351882493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/01/getting-started-with-haskell-in-eclipse.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/7812163032351882493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/7812163032351882493'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/01/getting-started-with-haskell-in-eclipse.html' title='Getting started with Haskell in Eclipse'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_BynttqNlK3w/S2RLODK7xiI/AAAAAAAAANw/c7f8ujEb3lQ/s72-c/haskell-platform.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2934352534884921566.post-5554210823872795530</id><published>2010-01-22T04:47:00.000-08:00</published><updated>2010-01-30T06:54:13.868-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Usus'/><title type='text'>EclipseMagazin article about Usus</title><content type='html'>In November 2009 we presented &lt;a href="http://projectusus.org/" target="_blank"&gt;Project Usus&lt;/a&gt; for the first time at the &lt;a href="http://wiki.eclipse.org/Eclipse_DemoCamps_November_2009/Frankfurt" target="_blank"&gt;Eclipse DemoCamp in Frankfurt&lt;/a&gt;. &lt;a href="http://www.eclipse-magazin.de/" target="_blank"&gt;&lt;em&gt;EclipseMagazin&lt;/em&gt;&lt;/a&gt; now features a short summary article on each of the demos. Usus is described on page 89 by Nicole, Stefan and me. Go grab a copy!&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2934352534884921566-5554210823872795530?l=examinedcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://examinedcode.blogspot.com/feeds/5554210823872795530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://examinedcode.blogspot.com/2010/01/eclipsemagazin-article-about-usus.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/5554210823872795530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2934352534884921566/posts/default/5554210823872795530'/><link rel='alternate' type='text/html' href='http://examinedcode.blogspot.com/2010/01/eclipsemagazin-article-about-usus.html' title='EclipseMagazin article about Usus'/><author><name>Leif Frenzel</name><uri>http://www.blogger.com/profile/06758262715150769180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://2.bp.blogspot.com/_BynttqNlK3w/S3zkWs85gNI/AAAAAAAAAPo/LPM8kxwc19o/S220/9.png'/></author><thr:total>0</thr:total></entry></feed>
