<?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:blogger='http://schemas.google.com/blogger/2008' 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-4304505761826299706</id><updated>2026-07-30T01:26:56.043+01:00</updated><category term="java"/><category term="javafx"/><category term="swing"/><category term="guice"/><category term="performance"/><category term="UI"/><category term="blogging"/><category term="design"/><category term="erlang"/><category term="COM"/><category term="algorithms"/><category term="architecture"/><category term="bugs"/><category term="estimation"/><category term="groovy"/><category term="ioc"/><category term="junit"/><category term="life"/><category term="microtrack2"/><category term="profiling"/><category term="software"/><category term="testing"/><category term="uml"/><category term="windows"/><title type='text'>WONTFIX</title><subtitle type='html'>Observations on coding and software engineering.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>59</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-1433613694109768678</id><published>2014-12-20T17:04:00.001+00:00</published><updated>2014-12-20T17:04:11.557+00:00</updated><title type='text'>Erlang Project Ideas</title><content type='html'>&lt;script src=&quot;https://gist.github.com/andytill/878ef84a8bc886887f3b.js&quot;&gt;&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/1433613694109768678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/1433613694109768678' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1433613694109768678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1433613694109768678'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2014/12/erlang-project-ideas.html' title='Erlang Project Ideas'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-8839916389637889696</id><published>2014-11-12T22:44:00.001+00:00</published><updated>2014-11-12T22:44:11.886+00:00</updated><title type='text'>Probability of Project Success</title><content type='html'>&lt;script src=&quot;https://gist.github.com/andytill/e401c9a9ae58e36c58b8.js&quot;&gt;&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/8839916389637889696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/8839916389637889696' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/8839916389637889696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/8839916389637889696'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2014/11/probability-of-project-success.html' title='Probability of Project Success'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-2900283341632076366</id><published>2013-07-27T14:31:00.001+01:00</published><updated>2013-07-27T19:18:14.635+01:00</updated><title type='text'>Erlang Dev Environment</title><content type='html'>I have started a tutorial on how to setup a professional development environment for erlang coding.&amp;nbsp; The github page below has better formatting.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://gist.github.com/andytill/6094931&quot;&gt;https://gist.github.com/andytill/6094931&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/andytill/6094931.js&quot;&gt;&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/2900283341632076366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/2900283341632076366' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/2900283341632076366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/2900283341632076366'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2013/07/erlang-dev-environment.html' title='Erlang Dev Environment'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-7773670524888281427</id><published>2013-03-30T21:47:00.000+00:00</published><updated>2013-03-30T21:47:11.294+00:00</updated><title type='text'>South Park Software License</title><content type='html'>&lt;br /&gt;
If you have ever watched the show South Park then you will have probably read the &lt;a href=&quot;http://southpark.wikia.com/wiki/Disclaimer&quot; target=&quot;_blank&quot;&gt;disclaimer &lt;/a&gt;that is flashed at the start.&amp;nbsp; Here is my software license tribute:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/andytill/5278478.js&quot;&gt;&lt;/script&gt;
&lt;br /&gt;
Remember that software development can often be much like an episode of South Park; constant swearing, youthful naivety and surprise endings.</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/7773670524888281427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/7773670524888281427' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/7773670524888281427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/7773670524888281427'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2013/03/south-park-software-license.html' title='South Park Software License'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-307432662463850387</id><published>2013-03-22T21:36:00.001+00:00</published><updated>2013-04-14T21:18:22.686+01:00</updated><title type='text'>Memories of Visual Basic 6</title><content type='html'>In the UK it is typical to study for two years and then have a placement year where you actually get a job before the final fourth year of study.&amp;nbsp; In 2006 I took on several small projects over the placement&amp;nbsp; year and pushed VB6 to it&#39;s limits.&amp;nbsp; VB6 has so many quirks, it is impossible not to use hacks to get things done.&amp;nbsp; Here are some of mine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
One tool required a DSL for interacting with phones, it would read a list of phone numbers and a file containing commands and run them over each of the numbers.&amp;nbsp; For example it would make a call to the phone and configure it using DTMF* tones.&amp;nbsp; I had no idea at that time how a compiler could be properly implemented so the resulting code was a complete mess and the DSL was looked like assembly for telephones.&amp;nbsp; Despite the hideous code, the program saved a lot of time.&amp;nbsp; To do this manually would have taken days instead of a couple of hours and be impossibly error prone.&amp;nbsp; One key missing feature was error handling, which is problematic in telecommunications.&amp;nbsp; Inevitably one of the calls would go wrong and the program would crash, the operator would then have to delete the completed phones numbers from the list and run the program again.&amp;nbsp; No problems!&lt;br /&gt;
&lt;br /&gt;
Another project provided a UI for editing INI file configuration.&amp;nbsp; The program was great, except that VB does not allow more than 256 controls on a single form.&amp;nbsp; My &#39;ingenious&#39; solution was to put each INI section in a tab pane which also had its own window.&amp;nbsp; When the user clicked a new tab, it hid the current window and showed a new window for that tab.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
VB6 also comes with it&#39;s own TCP control which you must drag onto the UI to instantiate.&amp;nbsp; The problem is that it had almost the same API as a serial connection control, meaning it only dealt with 1 to 1 connections.&amp;nbsp; This meant it was impossible to write a TCP server.&amp;nbsp; That is, until I worked out that an array of TCP controls waiting for connections worked pretty much like a TCP server.&amp;nbsp; This is OK except that an array has a finite capacity, I was again limited by the number of controls so the server could only ever handle a certain number of connections.&lt;br /&gt;
&lt;br /&gt;
I remember the year, the work and the company fondly and hope that some of my work is still in use.&amp;nbsp; Looking back, I don&#39;t know why I used VB6 for everything.&amp;nbsp; It&#39;s just so 
easy to get started and then keep typing, I was young and naive, that&#39;s 
all I can say...&lt;br /&gt;
&lt;br /&gt;
* DTMF tones are those strange sounds you hear when you press a number on a phone key pad.&amp;nbsp; Pieces of hardware such as phones and switches can interpret a sequence of tones as commands.</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/307432662463850387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/307432662463850387' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/307432662463850387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/307432662463850387'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2013/03/memories-of-visual-basic-6.html' title='Memories of Visual Basic 6'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-3897210146811434462</id><published>2012-12-25T23:18:00.000+00:00</published><updated>2012-12-26T02:02:18.997+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="javafx"/><title type='text'>EstiMate, a software estimation tool</title><content type='html'>I have just open sourced a software application that I have been working on in my spare time for the past few months called &lt;a href=&quot;https://bitbucket.org/atill/estimate&quot;&gt;EstiMate&lt;/a&gt;.  This is my attempt to create some software which improves the way I can estimate a task and make what that estimate includes more transparent so that it is clear to others and Myself in the future.  Areas which I feel are particularly important are:
&lt;ul&gt;
    &lt;li&gt;Task complexity, how complex it the task and how confident is the assignee with that technology.&lt;/li&gt;
    &lt;li&gt;Quickly documenting what a task consists of and breaking it into smaller tasks&lt;/li&gt;
    &lt;li&gt;Having a history of past estimates and how they worked out.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
There are many many more factors which affect estimation but these are the things that I want to implement first.
&lt;/p&gt;
&lt;p&gt;
So, what does it do?  At the moment it has some characteristics of an ERP application.  You are able to add some projects, tasks and people to implement them.  Tasks can be estimated and the sum of estimates are calculated for a project.
&lt;/p&gt;
&lt;p&gt;
Complexity is taken into account which I think is a huge factor in any task.  Tasks can be assigned &quot;skill requirements&quot; such as Java, SQL or anything you think you need and then can be rated out of ten.  People can assign skills to themselves and rate themselves.  If a task has skill requirements greater than those possessed by the assigned person then the estimate for a task is increased.  I plan to improve this calculation by allowing the estimate to be increased by a percentage set in the project, instead of by a fixed number.  Other factors affecting the time that a task can take will also be added.
&lt;/p&gt;
&lt;p&gt;
Tasks can also be &quot;templated&quot;, this means that the information entered for this task can be recreated.  This is great for reoccurring tasks like builds, deployments or coding tasks that are very similar.  It will allow these tasks to look similar and have a consistent base for estimation but be flexible and allow changes as needed.  I plan to improve this to capture best practices such as including sub-tasks for testing or bug fixing that are percentages of the task estimate or perhaps even complexity.
&lt;/p&gt;
&lt;p&gt;
EstiMate uses JavaFX for the frontend GUI and neo4j for data storage.  It allows the user to keep a local database, to use a shared neo4j server or a neo4j database hosted on the Heroku platform.  It is pure java and shouldn&#39;t need any set-up once I create an installer.  At the moment, you can download the code from bitbucket and run it from your favourite IDE or command line (there might be a Maven hack there right now so be warned!).
&lt;/p&gt;
&lt;p&gt;
It is licensed under GPLv3.  I have blogged about some of the code I have written for this project so assume any code in this blog is free for you to use in any way you see fit without recourse to Me if it doesn&#39;t work of course!
&lt;/p&gt;
&lt;p&gt;
If you have an idea or opinion or would like to contribute that would be great, feel free to comment here or tweet me &lt;a href=&quot;https://twitter.com/andy_till&quot;&gt;@andy_till&lt;/a&gt;.
&lt;/p&gt;
&lt;a href=&quot;http://farm9.staticflickr.com/8076/8303722095_4137faab87.jpg&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;222&quot; width=&quot;500&quot; src=&quot;http://farm9.staticflickr.com/8076/8303722095_4137faab87.jpg&quot; /&gt;&lt;/a&gt;

</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/3897210146811434462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/3897210146811434462' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/3897210146811434462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/3897210146811434462'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/12/estimate-software-estimation-tool.html' title='EstiMate, a software estimation tool'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-1659010981193378675</id><published>2012-12-24T15:56:00.000+00:00</published><updated>2012-12-26T02:01:48.587+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="javafx"/><title type='text'>Dragging to resize a JavaFX Region</title><content type='html'>&lt;p&gt;
Here is another handy JavaFX utility to allow you to drag the bottom edge of a JavaFX Region to resize it.  Layout containers inherit from Region although controls do not even though they both have a minHeight property so Controls cannot be resized using this class :(
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/4369729.js&quot;&gt;&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/1659010981193378675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/1659010981193378675' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1659010981193378675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1659010981193378675'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/12/dragging-to-resize-javafx-region.html' title='Dragging to resize a JavaFX Region'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-8911573380919860919</id><published>2012-11-04T13:58:00.002+00:00</published><updated>2012-11-04T17:15:25.099+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javafx"/><title type='text'>Features I would like to see in FXML</title><content type='html'>I really enjoy using FXML, it is robust, simple and well supported by the Scene Builder tool but there are some features I would really like to see.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Controllers allowed on arbitrary nodes&lt;/h3&gt;
Large controls usually have many action methods, many controls injected with the @FXML annotation and typically other objects like DAOs which can get quite messy.&amp;nbsp; Sometimes handling code for a single control such as a combo box can get quite large, creating an FXML for a small control seems like overkill. &lt;br /&gt;
&lt;br /&gt;
To tackle this, it would be useful to allow the fx:controller attribute on any FXML element specifying a node that is loaded into the scene graph.&amp;nbsp; This &#39;sub-controller&#39; would have controls injected with @FXML annotations in the same way as root controller except that the it would not be able have it&#39;s parent controls injected.&amp;nbsp; Only the element it is declared on or that element&#39;s children could be injected.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Allow effects to be created in Scene Builder and then injected into a controller&lt;/h3&gt;
It is much easier to create effects in Scene Builder than it is in Java code because I can get instant feedback and fine tune much easier.&amp;nbsp; It would be great if I could create an effect in FXML and have it injected into the controller using an @FXML annotation.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Support &#39;Actions&#39;&lt;/h3&gt;
One of the things that I miss from Swing is the javax.swing.Action interface.&amp;nbsp; This was used to encapsulate action logic of a button in a single class instead of having many action listeners in one class.&amp;nbsp; I &lt;b&gt;could &lt;/b&gt;create a class implementing &lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;EventHandler&lt;actionevent&gt;&lt;/actionevent&gt;&lt;/span&gt;&lt;/span&gt; and set it on the button in the controller class, but it would be nice to specify it under the code tab in the same as you would specify a method to handle an event.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Specify some validations on TextField controls&lt;/h3&gt;
For Me, FXML is all about productivity so it makes sense that it could support common requirements such as validations on TextField controls.&amp;nbsp; For example, a TextField might only allow numeric input up to a maximum number.&amp;nbsp; If you google &quot;javafx numeric textfield&quot; there are already many varied implementations.&amp;nbsp; It would be great to see this in Scene Builder, even better if it could be tested in preview mode.</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/8911573380919860919/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/8911573380919860919' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/8911573380919860919'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/8911573380919860919'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/11/features-i-would-like-to-see-in-fxml.html' title='Features I would like to see in FXML'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-1005426183990515320</id><published>2012-10-04T20:53:00.000+01:00</published><updated>2012-10-04T20:54:06.758+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javafx"/><category scheme="http://www.blogger.com/atom/ns#" term="junit"/><title type='text'>JUnit Rule for JavaFX Controller Testing</title><content type='html'>&lt;p&gt;
Testing JavaFX controllers is relatively easy although you do have to jump through a couple of hoops.  Firstly, JavaFX must be initialised and secondly JavaFX controls must only be mutated on the JavaFX thread created internally during initialisation.  The JUnit rule below will setup JavaFX once and run all tests on the FX thread.  All you need to do is create it as a field in your test case class and annotate it with &lt;code&gt;@org.junit.Rule&lt;/code&gt;.  You will need to be running JUnit 4.9 to use the rule API.
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/3835914.js&quot;&gt; &lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/1005426183990515320/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/1005426183990515320' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1005426183990515320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1005426183990515320'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/10/junit-rule-for-javafx-controller-testing.html' title='JUnit Rule for JavaFX Controller Testing'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-7379258872931930120</id><published>2012-09-04T13:16:00.000+01:00</published><updated>2012-09-28T21:42:24.619+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="guice"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="javafx"/><title type='text'>Reusable FXML Controls with Guice</title><content type='html'>&lt;div style=&quot;font-family: &amp;quot;Helvetica Neue&amp;quot;,Arial,Helvetica,sans-serif;&quot;&gt;
&lt;b&gt;Update:&lt;/b&gt;&lt;br /&gt;
This code is now integrated into the &lt;a href=&quot;https://github.com/cathive/fx-guice&quot; target=&quot;_blank&quot;&gt;fx-guice&lt;/a&gt; project where it will be maintained.&amp;nbsp; I am not intending to modify the GitHub gists so this post now only serves to document the code as seen here.&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;br /&gt;
It is very simple to inject controllers into an FXML control using Guice but once the UI starts to get bigger it is likely that we will need to split it out into smaller files.  I wanted to do this with a list builder control simple to that in SceneBuilder used to build a list of CSS classes.&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Helvetica Neue&amp;quot;,Arial,Helvetica,sans-serif;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Helvetica Neue&amp;quot;,Arial,Helvetica,sans-serif;&quot;&gt;
In my UI the controller of the parent control (called parent controller from now on) would tell the list builder control what items it could add to the list and what items were already in the list using the list builder&#39;s controller (the child controller).&amp;nbsp; Getting this to work this is far from simple.&amp;nbsp;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Helvetica Neue&amp;quot;,Arial,Helvetica,sans-serif;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Helvetica Neue&amp;quot;,Arial,Helvetica,sans-serif;&quot;&gt;
It is not possible to get or set a controller on an arbitrary control node.&amp;nbsp; I fired up VisualVM to see where the list builder controller was referenced and the only incoming references were to the event handlers I had set up.&amp;nbsp; If there were no event handlers it looks like the controller would get garbage collected.&amp;nbsp; It was also not possible to set a Guice singleton scope on the controller as there may be several list builders in the user interface at the same time.&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Helvetica Neue&amp;quot;,Arial,Helvetica,sans-serif;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Helvetica Neue&amp;quot;,Arial,Helvetica,sans-serif;&quot;&gt;
&lt;br /&gt;
Here is a run down of my final solution although it is not altogether as simple as I would have liked it.&amp;nbsp; This tutorial is much more complex than my previous FXML/Guice post, I had to look up my own tutorial on Guice scopes to work it out.&amp;nbsp; Please let me know if anything is not clear&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;


1. Add the Guice Module&lt;/h3&gt;
Add the following Guice module to your Injector.&amp;nbsp; This example also assumes that you are using the same Injector to inject controllers when loading FXML, this is detailed on my previous Guice/FXML post.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3620534.js&quot;&gt; &lt;/script&gt;
The module uses the following Guice scope to track all injected controllers.&lt;script src=&quot;https://gist.github.com/3620548.js&quot;&gt; &lt;/script&gt;
&lt;br /&gt;
&lt;h3&gt;
2. Use a scope annotation on the controller &lt;/h3&gt;
Reusable controllers are annotated with the custom @FXMLLoadingScope.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3620682.js&quot;&gt; &lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/3201278.js&quot;&gt;
 
&lt;/script&gt;&lt;br /&gt;
&lt;h3&gt;


3. Implement the IdentifiableController interface in the controller&lt;/h3&gt;
Reusable controllers must implement the IdentifiableController interface which has one method, #getId().&amp;nbsp; #getId() must return a non-null String containing the ID of the parent of the root pane of the control.&amp;nbsp; If this ID is null then return the second parent-parent&#39;s ID.&amp;nbsp; Keep going until a non-null ID is found. &lt;br /&gt;
&lt;ul style=&quot;font-family: &amp;quot;Helvetica Neue&amp;quot;,Arial,Helvetica,sans-serif;&quot;&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;script src=&quot;https://gist.github.com/3201489.js&quot;&gt;
 
&lt;/script&gt;

&lt;br /&gt;
&lt;h3&gt;


4. Set an ID on the parent &lt;/h3&gt;
When importing one FXML file into a parent, set the container ID to the ID you want for the controller.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3201415.js&quot;&gt;
 
&lt;/script&gt; &lt;br /&gt;
&lt;h3&gt;
5. Retrieve the child controller&lt;/h3&gt;
In our parent controller (the one that that will tell the list builder what to do) we need to retrieve the list builders controller to populate options and so on.&amp;nbsp; To do this, Inject an instance of ControllerLookup into the parent controller.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3620522.js&quot;&gt; &lt;/script&gt;

In the parent controller, make sure you implement the &lt;a href=&quot;http://docs.oracle.com/javafx/2/api/javafx/fxml/Initializable.html&quot; target=&quot;_blank&quot;&gt;Initializable&lt;/a&gt; interface.&amp;nbsp; In the initialise method of the parent controller call ControllerLookup#lookup(String) on the instance you have injected to retrieve the child controller.&amp;nbsp; The ID that is passed in should be the ID that is returned by IdentifiableController#getId().&amp;nbsp; This could be hard coded but in this example it is using the FXML ID of the parent control, &quot;factorsList&quot; in this case.&amp;nbsp; This allows several list builders to be used in the same parent control.&lt;br /&gt;
&lt;br /&gt;
I am using this in my own JavaFX project and although the implementation was not simple I have found it quite easy to use.</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/7379258872931930120/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/7379258872931930120' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/7379258872931930120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/7379258872931930120'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/09/reusable-fxml-controls-with-guice.html' title='Reusable FXML Controls with Guice'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-1840672266984811369</id><published>2012-08-20T13:23:00.001+01:00</published><updated>2013-04-14T21:00:22.349+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javafx"/><category scheme="http://www.blogger.com/atom/ns#" term="UI"/><title type='text'>JavaFX CSS Styling</title><content type='html'>I&#39;ve been working on a light grey look and feel for JavaFX with square corners, inspired by the Swing Substance (Business Grey) Look and Feel.&amp;nbsp; Here are the results so far:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt=&quot;&quot; src=&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAmAAAAJpCAIAAACFBhlPAAAgAElEQVR4nOzdeXgb130vfN/nfd/nvXm73Num7e3be99ut2mQNlvX9LZN7SZNU1tyNHHaulddEsuhJcvxqsSbbIqyYzt2LFtHlixZkiVLlCWZlqhdoixZokSRkhlRpghAMIjBOgSxDbETELi+f/yAg8FgsJEgCYLfzzOPgznnzJkhCOGbc2bhLYbeK1iwYMGCBQsW5XLbbbfdYui9MgkAAAAZTU1N2YCc86zGggULFixYamRBQGLBggULFiwai0ZA/j+/t3LKy899ZuXPfeaBn/vMAz/3+w/8/O//4Od//wc//9kf/MJnf/ALn33wFz774C/qaHnoFz/30H+h5Q8e/q+0/OHD//UPH/mlP3zklz7/yC99/pFf/vyjv/z5R3/5C49++guPfvoLj336i499+ouP/coXH/uVL636lS+t+tUvrfrVL6/61S//8Ne+/MNf+yNafvTf/ji9/PofP/7rf5Je/t8/fYKW3/izJ37jz578jT978r//OS1P/fevPPU/0svT/99fZJb/tfo3afnL1b/1l8/81l8+81t/9cxv/9Wzv/1Xz/72Xz/723/97O/8dePvfLXxd77a+Ltfbfzdr6753b9Z8z9pubXpf97a9Hu3Nv3ebU2/d9vaz9y29jN/S8tzv/+19PLZrz3/2a8//9mvP6/7+vO6v/sxLZ/7xo8/940XPveNF/7g72l58Q+++eIf0vIPL30+s3zh9p+klzt+8sU7Xv7iHS9/cdHLX1r08pcWvfKlxa98mZY7f/rlO3/6R7R869U/pmXJuj9esu5Plqz7E2Hdnwiv/anw2p9++7U//fZrf/bt1//srvTy5995/c+/s/7Pv7P+K99Z/5V/ZLT8xT+xv/inDX/xTxv+1z/T8sZf3p1Z/mXjX2WWv/7fm2j56tJNX1365leXvvnVf33zb/71zb/5181/82+bb6Xl37fc+u9bbvv3Lbf9x5bb/uOtv6Xlu2997btbv/bdrV/73tavfW/r17+37ev3bPv6Pdv+7p5tf7dsOy3fuHf7N+59+xv3vv33977999/f8fff3/HN7+/4ZsOObzbs/GbDzn+4L73cvvyd9LJi1x203L9r0f27aVm8cvfilc2LVzYvfqD5zgea73xgz50/2PMtWh58dwktD7275KG9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&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And just as a reminder as to the default JavaFX look and feel:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt=&quot;&quot; src=&quot;data:image/png;base64,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&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
This is a work in progress and not all of the controls are styled.&amp;nbsp; This skin has now become the first entrant in the &lt;a href=&quot;https://github.com/JFXtras/jfxtras-styles&quot; target=&quot;_blank&quot;&gt;jfxtras-styles&lt;/a&gt; project hosted on github or click &lt;a href=&quot;https://github.com/JFXtras/jfxtras-styles/blob/master/src/brume/brume.css&quot; target=&quot;_blank&quot;&gt;here &lt;/a&gt;if you just want to grab source.&lt;br /&gt;
&lt;br /&gt;
The extra space is to show the drop shadows on the titled panes which I use quite a lot in my own application.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Update:&lt;/b&gt;&lt;br /&gt;
Just to show the different a little CSS styling can do, below is a recent screenshot of &lt;a href=&quot;https://bitbucket.org/atill/estimate&quot; target=&quot;_blank&quot;&gt;EstiMate&lt;/a&gt;, the JavaFX project I have been working on.&amp;nbsp; It&#39;s come a long way!&amp;nbsp; You can take a look at the CSS &lt;a href=&quot;https://bitbucket.org/atill/estimate/src/22390a2ca034b55f1916e46435b714e5c489b90e/src/main/resources/projmon/brume-contrast.css?at=master&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://pbs.twimg.com/media/BGjFC8BCUAAayd7.png:large&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;299&quot; src=&quot;https://pbs.twimg.com/media/BGjFC8BCUAAayd7.png:large&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/1840672266984811369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/1840672266984811369' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1840672266984811369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1840672266984811369'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/08/javafx-css-styling.html' title='JavaFX CSS Styling'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-1439580980633315235</id><published>2012-07-01T19:03:00.001+01:00</published><updated>2012-07-01T19:03:35.386+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="guice"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="javafx"/><title type='text'>Creating JavaFX Controllers Using Guice</title><content type='html'>I really like Guice Dependency Injection so was pleased to hear that &lt;a href=&quot;http://fxexperience.com/2011/10/fxml-guice/&quot;&gt;some work&lt;/a&gt; has been done to make this interact with JavaFX.  The solution presented though, was less than ideal.  It had some duplication of configuration where the class name of the controller needed to specified in the FXML as you would expect but also when loading it.  After a brief fumble through FXMLLoader&#39;s methods I found #setControllerFactory.  By passing this wafer thin adapter below as a parameter to #setControllerFactory, any controllers will be instantiated via Guice.

&lt;p&gt; &lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/3029103.js&quot;&gt; &lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/1439580980633315235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/1439580980633315235' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1439580980633315235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1439580980633315235'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/07/creating-javafx-controllers-using-guice.html' title='Creating JavaFX Controllers Using Guice'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-634903677036673423</id><published>2012-06-04T01:07:00.000+01:00</published><updated>2012-06-04T01:07:29.304+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="swing"/><title type='text'>JScrollPane Repainting Problems</title><content type='html'>I was having some problems with the JScrollPane not repainting my custom component properly when scrolling.&amp;nbsp; The results were that the area that was now visible because of the scroll was painted unevenly and looked blurred.&amp;nbsp; This seems to happen when a component is doing some custom rendering inside a JScrollPane and using the clip to find out what area it should paint.&amp;nbsp; To fix this call the following methods on your JScrollPane:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;scrollpane.getViewport().setScrollMode(JViewport.SIMPLE_SCROLL_MODE);&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
In the modern swing implementation there is some &#39;clever&#39; caching of the content view to improve performance which seems to be the problem.&amp;nbsp; Setting SIMPLE_SCROLL_MODE will force the scroll pane to repaint it&#39;s entire contents while scrolling.&amp;nbsp; Although this is less performant, it at least shows the correct results with minimum fuss.</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/634903677036673423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/634903677036673423' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/634903677036673423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/634903677036673423'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/06/jscrollpane-repainting-problems.html' title='JScrollPane Repainting Problems'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-1363215206435638593</id><published>2012-04-06T19:00:00.000+01:00</published><updated>2012-04-06T19:05:06.075+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><title type='text'>Safely Removing an Element While Iterating a List</title><content type='html'>If you want to remove an element while you&#39;re iterating a Java ArrayList then you have some problems.&amp;nbsp; First off, if you use an iterator then the list will most likely throw a ConcurrentModificationException.&amp;nbsp; If you use a classic style for loop then when you remove an element the list will no longer be the same size or have it&#39;s other elements at the same position as when you started iterating which might cause an error, logical or otherwise.&lt;br /&gt;
&lt;br /&gt;
The simplest way to do this is to iterate backwards over the list.&amp;nbsp; This means when you remove an element, the other elements will not get reordered.&amp;nbsp; The method below demonstrates:&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void iterateBackwards()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; List&lt;integer&gt; list = new ArrayList&lt;integer&gt;(Arrays.asList(1,2,3,4,5));&lt;br /&gt;&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;&amp;nbsp; for (int i = list.size() - 1; i &amp;gt;= 0; --i) &lt;br /&gt;&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;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(list.remove(i));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/integer&gt;&lt;/integer&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
This prints....&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; 5&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; 4&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; 3&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; 2&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;&amp;nbsp; 1&lt;/span&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/1363215206435638593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/1363215206435638593' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1363215206435638593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/1363215206435638593'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/04/safely-removing-element-while-iterating.html' title='Safely Removing an Element While Iterating a List'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-8132854423965831949</id><published>2012-03-22T21:48:00.000+00:00</published><updated>2012-03-22T21:48:23.882+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="windows"/><title type='text'>Fastest Way to Delete a Directory In Windows</title><content type='html'>I had a load of large directories (several GBs) which I needed to delete so that I could meet the minimum free space requirement for Windows to run the defragmentation tool.&amp;nbsp; Unfortunately, Windows Explorer is unusably slow for this as it first scans the whole directory so that it can show the estimate and then copies everything into the recycle bin or not if the directory is too big.&lt;br /&gt;
&lt;br /&gt;
Below is some batch script to delete a directory very fast.&amp;nbsp; The code is on stack overflow &lt;a href=&quot;http://stackoverflow.com/questions/186737/whats-the-fastest-way-to-delete-a-large-folder-in-windows&quot; target=&quot;_blank&quot;&gt;here &lt;/a&gt;where the commenter &lt;a href=&quot;http://stackoverflow.com/users/724176/hugo&quot; target=&quot;_blank&quot;&gt;Hugo &lt;/a&gt;bench marked it at 3 times faster than rmdir which itself is a hell of a lot faster than deletion via Windows Explorer. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;bestrmdir.bat&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;rem to use, drop in your c:/windows/system32 directory&lt;code&gt; for this to be usable anywhere&lt;/code&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;code&gt;rem in then command line type &#39;bestrmdir MyDirectory&#39; to delete MyDirectory&lt;/code&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;code&gt;del /f/s/q %1 &amp;gt; nul&amp;nbsp;&lt;/code&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;code&gt;rmdir /s/q %1&lt;/code&gt;&lt;/span&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/8132854423965831949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/8132854423965831949' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/8132854423965831949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/8132854423965831949'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/03/fastest-way-to-delete-directory-in.html' title='Fastest Way to Delete a Directory In Windows'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-3203614267230087929</id><published>2012-02-29T23:03:00.000+00:00</published><updated>2012-02-29T23:03:00.352+00:00</updated><title type='text'>Typed Integers</title><content type='html'>I really like the idea of typed integers. For example, if you a number representing the number of cats and a number representing a number of dogs it is possible to add these together.&amp;nbsp; In a typed integer world it would not be possible and throw an error upon compilation.&amp;nbsp; I think this would be a big improvement for API safety and also a method of documentation.&amp;nbsp; There is nothing worse than a method with a structure like #foo(int, int) which is difficult to understand without reading or documentation every time.&lt;br /&gt;
&lt;br /&gt;
In general use this would be suicide in a managed language where the overhead of an object for every int could mean a huge jump in memory usage and GC wouldn&#39;t be worth the improvements.&amp;nbsp; The actual implementation in Java would also be extremely ugly, for example:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;class EventID {&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; private final int id;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; public EventID(int anID) {&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; id = anID;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
The class doesn&#39;t even contain basic methods like a way to get the ID, compare or hash it which with an int you get for free and it is still a fair wedge of code.&amp;nbsp; Lombok&#39;s @Data annotation can really improve classes like this and make the language feel more declarative.&lt;br /&gt;
&lt;br /&gt;
I have found the best language to implement this is c++, the following is my proof of concept implementation:&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;template &lt;class t=&quot;&quot;&gt; &lt;br /&gt;class TypedInt&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;&amp;nbsp; const int value;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; TypedInt(int v) : value(v) {};&lt;br /&gt;&lt;br /&gt;&amp;nbsp; TypedInt&lt;t&gt; operator + (TypedInt&lt;t&gt; num)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; TypedInt&lt;t&gt; result(value + num.value);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp; TypedInt&amp;nbsp; operator = (const int other)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; TypedInt&lt;t&gt; result(other);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;};&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/class&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
This allows the following usage:&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;struct eventid {};&lt;br /&gt;&lt;br /&gt;typedef TypedInt&lt;eventid&gt; EventId;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/eventid&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;EventId i = 2, j = 3;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;EventId result = i + j;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
Overall this feels natural to use.&amp;nbsp; If I was actually using class then the other operators such as == could be implemented without problems.&amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
One of the benefits of c++ is that an object wrapping an int does not take more memory than an int would, during compilation this abstraction is apparently stripped away.</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/3203614267230087929/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/3203614267230087929' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/3203614267230087929'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/3203614267230087929'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/02/typed-integers.html' title='Typed Integers'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-6593950214774938818</id><published>2012-02-26T21:23:00.000+00:00</published><updated>2012-11-02T10:09:54.775+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><category scheme="http://www.blogger.com/atom/ns#" term="swing"/><title type='text'>Compatible Images</title><content type='html'>A couple of weeks ago I was tasked with improving the performance on a legacy java swing application that was really crawling.&amp;nbsp; It would repaint the whole screen on any event, which it could receive a lot of, and painting the whole screen was really slow.&amp;nbsp; By using compatible images instead of the default kind of image read by ImageIO, the painting code was sped up by a factor of 70 and the event frequency was a non-issue.&amp;nbsp; The whole change was about 10 lines of code, much less than that to make the software use the graphics clip.&lt;br /&gt;
&lt;br /&gt;
If you are having an issue with graphics performance make sure you try compatible images before trying anything else since it is so easy to introduce. &lt;br /&gt;
&lt;br /&gt;
Before deploying to site I was worried that the speed up I was seeing was in some way down to my dev machine working well with compatible images so I wrote the tool below to test if the improvement was the same which it was.&amp;nbsp; Some notes:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;The tool requires an image.&amp;nbsp; When I attempted to create an in-memory image there was no difference in run times.&lt;/li&gt;
&lt;li&gt;Results are printed on the command line so remember to use java.exe and not javaw.exe&lt;/li&gt;
&lt;li&gt;I went to some effort so that this program was a single class to make it easy for the support guys to run.&amp;nbsp; I don&#39;t usually like to implement Runnable on a class that isn&#39;t &lt;b&gt;just &lt;/b&gt;a Runnable.&lt;/li&gt;
&lt;/ol&gt;

&lt;script src=&quot;https://gist.github.com/3999914.js&quot;&gt; &lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/6593950214774938818/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/6593950214774938818' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/6593950214774938818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/6593950214774938818'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/02/compatible-images.html' title='Compatible Images'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-4921495494764846657</id><published>2012-02-26T21:03:00.001+00:00</published><updated>2012-02-27T18:52:49.003+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="architecture"/><category scheme="http://www.blogger.com/atom/ns#" term="design"/><title type='text'>How Much Architecture is Enough?</title><content type='html'>In the past I have often wondered if I have provided enough architecture for the software team to work to.&amp;nbsp; Conversely I always like to leave enough room to maneuver for the guys to do design for their own parts of the software, I would really hate it if I was working on a project where everything was defined and all I needed to do was &quot;code in the blanks&quot;.&lt;br /&gt;
&lt;br /&gt;
The idealist in me wants to provide just enough architecture to start work at all, and emergency design will do the rest.&amp;nbsp; I have found this is not how great software is made.&amp;nbsp; When everyone is left somewhat to their own devices, the code starts to lose coherence.&amp;nbsp; Everyone will code their own mini framework that will not interact well with other stories or allow extension for all requirements.&amp;nbsp; This is natural as everyone might not be aware of all requirements for the project.&lt;br /&gt;
&lt;br /&gt;
The answer to this is pretty simple in practice, whenever two or more stories meet the following criteria you need some architecture:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;1. Other code interacts with the product of a story.&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;br /&gt;
For example some kind of remote or local service or data.&amp;nbsp; In my current work we do a lot of inter-process communication.&amp;nbsp; This is really a technical detail, web services or in-process framework meets the same criteria.&amp;nbsp; Whatever it is, it needs some documented architecture.&amp;nbsp; The documentation part here is important, it should be simple to find look-up the exposed interfaces with arguments including valid values, errors etc.&amp;nbsp; This rule tends to reduce errors and confusion (more errors) occurring from not knowing about or not understanding .&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;2. Two or more stories are similar&lt;/b&gt; &lt;br /&gt;
&lt;br /&gt;
For example, two kinds of message or input that could be handled in the same way or are similar enough to be categorised together.&amp;nbsp; Polymorphism and/or inversion of control can be used to have a central mechanism handle these in a reusable way.&amp;nbsp; This rule tends to reduce the overall amount of code and improve code quality.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
These two scenarios are sum up pretty much of every time where I had wished I had provided some architecture before work commenced</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/4921495494764846657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/4921495494764846657' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/4921495494764846657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/4921495494764846657'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2012/02/how-much-architecture-is-enough.html' title='How Much Architecture is Enough?'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-6647848318445032421</id><published>2011-12-12T20:17:00.000+00:00</published><updated>2011-12-21T18:17:23.429+00:00</updated><title type='text'>Some of My Coding Habits</title><content type='html'>This is a brief description of my coding habits including indentation, new lines and other things that I don&#39;t usually see although I think it makes code clearer.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Variable declaration and assignment on separate lines&lt;/b&gt;&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;JLabel nameLabel;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt; nameLabel = new JLabel(&quot;Name:&quot;);&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;nameLabel.setBackground(Color.RED);&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
Although I didn&#39;t take up SmallTalk seriously I did come away with, among other things a new coding habit.&amp;nbsp; SmallTalk variables are always declared in pipes i.e.&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; font-size: x-small;&quot;&gt; | myVar |&lt;/span&gt; before use.&amp;nbsp; In Java I use this, especially when the object needs one or more method calls after it is created.&amp;nbsp; It is almost like a paragraph header and allows the code on the left hand side to match up which I find quite easy to read.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Static imports&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
No need for an example here, I just really like static imports... in moderation.&amp;nbsp; They are particularly effective for enums where the enum name might be repeated over and over again.&amp;nbsp; It is also quite safe to use enums in this way because type safety will not allow you to do anything silly such as &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; font-size: x-small;&quot;&gt;EnumA.RED == EnumB.RED&lt;/span&gt; without giving a compilation error.&lt;br /&gt;
&lt;br /&gt;
Static imports are quite bad for importing primitive constants, it is much easier to make a mistake without the context of the class name from where it came.&amp;nbsp; For example, two different integers might mean very different things.&amp;nbsp; A number of cats and a number of dogs which should not be added together.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
It is quite rare for me to write static methods so this isn&#39;t usually an issue.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Returning new&lt;/b&gt;&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;public String findDayName(int dayIndex)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; assert dayIndex &amp;gt;= 1 &amp;amp;&amp;amp; dayIndex &amp;lt;= 7;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; switch(dayIndex)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; case 1:&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return &quot;monday&quot;;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; case 2:&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return &quot;tuesday&quot;;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; default:&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return null; &lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; // and when using an if statement&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; if(dayIndex == 1)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return &quot;monday&quot;;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; else if(dayIndex == 2)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return &quot;tuesday&quot;;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; else&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return null;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
When using a reasonable size switch or if statement I typically bring this out into a separate method with no variables other than the data needed to perform the switch.&amp;nbsp; Even this is not necessary if the data is a class field. There is no variable that gets assigned to so no need to worry about a name, or maintain the name and the method name make sense together.&amp;nbsp; If statements also do not have brackets to cut down on needless lines and white space which in this case would just make the code more bulky and difficult to read.&lt;br /&gt;
&lt;br /&gt;
The if statement is reminiscent of Erlang guarded methods.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/6647848318445032421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/6647848318445032421' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/6647848318445032421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/6647848318445032421'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2011/12/some-of-my-coding-habits.html' title='Some of My Coding Habits'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-2481275683126412522</id><published>2011-10-15T18:31:00.000+01:00</published><updated>2011-10-15T18:31:05.214+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bugs"/><category scheme="http://www.blogger.com/atom/ns#" term="testing"/><title type='text'>Resolving Bugs</title><content type='html'>There are at least three roles in a bug report.&amp;nbsp; The first two are the bug reporter or  owner of the bug who is equivalent to the Customer or Product Owner and  the Software Engineer responsible for the bug.&amp;nbsp; An Architect, Technical  Lead or Project Manager may exist who has more direct access to the  customer, this is called QA in Bugzilla.&amp;nbsp; In certain cases the Engineer  may need to escalate issues if they cannot resolve it themselves.&amp;nbsp; This can  happen all the time, the Customer might raise a bug stating that  functionality is missing when it is not in the requirements.&amp;nbsp; If this is  not dealt with in a way that includes all stake holders, it could cause  issues immediately or later on in the project at demo time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;Below is a table of resolutions  and the  circumstances in which they can be applied and by who.&amp;nbsp; The  only  possible option for the software engineer is to fix the bug or  agree  another resolution with the customer, or team lead.&amp;nbsp;  This means  that the bug will always be fixed or dealt with in a final  way where  the specification will be updated to reflect the new  behaviour (or new  understanding of behaviour) or at least a resolution  agreed which should  be traceable in the bug comments.&amp;nbsp; If the bug is  not fixed and not  agreed then it is bound to come back in the future  starting with the  line “I reported this months ago and it is still NOT  FIXED”!&lt;/div&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;MsoTableGrid&quot; style=&quot;border-collapse: collapse; border: none;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt; &lt;td style=&quot;border: solid black 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 91.75pt;&quot; valign=&quot;top&quot; width=&quot;122&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Fixed&lt;/div&gt;&lt;/td&gt; &lt;td style=&quot;border-left: none; border: solid black 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 387.05pt;&quot; valign=&quot;top&quot; width=&quot;516&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Only the Software Engineer can set.&lt;/div&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style=&quot;border-top: none; border: solid black 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 91.75pt;&quot; valign=&quot;top&quot; width=&quot;122&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Invalid&lt;/div&gt;&lt;/td&gt; &lt;td style=&quot;border-bottom: solid black 1.0pt; border-left: none; border-right: solid black 1.0pt; border-top: none; padding: 0cm 5.4pt 0cm 5.4pt; width: 387.05pt;&quot; valign=&quot;top&quot; width=&quot;516&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Only the Customer can set.&lt;/div&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style=&quot;border-top: none; border: solid black 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 91.75pt;&quot; valign=&quot;top&quot; width=&quot;122&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Won’t Fix&lt;/div&gt;&lt;/td&gt; &lt;td style=&quot;border-bottom: solid black 1.0pt; border-left: none; border-right: solid black 1.0pt; border-top: none; padding: 0cm 5.4pt 0cm 5.4pt; width: 387.05pt;&quot; valign=&quot;top&quot; width=&quot;516&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Architect, Technical Lead or Project Manager can set based on agreement with customer.&amp;nbsp; Should be extremely rare.&lt;/div&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style=&quot;border-top: none; border: solid black 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 91.75pt;&quot; valign=&quot;top&quot; width=&quot;122&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Later&lt;/div&gt;&lt;/td&gt; &lt;td style=&quot;border-bottom: solid black 1.0pt; border-left: none; border-right: solid black 1.0pt; border-top: none; padding: 0cm 5.4pt 0cm 5.4pt; width: 387.05pt;&quot; valign=&quot;top&quot; width=&quot;516&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Never set&lt;/div&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style=&quot;border-top: none; border: solid black 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 91.75pt;&quot; valign=&quot;top&quot; width=&quot;122&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Remind&lt;/div&gt;&lt;/td&gt; &lt;td style=&quot;border-bottom: solid black 1.0pt; border-left: none; border-right: solid black 1.0pt; border-top: none; padding: 0cm 5.4pt 0cm 5.4pt; width: 387.05pt;&quot; valign=&quot;top&quot; width=&quot;516&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Never set&lt;/div&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style=&quot;border-top: none; border: solid black 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 91.75pt;&quot; valign=&quot;top&quot; width=&quot;122&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Duplicate&lt;/div&gt;&lt;/td&gt; &lt;td style=&quot;border-bottom: solid black 1.0pt; border-left: none; border-right: solid black 1.0pt; border-top: none; padding: 0cm 5.4pt 0cm 5.4pt; width: 387.05pt;&quot; valign=&quot;top&quot; width=&quot;516&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Software   Engineer can set in the interest of efficiency.&amp;nbsp; Be careful that this   is truly a duplicate and the customer is in fact not describing some   other behaviour.&lt;/div&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style=&quot;border-top: none; border: solid black 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 91.75pt;&quot; valign=&quot;top&quot; width=&quot;122&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Works For Me&lt;/div&gt;&lt;/td&gt; &lt;td style=&quot;border-bottom: solid black 1.0pt; border-left: none; border-right: solid black 1.0pt; border-top: none; padding: 0cm 5.4pt 0cm 5.4pt; width: 387.05pt;&quot; valign=&quot;top&quot; width=&quot;516&quot;&gt;&lt;div class=&quot;MsoNormal&quot;&gt;Never.&amp;nbsp; Negotiate with the Customer for them to set the bug to Invalid instead.&lt;/div&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/2481275683126412522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/2481275683126412522' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/2481275683126412522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/2481275683126412522'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2011/10/resolving-bugs.html' title='Resolving Bugs'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-2180426762576843530</id><published>2011-09-25T13:59:00.002+01:00</published><updated>2011-09-25T14:03:21.414+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="guice"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><title type='text'>Detangling Dependencies Between Guice Injected Services</title><content type='html'>It is very easy to allow services to depend on each other, even when they are in different modules.&amp;nbsp; In fact Guice explicitly supports this behaviour with the AbstractModule#requiredBindings method.&amp;nbsp; I think this is very bad and in my experience has led to some complex interactions and strict requirements on order of creation.&amp;nbsp; Even worse, in some cases you may require a cyclic relationship to fulfill what you want to do which means you can&#39;t fully initialise the services via constructors.&lt;br /&gt;
&lt;br /&gt;
Instead of a clever technical solution, I believe it is the software design that is incorrect.&amp;nbsp; The issue can be resolved using &lt;a href=&quot;http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29&quot;&gt;SOLID&lt;/a&gt; principles to identify and rectify the issue.&lt;br /&gt;
&lt;br /&gt;
The services require the dependencies because they are trying to do too much, this is violating the Single Responsibility Principle (SRP).&amp;nbsp; I often think of SRP as a DON&#39;T whereas the Interface Segregation Principle (ISP) is a DO: to fix an SRP issue apply ISP and move that behaviour out into new classes.&lt;br /&gt;
&lt;br /&gt;
This still hasn&#39;t fixed the issue yet because those dependencies still have to be wired up in the modules, except you don&#39;t.&amp;nbsp; The new classes with dependencies can be instantiated via Guice when required with injected dependencies, the code to wire them up in the modules can be removed altogether.&lt;br /&gt;
&lt;br /&gt;
In this way, layers of objects are being created.&amp;nbsp; The bottom layer of services are injected into the next layer of composite services which are then injected into the application.&amp;nbsp; This is the Open Closed Principle (OCP) where classes should be open for extension but closed for modification.&amp;nbsp; In other words, prefer to building on top of existing classes instead of modifying them.&lt;br /&gt;
&lt;br /&gt;
I do suggest that all layers can talk to each other unless the software is huge enough to justify such abstraction.&amp;nbsp; Also, be sceptical of composite services which simply provide a layer over another service and perhaps wrap exceptions or even provide a something useful.&amp;nbsp; In this case a new API has been created to replace a more universal one.&amp;nbsp; Ask if the new API is actually better than what it is truly wrapping and it is worth the new layer being imposed.</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/2180426762576843530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/2180426762576843530' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/2180426762576843530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/2180426762576843530'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2011/09/detangling-between-guice-injected.html' title='Detangling Dependencies Between Guice Injected Services'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-7760469388063415409</id><published>2011-09-25T13:26:00.000+01:00</published><updated>2012-12-22T18:25:14.953+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="guice"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><title type='text'>Guice Custom Scopes</title><content type='html'>Guice custom scopes are, for some reason badly explained in almost all web documentation that I was able to find.&amp;nbsp; All implementations cover extra Guice concepts or muddy the code with concurrency handling while not describing the main concept which is surprisingly simple once realised.&lt;br /&gt;
&lt;br /&gt;
A scope is a condition for reusing injected objects, instead of creating a new one each time.&amp;nbsp; For example, if a network connection was being injected then the scope would be while the network connection was open, reuse the object.&amp;nbsp; When it is closed, open and inject a new one.&lt;br /&gt;
&lt;br /&gt;
The implementation for this is to basically provide a factory object,&amp;nbsp; implementing the &lt;a href=&quot;http://google-guice.googlecode.com/svn/trunk/latest-javadoc/com/google/inject/Scope.html&quot;&gt;Scope &lt;/a&gt;interface.&amp;nbsp; This has one method:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;Provider&lt;t&gt; scope(Key&amp;lt;T&amp;gt; key, Provider&amp;lt;T&amp;gt; unscoped)&lt;/t&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
The &lt;a href=&quot;http://google-guice.googlecode.com/svn/trunk/latest-javadoc/com/google/inject/Key.html&quot;&gt;Key&lt;/a&gt; object defines the injected type, the unscoped Provider can be used to create a new instance.&amp;nbsp; Typically the returned Provider implementation will&amp;nbsp; create the required object using the unscoped Provider and keep a reference to it while in scope.&amp;nbsp; When the object is requested again the stored object is returned if still in scope.&amp;nbsp; This example usage above is how I needed to use custom scopes but it is flexible enough to do all kinds of weird things.&lt;br /&gt;
&lt;br /&gt;
Here is the Scope implementation.&amp;nbsp; It is a bit more complex than necessary because for this example I wanted to allow objects to be created out of scope.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/4360283.js&quot;&gt;&lt;/script&gt;

Here is out annotation which we will use on classes that can be stored within the scope.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/4360295.js&quot;&gt;&lt;/script&gt;

The interface to inject:&lt;br /&gt;

&lt;script src=&quot;https://gist.github.com/4360323.js&quot;&gt;&lt;/script&gt;

The class that implements that interface to be injected.&amp;nbsp; Note that we have annotated this with our @BookScoped annotation.&amp;nbsp; The constructor will display new objects being created.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/4360303.js&quot;&gt;&lt;/script&gt;

Now our Guice module.&amp;nbsp; The scope annotation is bound to an &lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;EnterableScope &lt;/span&gt;&lt;/span&gt;instance which we&#39;ll keep a hold of.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/4360314.js&quot;&gt;&lt;/script&gt;

Finally the main class to demo the scope.
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/4360318.js&quot;&gt;&lt;/script&gt;

When the main class is run it outputs the following to the command line:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;entering scope&lt;br /&gt;
created customscopes.Hobbit@12a54f9&lt;br /&gt;
exiting scope&lt;br /&gt;
created customscopes.Hobbit@30e280&lt;br /&gt;
created customscopes.Hobbit@16672d6&lt;br /&gt;
created customscopes.Hobbit@fd54d6&lt;br /&gt;
created customscopes.Hobbit@1ccb029&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
When within scope the four calls to &lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;#getInstance&lt;/span&gt;&lt;/span&gt; only create one instance, when not in scope a new instance is created each time.&amp;nbsp; That&#39;s a whole lot of code although it is all fairly simple.&amp;nbsp; From a maintainability viewpoint I do see some issues with this, scopes are so arcane to anyone not experienced with Guice that it would be quite easy to misuse a scope which could cause all kinds of issues with retained state and possibly memory leaks.&amp;nbsp; All I can suggest is document everything and get this over to the team.</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/7760469388063415409/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/7760469388063415409' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/7760469388063415409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/7760469388063415409'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2011/09/guice-custom-scopes.html' title='Guice Custom Scopes'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-6949427823101432497</id><published>2011-08-30T22:39:00.001+01:00</published><updated>2011-08-30T22:41:38.980+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><title type='text'>Checked Exceptions Part 3</title><content type='html'>I found a bug last week that was caused by a checked exception anti-pattern or maybe code smell.  I name this smell &quot;foo() throws Exception&quot;.  The premise is that a method throws Exception, Throwable or any other exception which is low enough down in the class tree to capture the exceptions which may be thrown by the code that is being worked on.  The software engineer happily beavers away without realising that the code is throwing all kinds of exceptions that are not being handled correctly.  The handler is higher up the method chain and detached from what the code is actually doing so cannot reliably act, most likely it is simply logging exceptions.  Once handled and logged nothing more is done possibly leaving the thread and/or application in an invalid state.&lt;br /&gt;
&lt;br /&gt;
This can be caused by the programmer wanting the exception handling to go away perhaps because exceptions were used too liberally and now there is more exception handling than business logic.  Maybe handling the exception is too uncomfortable since there is no plan B, there is only failure, but the application is long running and cannot be restarted so a catch-all was a last resort for an error that supposedly could not happen.&lt;br /&gt;
&lt;br /&gt;
The application in question simulates a &lt;a href=&quot;http://www.google.co.uk/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CCEQFjAA&amp;amp;url=http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FGSM-R&amp;amp;rct=j&amp;amp;q=gsmr&amp;amp;ei=dlZdTou8KZLA8QP60OmcAw&amp;amp;usg=AFQjCNGKzKhvmi_acT_N31QWGMWgwMehaQ&amp;amp;sig2=Y_jJY5nO2zDAMqWm4iRmnA&amp;amp;cad=rja&quot;&gt;GSM-R&lt;/a&gt; application and calls are made to get the active call which the application is currently dealing with.&amp;nbsp; The other party could end the call at any time and the system is completely asynchronous and multi-threaded and it is highly likely that no call could exist the next time you check for it.&amp;nbsp; The exception being thrown was part of the null-checking strategy which has proved highly effective in reducing NPEs.&amp;nbsp; Instead of a null being returned from a method, a checked exception is returned: CallDoesNotExistException.&amp;nbsp; So this exception could happen in normal application flow and must be handled by application logic.&lt;br /&gt;
&lt;br /&gt;
As it turned out the fix was remarkably elegant once the functionality as a whole was understood (read remembered).&amp;nbsp; A catch for CallDoesNotExistException was added to the catch-all handler which would navigate the user out of the process they were in to one of the two possible application states fixing similar issues in the entire application.&amp;nbsp; This change was helped by the fact that CallDoesNotExistException is task specific and other parts of the application could easily identify the issue in the code, as opposed to a generic exception which would be almost impossible to identify whether it was checked or not.</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/6949427823101432497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/6949427823101432497' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/6949427823101432497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/6949427823101432497'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2011/08/checked-exceptions-part-3.html' title='Checked Exceptions Part 3'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-9210719658852223479</id><published>2011-08-03T00:14:00.001+01:00</published><updated>2012-11-02T10:25:09.737+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><title type='text'>Using Method Handles</title><content type='html'>A few weeks ago I ran some tests pitting method handles against typical reflection to see what was faster.  The result was that reflection was faster although since it was a quick test I don&#39;t have the result data or what run configuration I used.  Now that I&#39;m tasked with looking into porting our core systems to Java 7 I thought I&#39;d take a more critical look.&lt;br /&gt;
&lt;br /&gt;
Below is the source code I used to run the test.  It calls a method on a class called Incrementer a million times.  I didn&#39;t notice any difference when running the methods several times when running the test several times before timing values to &quot;warm up&quot; server mode.  &lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3999932.js&quot;&gt; &lt;/script&gt;
&lt;br /&gt;
Note that this code throws an exception when run from eclipse.  I had to use the javac/java executables from the command line for this to work.  When running the class in mixed mode I got the following results:&lt;br /&gt;
&lt;br /&gt;
java -verbose:gc  MethodHandleTest&lt;br /&gt;
[GC 4416K-&amp;gt;141K(15872K), 0.0011714 secs]&lt;br /&gt;
[GC 4557K-&amp;gt;141K(15872K), 0.0006216 secs]&lt;br /&gt;
[GC 4557K-&amp;gt;141K(15872K), 0.0006387 secs]&lt;br /&gt;
reflection took &lt;b&gt;515ms&lt;/b&gt;, result is 1000000&lt;br /&gt;
method handles took &lt;b&gt;16ms&lt;/b&gt;, result is 1000000&lt;br /&gt;
&lt;br /&gt;
There is plenty of garbage collection happening but not enough to account for the huge time difference.  When running in server mode I got the following results:&lt;br /&gt;
&lt;br /&gt;
java -verbose:gc  -server MethodHandleTest&lt;br /&gt;
reflection took &lt;b&gt;47ms&lt;/b&gt;, result is 1000000&lt;br /&gt;
method handles took &lt;b&gt;15ms&lt;/b&gt;, result is 1000000&lt;br /&gt;
&lt;br /&gt;
java -verbose:gc  -server MethodHandleTest&lt;br /&gt;
reflection took &lt;b&gt;32ms&lt;/b&gt;, result is 1000000&lt;br /&gt;
method handles took &lt;b&gt;31ms&lt;/b&gt;, result is 1000000&lt;br /&gt;
&lt;br /&gt;
All runs of the test gave almost identical results to the above where method handles would be twice as fast as reflection or equal with no garbage collection.  Interestingly, if I comment out the increment of the long value the same result as with the increment is produced:&lt;br /&gt;
&lt;br /&gt;
java -verbose:gc MethodHandleTest&lt;br /&gt;
[GC 4416K-&amp;gt;141K(15872K), 0.0011488 secs]&lt;br /&gt;
[GC 4557K-&amp;gt;141K(15872K), 0.0006595 secs]&lt;br /&gt;
[GC 4557K-&amp;gt;141K(15872K), 0.0006482 secs]&lt;br /&gt;
reflection took &lt;b&gt;500ms&lt;/b&gt;, result is 0&lt;br /&gt;
method handles took &lt;b&gt;31ms&lt;/b&gt;, result is 0&lt;br /&gt;
&lt;br /&gt;
This makes me think that incrementing the long is a very small proportion of the time it takes for the reflection example to run and the majority is for calling the method through reflection.  In server mode the reflection call is JITted and almost identical results are produced.  This is mostly conjecture since it is quite difficult to work out what the Hotspot compiler is doing.&lt;br /&gt;
&lt;br /&gt;
In conclusion, method handles consistently performs as good as, or better than reflection no matter what run configuration you are using.  Stability is an issue with the current tools, eclipse will have to support Java 7 before I could use method handles in our systems.</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/9210719658852223479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/9210719658852223479' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/9210719658852223479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/9210719658852223479'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2011/08/using-method-handles.html' title='Using Method Handles'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4304505761826299706.post-8538672503689730925</id><published>2011-05-07T17:41:00.001+01:00</published><updated>2011-05-07T17:42:48.683+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><title type='text'>An Immutable List in the JDK</title><content type='html'>It&#39;s quite strange that there is no immutable list class in the JDK, immutability is most likely the biggest part of any concurrent design.&amp;nbsp; It&#39;s well understood that an immutable object can be safely passed or accessed by other threads meaning that it is not necessary to lock.&lt;br /&gt;
&lt;br /&gt;
It&#39;s not quite true that there is no immutable lists in the JDK, there is always the Collections#unmodifiableList method, return a wrapper around the supplied List that does not allow modification.&amp;nbsp; However, it is only a wrapper and the underlying data structure can be modified so there are no guarantees about immutability, only conventions which are only convention if you knew about it in the first place.&amp;nbsp; Or the guy before you did.&lt;br /&gt;
&lt;br /&gt;
The problem with the unmodifiable list is that once you have it, there is no way to check if it is unmodifiable.&amp;nbsp; The implementation class, UnmodifiableList is package protected so it is not possible even to do an instanceof check.&amp;nbsp; I have found this to be a big source of inefficiency.&amp;nbsp; There is no way to check if the list is immutable so if you must have an immutable list you can &quot;ask&quot; via documentation that lists should be immutable or defensively copy the list.&amp;nbsp; Typically I would using defensive copying, because there is no way to know how the code is going to be used in the future and if the engineer is going to check the documentation.&amp;nbsp; I&#39;m not even sure that it is a reasonable requirement to ask someone to check the small print for every method they use.&lt;br /&gt;
&lt;br /&gt;
The fix for this is relatively easy and even doable without hacking the OpenJDK by using the -XbootClasspath command line option.&amp;nbsp; Using this you can specify the boot classes you want to load, by default its your JRE rt.jar.&amp;nbsp; If you modify some JDK classes you can specify that to be loaded first and then rt.jar so your modified classes will be first to load.&lt;br /&gt;
&lt;br /&gt;
All that needs to be done as a starting point is to make the UnmodifiableList class public and make that the return type from Collections#unmodifiableList instead of List so we know what we&#39;re getting and other classes can pass it around also.&amp;nbsp; It doesn&#39;t fix the possibility of the data structure being modified but we&#39;re 80% of the way there for such a small change.&amp;nbsp; Because UnmodifiableList is still a List implementation all current code will still compile.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
Unfortunately it is not legal to deploy this change to a production system, it&#39;s only for fun.</content><link rel='replies' type='application/atom+xml' href='http://andrewtill.blogspot.com/feeds/8538672503689730925/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4304505761826299706/8538672503689730925' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/8538672503689730925'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4304505761826299706/posts/default/8538672503689730925'/><link rel='alternate' type='text/html' href='http://andrewtill.blogspot.com/2011/05/immutable-list-in-jdk.html' title='An Immutable List in the JDK'/><author><name>Andy Till</name><uri>http://www.blogger.com/profile/13022942102319196525</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>