My first blog post on Scriptogram
Hello! This is my first blog post, hosted by Scriptogram. Let's see how it goes!
:)
My first blog post on Scriptogram
Hello! This is my first blog post, hosted by Scriptogram. Let's see how it goes!
:)
Défauts connus sur la R4#3
Voici les défauts connus sur la R4#3 :
- La migration avec PostgreSQL ne fonctionne pas. Ce défaut est corrigé dans la version R4#3.1
- Dans l’assistant, le changement de rôle de celui qui crée le projet provoque une erreur. Ce défaut est corrigé dans la version R4#3.1
- Quand iceScrum est installé dans Tomcat et qu’on arrête le serveur, il arrive que le process Java continue à s’exécuter, ce qui ne permet pas de réinstaller une nouvelle version d’iceScrum. Il faut d’abord arrêter le process (avec Linux et Mac, on lance la commande ps -ax pour récupérer le numéro du process puis un kill -1 avec ce numéro), enlever le répertoire icescrum de Webapps, mettre le nouveau war et relancer Tomcat.
- Quand on modifie la couleur d’une feature, ce n’est pas immédiatement rafraichi au niveau des stories.
- Le fonctionnement sur tablette et smartphone n’est pas optimisé.
- Si le serveur est configuré avec un proxy, il peut arriver que l’attachement de fichiers ne fonctionne pas quand le nom du fichier contient des caractères exotiques.
- L’attribut pour donner la valeur d’une feature propose des entiers dans le formulaire, mais dans la vue table, c’est restreint à la suite de Fibonacci (au lieu des entiers). Ce défaut est corrigé dans le build 220.
- Erreur quand un membre de l’équipe dont le rôle est développeur quitte le projet (l’équipe).
- Le drag and drop pour ordonner les stories dans le backlog ou les features ne fonctionne pas quand on agrandit la fenêtre. Ce défaut est corrigé dans le build 222.
- Une story estimée à 0 passe à ? en vue table ou quand on active le sprint.
- Selon la résolution utilisée, le dernier sprint du plan de release s’affiche sous le 1er et pas à côté du précédent (avec certaines versions de Firefox).
- La copie des tâches récurrentes du sprint précédent ne fonctionne pas. Ce défaut est corrigé dans le build 227.
- Le lien vers le fil RSS ne fonctionne pas. Ce défaut est corrigé dans le build 229.
- Dans le bac à sable, lorsqu’on ajoute plusieurs stories à la suite en utilisant le bouton « Proposer et poursuivre » et qu’on utilise le template « en tant que … », seule la première story ajoutée conserve les informations saisies dans le template. Toutes les stories suivantes saisies perdent les informations du template.
- Lorsque le backlog contient suffisamment de stories pour que les post-it remplissent la fenêtre il est impossible de sélectionner les post-it de la derniere ligne pour les déplacer. Ce défaut est corrigé dans le build 229.
- Lien incorrect dans l’historique utilisateur d’un profil d’une personne.
- On ne peut pas mettre à jour le reste à faire sur les tâches dans la vue table du plan de sprint.
- Il est possible de passer une tâche à fini même quand le sprint n’est pas commencé en mettant son reste à faire à 0.
- L’association d’une story à une feature est perdue lors de l’importation d’un projet exporté.
- Lors du changement d’état d’une story, il arrive que le message « Cannot create a session after the response has been committed ». Dans ce cas là, l’information n’est pas poussée vers les autres utilisateurs connectés, mais le changement d’état est effectué correctement.
Si vous en trouvez d’autres sur cette version, merci de les ajouter dans le bac à sable iceScrum.
Agile Teams - Chili Cook Off Contest
It's winter here in PA and nothing goes better with lousy weather than a bowl of chili.
We have a very competitive group and we do not need much motivation to turn anything into a compitition.
One week prior to cooking day we gathered all the teams and unveiled the event and rules. The feedback from teams and tasters was that it was a rousing team building success..
One team took it as far as to execute a prototype and feedback session every morning to dial in…
Cleaning up test code
My former colleague David just posted an example of verbose test code on his blog (the parts in French have been translated to English by myself):
/**
*
*/
@Test
public void testGetCustomerOK() {
LOGGER.info("======= testGetCustomerOK starting...");
try {
CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
// Check.
Assert.assertNotNull("Extra not found.", targetDTO);
Assert.assertEquals("accountIds must be the same.", "ABC99", targetDTO.getAccountId());
} catch (CustomerBusinessException exception) {
LOGGER.error("CustomerBusinessException : {}",
exception.getCause());
Assert.fail(exception.getMessage());
} catch (UnavailableResourceException exception) {
LOGGER.error("UnavailableResourceException : {}",
exception.getMessage());
Assert.fail(exception.getMessage());
} catch (UnexpectedException exception) {
LOGGER.error("UnexpectedException : {}" +
exception.getMessage());
Assert.fail(exception.getMessage());
} catch (Exception exception) {
LOGGER.error("CRASH : " + exception.getMessage());
Assert.fail(exception.getMessage());
}
LOGGER.info("======= testGetCustomerOK done.");
}
Facing this code, the first thing I would do is remove the logs in the catch clauses, which are clearly obscuring the code the most. They do not provide actual value, since the exception message is used in Assert.fail() calls.
/**
*
*/
@Test
public void testGetCustomerOK() {
LOGGER.info("======= testGetCustomerOK starting...");
try {
CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
// Check.
Assert.assertNotNull("Extra not found.", targetDTO);
Assert.assertEquals("accountIds must be the same.", "ABC99", targetDTO.getAccountId());
} catch (CustomerBusinessException exception) {
Assert.fail(exception.getMessage());
} catch (UnavailableResourceException exception) {
Assert.fail(exception.getMessage());
} catch (UnexpectedException exception) {
Assert.fail(exception.getMessage());
} catch (Exception exception) {
Assert.fail(exception.getMessage());
}
LOGGER.info("======= testGetCustomerOK done.");
}
Next, the catching of exceptions and calling Assert.fail() is in fact the same work that the test runner actually does. We can let the test runner handle those cases:
/**
*
*/
@Test
public void testGetCustomerOK() throws Exception {
LOGGER.info("======= testGetCustomerOK starting...");
CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
// Check.
Assert.assertNotNull("Extra not found.", targetDTO);
Assert.assertEquals("accountIds must be the same.", "ABC99", targetDTO.getAccountId());
LOGGER.info("======= testGetCustomerOK done.");
}
The remaining logs are actually information that can already be known from the test runner, since test results are presented by methods. My guess is that they were added to make the previous logs more readable. They can go now:
/**
*
*/
@Test
public void testGetCustomerOK() throws Exception {
CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
// Check.
Assert.assertNotNull("Extra not found.", targetDTO);
Assert.assertEquals("accountIds must be the same.", "ABC99", targetDTO.getAccountId());
}
The “check” comment serves no useful purpose. Also, there is an empty comment that obviously adds no value:
@Test
public void testGetCustomerOK() throws Exception {
CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
Assert.assertNotNull("Extra not found.", targetDTO);
Assert.assertEquals("accountIds must be the same.", "ABC99", targetDTO.getAccountId());
}
We are down to 6 lines of code. The first assert does a check that is also done implicitely by the following one. That seems redundant. Also, it is clearly a situation that should not happen in a normal test run. That can go:
@Test
public void testGetCustomerOK() throws Exception {
CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
Assert.assertEquals("accountIds must be the same.", "ABC99", targetDTO.getAccountId());
}
The remaining assertion has a comment that says what the test does. In some way, there is some value in this. However, in most (all?) cases, the person seeing the error would open the test class anyway and read the code. The test comment seems redundant. At the very least, its value is far from clear. In those situations, I remove the comments:
@Test
public void testGetCustomerOK() throws Exception {
CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
Assert.assertEquals("ABC99", targetDTO.getAccountId());
}
OK, a little inlining can now be done:
@Test
public void testGetCustomerOK() throws Exception {
Assert.assertEquals("ABC99", this.serviceImpl.getCustomer("ABC99").getAccountId());
}
The Assert.assertEquals method can also be statically imported:
@Test
public void testGetCustomerOK() throws Exception {
assertEquals("ABC99", this.serviceImpl.getCustomer("ABC99").getAccountId());
}
And the test could use a renaming:
@Test
public void can_obtain_a_customer_by_account_id() throws Exception {
assertEquals("ABC99", this.serviceImpl.getCustomer("ABC99").getAccountId());
}
Hm… the “this.” clause is not really necessary:
@Test
public void can_obtain_a_customer_by_account_id() throws Exception {
assertEquals("ABC99", serviceImpl.getCustomer("ABC99").getAccountId());
}
And… that’s it. I’m down to 4 lines of code. There might be fewer comments, but I believe the result is a lot more readable.
OOP Conference 2012
OOP Conference is the longest running conferences I’ve ever presented at. This year was it’s 21st year of running, and although coming from Object-Oriented programming roots, the contents of OOPConference have evolved with the times to represent so much more – just like JAOO has over the years.
This is the second conference I’ve presented at where the talks were in a mix of languages – obviously German, since the conference is based in Munich, and the other language being English. As a result, the number of sessions I attended was much lower than I normally would and I was able to catch up with a number of other speakers such as Johanna Rothman, Michael Nygard (author of Release it!), Kevlin Henney (97 Things curator) as well as meeting many new speakers.
I was also surprised at how many German speakers I’d met previously and got to practice a little bit of German. I did try sitting in on one session with a former colleague, Gregor Hohpe where he talked about (auf Deutsch) the Near-Field Communication technology the Japanese have. He talks pretty fast in English, let alone in German. I thought I was doing pretty well understanding the gist, but at probably half an hour into the talk, I think my brain seemed to explode and couldn’t take any more. A good way to test your limits
Fortunately he also used lots of photos in the slides so I could follow along.
I attended a number of other talks in English, one on the latest going on in the NoSQL space (reminding me of a news commentary on what was going on) as well as one of the keynotes by David Parnas. I’ll admit that none of the keynotes blew me away. They all had good solid points they wanted to get across but the message not really new to me. I appreciated listening to Parnas’ talk because of his significant impact to the way OO-Programming is done, although his focus on documenting and enforcing contracts meticulously (whilst having its place) isn’t necessarily as relevant in the internet applications of today (but highly relevant in embedded systems that last for 25 years!).
Something I learned from his keynote was a new tool for better thinking about object oriented design, providing a table to help people classify what sort of information they want to hide and some recommendations to do so. Although probably not a very new tool, I think it has been forgotten through the passage of time and I know plenty of developers who could learn more about real encapsulation who’d benefit from it.
I had two sessions presented at OOP Conference. The first, “Learning to see, A Systems Thinking Primer” gave people a focused introduction to systems thinking concepts, the ideas of archetypes and applying it to situations in software. I’m really glad that a German audience proved much more interactive than I’d hope and I think it proved some interesting insights into topics such as Mental Models and such.
The other sesison was working with my Hamburg-based colleague, Ken Fassone on a “Night School” lecture/workshop Pair Programming: Good, Bad and Ugly (which I have to give credit to another colleague, Rachel Laycock for). I’m not sure some some people anticipated a workshop, but I’m pleased at how some people enjoyed it. We swapped exercises after a mishap with some supplies and shipment, but afterwards, realised how difficult it was for some attendees to do some sentence writing, with a new group, in a language that is not their mother tongue. They did way better than I ever could, and from the enthusiastic thanks from some of the participants at the end of the workshop, proved to be an enjoyable exercise as well.
Network operators and identity
We had a big hoo-hah this week over O2 mis-sharing customer phone numbers. They've been sticking them in the HTTP headers for trusted partners for years (a few services FP built used them), but it looks like someone misconfigured a proxy and they leaked out on the wider web. They've been found, had a public slapping, and apologised.
It's a shame, really, because identity is probably one of the last places where operators could really do something useful. They've long prided themselves on their ownership of relationships with their customers, and part of that relationship is their knowing who you are (more for monthly subscribers than PAYG, but still). I'm a bit puzzled as to why they haven't done more with this: one problem that the web has is a complete lack of innate sense of identity, which is why we all have to either remember lots of passwords, use software to manage different passwords for different sites, or have one password we use everywhere - and all of these situations are painful.
(Aside: I can imagine passwords being one of those things that we have to explain to our incredulous grandchildren as an artefact of a Less Civilised Time)
I get that for many people and many situations, this anonymity is a feature not a bug, but I don't see why anonymity and convenience have to be mutually exclusive. Operators, of course, know who you are: it's not called a Subscriber Identity Module for nothing. And, just as they missed the boat with location services 5-7 years ago (by gathering useful location data and either refusing to release it, or trying to charge £0.10 per location lookup, ruling out some classes of application completely and making most of the others commercially unviable), they're probably doing, or have done, the same with identity.
Imagine if when you bought your Orange phone, you could opt in to a service which identified you to web sites (Facebook, ebay, Google, Hotmail) automatically. Perhaps it could do this by presenting them with unique token, a bit like a cookie, which they could use to get your personal details from your operator (with your permission, of course). It'd be great for them (easier sign-ups and logins means more customers and more use), great for the end user (no passwords, hooray) and a decent proposition for the operator ("never forget a password with Orange"). If you're worried about security - well, you can lock your phone already and control physical access to it as well as you can your wallet.
This needn't involve sharing your mobile number - the unique token could be a one-way hash of the number, or similar: something guaranteed to be you and only you, but of no value to spammers if they catch sight of it. As a customer you could control which web sites could use it, and which didn't. Parental controls could be used to restrict logins to specific web sites from the phones of children. It feels like this ought to be useful.
There are privacy issues, true, but if you're using a mobile then you're already trusting an operator with your calling circle, communications, logs of text messages, web pages accessed… a whole pile of very private stuff. Is offering management of your identity on top of all this really a step too far?
Agile Testing: Key Points for Unlearning
Don’t Rely Solely On jQuery’s “keyup” Event
A few days ago I pushed some changes to the form validation up to my WatchMeCode website. I was trying to fix a scenario where a browser cache would have some of the data in the purchase form already filled in. In that scenario, a potential customer would have to modify each field, even though they were already filled in, in order for my Backbone code to see the data in the field.
To “fix” the problem, I switched my code from a “change” event to a “keyup” event for the text boxes … bad idea!
Browser Auto-FillMost (if not all) browsers have an auto-fill feature, these days. I use it in Chrome a lot. It saves me a few seconds here and there and generally makes it easier for me to fill in the same repetitious information across websites.

But there’s a problem with auto-fill. It doesn’t fire the “keyup” event. It fires the “change” event for the things it fills in, but not “keyup”. This resulted in the data being truncated when it populated my Backbone model.
In the above screenshot, since i had typed “deri” in to the email address, the email that is stored in the Backbone model would only be “deri” – and that’s obviously not a valid email address.
Easy To FixThere are a number of very easy ways to fix this.
- Validate the email address format
- Use a combination of “blur”, “change”, and “keyup” events
- Delay reading the data until the user clicks the “Purchase” button
- Use a KVO (key-value observer) plugin like my Backbone.ModelBinding and let it deal with that for you
For the quick-fix to get my site working properly, I went with the combination of “change” and “keyup” events. I’ll be re-writing my purchase form sometime soon, and will likely delay reading the values until they click the “Purchase” button. I’m also going to put in better email address validation to make sure it at least has an @ and a . in it, and I’ll likely use the HTML5 “email” field and see how that will help me, if at all.
Not So Easy To Automate TestingWhen I originally made the change to use the “keyup” event, I did all my usual testing – which did not include using auto-fill. All of my testing passed, so I pushed the site live.
How do you test for bugs like this in an automated way? Is there even an automated way to test a browser’s auto-fill? I’d like to avoid mistakes like this in the future, and some automated testing around it would certainly be nice.
Lesson Learned: Don’t Rely Solely On “keyup”There certainly are some great things you can do with the “keyup” event – like autocomplete, for one – but it’s not a great idea to only use this when there’s a chance that the browser’s auto-fill will be used.
And unfortunately for me, 2 of my customers ran in to this problem before I got it fixed. It makes it very hard to email someone the download instructions for their order. One of them contacted me and I corrected the order. But the other purchaser has not yet contacted me, and I don’t have enough information to figure out who they are, so I can’t track them down. I hope this person realizes that they didn’t get their order, they contact me. My contact info is all over the site… so … hopefully … the lessons learned for running an e-commerce site are sometimes painful.
Tractors and Agile Development?

Whenever I use John Deere as an example of a fantastic Agile adoption, I always get looks of surprise. That’s quickly followed by an ‘a-ha’ moment when I share that today’s

From my visit to the test farm in Des Moines - note all of the hardware on top of the tractors
tractors are run by more lines of code than the early space shuttles. Yesterday, ComputerWorld published a great article about John Deere’s Agile adoption, characterized as a ‘big bang’ across their 800-person development organization within a year. It’s definitely worth the 5 minute read.
By 2050, there will be 9 billion people on the Earth.
In 50 years, the world population will require 100% more food. Seventy percent of that food is expected to come from efficiency-improving technology. John Deere considers these their user stories, and they strive to use technology to help solve these global problems. If the ComputerWorld article is worth 5 minutes of your time, then Chad Holdorf’s in-depth talk is worth every bit of 25 minutes to hear John Deere’s bigger vision and how they inspire teams to tackle it at John Deere.
You can work with John Deere too.
I’ve been honored to work with Tony Thelen, director of John Deere’s Intelligent Solutions Group, and Chad Holdorf, their Agile Coach, throughout this transformation. And I share their passion for connecting engineers to solve these potentially disastrous problems. I’d like nothing more than to see some smart folks go to work for John Deere.

With my son in a John Deere plow.
Tractors and Agile? Absolutely. I can’t think of a better example of how software is shaping the world we live in – every single day. Congratulations Tony and Chad and best of luck on your social mission.
Ryan Martens is founder and CTO of Rally Software, a hopeful Citizen Engineer and a recovering Entrepreneur-in-Residence at the Unreasonable Institute. You can follow him on Twitter @RallyOn.
Agile is niet te vermijden
Net als in 2010 heeft Xebia in 2011 het jaarlijks onderzoek naar de de status van Agile in Nederland uitgevoerd. Met ook dit jaar weer opvallende resultaten. Zo zegt bijna 90 procent van de bedrijven die met Agile werken sterk verbeterde resultaten te realiseren bij hun (ICT) projecten. De vraagt die direct bij mij opkomt bij dit soort hoge percentages is waarom niet iedereen met Agile aan de slag gaat.
Daarnaast ervaart 83 procent van de Nederlandse bedrijven die Agile werken hebben geadopteerd, meer werkplezier en 85 procent meer teammotivatie. Dit percentage is aanzienlijk hoger dan vorig jaar, toen gaf driekwart van de respondenten aan meer werkplezier en teammotivatie te ervaren. Dus de mensen die Agile werken varen er wel bij, naar mijn mening een van de belangrijkste redenen voor het succes van Agile. Dit komt ook veelal tot uiting in een lager ziekteverzuim en grotere loyaliteit naar de werkgever toe.
Andere belangrijke effecten zijn een verkorte time-to-market volgens 79 procent van de ondervraagden en toename van de productiviteit (66 procent). Het onderzoek laat ook zien dat kostenverlaging een belangrijker effect van Agile werken is dan vorig jaar (38 procent in 2011 tegen 21 procent in 2010). Niet zo vreemd natuurlijk in deze economisch zware tijden. Maar dit betekent wel dat Agile steeds meer wordt ingezet als onderdeel van een kostenverlagingstraject. Dan is het wel heel belangrijk ervoor te waken, dat met het (meer) sturen op deze doelen de Agile gedachte niet ten onder gaat in de zoektocht naar kostenverlaging. Indien kostenverlaging wordt neergezet als primair doel met Agile als middel, is de kans groot weer te verzanden in ‘ouderwets’ contract en KPI management waarvan we in het verleden nou juist geleerd hebben dat dat niet effectief is.
In de overgang naar het Agile werken is de bedrijfscultuur net als vorig jaar de belangrijkste bottleneck voor veel organisaties (49 procent). En ook dat is geen nieuw inzicht. Maar het is wel iets dat te vaak onderschat wordt, zeker door belangrijke personen die juist onderdeel zijn van die bestaande bedrijfscultuur. De adoptie van Agile vereist veel focus en energie voor langere tijd en de daadwerkelijke borging vindt plaats juist via een inbedding in die bedrijfscultuur.
Door het verbeteren van kennis, kunde en bovenal mindset van Agile zal de uitrol een grotere kans van slagen hebben. De ondervraagde organisaties erkennen dit gegeven zelf overigens ook, want volgens 36 procent is een gebrek aan kennis en kunde de belangrijkste beperkende factor in de (verdere) implementatie en uitrol van Agile. Door juist in deze economisch uitdagende tijden in kennis, kunde en mindset van Agile te investeren zullen organisaties meer rendement kunnen behalen. Het verbeteren van bedrijfsresultaat is nu bijvoorbeeld voor veel financiële instellingen in Nederland een belangrijke reden om Agile te gaan werken: zo kunnen zij namelijk effectief hun te hoge kostenstructuur aanpakken.
Agile belooft dus veel, maar maakt dit ook waar. Zeker gezien de huidige generaties Y en Z die nu opgroeien en de toekomstige werkbevolking van Nederland gaan vormen, is er geen ontkomen meer aan (iets als) Agile. Regelmatig spreek ik diverse (jongere) sollicitanten die Agile, en de manier van werken en omgaan met elkaar die daarbij hoort, heel normaal en gewoon vinden en die gruwelen bij een beschrijving van het traditionele waterval model en bijbehorende werkaanpak. Het aantrekken van jong talent en een werkwijze die niets met Agile of elementen daarvan te maken heeft, staat bijna haaks op elkaar. Blijvende continiuteit en succes op langere termijn voor ieder bedrijf bestaat voor een belangrijk deel uit het aan kunnen blijven trekken en behouden van jong talent. Agile worden of zijn, lijkt hier een belangrijke voorwaarde voor te zijn.
Ik ben benieuwd wanneer u op de succesvolle trein stapt die Agile heet!
Getting to grips with properties of sensors
One of the courses I'm really enjoying right now is Pervasive Computing. It involves playing with hardware (something I've never done to any real degree), ties into the trend of miniaturising or mobilising computing, and humours an interest I developed last year about the potential for mass use of sensors, and spoke about at Future of Mobile.
Dan Chalmers, who runs the Pervasive Computing course, has us playing with Phidgets in lab sessions, and very kindly lets us borrow some kit to play with at home, so I've had a little pile of devices wired up to my laptop for the last few days. The lab sessions are getting us used to some of the realities of working with sensors in the real world: notionally-identical sensors can behave differently, there are timing issues when dealing with them, and background noise is ever-present. At the same time we're also doing a lot of background reading, starting with the classic Mark Weiser paper from 1991 (which I'm now ashamed I hadn't already read), and moving through to a few discussing the role sensor networks can play in determining context (a topic I coincidentally wrote a hypothetical Google project proposal for as part of Business & Project Management, last term).
I've been doing a bit of extra homework, working on an exercise to implement morse code transmission across an LED and a light sensor: stick text in at one end, it's encoded into ITU Morse, flashed out by the LED, picked up by the light sensor, and readings translated back first into dots and dashes, then text. It's a nice playground for looking at some of those issues of noise and sensor variation, and neatly constrained: I can set up simple tests, have them fired from my laptop, and record and analyse the results quite simply.
Here's what the set-up looks like:
Note that the LED and light sensor are jammed as close together as I could get them (to try and minimise noise and maximise receipt of the signal). When I'm running the tests, I cover the whole thing to keep it dark. I have run some tests in the light too, but the lights in my home office aren't strong enough to provide a consistent light level, and I didn't want to be worrying about whether changes in observed behaviour were down to time of day or my code.
First thing to note is the behaviour of that LED when it's read by a light sensor. Here's a little plot of observed light level when you turn it on, run it for a second, then turn it off. I made this by kicking the light sensor off, having it record any changes in its readings, then turning the LED on, waiting a second, and turning it off. Repeat 200 times, as the sensor tends to only pick up a few changes in any given second. Sensor reading is on the Y axis, time on the X:
A few observations:
- This sensor should produce readings from 0 to 1000; the peak is around 680, even with an LED up against it. The lowest readings never quite hit zero;
- You can see a quick ramp-up time (which still takes 250ms to really get to full reading) and a much shallower curve when ramping down, as light fades out. Any attempt to determine whether the LED is lit or not needs to take this into account, and the speed of ramp-up and fade will affect the maximum speed that I can transmit data over this connection;
- There are a few nasty outlying readings, particularly during ramp-down: these might occasionally fool an observing sensor.
This is all very low-level stuff, and I'm enjoying learning about this side of sensors - but most of the work for this project has been implementing the software. I started out with a dummy transport which simulated the hardware in ideal circumstances: i.e. stick a dot or dash onto a queue and it comes off just fine. That gave me a good substrate on which to implement and test my Morse coding and decoding, and let me unit test the thing in ideal conditions before worrying about hardware.
The Phidgets API is really simple and straightforward: no problems there at all.
Once I got into the business of plugging in hardware, I had to write two classes which deal with real-world messiness of deciding if a given signal level means the bulb is lit or not. I used a dead simple approach for this: is it nearer the top or bottom of its range, and has it changed state recently? The other issue is timing: Morse relies on fixed timing widths of 1 dot between morse symbols, 3 between morse characters and 7 between words… but when it takes time to light and unlight a bulb, you can't rely on these timings. They're different enough that I could be slightly fuzzy ("a gap of 4 or fewer dots is an inter-character gap", etc.) and get decent results. There should be no possibility of these gaps being too short - but plenty of opportunity (thanks to delays in lighting, or signals travelling from my code to the bulb) for them to be a little slow.
I didn't implement any error checking or protocol to negotiate transmission speed or retransmits; this would be the next step, I think. I did implement some calibration, where the LED is lit and a sensor reading taken (repeat a few times to get an average for the "fully lit" reading).
I ran lots of tests at various speeds (measured in words per minute, used to calculate the length in milliseconds of a dot), sending a sequence of pangrams out (to ensure I'm delivering a good alphabetic range) and measuring the accuracy of the received message by calculating its Levenshtein distance from the original text. Here's the results, with accuracy on the Y axis (lower is fewer errors and thus better) and WPM on the X:
You can see two sets of results here. The blue dots are with the sensor and LED touching; the green ones are with sensor and LED 1cm apart. You can see that even this small distance decreases accuracy, even with the calibration step between each test.
Strange how reliability is broadly the same until 50WPM (touching sensors) or 35WPM (1cm apart), then slowly (and linearly) gets worse, isn't it? Perhaps a property of those speed-ups/slow-downs for the bulb.
So, things I've learned:
- Unit testing wins, again; the encoding and decoding was all TDDd to death and I feel it's quite robust as a result. I also found JUnit to be a really handy way to fire off nondeterministic tests (like running text over the LED/sensor combo) which I wouldn't consider unit tests or, say, fail an automated build over;
- I rewrote the software once, after spending hours trying to nail a final bug and realising that my design was a bit shonky. My first design used a data structure of (time received, morse symbol) tuples. Second time around I just used morse symbols, but added "stop character" and "stop word" as additional tokens and left the handling of timing to the encoding and decoding layer. This separation made everything simpler to maintain. Could I have sat down and thought it through more first time around? I have a suspicion my second design was cleaner because of the experiences I'd had first time around;
- I'm simultaneously surprised at the speed I managed to achieve; there was always some error, but 50 WPM seemed to have a similar rate to lower speeds. The world record for human morse code is 72.5 WPM, and I'm pretty sure my implementation could be improved in speed and accuracy. For instance, it has no capacity to correct obviously wrong symbols or make best-guesses.
Things I still don't get:
- Why accuracy decreases when the sensors 1cm apart are run super-slowly. I suspect something relating to the timing and fuzziness with which I look for dot-length gaps;
- Why the decrease in accuracy seems linear after a certain point. I would instinctively expect it to decrease linearly as WPM increases.
And in future, I'd like to try somehow taking into account the shape of that lighting/dimming curve for the bulb - it feels like I ought to factor that into the algorithm for recognising state changes in the bulb. Also, some error correction or a retransmit protocol would increase accuracy significantly, or let me run faster and recover from occasional issues, giving greater throughput overall.
Rotating the ScrumMaster Role
Some teams that struggle with choosing the best ScrumMaster decide that an appropriate strategy is to rotate the role among all team members. I don’t advocate this, as I don’t think it demonstrates an appropriate respect for the challenges and significance of the role. In my family, we rotate who cleans the table and loads the dishwasher. Any of us can do that job. We do not, however, rotate who cooks dinner. My wife is a far better cook than anyone else in the family. We want the cooking to be the best it can be, so we don’t rotate that job. If you want your Scrum team to be the best it can be, I do not recommend that you make a habit of rotating the job of ScrumMaster.
However, there are some occasions when you may want to rotate. The most common is when you want to create learning opportunities. For example, if team members are struggling to understand the duties of the ScrumMaster, they may want to consider rotating each team member through the role. This may allow each to develop an understanding of what it means to be a ScrumMaster. Similarly, if a team identifies four or five good ScrumMaster candidates among their ranks, it may want to rotate among them, giving each a chance to try the role. Then by considering the performance of each, the team will hopefully be able to choose the most appropriate ScrumMaster.
Bob Schatz and Ibrahim Abdelshafi of Primavera Systems point out another reason why rotating might be useful.
With time the team can begin to treat this position as their manager. And the person in that position typically detects and dutifully fills the apparent need. The result is a breakdown in the team’s self-management practice. By rotating the responsibility at the start of each sprint, it diffuses the role and makes it a shared team responsibility and establishes a balance of power. (The Agile Marathon in the Proceedings of Agile 2006)
So, although it is possible to rotate the job of ScrumMaster, I recommend doing it only for specific reasons, such as those just given, and only temporarily. Rotating should not be a permanent practice. There are simply too many problems with it, including the following:
- Someone who has rotated into the role usually has other, non-ScrumMaster tasks to perform during the sprint, and these often take priority.
- It’s hard to train enough people to do the role well.
- Some people will use their time as ScrumMaster to try to push through changes to the process.
- Designating someone as ScrumMaster for a sprint or two does not automatically make someone value the job, which can lead to ScrumMasters who think Scrum is a mistake.
Kanban Survey
CSM: Henrik Kniberg em São Paulo. Inscrições abertas!
Computerworld Article: John Deere Plows in to Agile
With Deere’s permission, we’ve chronicled Deere’s Intelligent Systems Group agile-at-scale, and all-in-really-fast transformation on this blog. There’s another post or two in process. In the meantime, this Computerworld article adds to the story. Pretty cool, really. Great to see a 150 yr old plus company taking the plunge to the latest methods of software development.
Oracle: dbstart – ORACLE_HOME_LISTNER is not SET, unable to auto-start Oracle Net Listener
We ran into an interesting problem when trying to start up an Oracle instance using dbstart whereby we were getting the following error:
-bash-3.2$ dbstart ORACLE_HOME_LISTNER is not SET, unable to auto-start Oracle Net Listener Usage: /u01/app/oracle/product/11.2.0/dbhome_1/bin/dbstart ORACLE_HOME Processing Database instance "orcl": log file /u01/app/oracle/product/11.2.0/dbhome_1/startup.log
Ignoring the usage message we thought that setting the environment variable was what we needed to do, but…
-bash-3.2$ export ORACLE_HOME_LISTNER=$ORACLE_HOME -bash-3.2$ dbstart ORACLE_HOME_LISTNER is not SET, unable to auto-start Oracle Net Listener Usage: /u01/app/oracle/product/11.2.0/dbhome_1/bin/dbstart ORACLE_HOME Processing Database instance "orcl": log file /u01/app/oracle/product/11.2.0/dbhome_1/startup.log
We ended up looking at the source of dbstart to see what was going on:
# First argument is used to bring up Oracle Net Listener ORACLE_HOME_LISTNER=$1 if [ ! $ORACLE_HOME_LISTNER ] ; then echo "ORACLE_HOME_LISTNER is not SET, unable to auto-start Oracle Net Listener" echo "Usage: $0 ORACLE_HOME"
The usage message does explain that you’re supposed to call it like this:
-bash-3.2$ dbstart $ORACLE_HOME
But it still seems a bit weird/misleading to me that you’d override the value of a global variable from inside a script which doesn’t suggest that it’s going to do that!
Such is life in Oracle land..
Agile Project Rescue
Agile Transitions and Human Nature
How we do “innovation time”
This article is cross-posted from Blogs From The Geeks, the 7digital development team blog:
How we do “innovation time”Assuming you had consent from up above*, you’d think it’d be a breeze to get an initiative like innovation time off the ground. Surprisingly at 7digital it took us three attempts before we got something to stick and speaking to someone else recently I found they’d had a similar experience. As we’ve had our “innovation time” initiative running successfully for over a year now I think it’s worth sharing how we’ve got it to work.
In our first two attempts we found the main reason it failed was putting too many barriers in the way. We didn’t think it was right that you could work on production code, you shouldn’t do it on your own, it should be justified and approved by your peers, like a business case. Innovation really hates these kind of things. Ironically we thought having “sensible” rules like this would ensure people didn’t waste their time on things we didn’t think could be classed as innovation, but they were based on a fundamental misunderstanding of how innovation occurs.
If you’re even slightly aware of your history regarding invention and discovery you’ll see a large proportion came about by happy accident, mostly when trying to prove something completely different. It’s such a common event it has its own name - serendipity. I strongly believe you’ve got to have a really open mind and shouldn’t have any particular expectations or goals in mind apart from innovation itself.
So for our third attempt we tried to really strip it down. Here’s the rules we agreed:
Conditions of use of innovation time- There is no jurisdiction on how you use the time.
- If you’re working on production code, or any application or tool which supports production code, you must do it properly i.e. follow the development team standards.
- If you’re working on something unrelated to production code or existing applications you may work in any way you like. However if you wish for whatever you produce to be used in anger it must meet the usual standards (i.e. either write it to expected standards to begin with or rewrite it afterwards).
- We should put anything suitable in the public sphere e.g. on GitHub and hosted where appropriate.
- You have 2 days a month you are able to request for innovation time.
- Innovation time does not accrue – if you don’t take your allocation in a particular month it does not carry over.
- If someone else does not use their allocation you cannot use it in their place.
- Request time through whosoff.com as “DevTeam Innovation Time” (we set up a special leave type).
- It’s to the discretion of your lead developer (or head of development) to approve. (e.g. they may not approve if they consider that the ability for the team to function effectively will be compromised due to too many people being off or we’re really busy with something and need all hands on the pumps).
- You must create a wiki page with the details of what you did and what you learnt.
- For each day you take against a particular activity you should have a diary-like entry with the date and who was involved.
Using our leave booking system was a particularly inspired move. It means innovation can be managed just like holiday – it shows up in everyone’s calendars and allows everyone to plan around your absence. It also means we can pull out stats on how much time people have been taking:
Interestingly out of a possible ~456 days in 2011 189 were used, making it “4.74% time”. Another particularly surprising observation was people took less innovation time when they were not feeling motivated about their usual work (we had a very painful database migration in the summer).
It really helps that we’re very team focused at 7digital (pair programming is really good for this) so it’s no great loss when any one person is away for a short time. It also really helps that we try very hard to work at a sustainable pace.
As for what’s been done we’ve had some really interesting and diverse projects. Many of them have simply been around investigating new technologies and ways of doing things rather than new product ideas (but we’ve had some of those too). I think in this respect a lot of the benefits are intangible, but that’s one of the interesting things about innovation – if you tried to measure it you’d kill it stone dead.
*I’ve no intention of going into the justification for initiatives like innovation time here. That would be another, very long article
