Les Mêlées

jeudi 10 janvier 2013

Reading xml from PowerShell is really easy !


It is amusing to see how simple we can read xml node values from powershell :

Here is a peace of xml file

<?xml version="1.0" standalone="yes"?>
<CoverageDSPriv>
  <Module>
    <ModuleName>myLib.dll</ModuleName>
    <ImageSize>122880</ImageSize>
    <ImageLinkTime>0</ImageLinkTime>
    <LinesCovered>791</LinesCovered>
    <LinesPartiallyCovered>23</LinesPartiallyCovered>
    <LinesNotCovered>856</LinesNotCovered>
    <BlocksCovered>1220</BlocksCovered>
    <BlocksNotCovered>1289</BlocksNotCovered>
    <NamespaceTable>
      <BlocksCovered>939</BlocksCovered>
      <BlocksNotCovered>1054</BlocksNotCovered>
    </NamespaceTable>
  </Module>
</CoverageDSPriv>

PowerShell converts XML elements to properties on .NET objects without the need to write any parsing code !!
 
$coverageFileXml = “C:\temp\myCoverageInfo.xml”
[xml]$xml = (get-content $coverageFileXml)
[int]$BlocksCovered = $xml.CoverageDSPriv.Module.BlocksCovered
[int]$BlocksNotCovered = $xml.CoverageDSPriv.Module.BlocksNotCovered
[int]$TotalBlocks = $BlocksCovered + $BlocksNotCovered
$CoveragePercent = $BlocksCovered * 100 / $TotalBlocks
$CoveragePercent2Decimals =  "{0:N2}" -f $CoveragePercent
Write-Host "Coverage is $CoveragePercent2Decimals %" 


è                         Output is   :   Coverage is 48.62 %



--> Share/Bookmark

lundi 16 janvier 2012

SpecFlow : StepArgumentTransformation

When writting BDD test features and feature steps, we often need to convert strings to types. Testing strings with a serie of if statement within steps does not maximise reusability and readability. The best would be to get the string recognise as a Type every time we use it in a feature without taking care of the conversion.

SpecFlow provides a StepArgumentTransformation attribute to achieve this :

https://github.com/techtalk/SpecFlow/wiki/Step-Argument-Conversions

Exemple :

 [Then(@"the value of the Shoulder mode is (.*) in the method file")]
public void ThenTheValueOfTheShoulderModeIsDropInTheMethodFile(string shoulderModeString)
{
ShoulderModeType shoulderMode = ShoulderModeType.OFF; ;
if (ShoulderModeType.Drop.ToString() == shoulderModeString) shoulderMode = ShoulderModeType.Drop;
else if (ShoulderModeType.OFF.ToString() == shoulderModeString) shoulderMode = ShoulderModeType.OFF;
else if (ShoulderModeType.Tangential.ToString() == shoulderModeString) shoulderMode = ShoulderModeType.Tangential;
else Assert.Fail("Invalid shoulderModeString: " + shoulderModeString);
...
Assert.AreEqual(expectedShouldMode, shoulderMode)
}


Can be refactored as 


[StepArgumentTransformation]
public ShoulderModeType ShoulderModeTransform(string shoulderModeString)
{
ShoulderModeType shoulderMode = ShoulderModeType.OFF;
if (ShoulderModeType.Drop.ToString() == shoulderModeString) shoulderMode = ShoulderModeType.Drop;
else if (ShoulderModeType.OFF.ToString() == shoulderModeString) shoulderMode = ShoulderModeType.OFF;
else if (ShoulderModeType.Tangential.ToString() == shoulderModeString) shoulderMode = ShoulderModeType.Tangential;
else Debug.Assert.Fail("Invalid shoulderModeString: " + shoulderModeString);
return shoulderMode;
}


[Then(@"the value of the Shoulder mode is (.*) in the method file")]
public void ThenTheValueOfTheShoulderModeIsDropInTheMethodFile(ShoulderModeType shoulderMode)
{
...
Assert.AreEqual(expectedShouldMode, shoulderMode)
}



 



 



 





Share/Bookmark

jeudi 20 octobre 2011

Converting Enum values to user frendly strings

    public enum ErrorLevel
    {
        None,
        Low,
        High,
    }
 
    public static class ErrorLevelExtensions
    {
        public static string ToLocalizedString(this ErrorLevel me)
        {
            switch (me)
            {
                case ErrorLevel.None:
                    return "Everything is OK";
                case ErrorLevel.Low:
                    return "SNAFU, if you know what I mean.";
                case ErrorLevel.High:
                    return "Reaching TARFU levels";
            }
            return "";
        }
    }
 
Then it is easy to use :
   1:  Console.WriteLine(ErrorLevel.Low.ToLocalizedStrings())


This uses Extensions Methods Share/Bookmark

jeudi 6 octobre 2011

Tool to remove useless references in .net projects

Including too much references in projects can lead to tricky dependency graphes.  Checking all references is just boring and long; it’s why we have searched for a way to remove useless references automatically. Resharper provide the Clean Code feature which remove useless using directrives but it does not remove the references.

Googling made me discover a free VisualStudio extension that does just but exaclty what we need (ie remove useless references and using directives) : Reference Assistant

image

It works perfectly well so I think it is a must have tool !

Share/Bookmark

mardi 22 février 2011

CHAPTER 4: Preparing for Sprint Planning

My notes out of the book “A Practical Guide to Distributed Scrum

Sprint planning =

  • Review of highest priority items with PO + decision on how much work could be done according to previous sprints and velocity
  • Task break down to decide how the work will get done
  • Commit to the sprint plan

Risk at the sprint planning is that PO cannot answer team’s questions without contacting stakeholders who are not available in the meeting. This is often the sign that the team is not ready to do the Sprint Planning meeting.

There is no official pre-planning meeting in SCRUM but the team needs to have ready for the sprint planning the following points

  • A prioritized Poduct BackLog
  • User stories the team can complete within a sprint
  • Clear acceptance conditions for each user story

Preplanning meeting can make the sprint planning meeting shorter

Preplanning

  • Discuss and clarify acceptance conditions for high-priority user stories.
  • Provide a relative estimate to help the PO identify their priorities
  • Break down high priority user stories so that they can fit within a sprint
  • Consider story dependencies owned by different teams

Clarification of user stories

The participants have to confirm that the stories have the same meaning to everyone and that they understand what the deliverables for a user stories are.

Hint: A good mean to make sure participants have the same understanding is to make them rephrase it with their own words.

  • The product owner answers questions or take note of them if he cannot answer to get ready for the Sprint Planning
  • The team can identify what needs to be investigated technically speaking to be able to commit at sprint planning
  • The participant confirm if the estimates seem accurate

Breaking down User Stories

Looking at the stories only at the sprint planning – particularly at the beginning of projects – may lead to long time of disaggregating user stories instead of planning for the sprint. The can lead to create user stories sprint after sprint and the team may never understand the quantity of work they need to do for the release.

KEY POINT: The large user stories must be breakdown the soonest possible in the release to make the team understand how much work they need to do. Teams should not create user stories for the release from sprint to sprint

Estimating user stories

When new stories are added to the backlog, the team can estimate them at pre planning meeting

Dealing with dependencies

3 types of dependencies

  • Simple dependency : A user story needs another user story done within the same team
    • Solution : reorder priorities to do first standalone user stories
  • External dependency : A user story needs another user story done from and other team
    • Negotiate integration and delivery dates and reorder priorities
    • The team should not commit the dependent user stories before integration of the other
  • Intertwined dependency: Two user stories need each other to get done.
    • Rework user stories breakdown to get simple dependencies

Cleanup of Product Backlog

The Product Backlog is not a Parking lot for every possible feature that could potentially be in the product.

The Product Backlog must be cleanup up so that it reflects what the team is likely to address. Stories with very low priority can be removed from the PB.

Approaches for the sprint preplanning meeting

  • 1 meeting at each sprint or 1 meeting every week or as needed
  • The regular meeting is best to get into a rhythm and limit interruptions
  • Time box the meetings to remain focused. 1 hour is good.
  • Sprint preparation can be 5 to 10% of team time

A ) The Full Team Approach

Regular meeting that involves the entire team.

PROS :

  • Provide a sense of team ownership
  • All team members can ask questions or voice concerns
  • The team can use meeting to size the stories
  • It allows the PO to get info from stakeholders before the Sprint Planning meeting

CONS :

  • It is harder to keep focus of the meeting with many distributed participants.
  • It may be difficult to schedule a time that works well for all Scrum Team members

B ) The Preplanning Team Approach

Weekly preplanning meeting with PO and the smallest subset of team representatives able to select and describe stories

PROS :

  • A smaller group of participant is more effective for teleconferences
  • It allows the PO to get info from stakeholders before the Sprint Planning meeting
  • It reduce the disruptions on the work of team members for the current Sprint

CONS :

  • There is a potential loss of communication or information by not having the full team present.
  • Neglecting to go back to the whole team for their contributions can result in a loss if team ownership.
  • This approach can easily slip from Scrum to a command and control center

C ) The Balanced Team Approach

Compromise between Full-Team and Preplanning Team approach.

Weekly meeting with a core group of participant and the entire team as optional participant. The entire team is present only for the last meeting before the sprint planning

PROS :

  • A smaller group of participant is more effective for teleconferences
  • It allows the PO to get info from stakeholders before the Sprint Planning meeting
  • It provides a sense of team ownership
  • All team members can ask questions or voice concerns
  • It allows the optional team members to manage the disruptions on their work for the current sprint

CONS :

  • There may be a loss of communication or information because the full team is not always present
Share/Bookmark

mardi 1 février 2011

CHAPTER 2: Challenges faced by distributed teams

My notes out of the book “A Practical Guide to Distributed Scrum

Communication

Generally speaking, communication is a lot about non verbal channel. Indeed, verbal channel is only 35% of communication. As a consequence distributed teams communicate with a real handicap.

Meeting at least once help to know each other’s personalities, mannerisms, communication style and culture.

Time zone and working hours

Every meeting is a challenge

Cultural differences

In some countries, it is inappropriate to say “I don’t understand” the speaker. This can result to a big waste of time and energy.

Humor can differ from country to country. Handle it with care.

Words can have different meaning.

Management style can also be different.

Language differences

A scrum team needs to communicate a lot so the language difference makes it harder. Keeping language simple will help those who are not speaking mother language.

Give everyone a chance to speak.

Use chat tools to share links

Confirm understanding

Address communication tools issue such bad phone or poor network connection.

Software Engineering practices

“Good software engineering practices are important for both collocated and distributed teams BUT for distributed teams poor engineering practices are much more obvious and are a greater problem”

- TDD helps delivering high quality tested code. It helps the team to evolve design over the time.

- Continuous integration helps teams to integrate their work frequently

- CI running automated tests detect regression problem quicker

Generally speaking, any tool helping to discover problems soon is a good tool because the later issues are discovered, the more expensive they are.

Delivering value at every 2-3 weeks sprint is a challenge and good engineering practices will considerably help distributed teams.

Schedule difference

Take into account holidays of the different zones to help commitment.

Team dynamics

“Making the daily scrum a priority is one example of how to keep the whole team engaged”

Telephone dynamics

Providing access to call -> toll free numbers (very important for home workers)

The Scrum Master takes the responsibility everyone hears and participates

Identify the speaker (Luc’s speaking : “bla bla bla”)

Handling visual cues encourage participation and limit side conversation

Check for agreement and disagreement.

Impact of Communication problems

Obvious problems: Team members not doing the right task, doing the task correctly or doing the task at the expected time.

More subtle problems: tasks outside team’s mission can pull away members to work on lower priority matters. This is more difficult to see on distributed teams.

Scrum helps mitigate this problem through the daily Scrum.

“KEY POINT: The more closely a distributed team can adopt Scrum as designed by its creators, the more likely a team will experience success. The design of Scrum promotes good communication. At the same time, with some minor adaptations for distributed teams, Scrum can help teams deliver the right product, at the right time, with the right quality”.

Forming-Storming-Norming-Performing model: http://en.wikipedia.org/wiki/Tuckman's_stages_of_group_development

- Distributed teams easily block at the storming stage. When the team changes, it can start over at forming stage. The performing stage is fragile and because of the limited personal contact, remote teams take longer to get through this stage.

How does Scrum help?

It does not help fixing problems! It just puts a spotlight on them so that the teams can identify and address them. All scrum artifacts are designed to help the team seeing progress and issues. Sprints, daily scrums, retrospectives, sprint planning are all important and mastering them can lead the team to performance. Scrum is like glasses, it makes more visible dysfunctions.

Share/Bookmark

lundi 31 janvier 2011

A Practical Guide to Distributed Scrum – IBM Press

By Elizabeth Woodward, Steffan Surdek, Matthew Ganis.

http://www.ibmpressbooks.com/bookstore/product.asp?isbn=0137041136

Untitled 

Here are my notes picked up when reading the book

CHAPTER 1 : The Evolution of Scrum

Collocation is no longer the norm: only 45% of collocated teams – from a recent survey –

Advantages of distributed teams

  • Use time shift for 24/24 h development effort
  • Reaching market more quickly with the “follow the sum model” :
  • Multinational companies produce more ideas than domestic counterparts

A lot of distributed teams are the result of acquisition.

Four level of distribution with more and more difficulties

Collocated

Collocated part-time

  • dailies with remote callers,
  • “out of sight, out of mind”,
  • biggest challenge is to invite remote people to planning and design sessions.

Distributed with overlapping hours

  • Not easy to plannify sprint planning and review
  • Scrum meetings lack of body language
  • Cultural / language difference

Distributed with no overlapping hours

  • Every meeting is a challenge

Three ways of handling distributed teams

Isolated Scrums model

  • No synchronization needed between teams
  • Each location has a cross functional team.
  • Usually the first two level of distribution

Distributed Scrum of scrum

Scrum of scrum daily (Ken Schwaber 2004)

    1. What did you team do yesterday?
    2. What will your team do today?
    3. What blockers have you met?
    4. + What blockers might you be throwing into another team’s way?
  • Longer meeting fewer time to give all members time to communicate
  • Several Product owners who make a single team : Need to speak with single voice

Totally Integrated teams

  • Each team has members in several location (Ex : All testers in a single location)
  • In such a context, Scrum can improve productivity by 5 to 10 compared to industry average

 

Comments are welcome ; Comming soon : Chapter 2 : Challenges faced by distributed teams

Share/Bookmark

vendredi 24 décembre 2010

How to implement a generic “waiting for” function with C#

In order to avoid repeating myself in the code of my team’s project where we need several times to wait for something to happen such as waiting for a file, I learned how to use the type “Func”.

Here is how was the code before the refactoring :

public static bool WaitForFile(string filePath, int timeOutMs)
{
    var fileFound = false;
    var timeElapsed = false;

    var startTime = DateTime.Now;
    DateTime currentTime;
    while (!fileFound && !timeElapsed)
    {
        currentTime = DateTime.Now;
        TimeSpan span = currentTime.Subtract(startTime);

        timeElapsed = span.TotalMilliseconds > timeOutMs;

        fileFound = System.IO.File.Exists(filePath);
        System.Threading.Thread.Sleep(1000);
    }
    return fileFound;

}

And here is the new generic implementation :

public static bool WaitForSynchrone(Func<bool> function, int timeOutMs)
{
    var actionReturnedTrue = false;
    var timeElapsed = false; var startTime = DateTime.Now;
    DateTime currentTime;
    while (!actionReturnedTrue && !timeElapsed)
    {
        currentTime = DateTime.Now;
        TimeSpan span = currentTime.Subtract(startTime);
        timeElapsed = span.TotalMilliseconds > timeOutMs;
        actionReturnedTrue = function();
        System.Threading.Thread.Sleep(1000);
    }
    return actionReturnedTrue;
}

public void WaitFile()
{
    WaitForSynchrone(() => File.Exists("C:\myfile.txt"), 10000);
}

So, now, we have a new function  WaitForSynchrone that take 2 arguments :

    - Func<bool> function : A function that returns a boolean

    - int timeOutMs : A timeout to prevent freezing !!

And we use it thanks to lambda expression for the first argument :

    - () => File.Exists("C:\myfile.txt")   : This is a function that takes no arguments and returns and boolean according to the left part of the expression

So now, we can use WaitForSynchrone for many other purpose instead of violating the DRY principle = ‘Do Not Repeat yourself ‘.


Share/Bookmark

jeudi 25 novembre 2010

Agile Grenoble 2010 – 10 Messages que j’ai retenu

ag2010_logoheader

“Nombre de WTF par minute = métrique représentant la qualité du code”

– Aslak Hellesoy - WTF = What the fuck

_

“Loi de Little : Moins on en fait à la fois, plus on va vite”

– Hervé Lourdin, Cyril Mégard

_

“Il faut garder du mou pour absorber la variabilité”

- Hervé Lourdin, Cyril Mégard

_

“L’Agilité est un long voyage. Elle évolue depuis la fin des années 90 et va continuer à évoluer”

– Claude Aubry – Laurent Bossavit

_

“Le TDD dans le Legacy Code, c’est possible et bénéfique”

– Bernard Huguet, Cyrille Roy, Johan Martinsson, Luc Jeanniard ;o)

_

“La programmation fonctionnelle permet de résoudre des problèmes de façon élégante et efficace”

– Emmanuel Gaillot

_

“Bonjour Mr Orsier, je vous apporte le cahier des charges (un énorme classeur) – c’est presqu’ … le définitif”

– Rémy Sanlaville, Bruno Orsier

_

“Il faut commencer le dev le plus tôt possible pour obtenir du feedback rapidement”

– Alexandre Boutin

_

“Portfolio agile : synchroniser les releases pour être réactif au changement”

- Jean Dupuis, Jean-François Jagodzinski

_

“'jcQualitystreet #agilegrenoble: On est loin mais on attend des tweets et du feedback! @NicoRuffel @claudeaubry @agilex @LucJeanniard @jfjago @calton13”

– Jean Claude GROSJEAN via Twitter !

_

Il y a très certainement d’autres messages importants mais c’est la loi de ce genre d’événement, il faut faire des choix, on ne peut pas tout voir, tout entendre, tout retenir … Rendez-vous en 2011 !

Le programme complet est sur http://agile-grenoble.org/

.

Share/Bookmark

jeudi 30 septembre 2010

Tester unitairement du “Legacy Code” : un exemple

(Note au utilisateur de GoogleReader : Pour une raison inconnue, les couleurs ne sortent pas … lisez plutôt ici)

 

Je souhaite vous montrer dans ce billet un exemple d’ajout de test unitaire dans du legacy code. Du legacy code, c’est du code non testé automatiquement. Je travaille tous les jours sur du code non couvert par des tests automatiques alors capitaliser en ajoutant petit à petit des tests est un réel enjeu pour éviter les régressions.

 

Le Problème

 

Voici une classe développée il y a presque 10 ans pour dessiner des annotations sur un graphique. Il se trouve que dans certaines  rares conditions, l’annotation sort du graphique et ceci ne fait pas propre lors de son impression. Nous avons donc souhaité corriger ce défaut.

__________________________________________________________________

TSKRAnnotDrawer = class

 private

   FAnnotList: TList;

   FSquaring: TSquaringType;

   FHorizontalMaille: Real;

   FVerticalMaille: Real;

 

   procedure Sort;

   function GetAnnot(Index: Integer): PAnnotRec;

   procedure FindCorrespondingSquaringRectangle(aRect: TRect;

X, Y: Integer;

var SquaringRow, SquaringCol: Integer);

   procedure CalculateSquaringRectanglesNumber(aRect: TRect;

W, H: Integer; var SquaringWidth, SquaringHeight: Integer);

   function FindFreeSpace(SquaringRow, SquaringCol,

SquaringWidth, SquaringHeight: Integer;

var SquaringFreeRow, SquaringFreeCol: Integer;

var UpOrDown:         Boolean): Boolean;

   function TestIfItIsInTheGraphic(row, col,

SquaringWidth, SquaringHeight: Integer): Boolean;

   function TestIfTheSpaceIsFree(row, col,

SquaringWidth, SquaringHeight: Integer): Boolean;

   procedure UpdateFSquaring(row, col, SquaringWidth, SquaringHeight: Integer);

 public

   PeakAnnotation: TSKRPeakAnnotationPrefs;

   EventAnnotation: TSKREventAnnotationPrefs;

   procedure Create;

   procedure Destroy; override;

   procedure ClearList;

   procedure AddToList(aAnnot: TAnnotRec);

   procedure Draw(Canvas: TCanvas3D; arect: TRect);

 end;

__________________________________________________________________

 

Nous allons nous intéresser à la méthode “Draw”. Après investigation, l’erreur provient du calcul de la hauteur de la première annotation. En effet, la ‘font size’ est assignée après le calcul de la hauteur du texte : voir ci-dessous le texte en rouge.

__________________________________________________________________

procedure TSKRAnnotDrawer.Draw(Canvas: TCanvas3D; aRect: TRect);

var

i, Width, Height: Integer;

UpOrDown: Boolean;

w, h: Integer;

AnnotationPrefs: TSKRAnnotation;

row, col: Integer;

SquaringRow, SquaringCol: Integer;

SquaringWidth, SquaringHeight: Integer;

SquaringFreeRow, SquaringFreeCol, XFree, YFree, YFreeTemp: Integer;

begin

assert(EventAnnotation <> nil);

assert(PeakAnnotation <> nil);

 

// sort annotation according time

Sort;

Width := 0;

Height := -1;

 

 //initializing the squaring array.

 for row := 0 to Pred(SquaringSize) do // Iterate

 begin

   for col := 0 to Pred(SquaringSize) do // Iterate

   begin

     FSquaring[row, col] := True;

   end; // for

 end; // for

 

 for i := 0 to Pred(FAnnotList.Count) do

   with GetAnnot(i)^ do

   begin

  

     if Typ = 0 then

       AnnotationPrefs := EventAnnotation

     else

       AnnotationPrefs := PeakAnnotation;

 

     UpOrDown := AnnotationPrefs.AutoUpDown = apUp;

 

     if AnnotationPrefs.Orientation = aoOblique then

     begin

      //We take the size of the rectangle projection on a vertical axis

       H := round(Sin(Pi / 4) * (Canvas.TextWidth(Text) + Canvas.TextHeight(Text)));

      //and for W the size of the rectangle projection on the horizontal axis

       W := round(Cos(Pi / 4) * (Canvas.TextWidth(Text) + Canvas.TextHeight(Text)));

     end

     else if AnnotationPrefs.Orientation = aoVertical then

     begin

       H := Canvas.TextWidth(Text);

       W := Canvas.TextHeight(Text);

     end

     else //Horizontal

     begin

       H := Canvas.TextHeight(Text);

       W := Canvas.TextWidth(Text);

     end;

 

     H := H + 4;

 

    if AnnotationPrefs.AutoUpDown = apAuto then

     begin

       Canvas.Font.Name := AnnotationPrefs.Font.name;

       Canvas.Font.Size := AnnotationPrefs.Font.Size; //INTERVIENT TROP TARD

     end;

 

     if AnnotationPrefs.LinkType = ltNone then

     begin

                ... 6 lines

     end

     else

     begin

                ... 30 lines

     end;

 

     DrawAnnotation(Canvas, Text, Point(XFree, YFree),

       XFree, AnnotationPrefs, UpOrDown, Width, Height, X, Y, aRect);

   end;

end;

__________________________________________________________________

 

La correction est triviale, il suffit de remonter l’affectation de la font size avant la première utilisation du Canvas.

 

Mais comment tester ce que l’on souhaite modifier?

 

Le cheminement vers le test unitaire

 

Ma première idée fut d’instancier la classe et appeler la méthode Draw dans un test unitaire. En effet, le constructeur ne prend pas de paramètre alors ça paraissait facile. Ensuite, il a fallu ajouter des assertions à mon test et là les ennuis commençaient. En effet, je n’avais aucune envie de vérifier le rendu sur le graphique (via le Canvas) car je ne savais pas comment m’y prendre.

 

Donc je suis reparti de zéro afin d’isoler mon problème. J’ai suivi les étapes suivantes :

 

1- Extraction de la partie de code problèmatique

 

Je ne prend pas de risque à ce niveau là et je fais confiance au compilateur pour m’indiquer les éventuels problèmes.

 

__________________________________________________________________

 

procedure TSKRAnnotDrawer.getTextHeightAndWidth(

     const aCanvas: TCanvas3D;

     const aAnnotationPrefs: TSKRAnnotation;

     const aText: string;

     var oTextHeight, oTextWidth: integer);

begin

   if AnnotationPrefs.Orientation = aoOblique then

   begin

    //We take the size of the rectangle projection on a vertical axis

     H := round(Sin(Pi / 4) * (Canvas.TextWidth(Text) + Canvas.TextHeight(Text)));

    //and for W the size of the rectangle projection on the horizontal axis

     W := round(Cos(Pi / 4) * (Canvas.TextWidth(Text) + Canvas.TextHeight(Text)));

   end

   else if AnnotationPrefs.Orientation = aoVertical then

   begin

     H := Canvas.TextWidth(Text);

     W := Canvas.TextHeight(Text);

   end

   else //Horizontal

   begin

     H := Canvas.TextHeight(Text);

     W := Canvas.TextWidth(Text);

   end;

    H := H + 4;

   if AnnotationPrefs.AutoUpDown = apAuto then

   begin

     Canvas.Font.Name := AnnotationPrefs.Font.name;

     Canvas.Font.Size := AnnotationPrefs.Font.Size; //INTERVIENT TROP TARD

   end;

end;

 

__________________________________________________________________

 

Là, ça devient plus simple de tester cette fonction mais celle-ci n’est pas publique et changer l’API, c’est à dire le contrat de la classe, à des fins de tests n’est pas élegant. En effet, cette méthode n’a pas d’intéret pour l’utilisateur de la classe.

 

 

2- Extraction de la méthode vers une classe spécifique

 

En ayant en tête les principes SOLID et plus particulièrement celui qui dit qu’une classe ne doit avoir qu’une responsabilité, je n’ai pas d’état d’âme à créer une classe pour isoler ma méthode:

 

__________________________________________________________________

 

TTextPixelSizeHelper = class

public

 class procedure GetTextHeightAndWidth(

   const aCanvas: TCanvas3D;

   const aAnnotationPrefs: TSKRAnnotation;

   const aText: string;

   var oTextHeight, oTextWidth: integer);

end;

 

class procedure TTextPixelSizeHelper .getTextHeightAndWidth(

     const aCanvas: TCanvas3D;

     const aAnnotationPrefs: TSKRAnnotation;

     const aText: string;

     var oTextHeight, oTextWidth: integer);

begin

  ... idem ...

end;

__________________________________________________________________

 

 

Je ne prend toujours pas de risque et je fais confiance au compilateur pour les éventuelles erreurs de refactoring. Je n’ai changé aucun comportement.

 

La méthode Draw peu maintenant utiliser cette nouvelle classe :

 

__________________________________________________________________

procedure TSKRAnnotDrawer.Draw(Canvas: TCanvas3D; aRect: TRect);

var

...

begin

...

 for i := 0 to Pred(FAnnotList.Count) do

   with GetAnnot(i)^ do

   begin

     if Typ = 0 then

       AnnotationPrefs := EventAnnotation

     else

       AnnotationPrefs := PeakAnnotation;

 

     UpOrDown := AnnotationPrefs.AutoUpDown = apUp;

 

     TTextPixelSizeHelper.GetTextHeightAndWidth(Canvas, AnnotationPrefs, Text, H, W);

        ...

 

     DrawAnnotation(Canvas, Text, Point(XFree, YFree),

       XFree, AnnotationPrefs, UpOrDown, Width, Height, X, Y, aRect);

   end;

end;

__________________________________________________________________

 

Au passage, nous avons diminué la complexité cyclomatique de la fonction et facilité sa compréhension.

 

 

3- Ecriture d’un test qui échoue

 

Le principe du test est d’appeler deux fois de suite la fonction ‘GetTextHeightAndWidth’  avec le même texte et de vérifier qu’elle donne deux fois le même résultat.

__________________________________________________________________

  

procedure TSKRAnnotDrawerTest.testPeakNamesMightBePrintedBeOutisdeOfTheChartArea;

const

  TEXT1_TO_DRAW = 'TestPeakAnnot';

  TEXT2_TO_DRAW = TEXT1_TO_DRAW;

  PEAK_ANNOTATION_TYPE = 1;

var

  chart: TOrlandoChart;

  form: TForm;

  canvas: TCanvas3D;

  peak_annotation_prefs: TSKRPeakAnnotationPrefs;

  text1_height_result, text2_height_result: integer;

  text1_width_result, text2_width_result: integer;

begin

  peak_annotation_prefs := TSKRPeakAnnotationPrefs.Create;

 

form := TForm.Create(nil);

chart := TOrlandoChart.Create(form);

chart.ParentWindow := form.Handle;

canvas := chart.Canvas;

 

 try

   canvas.Font.Size := 4;

   assert(canvas.Font.Size <> peak_annotation_prefs.Font.size, 'Font size must be different to show the defect problem');

 

   TTextPixelSizeHelper.GetTextHeightAndWidth(

canvas, peak_annotation_prefs, TEXT1_TO_DRAW,

text1_height_result, text1_width_result);

   TTextPixelSizeHelper.GetTextHeightAndWidth(

canvas, peak_annotation_prefs, TEXT2_TO_DRAW,

text2_height_result, text2_width_result);

 

   CheckEquals(text1_height_result, text2_height_result,

'calling twice the function with same text should provide the same Height  result!');

   CheckEquals(text1_width_result, text2_width_result,

'calling twice the function with same text should provide the same Width result!');

 finally

   peak_annotation_prefs.Free;

   chart.Free;

   form.free;

 end;

end;

_________________________________________________________________

  

red

 

 

 

4- Correction du bug

 

La correction conciste à déplacer quelques lignes de code afin d’assigner la “font size” du canvas avant de s’en servir:

 

_________________________________________________________________

  

procedure TTextPixelSizeHelper.getTextHeightAndWidth(

     const aCanvas: TCanvas3D;

     const aAnnotationPrefs: TSKRAnnotation;

     const aText: string;

     var oTextHeight, oTextWidth: integer);

begin

   if AnnotationPrefs.AutoUpDown = apAuto then

   begin

     Canvas.Font.Name := AnnotationPrefs.Font.name;

     Canvas.Font.Size := AnnotationPrefs.Font.Size;

   end;

   if AnnotationPrefs.Orientation = aoOblique then

   begin

    //We take the size of the rectangle projection on a vertical axis

     H := round(Sin(Pi / 4) * (Canvas.TextWidth(Text) + Canvas.TextHeight(Text)));

    //and for W the size of the rectangle projection on the horizontal axis

     W := round(Cos(Pi / 4) * (Canvas.TextWidth(Text) + Canvas.TextHeight(Text)));

   end

   else if AnnotationPrefs.Orientation = aoVertical then

   begin

     H := Canvas.TextWidth(Text);

     W := Canvas.TextHeight(Text);

   end

   else //Horizontal

   begin

     H := Canvas.TextHeight(Text);

     W := Canvas.TextWidth(Text);

   end;

    H := H + 4;

end;

_________________________________________________________________

  

green 

 

 

La barre est verte! Donc place au refactoring si nécéssaire.

 

 

Conclusion

 

Tester du legacy code peut décourager bon nombre de développeurs. Ce n’ai pas très compliqué mais ça demande une petite gymnastique intellectuelle. Tout m’a semblé plus facile après quelques essais et la lecture du bien connu livre de Michael C. Feathers “Working Effectively with Legacy Code” . Ce n’ai pas toujours possible à un coût raisonnable alors dans notre équipe, nous ne nous demandons pas une obligation de résultat.

 

Avec quelques amis développeurs Grenoblois, nous allons présenter une session dédiée à ce sujet sur du vrai code lors de la conférence Agile Grenoble 2010; venez nous voir ;o) !

 

 

 

 

Share/Bookmark

jeudi 2 septembre 2010

Les vacances sont finies !

Je vous ai proposé il y a quelques semaines un sondage pour connaitre vos motivations à me suivre sur ce blog. Vous êtes près de 70 abonnés aux flux RSS et je n’ai eu que 13 réponses à ce jour. Je ne vous cache pas ma déception!

 

Voici mes motivations à écrire :

  • Partager mes connaissances
  • Obtenir du feedback sur ma façon de voir les choses
  • Consigner ce que j’apprends
  • M’entrainer à écrire, art qui se perd sans pratiquer
  • Me faire connaitre un peu

Vous pouvez m’aider de deux façons :

  • En répondant au sondage qui ne comporte qu’une question à choix multiple ICI : 30 secondes montre en main.
  • En me donnant du feedback car les commentaires des billets sont souvent aussi intéressant que les billets eux-mêmes.
Share/Bookmark

jeudi 29 juillet 2010

Sondage

Share/Bookmark

mercredi 30 juin 2010

CARA – Grenoble : Rétrospective des Dojos 2009-2010

Lundi 28 Juin 2010 se tenait la dernière séance des Dojos du CARA pour cette année. Nous l’avons consacré à une rétrospective afin de nous améliorer pour l’année prochaine. J’ai eu le plaisir d’être facilitateur et voici le compte-rendu :

Nous étions 6 participants présents et plusieurs amis Agilistes nous ont envoyé leurs entrées.

Picture 007

Voici le plan :

Picture 003

En guise de check-in pour se mettre dans l’ambiance : Mr Face pour décrire son état d’esprit !

 Picture 003

Puis nous avons fais une BrainStorming afin de rassembler

  • les points qui ont bien marché et que nous voulons conserver (+)
  • les points qui ont moins bien marché et que nous voudrions améliorer (-)

Nous avons ensuite regroupé en thèmes tous les points afin d’en choisir deux à améliorer :

Picture 005

Picture 006

Picture 002

  Donc en point positifs, nous pouvons noter :

  • la qualité des échanges avec une confiance de haut niveau.
  • la variété des sujets abordés
  • la qualité des dojos lorsqu’ils sont préparés
  • la localisation de la salle
  • la permutation des animateurs
  • la mise en pratique des principes de programmation /TDD
  • le travail sur du code de production
  • … (jetez un oeil sur les post-its)

Nous avons voté et les deux sujets choisis pour amélioration sont :

    • La gestion du temps
    • Travailler sur du code réel

Voici les fruits de nos réflexions sur ces deux thèmes :

Picture 008

Bon, ça nécessite des petites explications :

  • Pour gagner un peu de temps lors des séances, nous avons estimé que les rétrospectives de 30 minutes / 2 heures n’étaient pas une bonne utilisation de notre temps. C’est pourquoi nous allons les réduire à 10 minutes en commençant par le ROTI. Nous pourrons expliquer notre choix et en particulier les notes extrêmes. Les Post-its ne seront plus un passage obligatoire! Nous déciderons également lors de ces 10 min si le sujet doit être poursuivi ou non.
  • Nous n’avons pas été très fort sur le démarrage des Dojos à 12h. Nous avons régulièrement commencé 15 ou 20 minutes en retard. Plusieurs causes sont à l’origine de cette dérive dont le fait qu’il ne soit pas évident de quitter son lieu de travail avant 12h et que nous avons eu plusieurs soucis d’utilisation du projecteur. Nous avons donc décidé de commencer à l’heure prévue quoi qu’il arrive; cette heure de début fera l’objet d’un sondage (12h, 12h10, 12h15, 12h20 ?). Nous rédigerons également un document de trouble shooting du projecteur. (Je vois deux actions sans propriétaire! … qui s’en occupe?)

  • Le fait de travailler sur du code réel / legacy code plutôt que sur des sujets très simples fait l’unanimité. Nous aimerions donc travailler sur une même base de code pendant plusieurs séances avec comme fil conducteur le fait de s’améliorer sur la prise en main de legacy code (code non testé).

Nous aurions bien poursuivi sur d’autres thèmes mais la time-box était terminée. Nous avons identifier le besoin de discuter sur le “recrutement” de nouveaux participants. Nous pouvons le faire via le groupe de discution : http://groups.google.fr/group/cara-dojo . (entrée perso : les séances planifiées sur jours tournants ne satisfont au final pas grand monde; il serait bien qu’on en discute également.)

Nous avons conclu par un ROTI pour noter la qualité du temps investi pour l’année des Dojos et pour cette rétrospective: 0 – J’aurais mieux fais de rester chez moi –> 5 – J’ai très bien investi mon temps

Picture 009

Merci à tous pour votre participation aux dojos!

Luc

Share/Bookmark

lundi 7 juin 2010

Test Scrum sur Scrum.org

Scrum.org propose un nouveau cadre de formation et certification. La certification Scrum est validée par un test de 50 questions sélectionnées au hasard dans une liste. Il faut obtenir 75%  de bonnes réponses pour obtenir la certification!

 

J’ai fais le test, certaines questions ne sont pas évidentes. Voici mon résultat :

_____________________________

41 bonnes réponses sur 50, soit 82%

33 minutes

_____________________________

Faites le test !  http://www.scrum.org/scrumopen/

Share/Bookmark

mercredi 31 mars 2010

Une rétrospective pas comme les autres

Introduction

Lundi 30 mars 2010 se tenait l'étape Suisse des XP Days 2010. La session que j'ai le plus aimé fut

"Apprenez les techniques de coaching avec le magicien d'Oz" de Portia Tung et Pascal Van Cauvenberghe

Cette session avait pour but de nous faire découvrir le Co-Coaching au travers d'un Jeu. En deux mots, le co-coaching permet à deux personnes de s'améliorer mutuellement en travaillant chacune leur tour sur un problème. Le jeu, quant à lui permet d'acquérir des techniques simple de coaching autour du questionnement, de l'observation de l'écoute et du feedback. 
En pratique, il faut trois joueurs:

  • Dorothy (le coaché)
  • Le coach
  • L'Observateur

Les trois joueurs réfléchissent à un problème qui leur tient à cœur personnellement

Puis trois cycles vont se succéder afin que chaque joueur puisse s'entraîner dans chaque rôle.

Le coach va tout d'abord questionner Dorothy avec des questions ouvertes (pas de réponse par oui ou par non), des questions de contrôle pour caractériser le problème puis avec des questions de vérification pour être certain que le coach et le coaché se comprennent bien. Puis, le coach va demander à Dorothy de se mettre dans la peau d'un personnage et de décrire ce qu'il ferait. Ceci permet de changer d'état d'esprit sur son problème et d'imaginer des solutions non intuitives.

Par exemple : Arthur, si tu es Lion, c'est à dire courageux et courtois, que ferais-tu pour solutionner ton problème

Arthur, si tu es Singe Volant, c'est à dire pratique et prêt à aider, que ferais-tu?

De cette façon, Arthur, le coaché va trouver des solutions à ses problème.

Enfin, l'observateur commente ce qu'il a vu et entendu pour que tout le monde puisse progresser!

Seule Portia Tung peut expliquer le jeu dans les règles de l'art alors je vous invite à assister à l'une de ses présentations avec Pascal Van Cauvenberghe!

Le jeu peut être téléchargé sur Agile Fairy Tales : http://www.agilefairytales.com/dist/The-Yellow-Brick-Road-2-0.zip

Jai profité de ce que j'ai appris lors de cette session pour voir comment je pouvais l'appliquer en interne dans mon entreprise et je me suis dis pourquoi pas la rétrospective de sprint! Ca tombait bien, il y avait 3 participants. D'où la rétrospective pas comme les autres ...

Le plan

10h30  - 10h45 :  Introduction / Check-in

  • Présentation du plan
  • Si vous aviez été un animal, qu'auriez vous été?

        Voici les réponses des 3 participants ! Nous avons bien rigolé !
    • Un hibou car je n'ai pas beaucoup été présent (Vacance, support chez un client, 5 jours avec l'équipe en 2 fois)
    • Un singe car j'ai changer plusieurs fois d'activité (Développement de User Story, Support, Enquête sur problème de build)
    • Un âne car nous avons échoué plusieurs User Stories alors que nous avions largement le temps de finir.

10h30  - 11h40 :  Le jeu de "La Route de Brique Jaune" expliqué brièvement ci-dessus

        Nous avons pris 10 minutes pour expliquer le jeu et pour que chaque participant identifie le problème sur lequel il voulait travailler

        Voici les problèmes choisis

    • Je crains que nous ayons d'autres problèmes tels que celui que j'ai du investiguer ce sprint
    • On a cru que toutes les User Stories étaient finies mais à la fin du sprint il y avait plusieurs grains de sables qui ont fait que seule la moitié des User Stories ont pu être montré.
    • Des tests automatisés se sont mis à échouer sans que l'on comprenne pourquoi

        Nous avons effectué 3 tours de jeu de 10 minutes et chacun a pris son rôle très au sérieux. De vraies idées d'actions ont été trouvées par les coachés!

11h40  - 11h55 :  Débriefing et choix des actions

        Nous avons ensemble fait le tour des actions potentielles et finalement l’équipe les a toutes adopté!

11h55  - 12h00 :  ROTI / Conclusion

        En fin de rétrospective, il est bien d'obtenir un feedback sur la qualité du temps investi. Tous les participants ont voté pour la note maximale (0-J'aurais mieux fais de rester chez moi --> 5-J'ai vraiment bien fait de venir)

    • 5 +
    • 5 ++    Nous avons identifié des solutions à nos problèmes qui ne seraient pas sorties dans une rétrospective plus classique.
    • 5+

Conclusion

Merci à Portia Tung et Pascal Van Cauvenberghe de m'avoir fait découvrir le Co-Coaching à travers le jeu de "la route de la brique jaune"

Merci à l'Equipe d'avoir joué le jeu !
Le co-coaching est très facile à mettre en place et un outil très efficace pour progresser.

Share/Bookmark