Agile principles: feedback – part 2

Some time ago our project received a new large-screen TV set. With my colleague and friend, László Tarcsányi, we thought it’d be a good means of providing feedback. We also thought it would be great if it was used for showing the current status of our most used project tracks. By status, of course, I mean: build has been ok for a while, broken for a while, currently building etc.

Fortunately, we use Hudson as continuous integration system, which has a very good support for plugins. It didn’t take us long time to find this plugin, called Radiator View (check it out here: http://wiki.hudson-ci.org/display/HUDSON/Radiator+View+Plugin). It can be configured to show one or more tracks at a time, to show/hide stable views, show/hide possible build breakers (people who checked in source code since the last green build). It looks like this:

 Broken builds are always shown in the upper part of the screen, in red. In order to be easily noticeable, these red builds cover the most part of the screen.

The idea behind the plugin seems to be working. Broken builds get caught much faster. We had an e-mail based build-status reporting system, but unfortunately that was not efficient. E-mails can be easily missed, the TV on the wall can not (unless you’re walking with your eyes closed). Another problem with the e-mail based solution was that it was sending messages to only that person who broke the build (or to one team, at most). In these situations there might not be enough capacity to fix the build. However, a projected red build is frustrating to all of us. The broken build can be fixed by any person with sveral minutes of spare time.

The TV is also showing the status of our nightly builds. The nice server monitoring application has been created by László Tarcsányi and Kornél Schmeiszer. You can immediately tell how many test cases failed, how many went well and how many test cases were run alltogether (See the screenshot). It looks really nice and can be understood in seconds.

We also project a red-green-refactor picture, in order to keep in mind what’s the right behavior when implementing new functionalities.
Advertisements

Agile principles: feedback

Quick and adequate feedback is important. It’s one of the core principles of agile, after all. However, people keep forgetting about its importance and value. They treat feedback related tasks like timewasters; they would even tell at standups “providing feedback is blocking me” if they could.

What is the best and quickest way of providing feedback – audience say with me – yes, code review. When I hear people presenting results of reviews, most of the times, it’s like: “well it’s ok with me…” I guess this effect can be tracked down to two reasons: laziness and a psychological factor.

Laziness is the obvious one. In order to produce quality feedback one needs to be very careful and thorough. Each and every new code line (and not only – I’ll get back to this immediately) needs be parsed, understood and processed. Are variables and methods named in a self explanatory way? Are methods and classes short enough to be understood with ease? Are unit tests in place, are they really testing the functionality, or are they coverage-increaser-liars? Too many questions to be answered in ten minutes. And in most cases people spend just that much time reviewing (usual case, usual developer, the nature of task to be reviewed does not matter). In order to produce the best possible review comments, some systems thinking is also implied. That’s why not only new code has to be processed; a new question arises: how well it fits into the legacy system? Which can be further broken down into a series of “what if” questions. What if we run the code in a multithreaded environment? What if an exception is thrown? What if we refactored things into several classes/methods? Is it possible, that any part of the new code has already been implemented? (that doesn’t start with “what if”, but happens very often in large systems).

The other reason why we don’t do review thoroughly enough, is that we don’t want to hurt authors’s feelings. Many people think like: “well, I could mention this as a possible comment, but what if they take it as an insult?”. Wrong question. In my opinion any suspicious code part has to be mentioned. Of course in a friendly and supportive manner, and not in “what the hell is this bullshit, dude?” style. Some people will take it personally anyway, but they’ll eventually realize it’s for everyone’s sake.

Further reading on producing quality feedback through code review: Zsolt Fabók’s Basics of code review

Most irritating bug of my life

Maybe not the worst I’ve seen, but it’s in the top 10, definitely. As I was unable to find any help on the Internet, it might help someone someday, so here it goes.

Currently, I’m working on an RCP + Spring + OSGI project. After a large-scale integration, I was getting the following exception at startup:

!ENTRY org.eclipse.ui 4 0 2011-08-10 10:46:59.838
!MESSAGE Unhandled event loop exception
!STACK 0
java.lang.NullPointerException
        at org.eclipse.ui.internal.handlers.HandlerProxy.loadHandler(HandlerProxy.java:352)
        at org.eclipse.ui.internal.handlers.HandlerProxy.setEnabled(HandlerProxy.java:231)
        at org.eclipse.core.commands.Command.setEnabled(Command.java:857)
        at org.eclipse.ui.menus.CommandContributionItem.isEnabled(CommandContributionItem.java:918)
        at org.eclipse.ui.menus.CommandContributionItem.updateToolItem(CommandContributionItem.java:611)
        at org.eclipse.ui.menus.CommandContributionItem.update(CommandContributionItem.java:528)
        at org.eclipse.ui.menus.CommandContributionItem.fill(CommandContributionItem.java:503)
        at org.eclipse.jface.action.ToolBarManager.update(ToolBarManager.java:353)
        at org.eclipse.jface.action.ToolBarManager.createControl(ToolBarManager.java:111)
        at org.eclipse.jface.action.ToolBarContributionItem.fill(ToolBarContributionItem.java:192)
        at org.eclipse.jface.action.CoolBarManager.update(CoolBarManager.java:928)
        at org.eclipse.jface.action.CoolBarManager.createControl(CoolBarManager.java:247)
        at org.eclipse.jface.internal.provisional.action.CoolBarManager2.createControl2(CoolBarManager2.java:76)
        at org.eclipse.jface.window.ApplicationWindow.createCoolBarControl(ApplicationWindow.java:523)
        at org.eclipse.ui.internal.WorkbenchWindow.createDefaultContents(WorkbenchWindow.java:1053)
        at org.eclipse.ui.internal.WorkbenchWindowConfigurer.createDefaultContents(WorkbenchWindowConfigurer.java:625)
        at org.eclipse.ui.application.WorkbenchWindowAdvisor.createWindowContents(WorkbenchWindowAdvisor.java:268)
        at org.eclipse.ui.internal.WorkbenchWindow.createContents(WorkbenchWindow.java:1000)
        at org.eclipse.jface.window.Window.create(Window.java:431)
        at org.eclipse.ui.internal.Workbench$20.runWithException(Workbench.java:1032)
        at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
        at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
        at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:134)
        at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3885)
        at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3506)
        at org.eclipse.ui.application.WorkbenchAdvisor.openWindows(WorkbenchAdvisor.java:803)
        at org.eclipse.ui.internal.Workbench$28.runWithException(Workbench.java:1384)
        at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
        at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
        at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:134)
        at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3885)
        at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3506)
        at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2316)
        at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2221)
        at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:500)
        at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
        at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:493)
        at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
        at xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(Application.java:60)
        at xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(Application.java:36)
        at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
        at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
        at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
        at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
        at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
        at org.eclipse.equinox.launcher.Main.main(Main.java:1287)
Not that self explanatory, is it? After a week of try-error cycles, it turned out that Spring’s configuration.xml was missing a bean (thank you, automatic merge…), so Spring context was unable to start up. It has thrown an exception that was caught by the RCP framework. After correcting the XML file, the application magically got well… I wish these frameworks could work together and give valuable error messages…

Agile development and UML

In case of agile development, we usually don’t run into hundreds of lines of documentation, with detailed diagrams, architecture proposals etc. This is good for several reasons; developers can use their creativity in order to materialize requirements. This way, people won’t fall into the pitfall of blindly following someone’s vision either.

However, UML may become in handy at feature development. With just a small investment (as low as the price of a whiteboard) a team can boost their productivity. This is how: promote a whitheboard as “design board”. The design board has no other role, than to store the current architecture of the feature under development. It, of course,  supposes that each and every team member updates the board whenever they make a change to the current state.

One might argue that there are a lot of software tools out there, why not use those? Well, the answer is simple; people are lazy (and forgetful, in the same time). Even if the UML diagram is stored somewhere everyone has access to, they won’t open it, let alone update it. They simply forget it, becouse the thing is not in front of their eyes all day long. However, if it is present materially, people actually tend to update it on a regular basis (also, daily standup meeting is a really good period to remaind everyone to do so, in the case they somehow forget it). The diagram doesn’t have to be that detailed. It’s perfectly enough if it contains the classes and interfaces, associations (uses, implements, extends …) and main methods.

How does this help increase velocity? Simple. People don’t have to randomly open different classes in order to find the right one to place some new code in. They just take a look at the board and know immediately how classes are related, which is the right one for the new logic. They also don’t have to remember all the class names and the relationships between the different components. Planning meetings (along with task breakdowns) will also get shorter. It eliminates the phrases that start with the infamous “well, I guess…” stuff; people will talk about facts not beliefs. Less stress, less time spent on arguing.