nice IE6 bashing



Must read : The unspoken truth about managing geeks

Thanks to Nathan on coderspiel, I stumbled upon this excellent article : Opinion: The unspoken truth about managing geeks.

So true !

++

Certification, part 2 ;)

hi

Small post to tell that I’ve started to look into SCJD, another certification. As such, I fear I will once again post way less (in case anyone cared, which might be quite optimistic, yes I know, thanks ;) ).

Anyway, not to do a totally useless entry, let’s share a few links :

see ya !
++

Book review : SCJP Sun Certified Programmer for Java 6 Study Guide

In order to get ready for the SCJP 6 exam, I’ve read SCJP Sun Certified Programmer for Java 6 Study Guide, from Katherine Sierra and Bert Bates, aka some of the certification’s exam creators.

The authors make clear at the beginning that the book is about, and only about, being ready for the SCJP exam. No more, no less. And they keep to their words : the book is strictly focused on the exam.

The bad consequence is that sometime (often) I was eager to know more, to go further the “there’s plenty more to tell, but that’s enough for the exam, so we stop here”. Furthermore, as you can imagine, this isn’t the most fancy book I’ve ever read. Katherine and Bert do attempt a few times to instil some fun, but it didn’t fall quite right.

The very good side is that the book teaches all you need to know, no more, no less. I would even go a bit further : if the authors say “methods X and Y are also part of the exam”, then you should really know exactly what’s in these methods. I’m pretty sure I lost some points due to some API I didn’t know enough. Even better, they say clearly what’s in the exam and not. No need to worry because some dumb mock exams found on the web put stuff you hadn’t any clue off. If it wasn’t in the book, it’s not on the exam.
Even more important, the writers are very good at explanations. Really, they know out to make things clear. Awesome. I now have a grip on regexp. Really !

To conclude, this book is really one (if not the one – I haven’t read the others so it’s hard to tell) to go for when preparing SCJP 6, no more, no less. At least it was for me!

++

EDIT : did a bit of clean-up

Wave Panel for Wicket

in case someone thought it was a good idea:

We’re delighted to introduce a new wicket component which will allow you to easily integrate Google Waves right into your application. Please meet GoogleWavePanel !
The idea of making this component came from a recent tutorial which aimed at clarifying the use of Google’s Wave Embed API.

http://blog.zenika.com/index.php?post/2010/02/03/Surf-the-Wave-with-Wicket-and-the-GoogleWavePanel

Book review : Don’t make me think

I had already read some books on usability. The last one had about 400 pages and lots of texts. It laid out 10 (or 12) rules regarding usability. I can’t even remember one !

On the other hand, Steve Krug’s Don’t make me think is still deeply in my mind. Not only the author applied usability to his book (about 200 pages, very easy to read with drawings right to the point), but, even better, what he wrote is enlightening.

First, Steve Krug introduces the “guiding principles”, all evolving around his First Law of Usability : Don’t make me think. Simply put, the aim is to remove all questions, even unconscious ones, when browsing the web. All these littles inconveniences or inconsistencies which go in the way must disappear. And Steve Krug presents this with way more skills and drawings than I do, making it really impressive and long lasting.

He goes on speaking on the way we use the web (scanning, not reading), than that we should “Omit needless words”.

These first chapters are still vivid in my mind. They come with very relevant examples that we’ve all seen before, and thus that we’ll see again in the future, bringing back the good stuff of this book.

Then, Steve Krug goes on a more general level : why/how to avoid these endless discussions about “mine design is better than yours”, how to do “real size” usability tests (and not the ones requiring huge resources/teams/testers/rooms/… as was put in this previous book!) and how to deal with Pointy-Haired Bosses. Less crazy than the first chapters, but really helpful.

Overall, this book really helped me. I now have quite a tool set (and mindset) to deal with usability questions. To put it shortly, I feel now empowered on this topic, quite a change from my previous readings.

To conclude, if usability is remotely some of your concern (and you don’t know it all already), read this book !

++
joseph

Playing with Wicket’s templates

Wicket comes with some templating facilities. They’re often handy, especially when integrating JavaScript components.

Yet, for some reasons I don’t get, these functionalities aren’t much advertised. Anyway, let’s dig in !

Basically, this templating is about some text containing variables, for example ${variable}, whose values are provided through Java code.

Let’s take a simple example, a template file named javascript.tpl containing :

alert('${variable}');

Wicket is nice enough to provide an easy to access the templates as package resources, through the PackagedTextTemplate class :

 Java |  copy |? 
public PackagedTextTemplate(final Class< ? > clazz, final String fileName)

For example :

 Java |  copy |? 
PackagedTextTemplate jsTemplate = new PackagedTextTemplate(this.getClass(), "javascript.tpl");

Thus the template can be next to the .html page and the Java class using it, making the whole quite cohesive.

Providing the variables is done through a simple Map :

 Java |  copy |? 
Map< String , Object > parameters = new HashMap< String , Object >();
parameters.put("variable","test working");

And then, you most probably want to include this template in some html. Wicket provides you different options :

  • as an header contribution :
     Java |  copy |? 
    add(TextTemplateHeaderContributor.forJavaScript(jsTemplate, new  Model((Serializable) parameters)));
  • directly next to some element in the html file:
    Java side :
     Java |  copy |? 
    Label myScript = new Label("myScript", new JavaScriptTemplate(jsTemplate).asString(parameters));
    myScript.setEscapeModelStrings(false);
    add(myScript);

    Html side :

    <wicket:container wicket:id="myScript"></wicket:container>

You may have noticed that, in both cases, I didn’t provided the surrounding script tag (and the appropriate inner wrapping). Fear not, Wicket does it for you !
Indeed, the rendered html is :

<script type="text/javascript"><!--/*--><![CDATA[/*><!--*/
alert('test working');
/*-->]]>*/</script>

If the template was about some CSS stuff, one would just need to warp it using a CssTemplate instead of the JavaScriptTemplate.

A bit more info are available there Including CSS resources.

++
joseph

Primitive Array to Object[]

If ever you face the need of ‘boxing’ the elements of a primitive array into an array of Objects, this might be handy:

 Java |  copy |? 
    public static Object[] convertPrimitiveArray(final Object array)
    {
        final int arrayLength = Array.getLength(array);
        final Object[] result = (Object[]) Array.newInstance(Object.class, arrayLength);
        for (int i = 0; i < arrayLength; i++)
        {
            Array.set(result, i, Array.get(array, i));
        }
        return result;
    }
 

Noteworthy: MS adds Mercurial support to Codeplex

via http://blogs.msdn.com/codeplex/archive/2010/01/22/codeplex-now-supporting-native-mercurial.aspx

m2eclipse workspace resolution not working ?

We have this “fix”:

  • Go to your workspace folder
  • in the folder .metadata/.plugins/org.maven.ide.eclipse, remove all file ending with .container
  • in eclipse, clear all projects
  • hope for the best

For us, it has resolved a nasty issue we had : some projects’ dependencies weren’t resolved locally even if the projects in question were in the workspace.

Hope it helps

++

Eclipse Builder plugin

in case you use Eclipse and like the builder pattern, try this plugin. Update Site: http://boss.bekk.no/bpep/update

Spinner via css while image loading

very simple but neat idea by martijn dashorst:

<img src="http://example.com/images/someimage.jpg" style="background-image:url('style/spinner.gif');" />

Assuming the local machine is faster than the external server, the
spinner should be visible while the external image loads.

Martijn

Book review : Test-Driven Development By Example

hi

I’ve recently read Test-Driven Development By Example, a book from Kent Beck.

I’ve liked the following:

  • description of the TDD cycle : Red – write a little failing test/Green – make the test pass quickly, even if it involves dirty tricks or duplication/Refactor – make the code clean, including hunting for duplicates for example.

    The emphasis on making the test working quickly first was a bit unexpected to me. Indeed, I tend to try to write “clean code” first. It’s not bad in itself, but it happens sometime that I’m not confident with the design. Thus, I feel uneasy. Smaller steps, maybe less clean, would probably help: seeing a green bar is always a good feeling. This leads me to the next point.

  • Kent writes that one of the key point of TDD is about reducing stress : being able to do small steps reduces the stress/fear level, hence fewer errors and better feeling. If the target design is unknown or intimidating, use (very) small steps.

    As pointed before, I wasn’t really aware of this, even if I appreciated the final feeling one has after writing proper unit tests. I’ll try it :)

  • The notion of “emerging/organic” design is as well spoken of. It’s the idea that with proper TDD the design will evolve to fit exactly the needs, no more, no less. A kind of perfect match in the end.

    I had already heard of it but it was a nice refresher. Still, it doesn’t fit with our actual practices : we tend to prototype first the design.

    But maybe once I should try starting with a very easy and naive implementation and see where it goes. After a few refactorings, it may end at the same design, or may be even better. Still, I fear it would take more time and I’m unsure about the results.

    On the other hand, as told by Kent, if ever the code has to evolve to become more general, this can be done easily, with the tests providing the required safety net. Then, how many code are designed with a way broader scope that they’ll actually use, leading to verbose and/or a bit inappropriate abstractions ?

    Once again, feedback is welcome, and anyway I’ll test it.

  • TDD helps narrowing and keeping focus. That’s a big reason for the small steps, one thing at a time, so if something behaves in a unexpected way it’s easy to spot early.

    But Kent pushes it further : when doing TDD and using “dirty tricks” to get the green bar, he suggests writing done a list of the stuff left to do. He does so as well for other related ideas popping up. The aim is to keep focus on the current work, coming back later on the todo/improvements noted (which in turn, for sure, can/should be done test first ;) ). He suggests using a good old paper list, and simply to strike the work done. As such, progress can be seen easily and is quite satisfactory. Furthermore, the overview is always present and one can easily pick the easiest/smallest stuff to do, for example just before leaving.

    Said this way, it may sound obvious, but the fact is that we tend to lost focus when doing pair programming. Maybe Pomodoro could help us, but this way of doing as well. Again, it’s worth a try !

Still, the book wasn’t only joy to read. The first 80 pages are a TDD example where Kent Beck uses very small steps. Personally, it really went on my nerves. Furthermore, he complains about some lack of features in Java which have been added since (the book is from 2003). It didn’t help neither.

He finishes the book with a small chapters on different patterns, like “red bar”, “green bar” , testing, xUnit, design and refactoring. If you have a bit of practices regarding unit testing and if you have knowledge on patterns and refactoring (personally I’ve read books like Refactoring and Head First Design Patterns), there is few to learn there. Only the null pattern did interest me and will be the topic of another post. I wish he has spent more time on testing, like which code coverage to aim for (and why), gui unit testing and common pitfalls.

Maybe some answers lie in the “Testing Object Oriented Systems: Models, Patterns, and Tools” which he presents as “the comprehensive reference on testing”. This time is a 1000 pages book, sounds intriguing ;) lol

++

Side note : I often wonder if my reviews aren’t too verbose… I would welcome feedback on the matter !

Hibernate statistics page

Hi !

We were some time ago at a presentation about hibernate (at a Karlsruhe JUG event). The presenter, Michael Plöd showed us a nice Hibernate statistics page. As you can bet, we went for reusing it :)

However, in doing so, some issues appeared, and in the end we thought the updated version could be useful for others as well.

It mainly consists in an adaptation to Wicket 1.4 (generics).

In details, the changes are :
- use of ReloadableDetachableModel, needed AFAIK by Hibernate statistics (they have transient fields in their objects, and as such I was getting NPE after refreshing the page),
- page completely “genericfied” : compact code, no more cast or compiler warning (the page was written for wicket 1.3 I presume),
- minor display issues fixed : date showed as a formatted date, executionMinTime’s default value (Long.MAX_VALUE) taken in account (and replace by zero),
- html closer from the “standards” : use of h1, thead and the like (which we use in our template, so…),
- in order to make the component injection independent, there is now a setter for the entity manager provider (consequently the actual page construction is made in “onBeforeRender”),
- the code is now in a panel, so it can be easily put in any application specific page.

Whatever, the code, quite long long, is following.

 Java |  copy |? 
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
import javax.persistence.EntityManager;
 
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.stat.CollectionStatistics;
import org.hibernate.stat.EntityStatistics;
import org.hibernate.stat.QueryStatistics;
import org.hibernate.stat.SecondLevelCacheStatistics;
import org.hibernate.stat.Statistics;
 
public class HibernateStatisticsPanel extends Panel
{
    private static final String DATE_FORMAT = "hh'h'mm dd.yy.MM";
 
    private EntityManager entityManager;
 
    private static DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
 
    public HibernateStatisticsPanel(final String id)
    {
        super(id);
    }
 
     @Override
    protected void onBeforeRender()
    {
        if (!hasBeenRendered())
        {
            if (entityManager == null)
            {
                throw new IllegalStateException("The entityManagerProvider must be set.");
            }
            final CompoundPropertyModel< Statistics > model = new CompoundPropertyModel< Statistics >(
                    new LoadableDetachableModel< Statistics >()
                    {
                         @Override
                        protected Statistics load()
                        {
 
                            return getSessionFactory(entityManager).getStatistics();
                        }
                    });
            setDefaultModel(model);
 
            add(new Label("isStatisticsEnabled", new LoadableDetachableModel< String >()
            {
 
                 @Override
                protected String load()
                {
                    String result;
                    if (areStatsEnabled() == true)
                    {
                        result = "enabled" + " since " + dateFormat.format(new Date(model.getObject().getStartTime()))
                                + " (" + DATE_FORMAT + ")";
                    }
                    else
                    {
                        result = "disabled";
                    }
                    return result;
                }
 
            }));
 
            Link< Void > switchStats = new Link< Void >("switch_stats")
            {
                 @Override
                public void onClick()
                {
                    final SessionFactory sessionFactory = getSessionFactory(entityManager);
                    sessionFactory.getStatistics().setStatisticsEnabled(
                            !sessionFactory.getStatistics().isStatisticsEnabled());
                    sessionFactory.getStatistics().clear();
                    final CompoundPropertyModel< Statistics > model = new CompoundPropertyModel< Statistics >(
                            new LoadableDetachableModel< Statistics >()
                            {
                                 @Override
                                protected Statistics load()
                                {
                                    return sessionFactory.getStatistics();
                                }
                            });
                    setDefaultModel(model);
                }
            };
            switchStats.add(new Label("switchText", new LoadableDetachableModel< String >()
            {
 
                 @Override
                protected String load()
                {
                    if (areStatsEnabled())
                    {
                        return "Click to disable stats";
                    }
                    return "Click to enable stats";
                }
            }));
            add(switchStats);
 
            add(new Label("sessionOpenCount"));
            add(new Label("sessionCloseCount"));
            add(new Label("flushCount"));
            add(new Label("connectCount"));
            add(new Label("prepareStatementCount"));
            add(new Label("closeStatementCount"));
            add(new Label("entityLoadCount"));
            add(new Label("entityUpdateCount"));
            add(new Label("entityInsertCount"));
            add(new Label("entityDeleteCount"));
            add(new Label("entityFetchCount"));
            add(new Label("collectionLoadCount"));
            add(new Label("collectionUpdateCount"));
            add(new Label("collectionRemoveCount"));
            add(new Label("collectionRecreateCount"));
            add(new Label("collectionFetchCount"));
            add(new Label("secondLevelCacheHitCount"));
            add(new Label("secondLevelCacheMissCount"));
            add(new Label("secondLevelCachePutCount"));
            add(new Label("queryExecutionCount"));
            add(new Label("queryExecutionMaxTime"));
            add(new Label("queryExecutionMaxTimeQueryString"));
            add(new Label("queryCacheHitCount"));
            add(new Label("queryCacheMissCount"));
            add(new Label("queryCachePutCount"));
            add(new Label("commitedTransactionCount"));
            add(new Label("transactionCount"));
            add(new Label("optimisticFailureCount"));
 
            ListView< EntityStatistics > entityStats = new ListView< EntityStatistics >("entities",
                    new LoadableDetachableModel< List < EntityStatistics > >()
                    {
 
                         @Override
                        protected List< EntityStatistics > load()
                        {
                            String[] entities = model.getObject().getEntityNames();
                            List< EntityStatistics > entityNames = new ArrayList< EntityStatistics >();
                            for (int i = 0; i < entities.length; i++)
                            {
                                entityNames.add(model.getObject().getEntityStatistics(entities[i]));
                            }
                            return entityNames;
                        }
                    })
            {
                 @Override
                protected void populateItem(final ListItem< EntityStatistics > item)
                {
                    item.setModel(new CompoundPropertyModel< EntityStatistics >(item.getModelObject()));
 
                    item.add(new Label("deleteCount"));
                    item.add(new Label("updateCount"));
                    item.add(new Label("fetchCount"));
                    item.add(new Label("insertCount"));
                    item.add(new Label("loadCount"));
                    item.add(new Label("optimisticFailureCount"));
                    item.add(new Label("categoryName"));
                }
            };
            add(entityStats);
 
            ListView collectionStats = new ListView("collections",
                    new LoadableDetachableModel< List >()
                    {
 
                         @Override
                        protected List load()
                        {
                            String[] collections = (model.getObject()).getCollectionRoleNames();
                            List collectionNames = new ArrayList();
                            for (int i = 0; i < collections.length; i++)
                            {
                                collectionNames.add(model.getObject().getCollectionStatistics(collections[i]));
                            }
                            return collectionNames;
                        }
                    })
            {
                 @Override
                protected void populateItem(final ListItem item)
                {
                    item.setModel(new CompoundPropertyModel(item.getModelObject()));
 
                    item.add(new Label("recreateCount"));
                    item.add(new Label("updateCount"));
                    item.add(new Label("fetchCount"));
                    item.add(new Label("removeCount"));
                    item.add(new Label("loadCount"));
                    item.add(new Label("categoryName"));
                }
            };
            add(collectionStats);
 
            ListView< QueryStatistics > queryStats = new ListView< QueryStatistics >("queries",
                    new LoadableDetachableModel< List < QueryStatistics > >()
                    {
 
                         @Override
                        protected List< QueryStatistics > load()
                        {
                            String[] queries = (model.getObject()).getQueries();
                            List< QueryStatistics > queryNames = new ArrayList< QueryStatistics >();
                            for (int i = 0; i < queries.length; i++)
                            {
                                queryNames.add(model.getObject().getQueryStatistics(queries[i]));
                            }
                            return queryNames;
                        }
                    })
            {
                 @Override
                protected void populateItem(final ListItem< QueryStatistics > item)
                {
                    item.setModel(new CompoundPropertyModel< QueryStatistics >(item.getModelObject()));
 
                    item.add(new Label("cacheHitCount"));
                    item.add(new Label("cacheMissCount"));
                    item.add(new Label("cachePutCount"));
                    item.add(new Label("executionCount"));
                    item.add(new Label("executionRowCount"));
                    item.add(new Label("executionAvgTime"));
                    item.add(new Label("executionMaxTime"));
                    item.add(new Label("executionMinTime", new AbstractReadOnlyModel< String >()
                    {
 
                         @Override
                        public String getObject()
                        {
                            // by default the hibernate stats. object put
                            // Long.MAX_VALUE to the executionMinTime, so we
                            // look for it and replace it by 0 where needed
                            long executionMinTime = item.getModelObject().getExecutionMinTime();
                            if (executionMinTime == Long.MAX_VALUE)
                            {
                                return "0";
                            }
                            return "" + executionMinTime;
                        }
                    }));
                    item.add(new Label("categoryName"));
                }
            };
            add(queryStats);
 
            ListView< SecondLevelCacheStatistics > cacheStats = new ListView< SecondLevelCacheStatistics >("caches",
                    new LoadableDetachableModel< List < SecondLevelCacheStatistics > >()
                    {
                         @Override
                        protected List< SecondLevelCacheStatistics > load()
                        {
                            String[] caches = model.getObject().getSecondLevelCacheRegionNames();
                            List< SecondLevelCacheStatistics > cacheNames = new ArrayList< SecondLevelCacheStatistics >();
                            for (int i = 0; i < caches.length; i++)
                            {
                                cacheNames.add(model.getObject().getSecondLevelCacheStatistics(caches[i]));
                            }
                            return cacheNames;
                        }
                    })
            {
                 @Override
                protected void populateItem(final ListItem< SecondLevelCacheStatistics > item)
                {
                    item.setModel(new CompoundPropertyModel< SecondLevelCacheStatistics >(item.getModelObject()));
 
                    item.add(new Label("hitCount"));
                    item.add(new Label("missCount"));
                    item.add(new Label("putCount"));
                    item.add(new Label("elementCountInMemory"));
                    item.add(new Label("elementCountOnDisk"));
                    item.add(new Label("sizeInMemory"));
                    item.add(new Label("categoryName"));
                }
            };
            add(cacheStats);
 
        }
        super.onBeforeRender();
    }
 
    private boolean areStatsEnabled()
    {
        return ((Statistics) getDefaultModelObject()).isStatisticsEnabled();
    }
 
    public static SessionFactory getSessionFactory(final EntityManager entityManager)
    {
        Object delegate = entityManager.getDelegate();
        if (delegate instanceof Session)
        {
            Session session = (Session) delegate;
 
            return session.getSessionFactory();
        }
        return null;
    }
 
    public void setEntityManager(final EntityManager entityManager)
    {
        this.entityManager = entityManager;
    }
 
    public EntityManager getEntityManager()
    {
        return entityManager;
    }
}

And the html page :

<html>
     <wicket:panel>
              <h1>Hibernate Statistics</h1>
               Statistics are <span wicket:id="isStatisticsEnabled"/>.<br /> <a href="#" wicket:id="switch_stats"><span wicket:id="switchText"></span></a>
     <br /><br />
     <h2>Overview</h2>
    <table class="whiteGrey">
        <tr><th>sessionOpenCount</th><td><span wicket:id="sessionOpenCount"/></td></tr>
        <tr><th>sessionCloseCount</th><td><span wicket:id="sessionCloseCount"/></td></tr>
        <tr><th>flushCount</th><td><span wicket:id="flushCount"/></td></tr>
        <tr><th>connectCount</th><td><span wicket:id="connectCount"/></td></tr>
        <tr><th>prepareStatementCount</th><td><span wicket:id="prepareStatementCount"/></td></tr>
        <tr><th>closeStatementCount</th><td><span wicket:id="closeStatementCount"/></td></tr>
        <tr><th>entityLoadCount</th><td><span wicket:id="entityLoadCount"/></td></tr>
        <tr><th>entityUpdateCount</th><td><span wicket:id="entityUpdateCount"/></td></tr>
        <tr><th>entityInsertCount</th><td><span wicket:id="entityInsertCount"/></td></tr>
        <tr><th>entityDeleteCount</th><td><span wicket:id="entityDeleteCount"/></td></tr>
        <tr><th>entityFetchCount</th><td><span wicket:id="entityFetchCount"/></td></tr>
        <tr><th>collectionLoadCount</th><td><span wicket:id="collectionLoadCount"/></td></tr>
        <tr><th>collectionUpdateCount</th><td><span wicket:id="collectionUpdateCount"/></td></tr>
        <tr><th>collectionRemoveCount</th><td><span wicket:id="collectionRemoveCount"/></td></tr>
        <tr><th>collectionRecreateCount</th><td><span wicket:id="collectionRecreateCount"/></td></tr>
        <tr><th>collectionFetchCount</th><td><span wicket:id="collectionFetchCount"/></td></tr>
        <tr><th>secondLevelCacheHitCount</th><td><span wicket:id="secondLevelCacheHitCount"/></td></tr>
        <tr><th>secondLevelCacheMissCount</th><td><span wicket:id="secondLevelCacheMissCount"/></td></tr>
        <tr><th>secondLevelCachePutCount</th><td><span wicket:id="secondLevelCachePutCount"/></td></tr>
        <tr><th>queryExecutionCount</th><td><span wicket:id="queryExecutionCount"/></td></tr>
        <tr><th>queryExecutionMaxTime</th><td><span wicket:id="queryExecutionMaxTime"/></td></tr>
        <tr><th>queryExecutionMaxTimeQueryString</th><td><span wicket:id="queryExecutionMaxTimeQueryString"/></td></tr>
        <tr><th>queryCacheHitCount</th><td><span wicket:id="queryCacheHitCount"/></td></tr>
        <tr><th>queryCacheMissCount</th><td><span wicket:id="queryCacheMissCount"/></td></tr>
        <tr><th>queryCachePutCount</th><td><span wicket:id="queryCachePutCount"/></td></tr>
        <tr><th>commitedTransactionCount</th><td><span wicket:id="commitedTransactionCount"/></td></tr>
        <tr><th>transactionCount</th><td><span wicket:id="transactionCount"/></td></tr>
        <tr><th>optimisticFailureCount</th><td><span wicket:id="optimisticFailureCount"/></td></tr>           
    </table>
    
    <h2>Entity Statistics</h2>
    <table class="whiteGrey">
        <thead>
             <tr>
                 <th>Entity</th>
                 <th>Load Count</th>
                 <th>Fetch Count</th>
                 <th>Insert Count</th>
                 <th>Delete Count</th>
                 <th>Update Count</th>
                 <th>Optimistic Failure Count</th>
               </tr>
        </thead>
          <tbody>
            <tr wicket:id="entities">
                <td><span wicket:id="categoryName"/></td>
                <td><span wicket:id="loadCount"/></td>
                <td><span wicket:id="fetchCount"/></td>
                <td><span wicket:id="insertCount"/></td>
                <td><span wicket:id="deleteCount"/></td>
                <td><span wicket:id="updateCount"/></td>
                <td><span wicket:id="optimisticFailureCount"/></td>
            </tr>
          </tbody>               
    </table>
    
    <h2>Collection Statistics</h2>
    <table class="whiteGrey">
        <thead>
             <tr>
                 <th>Collection</th>
                 <th>Load Count</th>
                 <th>Fetch Count</th>
                 <th>Recreate Count</th>
                 <th>Remove Count</th>
                 <th>Update Count</th>
               </tr>
        </thead>
          <tbody>
            <tr wicket:id="collections">
                <td><span wicket:id="categoryName"/></td>
                <td><span wicket:id="loadCount"/></td>
                <td><span wicket:id="fetchCount"/></td>
                <td><span wicket:id="recreateCount"/></td>
                <td><span wicket:id="removeCount"/></td>
                <td><span wicket:id="updateCount"/></td>
            </tr>
          </tbody>
    </table>
    
    <h2>Query Statistics</h2>
    <table class="whiteGrey">
        <thead>
             <tr>
                 <th>Query</th>
                 <th>Execution Count</th>
                 <th>Execution Row Count</th>
                 <th>Avg Time</th>
                 <th>Min Time</th>
                 <th>Max Time</th>
                 <th>Cache Hit Count</th>
                 <th>Cache Miss Count</th>
                 <th>Cache Put Count</th>
               </tr>
          </thead>
          <tbody>
            <tr wicket:id="queries">
                <td><span wicket:id="categoryName"/></td>
                <td><span wicket:id="executionCount"/></td>
                <td><span wicket:id="executionRowCount"/></td>
                <td><span wicket:id="executionAvgTime"/></td>
                <td><span wicket:id="executionMinTime"/></td>
                <td><span wicket:id="executionMaxTime"/></td>
                <td><span wicket:id="cacheHitCount"/></td>
                <td><span wicket:id="cacheMissCount"/></td>
                <td><span wicket:id="cachePutCount"/></td>
            </tr>
          </tbody>
    </table>
    
    <h2>Cache Statistics</h2>
    <table class="whiteGrey">
         <thead>
             <tr>
                 <th>Cache</th>
                 <th>Hit Count</th>
                 <th>Miss Count</th>
                 <th>Put Count</th>
                 <th>Elements in Memory</th>
                 <th>Elements on Disk</th>
                 <th>Size in Memory</th>
             </tr>
          </thead>
          <tbody>               
            <tr wicket:id="caches">
                <td><span wicket:id="categoryName"/></td>
                <td><span wicket:id="hitCount"/></td>
                <td><span wicket:id="missCount"/></td>
                <td><span wicket:id="putCount"/></td>
                <td><span wicket:id="elementCountInMemory"/></td>
                <td><span wicket:id="elementCountOnDisk"/></td>
                <td><span wicket:id="sizeInMemory"/></td>
            </tr>
          </tbody>
    </table>
     </wicket:panel>
</html>

The guicy one is as simple as :

 Java |  copy |? 
import javax.persistence.EntityManager;
 
import org.apache.wicket.markup.html.panel.Panel;
 
import com.google.inject.Inject;
 
public class GuicyHibernateStatisticsPanel extends Panel
{
 
     @Inject
    private EntityManager entityManager;
 
    public GuicyHibernateStatisticsPanel(final String id)
    {
        super(id);
        HibernateStatisticsPanel statisticsPanel = new HibernateStatisticsPanel("hibernateStatisticsPanel");
        statisticsPanel.setEntityManager(entityManager);
        add(statisticsPanel);
    }
 
}

and :

<html>
     <body>
          <wicket:panel>
               <wicket:container wicket:id="hibernateStatisticsPanel" />
          </wicket:panel>
          
     </body>
</html>

Hope it helps :)
++

PS : I know the html code isn't shown as best as it could, but I was fed up of trying to get wordpress to render the tags...

Wicket gem: Gravatar

from the javadoc:

Creates an image that is rendered by the Gravatar online service. Gravatars are user
icons that are registered by a central server and that can be used across the
internet with blogs, forums and other profile based websites.

The Gravatar requires the email address for which the gravatar image
needs to be rendered (each gravatar account can have multiple email addresses
registered).

Available options:

  • you can set the {@linkplain #setSize(int) size of the rendered image}
  • you can pick a {@linkplain #setRating(String) rating} for the intended
    audience
  • you can set the {@linkplain #setDefaultImage(String) default image} that
    is rendered when no gravatar was found with the provided email address
  • you can choose to use a {@linkplain setSecure secure https protocol or
    plain http}
  • the gravatar supports both the {@link #setAlt(IModel) alt} and
    {@link #setTitle(IModel) title} attributes

Set the static fields if you want to modify the defaults for your whole
application.

@author dashorst

http://gist.github.com/266444

Wicket gem: AdapterModel implements IModel

Recently, on the Wicket-User mailing list:

What’s the best practice when using generics with models that take some
object but return another type of object?

examples:
When you have a collection and need to convert it to a list for listview
purposes.

to which mighty Igor replied:

 Java |  copy |? 
/**
 * Simplifies implementing wrapper models that adapt from model object of one type to another
 *
 * @author igor.vaynberg
 *
 * @param < N >
 *            new type
 * @param < O >
 *            old type
 */
public abstract class AdapterModel< N, O > implements IModel< N >
{
    private static final long serialVersionUID = 1L;
 
    /** delegate model */
    private final IModel< O > delegate;
 
    /**
     * Constructor
     *
     * @param delegate
     *            model to be wrapped
     */
    public AdapterModel(IModel< O > delegate)
    {
        this.delegate = delegate;
    }
 
    /** {@inheritDoc} */
    public N getObject()
    {
        return getObject(delegate);
    }
 
    /**
     * Translates from IModel of type T to object of type A
     *
     * @param delegate
     * @return adapter value of delegate model
     */
    protected abstract N getObject(IModel< O > delegate);
 
    /** {@inheritDoc} */
    public void setObject(N object)
    {
        setObject(object, delegate);
    }
 
    /**
     * Translates from object of type A to IModel of type T
     *
     * @param object
     *            adapted object that needs to be unadopted
     * @param delegate
     *            delegate model whose value should be set to unadopted version of
     *            object
     */
    protected abstract void setObject(N object, IModel< O > delegate);
 
    /** {@inheritDoc} */
    public void detach()
    {
        delegate.detach();
    }
}
-igor 

Awesome guide to mercurial branches

via http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/

it has

  • Branching with Clones
  • Branching with Bookmarks
  • Branching with Named Branches
  • Branching Anonymously

with a list of

  • Advantages
  • Disadvantages
  • Comparison to git

each.

JDK7 might finally be fun

via puredanger.com

Doug Lea posted a note today on the concurrency-interest list that the bulk of the JDK 7 changes from JSR 166y (the second maintenance update) have been pushed in the latest JDK 7 M5 snapshots.

The fork-join library provides support for fine-grained parallel divide-and-conquer style parallelism. You can think of many of the classes adding in JDK 5 for queues, executors, etc as excellent building blocks for coarse-grained parallelism (on the level of a “task” or “transaction”). Fork-join works at a lower level, providing parallelism for working on a subset of a large data set in parallel.

Maiden Flight with a Hornet

after ActiveMQ let us down the third time (rant to follow), it was time for alternatives. as i am a strong believer in OSS and the budget is tight these days, i´d love to stay in that ballpark instead of just buying SonicMQ.

so looking for alternatives i came across the recent announcement of HornetQ formerly known as jboss-messaging. even though i am not particularly known as a friend of jboss due to prior experiences with their AS, i chose to take that hornet for a flight. here´s what it turned out to be:

Arrival

download, done. as easy as that. well almost.

certainly you want to take a look at HornetQ-configuration.xml. there is binding to non-localhost and a few options like redelivery-delay, redistribution-delay and rates for consumer and producer to take care of.

if you´re on a linux env, you might want to use their AIO stuff, which is explained in great detail here.

Pre-Flight Preparation

as a happy maven user it took me a while to find out what libs i actually needed as a minimum to use HornetQ as JMS Implementation. just afterwards i discovered this nice blog article that gives it all.

basically it is:

 XML |  copy |? 
   <!-- if you like that API better than JMS -->
   <dependency>
      <groupid>org.HornetQ</groupid>
      <artifactid>HornetQ-core-client</artifactid>
      <version>2.0.0.BETA5</version>
      <scope>compile</scope>
   </dependency>
 
   <!-- the actual JMS Impl -->
   <dependency>
      <groupid>org.HornetQ</groupid>
      <artifactid>HornetQ-jms-client</artifactid>
      <version>2.0.0.BETA5</version>
      <scope>compile</scope>
   </dependency>
 
   <!-- transport layer -->
   <dependency>
      <groupid>org.HornetQ</groupid>
      <artifactid>HornetQ-transports</artifactid>
      <version>2.0.0.BETA5</version>
      <scope>compile</scope>
   </dependency>
   <dependency>
      <groupid>org.jboss.netty</groupid>
      <artifactid>netty</artifactid>
      <version>3.1.0.GA</version>
   </dependency>
 
 

plus the JMS API.

sidenote: i don´t get why HornetQ-transports for instance does not declare a dependency to netty. unfortunately with any jboss product, you have to dig for a particular foggy combination of jars that work together. (sorry for that obvious reference to hibernate :-P )

Tower

there is none. ok, the HornetQ server exposes itself heavily via JMX, but you cannot expect anything similar to ActiveMQ in terms intuitive usability or comfort. on the other hand, using (and understanding) the JMX-exposed API gives you much more power than what the average JMS server provides.
what we (my company) did, was to create a simple webapp considerably equal to what the ActiveMQ admin-webapp is (without the screwing up part) to manage queues/topics, messages and monitor the nontrivial processes that JMS provides in terms of redelivery, dead-letters etc…

SCREENSHOT TO FOLLOW

there also is hermes, but we never got it running with HornetQ in a way that we could manage queues and move messages.

Choose Gangway

HornetQ is a JMS provider, yes. and even though i am not a fan of using a proprietary API over a standardized one, you might want to take a look at their direct API to messaging. it is a slightly different perspective (no difference between queue and topic) to JMS, but it is a little simpler in some corners.

we can afford going that way, because we have an abstraction on top of that, that protects our application code from a dependeny on a particular API, anyway.

Lift-off

first of all, you can easily embed HornetQ server into any app. beside tests, the usecase we had for that was the admin application mentioned above. this is not too important, but very handy as you can easily bundle these things together.
using the client API, as well as the JMS API is as trivial as you would expect. the only thing you might want to know is their way of implementing streaming of big messages.

Heavy Lifting

some people say, that sending big messages over JMS is terribly wrong from a conceptual perspective. well, it depends. we do have some usecases, where a message contains a job that really carries quite some data. i wont enter the discussion, if this job should better be persisted and just being triggerd by a small JMS message, but one thing is for sure: it is much easier this way.
so what am i talking about when i say “quite some data”? significantly less than 5mb. while this is not considered “big” in any other context, an ActiveMQ faild us with OOMs when recieving such a message even though he had 512m of heap.

any possible replacement for ActiveMQ for us had to demonstrate a reliable operation with messages that go up to 30mb.

HornetQ delivered quite good here. be it the JMS API or their own (supposed to be simpler) API to messaging, you can easily stream data into messages. the server then streams those messages into a large-messgae directory and the cake is eaten. this is not particularly reocket science, but our bad experience with ActiveMQ makes me emphasize this:
HornetQ copes with messages of any reasonable size!

in fact, we chose to use this pattern for any message we send (ignoring the performance resulting from the extra handling of this kind of message) in order to be safe and relax on mem requirements as much as possible.

Landing

we replaced some ActiveMQ servers in production environments by hornets and since then, we did not touch them. we set up (very frequent) nagios roundtrip tests and the like, and hornet did not let us down once.

even though i am not particularly known as a friend of jboss, i am grateful of this being not only open source but also isolated from jboss AS and the rest of their (sometimes bloated) ecosystem.

Final words

the advanced configuration is a little weird here and there and lacks documentation. it has a bunch of things, that do not provide value FOR US, like throttleing.
in operational tests, we discovered some weird (but reproduceable) behaviour when ungracefully stopping HornetQ. some messages were safe, but no longer moveable to another queue (brings NPE). we suspect this to be a beta issue that´ll be taken care of.

apart from that: HornetQ is easy to get started with, reliable, reasonably fast, highly configurable and (once you got the API) flexibly managable.

it instantly is a major player in OSS JMS provider market and, if you happen to have requirements similar to ours, a very good choice.

Scripting in Scala….

Interpreter style can be easier than one might think.

See Vassil Dichev´s Embedded Scala Interpreter

Uups, they did it again…

via theserverside.com: IBM WASV7 Java Persistence API (JPA) 2.0 Open Alpha

once more, they repackage an apache project to charge for it.

The WebSphere Application Server JPA implementation is based on Apache OpenJPA, a leading open source Java persistence framework. This alpha provides the Apache OpenJPA 2.0 implementation with IBM enhancements to benefit integration with WebSphere Application Server. The Apache OpenJPA 2.0 implementation includes improvements and benefits over previous releases and even beyond the JPA 2.0 specification.

How to do UI test ?

Me again…

Well, I just wanted to speak about an issue for which I didn’t find any proper answer yet.

The matter is gui testing. Currently, at work, we do proper unit test for “framework level code”. By “framework code”, I mean code being in some utilities or services projects which are put there to be reused. These tests are usually fairly easy to do, since the context is well known. Furthermore, as once as we change this code, these tests prove their value. As changes are made quite often, be it only when adding new stuff and thus refactoring, we feel like these tests are good bang for bucks.

For example, recently, we saw a bug in some on “framework code”. We wrote a failing test for it (well, I’m not 100% sure of that, but we should have had anyway ;) ), fixed it and, on the go, spotted some possible improvements. We did them as well, then ran again all tests and we were pretty confident about it.

But, then, what about “project specific code” ?

Hum, what’s in it anyway ? Some “framework level code”, for sure, which is already tested, and then some JPA, wicket and business related code. Testing the JPA code would basically mean testing the JPA layer, which is pointless. What about the GUI then ? Well, wicket isn’t exactly the easiest framework for it… The way its generates the ids make it hard(er) for most of the html test tools, like for example selenium. And even if, what to test actually ? Should we do some “clicks through” tests for all use cases ? All possible navigation paths ? And what about the data needed by these tests ? Using WicketTester, then we would be at pain with jquery heavy pages (well, I guess most of the selenium like frameworks are at pain in this case…). Overall, the efforts to put there are likely to be important.

So, what about the gain ? The odds that we’ll touch again these classes are quite low, way lower than framework level code. Basically, we don’t reuse these stuff. And if some functionalities/pages are fine enough, then we may even not touch them again before very long.

In the end, we have some layers which are, at the same time, harder to test and with less “return on investment”. It looks like not testing these “project specific/gui layers” is a good idea…

However, which bugs the end users, tester or product owner are likely to see the first ? The gui bugs, for sure. Worse, whereas framework layer code tends to be mostly Java, the front end relies heavily on nice stuff like CSS, html and javascript. And as if refactoring wasn’t already hard enough there, Wicket, with its string based property and compound models, makes it even harder. So in the end, this gui layer is quite error prone and highly visible to the “customers/users”… Bad isn’t it ? And don’t forget all these quirks about back button, interruption of page loading, browsers inconsistencies and many ui possibilities… Even worse !

That’s where my issue with ui test lies… This ui layer is a pain to test, and would be tested mainly for just a development, without much reuse. But, it’s an error prone layer. And it’s the most visible one… So, if, like me, you’re kind of fond of tests and bullet proof code, then you might well share my dilemma…

What to do then ? Well, for the time, I’ve no proper answer. I guess I should try to spend more time testing my ui before giving it to the outer world, even it feels awkward to do it manually. For sure, exploratory tests might help, but again they’re manual and in no way comprehensive… No clear solution here for me, unfortunately…

Any hint deeply welcome ! In fact, I guess that’s the (hidden) aim of this post : maybe someone’ll come with some magic bullet(s). After all, Christmas is coming soon, so it’s dreaming time anyway ;)

++

Agile Tour 2009 in Strasbourg : what’s the fuss about Pomodoro ?

hi

The last session I was in was about Pomodoro (NB : a free pdf about Pomodoro is available on this website – I didn’t read it yet though).

Well, simply put, the idea is to use a timer and then work being focused until it rings. Then one should reconsider whether he’s still making what the best he can do. For example, if stuck on something, maybe it is best to skip it for now. Originally, it’s a “one man” stuff, with time between each timer wake up of 25 minutes, and then a break of 5 minutes. The aim is to keep control on the time flow.

Olivier Albiez, another guy from Smartesting, told us a bit more on how they adapted it : they use as a team tool. In fact, when they decide to use it, it’s with a team of people all working on the same stuff. Thus, they inform the rest of the world that they won’t be available for the Pomodoro time.

Then, they start the timer (set on 55 minutes) and work as focused as they can (normally no email or phone call during it). When the timer yells, each guy says where he thought he would be and where he is. If someone is stuck, then the team decides what to do. It could be simple suggestions, pair programming shift or even a full blown meeting if needed.

However, they introduced a fancy rule : if for some reason the same sprint’s issue is stuck three times in a row, they just skip it. Indeed, estimation was obviously wrong and they have, hopefully, better to do. The main idea is to avoid this “I’m nearly done” sentence we’ve all heard (and I must admit I’ve often said it lol), which ends with 3 extra days of unplanned work. With this rule, the unplanned work is of half a day at max.

Just to provide a complete picture of their version of Pomodoro, each team member has the right to interrupt any other team member during the pomodoro. Indeed, they work all on the same stuff. However, not to spoil one’s efficiency, the interrupted guy can say “wait for the end of this pomodoro”, and then keep going.

I don’t know how you feel about Pomodoro (and my poor introduction to it), but I feel quite eager to test in real life :)

++
joseph

Agile Tour in Strasbourg : session on tests and Agility

The 2nd session I went to in the Agile Tour 2009 was about testing in an Agile process. This presentation was done by Frédéric Oehl, from Smartesting.

The presentation mainly consisted of 2 parts : one about tests and agility, the others about Smartesting tool for… testing. Surprising isn’t ;)

Anyway, the first part provided good insight on testing, with some surprise in it : they spoke of “Exploratory test”. What’s that ? In a few words (the wikipedia tells way more), it’s just the idea that the developers should have time to test the application without strict guideline, relying instead on their knowledge and gust feeling.

Per se, the idea isn’t new, even if I never encountered a name for it up to now. Furthermore, we speaking more of it with Frédéric, it appeared that it could be done in different ways, like : let each developer do exploratory tests on other dev. code or plan some time for the whole team to do such tests before the sprint is over, in order to bullet proof it.

For sure, exploratory testing has to be part of a bigger testing plan. Furthermore, we tend all to do such kind of tests. Yet, to put a name on it and then plan for it is quite different, and may let enough time to actually do it, which sounds nice. For sure, there are drawbacks as well, notably about inefficiency if 2 teams members do the same test every time. As usual, communication could help here ;)

Regarding Smartesting product, named Test Designer, it’s a Eclipse RCP application, using the work flow tools available there. Its main goal is to be able to describe some application work flow. In fact, it starts with some business requirements list (ordered by priority), then links them to part of some UML models describing the application’s work flow. Then, some guys have to make it happen, meaning that they have to write the tests needed by these UML models. This automation process, as they name it, is not part of the product.

I won’t say it’s revolutionary in itself, but to be able to use the same tools for both requirements gathering and functional testing sounds sensible.

They claim as well that it helps not having to redo all tests every time something change. Indeed, these functional tests are written per page (or I guess per page transition). As such, changing some part of the work flow involves only the related tests. Once again, nothing amazingly new, but this idea of slicing functional tests as well, to help maintain them, makes sense again.

In the end, as usual, one still has to provide the actual tests and then to maintain them. As such, it appears that this tool is used mainly by “big players”. These big players include some in India… yes, they sell their app there, without developing it there… fun isn’t it ?

In the end, this talk provided me with elements on my quest to find some way to do proper GUI testing, so I enjoyed this session as well :)

++

Agile Tour in Strasbourg – (partial) feedback

hi

I went yesterday to the Agile Tour 2009 event in Strasbourg. Overall, I was fearing it to be a bit dull, the program looking not so attractive. Yet I found it quite interesting and worth the time spent. Maybe low expectations helped, I don’t know, still I’m happy of this outcome.

Let’s dig through it in more details :)

First, I went to Stéphane Becker talk. In fact, it was a feedback from his XP implementation. Indeed, working in the video game industry (in Strasbourg, crazy!, in a company named Creative Patterns), the first project he did was quite a hell (80h and plus per week of work for the last 8 months) and as such they decided to act upon it. It was in the very beginning of the 21st century (2000 or 2001 I don’t remember), so they went for XP.

Among the interesting bits is the fact that they went for not having titles in the dev. teams.

Indeed, they had the feeling that it was stopping members of the team to feel/be responsible of their act, under the assumption that the guy with the higher title would do it (or at least would have to do it). Furthermore, the idea was that one should be proud of his achievements and actual work rather than some “dumb” title saying nothing in the end. The outcome is, apparently, what they were aiming for : each one is the team feels now “responsible”, and they see quite often each team member taking naturally the lead “from time to time”, depending on the topic, all without external action or internal discussion. Thus, it looks like quite effective on team empowerment.

Still, it raised the question of how to evaluate/pay each guy in the team. First, the answer was that it was all team based : all the guys have roughly the same salary and share the team’s fate… Yet, after closer interrogations, it came up that the salaries were linked with each one experience and skills, thus breaking this “one pay for all” rule. In the end, I’ve no clear picture of how they do to evaluate/pay each guy, even if this choice of “no title” rings some bells.

In less details, these parts were also of interest :
- at first, they went for paper based issues lists and the like. However, for follow up, they ended using some software (from what I got it’s this Agiletrack software I never heard of before). However, now, they put the issues on paper (on “post-it”) for the planning meetings, because it helps quite a bunch to deal with it efficiently…
In the end, I’ve more and more the feeling that that having both papers and software looks like the (unfortunate and required) way to go. If anyone tried Henrik Knibberg “paper/dashboard only” approach, I’m eager to hear/read feedbacks !
- Stéphane had this nice sentence : “Agile is just about giving the proper occasions to communicate for the team”. I deeply agree with this : all these fancy words and tools should not forget about the final aim of better communication.
- when planning for more than the next sprint, like planning for the next batch to be delivered to the customer, they involve the team members which will do the development, apparently on a “per feature” basis. The idea is to get them on board as soon as possible (better for their involvement and for the overall precision of the estimation). I was quite interested in this because Agile Estimating and Planning always speaks of the whole team, which sounded a bit too much to me.

Hum, I’ve been writing more than expected and it’s getting late… Well, I guess I’ll dig into the others sessions another time ! So stay tuned for more on “exploratory test” and Pomodoro ;)

++

MyEclipse Blog | Pulse Blog | MobiOne Blog | Genuitec Blogs

will that finally make gmaps embedable in rcp apps?

via MyEclipse Blog | Pulse Blog | MobiOne Blog | Genuitec Blogs.

Open Source Contribution, WebKit for SWT (ver. 0.6)

As strategic members of the Eclipse Foundation we enjoy giving back to the open source community when the opportunity arises. This time we’re releasing  WebKit for SWT (ver. 0.6), an open-source embeddable Java™ WebKit browser component.  This component can be used in the development of a wide range of Java SWT applications that require integration of rich HTML5, CSS3, JavaScript and Flash content and functionality.

Fun with Java’s syntax !

Have you ever prepared a certification ?

Well, for me, it’s the first time, and it proves a very nice occasion to learn stuff you should never do and hopefully will never meet in real code. Still, it’s fun like hell :)

So, what am I speaking about ?

Well, stuff like these :

 Java |  copy |? 
class ExtractsFromTheExams
{
    int[] array[]; // such a nice array declaration 
 
    String fooArray[] = new String[]
    { "a", "b", }; // yes, this last comma is fine
 
    String bla = new String[]
    { "foo", "bar", }[1]; // seen in some tests...
 
    Object a\u0001; // readable like hell
}
 
public class A // some sample class are very clear
{
 
    public transient String foo;
    Bar aBar = new Bar(10);
    static Integer nb = 10;
 
    public static void main(final String[] args)
    {
        A a1 = new A();
        a1.nb++;
        A a2 = a1;
        a1.nb = 0;
        System.out.println(++a2.nb);// BTW : what to expect from it ? Will
        // this class even compile ?
    }
 
    class Bar
    {
 
        public Bar(final int i)
        {
        // TODO
        }
    }
}
class Huh{
    char A = '\u000A' ;// this one for the end. Try compiling it...
}

Well, don’t understand me wrong, I appreciate working on this certification. Really. The unclear samples are made to make the reader think twice… And I’m pretty sure anyone having tried to figure out these lines above will have read some of them twice. Furthermore, it’s funky only from time to time, it can also be interesting. Overall, this in depth exploration of Java is valuable, even if mostly on corner cases.

++

Writing your pom files in Groovy – a sneek preview of Maven 3’s polyglot features

Maybe,  i´m really getting conservative with age. :)

Writing your pom files in Groovy – a sneek preview of Maven 3’s polyglot features.

InfoQ: IntelliJ Goes Open Source

…Starting with the upcoming version 9.0, IntelliJ IDEA will be offered in two editions: Community Edition, free and open-source, and Ultimate Edition, which until today has been referred to as simply IntelliJ IDEA.

via InfoQ: IntelliJ Goes Open Source.

Unfortunately, without html/css and refactoring support in the community version, i´d not even consider installing it to take a look. if they try to hook me up, they´d have to extend the bundled features a little. maybe when i have time for scala, i´d look into it, for the eclipse scala plug sucks.

OpenOffice.org development switches to Mercurial – GullFOSS

via OpenOffice.org development switches to Mercurial – GullFOSS.

I’m very pleased to announce, that after five months of piloting, implementation and and testing, we are finally ready to switch OpenOffice.org development to Mercurial (hg) as our SCM (Source Code Management) tool.

Mercurial is a modern and flexible distributed SCM tool with the fast and convenient merging capability which is so required for OOo development.

We have chosen Mercurial out of the three major open source DSCM tools available (Git, Bazaar and Mercurial) because we believe that its combination of ease of use, flexibility and performance fits best with the overall OOo needs. We are well aware that a slightly different emphasis on the selection criteria might well have led to a choice of Git or Bazaar, which are both very capable DSCMs as well.

Book review : Scrum and Xp from the Trenches

At work, we’re currently reviewing our Agile process. So I thought it was a nice occasion to read again Scrum and Xp from the trenches, esp. since we have a paper edition of it.

Simply put, this book is why I started to be so much interested in Agile software development : the process it described is really compelling. The author hardly presents what is an Agile process (from a theoretical point of view), rather it dives immediately on how they did it. Still, he provides the different choices they faced and explains why they went for such or such solutions, all in order to accomplish the various “agile steps” which are to be done. It really enlightens the reader, helping to grasp properly what it’s all about. Furthermore, it gives ground to the author’s claim that it’s just how they did it : one gets easily that’s adaptation is the key, that Agility is not a stone graved process. This helps to consider it’s own environment with a fresh eye.

At the end of the book, I had the feeling I had a proper overview of the whole process, on how these teams worked. Added to the explanations on why they choose such solutions, it makes it all reasonable, sound and efficient. Attractive and, hosnestly, a real breakthrough compared to all these RUP, ITIL and others crappy acronyms. What else could we expect from a process ? It actually seemed like helping and being efficient ! Crazy ! The only question I had left was “when can I start ?” (which is part of the reason I moved to Thomas Daily by the way lol).

In retrospective, now that I’ve been working in a Agile shop for now 7 months, the book didn’t answer all the questions I had since. Furthermore, more theoretical books have helped me really grasp why such a process was working, that it was all about the empiric nature of each IT project. Still, when coming back to this book, it was once again compelling. Going through the experience and writing of Henrik Knibberg has helped me once again, spotting points where we didn’t get it all.

As such, I really advice this book (which comes as well as a free ebook, both having been updated since publication) for all people interested in getting Agile, how it works, what it provides or even to improve one’s own way of applying it. So don’t hesitate : read it !

++

Side note : Henrik speaks of other “from the trenches” stories in his book. I never found any, so if anyone knows some other, I’m interested !

Another nice online UML Diagram creator

can be found here and creates images like this:
sample

And wave goodbye….

although technically quite impressive, this article reveals the shortcomings of google wave nicely.

Hibernate default fetching strategy…

hi

We all know that the default fetching strategy for hibernate is lazy. But, wait, is it, really ?

As you might have guessed by now, it’s not. Indeed, for @OneToOne and @ManyToOne annotations (and only theses annotations), the default is eager. Funny no ? Oh, I forgot : don’t ask me why, I can just tell it’s the case (from one issue at work, some digging into the topic and this nice topic – which includes links to the doc for the non believers - on the hibernate forum).

Time to think at some way to always ask for explicit fetching strategy for ManyToOne annotations… Maven plugin to the rescue ? We shall see ! :)

++

Is Spring still lightweight?

Nice article speaking out loudly, what has to be said.

http://azeditech.com/spring/is-it-still-lightweight.html

And I can’t even work out what each Spring Source product does and whether it makes sense for me to even consider spending the cash, I quickly get bogged down by solution-speak every time I try to get a quick understanding. Then I saw a notice about Discovery Days, and hey! a day-long seminar which goes over the various Spring Source solution offerings and explains what the hell they are, sounds perfect. Oh, wait, it costs £400. They want me to pay to go to their sales presentation.

Bleh.