L'Agilitateur - In EnglishCréation de logiciels : de l'agilité à l'artisanat2021-10-09T15:11:31+02:00urn:md5:7668924f626a6543fa389f1b4e47e529DotclearSteve Wozniak is not boringurn:md5:675960135fc9e68c4c9d3948d022b4df2016-09-10T21:45:00+01:002016-09-10T21:45:00+01:00Olivier AzeauIn Englishanti-ifcsharpgolanggotorefactoring<p>I saw <a href="https://twitter.com/francesc/status/774438145433534466">this tweet</a> a few hours ago and found the piece of code quite interesting: a small algorithm with searches, logic, external interaction and a nice comment explaining the whole thing. I could have written this kind of code ten years ago. Today, my problem is that my eyes start bleeding when I bump into a mix of loop and conditions, especially when the mix cannot be easily tested.<br />
Let's try to write it differently.</p> <p>First, let's have a look at the code.
<a href="https://agilitateur.azeau.com/public/agilitateur/boringWozniakGoLang.jpeg" title="boringWozniakGoLang.jpeg"><img src="https://agilitateur.azeau.com/public/agilitateur/.boringWozniakGoLang_m.jpg" alt="boringWozniakGoLang.jpeg" style="display:table; margin:0 auto;" title="boringWozniakGoLang.jpeg, sept. 2016" /></a></p>
<p>We hope to write it in a different way but we first need a safety net to avoid changes in the code behaviour. We usually have test cases for that.<br />
Since this code uses a random number generator, we cannot really test it as is. A classic technique is to decouple the random number generator so that we can inject a fake one (called a 'stub') during the tests.</p>
<p>Since I don't know much about the Go language, I will first convert the code to a language I'm more familiar with (here C#). The two codes are almost identical.</p>
<pre class="brush: csharp;">
// GetRandomName generates a random name from the list of adjectives and surnames in this package
// formatted as "adjective_surname". For example 'focused_turing'. If retry is non-zero, a random
// integer between 0 and 10 will be added to the end of the name, e.g `focused_turing3`
public static string GetRandomName(int retry)
{
var rnd = new Random();
begin:
var name = string.Format ("{0}_{1}", left[rnd.Next(left.Length)], right[rnd.Next(right.Length)]);
if( name == "boring_wozniak" )/* Steve Wozniak is not boring */
{
goto begin;
}
if( retry > 0 )
{
name = string.Format ("{0}{1}", name, rnd.Next(10));
}
return name;
}
</pre>
<p>Now I can decouple the random number generation</p>
<pre class="brush: csharp;">
public static string GetRandomName(int retry)
{
var rnd = new Random();
return GetRandomName(retry, max => rnd.Next(max));
}
public static string GetRandomName(int retry, Func<int,int> rnd)
{
begin:
var name = string.Format ("{0}_{1}", left[rnd(left.Length)], right[rnd(right.Length)]);
if( name == "boring_wozniak" )/* Steve Wozniak is not boring */
{
goto begin;
}
if( retry > 0 )
{
name = string.Format ("{0}{1}", name, rnd(10));
}
return name;
}
</pre>
<p>At this point, we can write a bunch of tests. These tests will serve 2 purposes:</p>
<ul>
<li>provide a safety net for refactoring</li>
<li>document the program behaviour</li>
</ul>
<p>The 2nd purpose allows us to remove part of the comments: the examples ('focused_turing', 'focused_turing3') and the whys ("Steve Wozniak is not boring").<br />
They are better written as plain code because the code cannot lie.<br /></p>
<p>The full set of tests is <a href="https://github.com/Oaz/BoringWozniak/blob/master/Tests/Test.cs">here on github</a>.<br />
The tests are better than comments because when the code becomes wrong, for example, if remove the "boring_wozniak" condition, a good test tells me why the code is not correct:
<img src="https://agilitateur.azeau.com/public/agilitateur/SteveWozniakIsNotBoring.png" alt="SteveWozniakIsNotBoring.png" style="display:table; margin:0 auto;" title="SteveWozniakIsNotBoring.png, sept. 2016" /></p>
<p>Now we can try to remove the mix of loop and conditions.<br />
I have no problem with the use of goto but a mix of "goto" and "if" leads to unnecessary complicated code. Here, the goto serves a single purpose: loop over the names generation.<br />
Here is an alternate implementation where the loop is decoupled from the conditions:</p>
<pre class="brush: csharp;">
private static IEnumerable<string> RandomNames(Func<int,int> rnd, Func<string,string,string> format)
{
begin:
yield return format(adjectives[rnd(adjectives.Length)], surnames[rnd(surnames.Length)]);
goto begin;
}
</pre>
<p>Being given an enumeration of random names, the main logic becomes easier to write: we want the first name which is not "boring_wozniak" and we want to concatenate it with an optional suffix:</p>
<pre class="brush: csharp;">
public static string GetRandomName(int retry, Func<int,int> rnd)
{
var baseName = RandomNames (rnd, (adjective, surname) => string.Format ("{0}_{1}", adjective, surname))
.First (name => name != "boring_wozniak");
var optionalSuffix = (retry > 0) ? rnd (10).ToString () : string.Empty;
return baseName + optionalSuffix;
}
</pre>
<p>When the code is written this way, I no longer feel the need for a comment explaining what is going on. The logic is now written with immutable variables. We no longer have to scratch our head about this "name" variable whose value could change many times.<br />
The conditions are no longer if blocks and, as a consequence, have a narrow focus. One of them just just taking the first item verifying some predicate in an enumeration.
The other one is now a ternary conditional operator where we just choose between two values without any side effect.</p>
<p>Is the final code much better, as I tend to think, or am I just splitting hairs?
What do you think?</p>Back from the Scrum Gathering Paris 2013urn:md5:07e07ed6b27228a36961480d79fd66652013-09-29T18:39:00+02:002013-10-22T00:59:28+02:00Olivier AzeauIn English<p><img src="https://agilitateur.azeau.com/public/agilitateur/evenements/Scrum_in_Paris_-_Keep_on_Moving.png" alt="Scrum in Paris - Keep on Moving" style="float:right; margin: 0 0 1em 1em;" title="Scrum in Paris - Keep on Moving, sept. 2013" />A quick retrospective of my <a href="http://www.scrumalliance.org/events/611-paris-">Global Scrum Gathering Paris 2013</a></p> <h4>What Went Well</h4>
<ul>
<li>The opening keynote <a href="http://www.scrumalliance.org/courses-events/events/global-gatherings/2013/paris-2013/schedules-and-program/monday-sept-23-2013/9-00-%E2%80%93-10-30-welcome-remarks-opening-keynote">"Culture > Process"</a> by Henrik Kniberg. This journey throughout Spotify culture was inspiring. From now on, it will be difficult for me to think about organizations without referring to squads, tribes or guilds. <a href="https://dl.dropboxusercontent.com/u/1018963/Projects/2013-09-23%20Paris/culture-over-process.pdf">The slides of the session are available here</a>. And for those who could not attend, you still can read <a href="http://www.shino.de/2013/09/23/scrum-gathering-paris-culture-process-henrik-kniberg/">Markus Gärtner blog</a>.</li>
<li>Following the keynote, I attended "Removing cultural barriers in an Agile Team" by Luis Castro: a good introduction to indexes in <a href="http://en.wikipedia.org/wiki/Hofstede%27s_cultural_dimensions_theory">Hofstede's cultural dimensions theory</a>.</li>
<li>The "Training from the back of the room" workshop by Jef Cumps and Kris Phillipaerts had the highest pace I ever experienced. Working in small groups, we had to create a training sequence meant to learn one of the Cs (Connect-Concepts-Concrete Practice-Conclude) to the other attendees. Our group was working on "Concrete Practice". Of course, we had to use the 4 Cs to create this training. At some point, there was this strange feeling of being like Leonardo DiCaprio in Inception with everything looping over itself, except that, in this case, time was not slowing down at deeper levels. Being surrounded by seasoned trainers flying at 10 ideas per second did not help me :) Nevertheless, this was a good experience. I might not put <a href="http://www.amazon.fr/gp/product/0787996629/ref=as_li_ss_tl?ie=UTF8&camp=1642&creative=19458&creativeASIN=0787996629&linkCode=as2&tag=lagilit-21">Sharon Bowman's book</a> on the top of my reading list but I grabbed some ideas on how to improve the Soft(ware)Ball sessions to come.</li>
<li>The Tuesday keynote <a href="http://www.scrumalliance.org/courses-events/events/global-gatherings/2013/paris-2013/schedules-and-program/tuesday-sept-24-2013/11-00-%E2%80%93-12-30-keynote-dan-mezick">"Open Agile Adoption"</a> by Dan Mezick brought interesting ideas about going agile by changing an organization culture. More details on <a href="http://www.openagileadoption.com/">http://www.openagileadoption.com/</a>.</li>
<li>An agile event without legos is not really an agile event. I did not miss the opportunity to discover a new game: <a href="http://wtdom.org/">"Whole-Team Dynamic Organizational Modeling"</a> by Raj Mudhar and Catherine Louis. Basically, you use legos to represent the structure and interactions within an organization. This game is still in its infancy but it shows, I think, good potential to involve people in designing their own organisation and let ideas emerge.</li>
<li>My favorite session of the gathering was <a href="http://fr.slideshare.net/mrsungo/gs-presentation-final">"The Agile Girl Scouts"</a> by Karen and Dave Prior. It certainly will not change my daily life at work but it was the most entertaining and the most mind-boggling when you think about agile in a broader perspective (and we also had cookies). Every people should think about the simple idea that agile is natural and that waterfall processes are instilled at some point in life.</li>
<li>My <a href="http://www.softwareball.org/index.en.html">Soft(ware)Ball</a> session was ok. The audience could have been larger but the ones that were present and active enjoyed the game. The feedback trend is that there's something new and fresh in this game but it has to be improved.</li>
</ul>
<h4>What Went Wrong</h4>
<ul>
<li>The welcome reception is a challenge when you are not familiar with this kind of event. I got the feeling of attending someone else family meeting where every people knew each other...</li>
<li>Number of hearts for target audience was mostly a joke. I attended two lame "3 hearts"(=expert) session. The one on automated testing was so painful that I had to leave during the session. I would be ashamed to present such a poor content at a local group meeting - and here it was in front of an international audience.</li>
<li>Most of the open space topics did not strike me. I expected something spicier.</li>
<li>Theoritically, the hotel was a 4-star. In practice, I already had a better experience in a 2-star hotel, even in Paris.</li>
</ul>
<h4>Puzzles</h4>
<ul>
<li>Given "100% predictability = 0% innovation", how much predictability do we really need?</li>
<li>Is there a good way to define a target audience for session?</li>
<li>Is "Screw the rules" a rule to follow?</li>
<li>How are we, as kids, teenagers or young adults, drawn to waterfall? Is it the educational system or the work place ?</li>
</ul>
<h4>Lessons Learnt</h4>
<ul>
<li>"Culture is something you do without thinking. All else is process."</li>
<li>"Majority of squads at Spotify do not estimate and do not measure velocity"</li>
<li>Release trains and feature toggles. Unfinished features are turned off, so they can release without forks.</li>
<li>"A code branch is a kind of technical debt."</li>
<li>"If everything’s under control, you’re going too slow!"</li>
<li>"If you need to know exactly who is making decisions, you're in the wrong place"</li>
<li><a href="http://martinfowler.com/bliki/AgileImposition.html">"Imposing a process on a team is completely opposed to the principles of agile software, and has been since its inception."</a></li>
<li><a href="http://drunkenpm.blogspot.fr/2013/03/girl-scout-kanban.html">"We have to find a way to help kids sharpen their agile nature and find a way to protect it from the waterfall"</a></li>
</ul>
<h4>Appreciations</h4>
<p>To all the people I met from so many different countries.<br />
New Orleans 2014 is not an option for me but I have to think about Berlin...</p>I'm speaking @ Scrum Gathering Parisurn:md5:5dd63f364a2d69ebeeda9bd9a3de52232013-06-10T08:22:00+02:002013-10-22T01:05:13+02:00Olivier AzeauIn English<p><a href="http://scrumalliance.org/events/611-paris-"><img src="https://agilitateur.azeau.com/public/agilitateur/evenements/scrumgatheringparis_speakerlogo.jpg" alt="scrumgatheringparis_speakerlogo" style="float:right; margin: 0 0 1em 1em;" title="scrumgatheringparis_speakerlogo" /></a></p>
<p>I haven't written in English for a while on this blog but, in September, things are getting worse: I'll have to talk in English since <strong>I'm speaking at <a href="http://scrumalliance.org/events/611-paris-">Scrum Gathering Paris</a>!</strong></p> <p>To be honest, I'm not really <em>speaking</em>. I'm merely facilitating a <a href="http://www.softwareball.org/">Soft(ware)Ball</a> session. The biggest part of the job will consist in translating the materials and maybe adapting the session to the audience. I have to think about it. Since this is a Scrum event, I assume that only a smaller-than-usual part of the attendees will be coders.</p>
<p>I have never attended to a Scrum Gathering. Actually, I have never been to any Scrum Alliance event. And (should I mention it?) I have never been certified by the Scrum Alliance.<br />
That being said, I'm really grateful to the organizing team for having selected a session that is deeply rooted in agile software development culture but remotely linked to the "Scrum world". I hope it will really bring something to the Scrum community.</p>
<p>After a quick look at the <a href="http://scrumalliance.org/system/resource_files/0000/4388/ScrumParisProgram4Postingv6.pdf">program guide</a>, I'm quite impressed by the international flavor of the event. I expected people from Europe but I did not expect people from all over the world coming to Paris. I still cannot believe that my game was selected for this gathering.</p>
<p>Great time ahead!</p>Architectural Design Challenge by James Shore : a reviewurn:md5:457d2a1410a2bd6564a8f966a38327b22010-07-06T00:07:00+02:002010-07-06T00:07:00+02:00Olivier AzeauIn English<p>A few weeks ago, James Shore had initiated <a href="http://jamesshore.com/Blog/Architectural-Design-Challenge.html">an architectural design challenge</a> for which <a href="https://agilitateur.azeau.com/post/2010/05/30/An-Architectural-Design-Challenge-by-James-Shore">I submitted an entry</a>.<br />
Some other people also proposed an implementation. I have listed 4 :</p>
<ul>
<li><a href="https://code.google.com/p/jamesshorearcdesignchallenge/">Ralf Westphal</a></li>
<li><a href="http://justinbozonier.posterous.com/message-oriented-object-design-and-james-shor">Justin Bozonier</a></li>
<li><a href="http://abeletsky.blogspot.com/2010/06/architectural-design-challenge-by-james.html">Alexander Beletsky</a></li>
<li><a href="http://jamesshore.com/Blog/Architecture-Review-Mock-Driven-Three-Layer-Architecture.html">James Shore</a> himself</li>
</ul>
<p>I wanted to review these implementations. I tried to look at them from various perspectives and the exercise was quite interesting.<br />
Here is what I found for 3 of them. I will not talk about James Shore implementation. It could be the topic of a dedicated blog post in the future.</p>
<p>The perspectives that interested me were :</p>
<ul>
<li>the global workflow of commands</li>
<li>the coupling between software units</li>
<li>the unit testing method</li>
</ul>
<p>Here we go.</p> <hr />
<p><strong>Ralf Westphal : an Event-Based Components approach</strong></p>
<p>Ralf has set-up <a href="https://code.google.com/p/jamesshorearcdesignchallenge/">a web site</a> where he describes his solution. It is composed of lots of simple components assembled as if they were electronic components on a board.<br />
See the nice drawings on Ralf google code website. Here is one :
<img src="http://jamesshorearcdesignchallenge.googlecode.com/hg/doc/Architectural%20diagrams/arcchallenge3%20Part2.gif" alt="" /></p>
<p>Communication between components is only event based so the <ins>flow of commands</ins> follows the flow of events. The config path is pushed to the components that do the reading and the writing. The reader get the data and pushes it to the logic that, in turn, pushes the transformed data to the writer and to the display.</p>
<p>All components are implementations of a public contract. Basically, each public contract describes the pins for soldering the components.<br />
Regarding <ins>software coupling</ins>,</p>
<ul>
<li>each basic component has no knowledge of any other component</li>
<li>each board composed of multiple components has knowledge of the contract implemented by the components that are part of it -- except for the standard components whose instances are created by the board itself.</li>
</ul>
<p>All basic components are <ins>unit tested</ins>. The event-style output ensures that the behavior of each component is observable hence testable without any fake, stub or mock.<br />
Though, the absence of unit testing for the "domain board" lead to think that the global design was not test-driven.<br />
But we could probably imagine a top down approach where the "domain board" would have been designed using mocks for its inner parts (reader, writer and transformer).</p>
<p>This component approach was new to me and I find it quite impressive and attractive.<br />
My biggest concern is about scaling : what if a system needs thousands of components? In such a case, can we still use really simple piece of information through the pins?</p>
<hr />
<p><strong>Justin Bozonier : Message Oriented Object Design</strong></p>
<p>Message Oriented Object Design is quite similar to the previous component based approach in the sense that the <ins>flow of commands</ins> goes from the initial reader to the final destination going through all needed steps.<br />
This approach features the <a href="http://pragprog.com/articles/tell-dont-ask">tell don't ask</a> principle in every piece of software.</p>
<p>The main difference with the component approach is that each object knows the other contracts and directly "tell" the other objects what to do instead of raising an event.
The real implementations of the other objects are, of course, unknown.<br />
This leads to a <ins>loose coupling</ins> where each class only has to know few interfaces.</p>
<p><a href="https://agilitateur.azeau.com/public/agilitateur/jamesshore/JustinBozinier.png"><img src="https://agilitateur.azeau.com/public/agilitateur/jamesshore/.JustinBozinier_m.jpg" alt="JustinBozinier.png" style="display:block; margin:0 auto;" title="JustinBozinier.png" /></a></p>
<p>Classes are <ins>unit tested</ins> using stubs behind each interface.</p>
<p>My concern is similar to the previous approach : what about scaling? "tell don't ask" is nice and provide a loosely coupled design but I don't know if this principle can be applied - keeping the same readability level- on programs where the data flow is not so straightforward.</p>
<hr />
<p><strong>Alexander Beletsky : simple design from requirements to implementation</strong></p>
<p>I have very little to say regarding this approach because <a href="https://agilitateur.azeau.com/post/2010/05/30/An-Architectural-Design-Challenge-by-James-Shore">I used more or less the same</a> ;-)</p>
<p>Alexander adopts an inside-out design strategy : first the business logic, then moving towards the I/O.<br />
Each design step is <ins>unit tested</ins> using mocks for verifying the interactions with the components that are not yet present. The mock framework is <a href="http://www.ayende.com/projects/rhino-mocks.aspx">rhino mocks</a>. It is good that some people like it but, to me, the verifications of <a href="http://code.google.com/p/moq/">Moq</a> are much more readable than the expectations of Rhino Mocks.</p>
<p>The resulting design is mostly <ins>loosely coupled</ins> with a central business logic component that consumes strings as input and stores strings as output, featuring a bidirectional command flow.</p>
<p><a href="https://agilitateur.azeau.com/public/agilitateur/jamesshore/AlexanderBeletsky.png"><img src="https://agilitateur.azeau.com/public/agilitateur/jamesshore/.AlexanderBeletsky_m.jpg" alt="AlexanderBeletsky.png" style="display:block; margin:0 auto;" title="AlexanderBeletsky.png" /></a></p>
<p>The only thing that I do not understand is the use of factories. They usually enhance loose coupling but, in this case, they are not really useful.</p>
<hr />
<p><strong>Conclusion</strong></p>
<p>Actually, I do not have any conclusion except that lots of different approaches can lead to software that satisfy the same needs while following basic good principles (loose coupling, unit testing...)</p>Software Craftsmanship Comic Revisitedurn:md5:cc83e0e1766a42cad137d8522c0777542010-06-23T08:24:00+02:002010-06-23T08:24:00+02:00Olivier AzeauIn Englishcraftsmanship <p>Last week, <a href="https://agilitateur.azeau.com/post/2010/06/19/Software-Craftsmanship">I drew a comic about software craftsmanship</a> and I asked for feedback on the <a href="http://groups.google.com/group/software_craftsmanship">software craftsmanship discussion list</a>.<br />
The main output was that my drawing could be interpreted as "software craftsmanship is superior to agile". Since it was not my intent, I'm trying to come with something better.</p>
<p>When you step into the agile world, you start a journey. It is up to each practitioner to find her path. Software craftsmanship is the way I'd like to go on this path because it <em>features</em> values and principles that I like.</p>
<p>Actually, just as a software developer might follow agile principles without claiming to be "agile", one might follow the software craftsmanship principles without labeling herself as a "craftsman".<br />
This might have even happened before the words were invented.<br />
To me, the biggest change with agile a few years ago and software craftsmanship today is that one can read a few word on a manifesto and says "Hey! That sounds like me! This is the place I want to go!".</p>
<p><a href="https://agilitateur.azeau.com/public/agilitateur/craftsmanship_path_en.png"><img src="https://agilitateur.azeau.com/public/agilitateur/.craftsmanship_path_en_m.jpg" alt="Software Craftsmanship Path" style="display:block; margin:0 auto;" title="Software Craftsmanship Path, June 2010" /></a></p>Software Craftsmanshipurn:md5:e786048dd490f4c4df7f695dfc287a842010-06-19T19:51:00+02:002010-06-19T19:51:00+02:00Olivier AzeauIn Englishcraftsmanship <p><a href="https://agilitateur.azeau.com/public/agilitateur/craftsmanship_en.png"><img src="https://agilitateur.azeau.com/public/agilitateur/.craftsmanship_en_m.jpg" alt="craftsmanship_en.png" style="display:block; margin:0 auto;" title="craftsmanship_en.png, juin 2010" /></a></p>An Architectural Design Challenge by James Shoreurn:md5:19d6288bb412153df57b3f6940d5bdea2010-05-30T23:12:00+02:002010-06-06T08:15:26+02:00Olivier AzeauIn English<p>James Shore <a href="http://jamesshore.com/Blog/Architectural-Design-Challenge.html">proposes to experiment a design challenge to deal with architecture issue</a>. It was posted a week ago and some answers already came out. I haven't looked at them yet and I wanted to try on my own. So, here it is.<br />
My solution is coded in C# with basic tooling : <a href="http://monodevelop.com/">Monodevelop</a> IDE, <a href="http://www.nunit.org/">NUnit</a> testing framework and <a href="http://code.google.com/p/moq/">Moq</a> mocking framework.</p> <p>The main logic of the software to build deals about <a href="http://en.wikipedia.org/wiki/ROT13">ROT13</a>. So let's start with a basic test for ROT13 on individual chars.</p>
<pre>
public void PerformRot13OnIndividualChars ()
{
Assert.That( Rot13Converter.CharRot13('A'), Is.EqualTo('N') );
Assert.That( Rot13Converter.CharRot13('U'), Is.EqualTo('H') );
Assert.That( Rot13Converter.CharRot13('c'), Is.EqualTo('p') );
Assert.That( Rot13Converter.CharRot13('s'), Is.EqualTo('f') );
Assert.That( Rot13Converter.CharRot13('3'), Is.EqualTo('3') );
Assert.That( Rot13Converter.CharRot13('*'), Is.EqualTo('*') );
}
</pre>
<p>And then we come with a simple implementation of the char rotation method. It might be improved for non-English chars but these details are not relevant for our problem.</p>
<pre>
public class Rot13Converter
{
public static char CharRot13(char c)
{
if( char.IsUpper(c) )
return CharRot13Impl(c,'A');
else if( char.IsLower(c) )
return CharRot13Impl(c,'a');
else
return c;
}
static char CharRot13Impl(char inputChar, char baseChar)
{
return Convert.ToChar(AsciiRot13(Convert.ToInt32(inputChar),Convert.ToInt32(baseChar)));
}
static int AsciiRot13(int inputCode, int baseCode)
{
return ((inputCode - baseCode + 13) % 26) + baseCode;
}
}
</pre>
<p>Now it's time to design the conversion logic as a whole. Since we want to unit test the logic with no I/O code, we'll have to mock the I/O layer.<br />
Beside this, since Uncle Bob once said <a href="http://www.objectmentor.com/publications/dip.pdf">''High-level modules should not depend on low-level modules. Both should depend on abstractions''</a>, we all know that a good approach is to create an abstraction of the I/O layer and let the logic depend on it.</p>
<p>We're dealing with a conversion of a char stream into another char stream. So a char stream might be a good abstraction.<br />
But, wait a minute. Uncle Bob also said <a href="http://www.objectmentor.com/resources/articles/isp.pdf">''Clients should not be forced to depend upon interfaces that they do not use''</a>. If my abstraction is a char stream, then it will probably contains ways to read the stream <em>and</em> to write into the stream, which means that, for an I/O implementation where we only have to write to (e.g. a console), we will bring unnecessary dependency to the reading part of the abstraction.</p>
<p>As a consequence, we will prefer 2 abstractions : an input char stream and an output char stream. Now we can code a unit test for the ROT13 logic on char streams.</p>
<pre>
public void TransformCharStreamIntoRot13edCharStream ()
{
var inputStream = new Mock<InputCharStream>();
inputStream
.Setup( stream => stream.HasChars() )
.ReturnsInOrder( true, true, false );
inputStream
.Setup( stream => stream.GetChar() )
.ReturnsInOrder( 'A', 'c' );
var outputStream = new Mock<OutputCharStream>();
var converter = new Rot13Converter();
converter.ExecuteOn( inputStream.Object, outputStream.Object );
outputStream.Verify( stream => stream.PutChar('N'), Times.Once() );
outputStream.Verify( stream => stream.PutChar('p'), Times.Once() );
outputStream.Verify( stream => stream.PutChar(It.IsAny<char>()), Times.Exactly(2) );
}
</pre>
<p>And then we write the code to pass the test.</p>
<pre>
public interface InputCharStream
{
char GetChar();
bool HasChars();
}
public interface OutputCharStream
{
void PutChar(char c);
}
public class Rot13Converter
{
public void ExecuteOn (InputCharStream inputStream, OutputCharStream outputStream)
{
while( inputStream.HasChars() )
outputStream.PutChar( CharRot13(inputStream.GetChar()) );
}
}
</pre>
<p>We're done with the logic !</p>
<p>Next step : coding the I/O, with <em>focused integration tests</em>.</p>
<p>First we are going to deal with the part where we read data from an input char stream implemented as a file on disk. We create a text input file and we write a test.</p>
<pre>
public void ReadFileFromDisk()
{
var reader = new FileReader( "someInput.txt", new TestConfiguration() );
Assert.That( reader.HasChars(), Is.True );
Assert.That( reader.GetChar(), Is.EqualTo('A') );
Assert.That( reader.HasChars(), Is.True );
Assert.That( reader.GetChar(), Is.EqualTo('B') );
Assert.That( reader.HasChars(), Is.True );
Assert.That( reader.GetChar(), Is.EqualTo('C') );
Assert.That( reader.HasChars(), Is.False );
}
</pre>
<p>A key decision is how to design the configuration part. We write a toy program where file on disk is there to mimic some data storage, so the configuration might be anything : a folder on disk, a server name, etc.<br />
Since the FileReader might need multiple information from the configuration, we will use dependency inversion again : we define a configuration as an abstraction and give an implementation of this abstraction to the FileReader.<br />
So, basically, we define a FileReader by giving a storage context (the configuration) and the data we want to read (here, a file name).<br />
We write the code to pass the test and that's it.</p>
<pre>
public interface Configuration
{
string GetDataPath (string fileName);
}
public class FileReader : InputCharStream
{
char[] content;
int index;
public FileReader(string fileName, Configuration configuration)
{
content = System.IO.File.ReadAllText(configuration.GetDataPath(fileName)).ToCharArray();
index = 0;
}
public char GetChar ()
{
return content[index++];
}
public bool HasChars ()
{
return index < content.Length;
}
}
</pre>
<p>As requested, we implemented a solution where the data is first read into the memory as a whole.</p>
<p>Now we are going to implement an output char stream to write our ROT13 data. We need to write it to console output <em>and</em> to file on disk. We could bundle both writes in a single class but that would not really follow the <a href="http://www.objectmentor.com/resources/articles/srp.pdf">Single Responsibility Principle</a>. So we will write 2 classes : one for writing to file on disk and the other one to write to console output.<br />
Actually we need a third one. Since our logic code writes into a single output stream, we will also create an output duplicator : a class that implements the OutputCharStream and that duplicates the output on multiple output streams.</p>
<p>We will start with this output duplicator. For that, we leave the world of I/O and go back to our unit tests.</p>
<pre>
public void DuplicateCharStream()
{
var outputStream1 = new Mock<OutputCharStream>();
var outputStream2 = new Mock<OutputCharStream>();
var multipleOutput = new MultiOutputCharStream( outputStream1.Object, outputStream2.Object );
multipleOutput.PutChar('A');
outputStream1.Verify(stream => stream.PutChar('A'));
outputStream2.Verify(stream => stream.PutChar('A'));
multipleOutput.PutChar('B');
outputStream1.Verify(stream => stream.PutChar('B'));
outputStream2.Verify(stream => stream.PutChar('B'));
}
</pre>
<p>We write the code to pass the test.</p>
<pre>
public class MultiOutputCharStream : OutputCharStream
{
OutputCharStream[] streams;
public MultiOutputCharStream(params OutputCharStream[] outputStreams)
{
streams = outputStreams;
}
public void PutChar(char c)
{
foreach(var stream in streams)
stream.PutChar(c);
}
}
</pre>
<p>Now we can go back to I/O and write a test for the stream output into a file on disk.</p>
<pre>
public void WriteFileToDisk()
{
var config = new TestConfiguration();
var fileName = "someOutput.txt";
var filePath = config.GetDataPath(fileName);
System.IO.File.Delete(filePath);
Assert.That( System.IO.File.Exists(filePath), Is.False );
var writer = new FileWriter( fileName, config );
writer.PutChar('X');
writer.PutChar('Y');
writer.PutChar('Z');
Assert.That( System.IO.File.Exists(filePath), Is.True );
Assert.That( System.IO.File.ReadAllText(filePath), Is.EqualTo("XYZ") );
}
</pre>
<p>And we write the corresponding code.</p>
<pre>
public class FileWriter : OutputCharStream
{
string filePath;
public FileWriter(string fileName, Configuration configuration)
{
filePath = configuration.GetDataPath(fileName);
}
public void PutChar(char c)
{
System.IO.File.AppendAllText(filePath, c.ToString());
}
}
</pre>
<p>We also need an output stream for the console but this one is hard to test automatically - as is every user interface test,<br />
So we will code it directly. Anyway, a manual test would be very simple to write if needed.</p>
<pre>
public class ConsoleWriter : OutputCharStream
{
public void PutChar(char c)
{
Console.Write(c);
}
}
</pre>
<p>Now we're done with the I/O. We almost have all our parts, we just need a real configuration context and then we can link all these little classes in our main program.<br />
We could use a dependency injection framework to do the job, but, since this program is quite simple we can just write all the code in our main routine :</p>
<pre>
class MainClass
{
public static void Main (string[] args)
{
var config = new CurrentFolderConfiguration();
var converter = new Rot13Converter();
converter.ExecuteOn(
new FileReader(args[0], config),
new MultiOutputCharStream(
new FileWriter(args[1], config),
new ConsoleWriter()
)
);
Console.WriteLine();
}
}
</pre>
<p>And then we're done with Part I of the challenge!</p>
<p>Now, what do we have to change for part II? The logic is there, the config mechanism too. The output part does not change. We just need to change our FileReader so that it does not load everything into memory and see if we have an impact on the other classes.<br />
We know that <a href="http://www.objectmentor.com/resources/articles/ocp.pdf">''Classes should be open for extension but closed for modification''</a> and our design came naturally with extension facilities. So we will not modify our File Reader : we will create a LazyFileReader that will do the same job but loading chars only when they are needed.</p>
<p>The test for this LazyFileReader is quite similar to the FileReader but it is better to have separate tests so that we can add any specific assertions if needed.</p>
<pre>
public void ReadLazilyFileFromDisk()
{
var reader = new LazyFileReader( "someInput.txt", new TestConfiguration() );
Assert.That( reader.HasChars(), Is.True );
Assert.That( reader.GetChar(), Is.EqualTo('A') );
Assert.That( reader.HasChars(), Is.True );
Assert.That( reader.GetChar(), Is.EqualTo('B') );
Assert.That( reader.HasChars(), Is.True );
Assert.That( reader.GetChar(), Is.EqualTo('C') );
Assert.That( reader.HasChars(), Is.False );
}
</pre>
<p>And then we have the code of the LazyFileReader</p>
<pre>
public class LazyFileReader : InputCharStream
{
System.IO.StreamReader readerImpl;
public LazyFileReader(string fileName, Configuration configuration)
{
readerImpl = System.IO.File.OpenText(configuration.GetDataPath(fileName));
}
public char GetChar()
{
return Convert.ToChar(readerImpl.Read());
}
public bool HasChars()
{
return !readerImpl.EndOfStream;
}
}
</pre>
<p>In order to make our program use the lazy reader, we just have to change the reader creation in our main program :</p>
<pre>
class MainClass
{
public static void Main (string[] args)
{
var config = new CurrentFolderConfiguration();
var converter = new Rot13Converter();
converter.ExecuteOn(
new LazyFileReader(args[0], config),
new MultiOutputCharStream(
new FileWriter(args[1], config),
new ConsoleWriter()
)
);
Console.WriteLine();
}
}
</pre>
<p>Note that if we had used a dependency injection framework, we could have done this change in the main program through a simple configuration file which means no code change at all : we would only have added a new class to the code base!</p>
<p>Now I think it's time to draw conclusions but I will first review the proposed solutions to see if I have correctly understood the challenge. I saw that James Shore published today <a href="http://jamesshore.com/Blog/Architecture-Review-Mock-Driven-Three-Layer-Architecture.html">a new blog entry</a> on this topic.<br />
Up to now, all I can say is that this challenge made me review the <a href="http://en.wikipedia.org/wiki/Solid_%28object-oriented_design%29">S.O.L.I.D. principles</a> -which is always good- but did not led me to think about big software architecture issues.</p>
<p>Note : the full source code and project files are attached to this blog entry.<br />
Note 2 : the source code is now also available on github : <a href="http://github.com/Oaz/JamesShoreArchitecturalDesignChallenge">http://github.com/Oaz/JamesShoreArchitecturalDesignChallenge</a></p>
<p><em>Addition June 6th : class diagram (click on it for bigger size)</em>
<a href="https://agilitateur.azeau.com/public/agilitateur/JamesShoreArchitecturalDesignChallenge.png"><img src="https://agilitateur.azeau.com/public/agilitateur/.JamesShoreArchitecturalDesignChallenge_m.jpg" alt="JamesShoreArchitecturalDesignChallenge.png" style="display:block; margin:0 auto;" title="JamesShoreArchitecturalDesignChallenge.png, juin 2010" /></a></p>How does design get done on an Agile Project ?urn:md5:7f7fe7e58207d20ec970b4b989f037802008-07-07T12:11:00+02:002008-07-07T12:11:00+02:00Olivier AzeauIn English<p>I watched a great presentation by <a href="http://codebetter.com/blogs/jeremy.miller/">Jeremy D. Miller</a> : <a href="http://codebetter.com/blogs/jeremy.miller/archive/2008/07/06/how-does-design-get-done-on-an-agile-project.aspx">How does design get done on an Agile Project ?</a>.</p>
<p>Jeremy shows through multiple examples the kind of design issues you inevitably face during an project and explains how to handle them in an agile way.</p> <p>I converted the slides of his presentation into a flash document in order to get a side by side view of slides and video on this web page (though you'll have to click on the slides to go to next one).</p>
<p>Enjoy !</p>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=5,0,0,0" height="330" width="440"><br /> <param name="movie" value="http://www.azeau.com/dotclear/public/agilitateur/HowDoesDesignGetDoneOnAnAgileProject.swf" />
<param name="quality" value="high" />
<param name="wmode" value="transparent" />
<param name="bgcolor" value="#FFFFFF" />
<embed src="http://www.azeau.com/dotclear/public/agilitateur/HowDoesDesignGetDoneOnAnAgileProject.swf" quality="high" bgcolor="#FFFFFF" height="330" width="440" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed>
</object>
<br/>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="437" height="266" id="viddler_f19847a5"><param name="movie" value="http://www.viddler.com/simple/f19847a5/" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /><embed src="http://www.viddler.com/simple/f19847a5/" width="437" height="266" type="application/x-shockwave-flash" allowScriptAccess="always" allowFullScreen="true" name="viddler_f19847a5" ></embed></object>
Pod pod pod podurn:md5:d463bb87fdad5c0544e058880b9351072007-08-09T23:55:00+02:002007-08-09T23:55:00+02:00Olivier AzeauIn English <p>Thanks to <a href="http://codebetter.com/blogs/jeremy.miller/archive/2007/08/06/fred-george-is-blogging.aspx">Jeremy D. Miller</a> I just discovered a place that is worth a web surf: <a href="http://processpeoplepods.blogspot.com/">Process, People, and Pods</a>. Fred George started to blog less than a month ago and, in a few articles, he described the very nature of agile software development.<br />
From <a href="http://processpeoplepods.blogspot.com/2007/07/secret-assumption-of-agile.html">agility inner secret</a> to <a href="http://processpeoplepods.blogspot.com/2007/07/masters-journeymen-and-apprentices-part.html">encounters</a> of the <a href="http://processpeoplepods.blogspot.com/2007/07/masters-journeymen-and-apprentices-part_19.html">third</a> <a href="http://processpeoplepods.blogspot.com/2007/07/masters-journeymen-and-apprentices-part_23.html">kind</a> (of developers) and path to <a href="http://processpeoplepods.blogspot.com/2007/07/building-better-programmer.html">development</a> <a href="http://processpeoplepods.blogspot.com/2007/07/building-better-programmer-part-2.html">wisdom</a>, we go through all what we would like to tell about our jobs if we knew the words for that.</p>
<p>Oh, and did I tell you about the pods? You should really <a href="http://processpeoplepods.blogspot.com/2007/08/pods-ideal-agile-team-structures.html">read</a> <a href="http://processpeoplepods.blogspot.com/2007/08/ideal-skill-ratios-in-pods.html">those</a> <a href="http://processpeoplepods.blogspot.com/2007/08/ideal-development-skills-for-pods.html">ones</a> too!</p>The Time Dilation of an Ideal Dayurn:md5:713afc8c799c2a57d2b2420307959f5c2006-11-17T01:02:00+01:002007-08-04T11:23:02+02:00Olivier AzeauIn EnglishIdeal Day, Story Points, Load Factor, Velocity... Lots of concepts for a simple goal : predicting the amount of work that will get done for a given date. Anybody who went through this kind of measurement system probably tried to grasp its validity. Dave Churchville wonders <a target="_blank" href="http://www.extremeplanner.com/blog/2006/11/agile-estimating-how-long-is-ideal-day.html">"How long is an ideal day ?"</a> in calendar time. Ed Gibbs <a target="_blank" href="http://edgibbs.com/2006/11/05/from-story-points-to-ideal-days/">rebounds</a> on the difficulty that people have with story points when time units come more naturally.<br />
<br />
I'm no exception. I used plain story points for a while but I recently started to trick this tool to get (I hope) a better matching between the developer estimates and the amount of work units.<br /> Estimating in story points relative sizes is not easy because you quickly loses the connection with calendar time. A developer will provide much more consistent estimates with time units : "I can do that in a couple of hours", "It will take two or three days". These estimates might not indeed be accurate. On one hand, developers are sometimes optimistic because they underestimate the time needed to write the full range of tests, because they forget that some documentation has to be updated, ... On the other hand, developers can be pessimistic : a difficult task can be seen as a huge amount of work, a tedious one might look like lasting forever, ...<br />
The estimates might not be accurate but they will probably be consistent. When someone asks you such a figure, you quickly imagine the size of the code you need to write and you transform this size into your own time unit system. As a consequence, the same task will be given the same figure in time units.<br />
<br />
Now, the question is : is there a linear transformation between the developer personal ideal day (DPID) and a "standardized" ideal day?<br />
I assume that this transformation is not linear. I have no evidence for this assumption but, in my current environment, I often get the feeling that short tasks tend to be underestimated and long tasks tend to be overestimated. I think I need some logarithmic transformation.<br />
<br />
Actually, I prefer to have a transformation from DPID to story points. The reason is simple. I think that story points are better for a planning game. When you mention a ratio between "ideal" days and calendar days, there is always someone to make it known that the developers are lazy if this ratio is less than 1. The story point is a much more neutral unit because it looks like the cost is inherent to the work unit.<br />
<br />
I proposed the following scale to the team and we started to test it:<br />
<div style="text-align: center;"><img alt="" src="http://www.azeau.com/dotclear/public/agilitateur/TimeDilation1.png" /></div><br />
<br />
Basically, the developer has to decide if the work unit:<table>
<tbody><tr><th width="33%"><br /></th><th width="33%">Developer Personal Ideal Hours</th><th>Points</th></tr><br />
<tr><td>will take one hour or so</td><td>1</td><td>1</td></tr><br />
<tr><td>is between one hour and one day (more or less half a day)</td><td>4</td><td>2</td></tr><br />
<tr><td>will take one day or so</td><td>8</td><td>3</td></tr><br />
<tr><td>is between one day and one week (more or less half a week)</td><td>20</td><td>5</td></tr><br />
<tr><td>will take one week or so</td><td>40</td><td>8</td></tr><br />
<tr><td>is really longer than a week (about two weeks)</td><td>80</td><td>13</td></tr><br />
</tbody></table><br />
<br />
I found out that the <a target="_blank" href="http://en.wikipedia.org/wiki/Fibonacci_number">Fibonacci numbers</a> (which are <a target="_blank" href="http://www.amazon.com/Agile-Estimating-Planning-Robert-Martin/dp/0131479415/ref=pd_lpo_k2_dp_k2a_2_img/104-8033738-0911932?ie=UTF8">sometimes used</a> for story points) were perfectly fitting this model. The idea is that we can try to adress the "relative sizes" dilemma by assuming that a 1 hour task + a half day task (in the developer own time system) will actually take as long as a one day task in the same system. Same thing for a 1 day task + a half week task matching a 1 week task.<br />
<br />
These figures lead to the following graph. A short period of time represents more points than a longer one.<br /><div style="text-align: center;"><img alt="" src="http://www.azeau.com/dotclear/public/agilitateur/TimeDilation2.png" /></div><br />
<br />
I don't know if this model will provide better results in terms of stability of the velocity but I hope it will help to remove the potential mismatchs between an iteration full of small tasks and another one containing a few big ones.<br />
Anyway, time (dilated or not) will tell...<br />Black-box project managementurn:md5:07b97accbf7ec44ecd64307d6f1d40682006-11-03T22:06:00+01:002007-08-04T12:55:09+02:00Olivier AzeauIn EnglishI love metaphors on project management. I just read a good one by Tom Looy : <a target="_blank" href="http://conversationswithandrew.blogspot.com/2006/05/how-long-is-piece-of-string.html">"How Long is a Piece of String?"</a>. You can get an estimate by looking at it but you will get a more accurate value by measuring it with a ruler. Estimating is not an easy job, especially when it comes to predicting when a piece of software is done. In the early stages of a software project, when you can barely estimate and certainly not measure anything, fixing scope, cost and dates is impossible.<br />
<br />
Years ago, I was appointed software project manager for the first time. Being a software developer, I intuitively knew that I should be careful with scope, cost and dates issues. I was reluctant to draw a full gannt chart too early in the project because I suspected that people would rely too heavily on it. The projects director I was reporting to told me : "This is not a way to run a project. You must list every task for the project, estimate them and put them in the chart then you will get a release date. From there you will start tracking the team progress". I complied with the order.<br />
Any experienced project manager obviously knows what happened : as the first tasks were not completed on time, the release date started to slip.<br />
The estimates were indeed very bad. Half of the developers had just graduated from university and relying on their estimates was the worst thing to do but the rookie project manager didn't know that.<br />
<br />
Now imagine this project is a big black box with 3 levers...<br /> The first one is labelled 'product'. It shows the number of features implemented by the project weighted by their associated quality level (which is either explicit or implicit).<br />
The second one is labelled 'cost'. It represents the global cost of the project from hardware to human resources including the productivity of each resource.<br />
The last one is labelled 'duration' and is the release date.<br />
As a project manager, you only have 2 hands so that you can grip 2 out of 3 levers and watch the 3rd one move freely...<br /><br />
<div style="text-align: center;"><img alt="Black box" src="http://www.azeau.com/dotclear/public/agilitateur/blackbox.png" /></div><br />
<br />
Listing every possible task for the project means that you set a list of feature and decide some quality for each of them : the left hand is on the 'product' lever.<br />
Estimating these tasks means that you evaluate a cost for each of them : the right hand is on the 'cost' lever.<br />
Now you can start watching the 3rd lever (the release date) moving upwards !<br />
<br />
Of course, time is money. If you don't want to see the 3rd lever being stuck centuries from today (which would mean a project that has no way of ending), you've got to move the cost lever upwards for paying the resources extra time.<br />
This is exactly what happened in my first project.<br />
At some point, people said that we could not afford releasing after a given date : we had to catch this damned 'duration' lever and hold it tight.<br />
We had to choose a hand to do the job. As somebody had promised a list of features to the customer, the left hand was not available. The right hand had to let the 'cost' lever go freely and grip the 'duration' lever.<br />
<br />
Guess what ? The 'cost' lever started to move upwards !<br />
People were pushed to stay later and come to work on week ends "to give some fresh air to the project", in the general manager own words.<br />
The productivity fell as developers got depressed. They were indeed paying the cost rise.<br />
The customer had to pay too. In this period, I was asked to find every possible woolliness in the customer requirement documents in order to get some extra cash. "Hey Mr Customer ! What you want now is not exactly what you wrote, You've got to pay for it !"<br />
<br />
No need to say that when the cost rose too much someone said "Stop !". The right hand being on the 'duration' lever, the left hand had to stop the 'cost' lever before it hits the ceiling...<br />
Cost and duration were now in control. As it was still impossible to tell the customer that features had to be dropped, the quality level dramatically fell as the free 'product' lever went downwards.<br />
<br />
Eventually, features were dropped and someone had to explain to the customer why this project was a <a target="_blank" href="http://en.wikipedia.org/wiki/Death_march_%28software_development%29">death march</a>.<br />
<br />
Most of the time, holding the 'cost' and 'duration' lever from the beginning is the most sensible solution because : <br />
<ul><br />
<li>If you hold onto 'product' and finish below expected schedule, your customer misses the opportunity to get some extra features</li>
<br />
<li>If you hold onto 'product' and finish beyond expected schedule, you're late and the customer is not happy</li>
</ul>
<br />
I once read that "project plans are either lucky or late" but, actually, project plans are either <em>lazy</em> or late : fixing a scope does not bring any guarantee that the product will be available on schedule and budget and in the same time, it makes no sense to stick to a scope when there's some room left.<br />
That being said, sometimes feature can be really mandatory (e.g. safety issues). In these cases, focusing on cost and duration is meaningless because being late is less important than being out of scope.<br />
<br />
In the end, the only thing we should care about is knowing, at any time, where our hands are, which levers are in control and which lever is currently moving freely so that we can have a look at it.<br />To Fix or Not to Fix : That is the Questionurn:md5:3d3858bd7f298abf6fe7468e429e48072006-06-12T20:41:35+02:002006-06-12T21:41:35+02:00Olivier AzeauIn EnglishDave Churchville talks about <a target='_blank' href='http://www.extremeplanner.com/blog/2006/06/software-misconceptions-revisited.html'>things you should care about when planning bug fixes</a>. I totally agree with his point. On one hand, it does not make sense to implement more and more features without fixing serious hazards first. This is sometimes called <a target='_blank' href='http://c2.com/cgi/wiki?CreepingFeaturitis'>creeping featuritis</a>. On the other hand, stopping any shipping till every bug is fixed can make more harm than good : a buggy software can provide more value to the user than no software at all.<br />
I must confess that I had not fully understood the arguments in his <a target='_blank' href='http://www.extremeplanner.com/blog/2006/06/biggest-misconception-in-software.html'>first post</a>. Indeed, one of the biggest <i>misconception in software development is that bugs don't need to be prioritized just like any other feature</i>. <br />
That being said, it is a wise decision to let the business, the customer or the product owner, decide if the development team should implement new features or fix a few more bugs. Now the problem is : does the business have enough information to make a good decision ?<br /> The person, or group of persons, making the decision must:<br />
<ol><br />
<li>be aware of the final user needs at a fine level of details</li><br />
<li>know the technical impacts of an issue whether it is fixed or not</li><br />
</ol><br />
<br />
Regarding #1, one could tell that it's the business people job to make decision regarding actual user needs. Things are not so simple.<br />
If we are talking about in-house software development and the final users are a group of people working at the next floor, they are probably involved in the decision process, or, at least, someone will ask them when a decision on a tricky issue is needed.<br />
If we are talking about a software shop and the final users are people working in other companies, things are getting touchy. In this case, the product owner probably has a customer's business background but she might not have the knowledge required by every position in this business. It is ok when prioritizing features at a coarse level but it can turn into dice rolling when dealing with detailed activity of a real user.<br />
<br />
Listing #2 as a pre-requisite for business people might look counter intuitive : why should we care about technical details when deciding on which bug or feature the development team should work on ? The answer lies in the nature of a bug.<br />
When a feature is not implemented, there are no side effects. One can find a workaround to fulfill the same needs but does not get unexpected behaviour.<br />
When a bug is not fixed, it is a different story. The bug might be hidden in a lower layer of the software. From there it can have impacts on many features of the application. These "other" bugs were not discovered (yet). It is just a matter of test coverage. Of course, we could just do "more tests" but then the economic argument (do not spend time on fixing bugs because time is money) is no longer valid. Things turn into an arbitration between spending time on tests/spending time on bug fixes/spending time on new features...<br />
<br />
I have no answer for these two items but I know for sure that letting the business people unilaterally making the fix/not fix decisions is as bad as letting the developers or the QA people making these decisions. At some point, all these people have to talk to each other to find an agreement regarding the prioritization of bug fixes.<br />Every Process is an Iterative Waterfallurn:md5:becd428c4d34994712f5f70114b50f322006-05-23T05:55:00+02:002021-10-09T16:11:31+02:00Olivier AzeauIn English<p>Dave Nicolette <a href="http://dnicolet1.tripod.com/agile/index.blog?entry_id=1480142" target="_blank">raises concerns</a> about organisations moving to agile development while appointing "traditionally-minded" managers. Risk #1 is that these managers turn the agile processes upside down by transforming them into a <a href="http://kanemar.wordpress.com/2005/11/03/the-staggered-iterative-waterfall-anti-pattern-part-1/" target="_blank">Staggered Iterative Waterfall</a> as described by Kane Mar.<br />
I deeply agree with the key statement of those articles : agility's main duty is improvement of interactions between individuals with the help of suitable processes. It is not about focusing on a well-polished process aimed at eliminating every possible waste in human activities. However, I do not subcribe to the <a href="http://www.davenicolette.net/articles/slouching_towards_waterfall.html" target="_blank">RUP-bashing movement</a> that seems to result from it.</p> <p>It does not take a long time to realize that performing sequentially across consecutive iteration the analysis, design/coding and testing activities is a waste of opportunities. In the Staggered Iterative Waterfall <a href="http://kanemar.wordpress.com/files/2005/12/Staggered-Iterative-Waterfall.jpg" target="_blank">pictured by Kane Mar</a>, feedback that could happen inside an iteration takes three of them to arise.<br />
Nevertheless, performing all the activities in the same iteration is not an easy job. For example, in an eXtreme Programming case :</p>
<ul><br />
<li>The iteration plan needs the user stories to be written and estimated before the iteration start (we have to know which stories fit into the iteration). As a consequence, the time spent by the customer to workout the story must be shortened to its minimum. Every minute spent writing a story without interacting with the developers is a loss of feedback.</li>
<br />
<li>The customer tests must be run after (and also before) the iteration deliverable is built but before the iteration is over. This implies that customer tests are heavily automated and written as soon as coding starts. Failing to do so means that developers will not be able to produce value while the deliverable candidate is tested.</li>
</ul>
<p><br />
It is not an easy job but great teams can certainly achieve it to a certain extent.<br />
<br />
The question is : can they <em>fully</em> achieve it ?<br />
Obviously not.<br />
<br />
In most projects, the best on-site customer (or group of on-site customers) cannot stay on the playground full time and simultaneously being fully aware the underlying customer activities. These on-site customers must be as close as possible to the development team but they have to stay in touch with their own businesses.<br />
The problem is that you cannot put the whole world into a single room.<br />
This is the reason why the stories describing the customer business need to be partly written off-site in an high level analysis activity. This is the reason why the the customer tests cannot be fully written while designing the system. The deliverable must be checked against some off-site <a href="http://c2.com/cgi/wiki?ExploratoryTesting" target="_blank">exploratory testing</a> activities involving other users.<br />
<br />
The combination of those two activities with the software system development enhances the ability of the customer to think about her business process in a <a href="http://en.wikipedia.org/wiki/Waterfall_%28M._C._Escher%29" target="_blank">true iterative waterfall</a>.<br />
Maybe we can call that "Iterative <a href="http://en.wikipedia.org/wiki/Business_process_modeling" target="_blank">Business Process Modeling</a>". I'm far from being a BPM expert (just started reading stuff on that subject) but, intuitively, it looks like a good name.<br />
The idea is that two processes, ran on each side, can reinforce each other. Feedback from the real user activity helps the developers to build the expected system while feedback from a delivered system helps real users to think about the way they work.<br />
<br />
When going through the iterations, this process can be pictured as following.<br />
The core system development activities are performed in each iteration with agile interactions between individuals at their peak.<br />
</p>
<figure style="margin: 0 auto; display: table;"><a class="media-link" href="https://agilitateur.azeau.com/public/agilitateur/IterativeWaterfall.png"><img alt="IterativeWaterfall.png, août 2007" class="media" src="https://agilitateur.azeau.com/public/agilitateur/IterativeWaterfall.png" /></a></figure>
<p><br />
<br />
Now let's have a look at the RUP-bashing thing.<br />
<a href="http://www.davenicolette.net/articles/slouching_towards_waterfall.html" target="_blank"><em>The four phases of a RUP iteration look like a miniature waterfall: Inception, Elaboration, Construction, and Transition. [...] The reason RUP is used for iterative waterfall processes and not for agile processes is simply that it is unnecessary in a true agile process; its four phases become unproductive administrative overhead.</em></a><br />
<br />
So the point is that RUP does not work for agile processes. I could just argue that <a href="http://c2.com/cgi/wiki?IfXpIsntWorkingYoureNotDoingXp" target="_blank">"If you cannot run a RUP framework in an agile mode then you're not running a RUP framework"</a> but I do not like this <a href="http://www.libervis.com/blogs/15/Jastiv/eric_raymond_and_the_rtfm_jerks" target="_blank">kind of extremism</a>.<br />
It looks like there's a big misundertanding regarding the RUP phases. Inception, Elaboration, Construction and Transition are not performed <em>inside a single iteration</em>. They are the <a href="http://www-128.ibm.com/developerworks/rational/library/content/RationalEdge/may04/4763_fig2.jpg" target="_blank">phases of a release</a> and each of these phases contains one iteration or more. Inside an iteration, you can do strict Waterfall, you can perform a <a href="http://fr.wikipedia.org/wiki/Cycle_en_V" target="_blank">V-shape</a> or you can blend all the activities in the agile way. You could overlap the iterations but this is considered as a <a href="http://consulting.dthomas.co.uk/ooad_articles_resources/More_RUP_anti-patterns.pdf" target="_blank">RUP Anti-pattern</a>. It is advisable to do frequent reviews and have multi-skilled teams. Both of them are agile practices.<br />
The RUP phases are the "macroscopic tempo". In a simplistic view of an agile instanciation of RUP, the inception phase is merely the first draft of user stories before development begins. The elaboration phase shows an important milestone : when it is over, the team considers that every "major" user story is implemented. The vision is established and the risk of a project failure is now lowered. The construction phase is about polishing the system until every customer need is implemented. The transition phase hands over the application to the users.<br />
<br />
RUP is not inherently less agile than methodologies known for their agility. It is just <a href="http://www.ddj.com/dept/architect/184415460" target="_blank">a matter of usage</a>. Its versatile nature support iterative waterfall processes including a bit of administrative tasks that inevitably happen in the real life with its <em>natural time and space boudaries</em>. Hence, one could even argue that RUP is more able to cope with human concerns than <a href="http://c2.com/cgi/wiki?PureXp" target="_blank">strict methodologies</a>.</p>