Case Study CS00014: Reporting code bug lines by responsible person

The problem: You have several people working on chunks of code. Early in the process, testers find bugs (lines that fail). They record these line numbers. The owners of the code need to be notified. This example shows how, if you comment the responsible people into the code, the bug assignment list can be created directly.

The solution:

  1. Locate sections of code by person responsible
  2. Create a vector of line numbers by responsible person
  3. Given a vector of line numbers with bugs, list line ranges by responsible person.

Ron Jeffries has been championing a system development methodology called Extreme Programming, originally described by Kent Beck. Ron illustrates a technique for assigning lines with bugs to be fixed. Here I illustrate a Glee flavored technique.

Note: You can cut and paste these code fragments into the code pane of the Glee interpreter and experiment as you go along to see the actual operations live.

Normally you would read the code directly from file. But for this illustration I capture it literally; break the text by line (removing line breaks) into a sequence; and save it in the variable named code.

$$ The Glee code to capture the illustration:.
$R__$r//==============================================================================
class Owners{ // <<<Owned by Jeff Davis>>>
  private ArrayList owners;
  public Owners(String s) {owners = new ArrayList();AddOwners(s.Split());}
  private void AddOrMerge(Owner owner) {if ( !Merge(owner) ) owners.Add(owner);}
  private void AddOwners(String[] names) {
    for ( int i = 0; i < names.Length; i++) {ProcessName(names[i], i);}}
  private Owner CurrentOwner {get { return this[Count-1]; }}
  private bool Merge(Owner owner) {
    if (Count == 0 ) return false;
    if (CurrentOwner.Name != owner.Name) return false;
    CurrentOwner.AddLineNumber(owner.StartLine);return true;}
  private void ProcessName(String name, int i) {
if ( name == "" ) return;AddOrMerge(new Owner(name, i));}
  public Owner this[int index] {get { return (Owner) owners[index]; }}
//==============================================================================
class Owner { // <<< Owned by Bob Lee >>>
  private String name; private int startLine; private int endLine;
  public Owner(String n, int i) {name = n; startLine = i; endLine = i;}
  public String Name {get { return name; }}
  public int StartLine {get { return startLine; }}
  public int EndLine {get { return endLine; }set { endLine = value; }}
  public void AddLineNumber(int lineNumber ) {EndLine = lineNumber;}}
//==============================================================================
class Owner { // <<< Owned by Abe Lincoln >>>
  public String Name;public int StartLine;public int EndLine;
  public Owner(String n, int i) {Name = n;StartLine = i;EndLine = i;}
  public void AddLineNumber(int lineNumber ) {EndLine = lineNumber;}}
__ \~ =>code;

$$ The Glee Ranges code:
'Ranges'#pgm{n& =>n\(n-- *~=1``)@&(=>r;:?(r# =1){r}::{(r<-)(r->)}),,(('-')('; '))%*};

$$ The Glee code:

'bugLines:'$;(9..13)(6 7)(26..28)< =>bugLines$;

'iOwners:'$;code *^& 'Owned by' `` =>iOwners$;
'rOwners: '$;code # ` \iOwners<-_1 =>rOwners %**$;
'Resp:'$;code[iOwners],|rOwners =>resp %**$;

13 #asc =>nl; '='%%50=>b;

'Bugs by responsibility:'$;b$;
:@&(resp[.r]){
    r[2]< & bugLines =>rl;
     :?(rl){
        (r[1]< =>t;
        t<-(t @== `&'<<<'-1-))
        (rl[.n]Ranges)}}~(#nil)
         ,,((nl)(nl b nl))$;

The Output:
bugLines:
9 10 11 12 13 6 7 26 27 28
iOwners:
2 17 25
rOwners:
Seq[R1C3:K]
[1]Num[R2C15:I]2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
[2]Num[R2C8:I]17 18 19 20 21 22 23 24
[3]Num[R2C4:I]25 26 27 28
Resp:
Seq[R1C3:K]
[1]Seq[R2C2T:K]
*[1]String[R2C44:C]class Owners{ // <<<Owned by Jeff Davis>>>
*[2]Num[R2C15:I]2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
[2]Seq[R2C2:K]
*[1]String[R2C46:C]class Owner { // <<< Owned by Bob Lee >>>
*[2]Num[R2C8:I]17 18 19 20 21 22 23 24
[3]Seq[R2C2:K]
*[1]String[R2C47:C]class Owner { // <<< Owned by Abe Lincoln >>>
*[2]Num[R2C4:I]25 26 27 28
Bugs by responsibility:
==================================================
<<<Owned by Jeff Davis>>>
6-7; 9-13
==================================================
<<< Owned by Abe Lincoln >>>
26-28

The play-by-play:

  1. $R__$r//=== ... __ \~ =>code;. The first section just literally captures the sample code bytes, breaks it into a sequence by line; and removes the line breaks.
  2. 'Ranges'#pgm{ n& =>n\(n-- *~=1``)@& (=>r;:?(r# =1){r}::{(r<-)(r->)}) ,,(('-')('; '))%*};. This is just the Ranges program developed in CS00013.
  3. 'bugLines:'$;(9..13)(6 7)(26..28)< =>bugLines$;. Just creates and saves some sample testing data and displays it:
    bugLines:
    9 10 11 12 13 6 7 26 27 28
  4. code *^& 'Owned by' `` =>iOwners;. Reading left to right, given code I mark lines containing "Owned by" *^& 'Owned by'; save the indices of lines marked `` =>iOwners;; and display. These are the lines where each owner's code begins.
    iOwners:
    2 17 25
  5. 'rOwners: '$;code # ` \iOwners<-_1 =>rOwners$;I create a numeric vector of line numbers. This is the number of lines of code as an argument to the monadic index generator. code # `. I segment this by the index of the owners. \iOwners. I need to drop the first item; then save and display the result verbosely to see the segmentation. <-_1 =>rOwners %**$;
    rOwners:
    Seq[R1C3:K]
    [1]Num[R2C15:I]2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
    [2]Num[R2C8:I]17 18 19 20 21 22 23 24
    [3]Num[R2C4:I]25 26 27 28
  6. (9..13)(6 7)(26..28)< =>bugLines;. Assume somehow we are given the line numbers with bugs. Here I just assign it literally. This solution does not expect them to be in any particular order.
  7. 'Resp:'$;code[iOwners],|rOwners =>resp %**$;. Indexing the code lines by the indices of the owners I get my caption for each owner. code[iOwners]. I catenate as a column, the line responsibility for each owner.,|rOwners. I save and display the result verbosely to see the segmentation. =>resp %**$;
    Resp:
    Seq[R1C3:K]
    [1]Seq[R2C2T:K]
    *[1]String[R2C44:C]class Owners{ // <<<Owned by Jeff Davis>>>
    *[2]Num[R2C15:I]2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
    [2]Seq[R2C2:K]
    *[1]String[R2C46:C]class Owner { // <<< Owned by Bob Lee >>>
    *[2]Num[R2C8:I]17 18 19 20 21 22 23 24
    [3]Seq[R2C2:K]
    *[1]String[R2C47:C]class Owner { // <<< Owned by Abe Lincoln >>>
    *[2]Num[R2C4:I]25 26 27 28
  8. 13 10 #asc =>nl; '='%%50=>b;. I create two variables to assist in formatting. First, the new line13 10 #asc =>nl;. Then a string of 50 equal signs ('=') forming a bar '='%%50=>b;.
  9. 'Bugs by responsibility:'$;b$;
    :@&(resp[.r]){
        r[2]< & bugLines =>rl;
         :?(rl){
            (r[1]< =>t;
            t<-(t @== `&'<<<'-1-))
            (rl[.n]Ranges)}}~(#nil)
             ,,((nl)(nl b nl))$;

    First comes the report title and a bar: 'Bugs by responsibility:'$;b$;. Reading left to right, top to bottom; for the items in resp (referenced in the block as variable r) :@&(resp[.r]){; disclose the second item of the sequence r[2]<and intersect it with bugLines& bugLines. This gives the lines of responsibility having bugs for this owner and saves it =>rl;. If it contains anything :?(rl){, get and disclose the first item owner caption caption r[1]< =>t;; Drop everything before the " <<< "  substring t<-(t @== `&'<<<'-1-) including the result as a sequence item. Call the Ranges program with the responsible lines to format them.(rl[.n]Ranges)}}. This is the second item and ends the if block and for loop. Any owners with no buggy lines show up as nils and we delete them. (rl[.n]Ranges)}}~(#nil). We now have the result we want and just need to format the sequence items and display. This means putting newlines (nl) between inner items and (nl bar nl) between outer items.,,((nl)(nl b nl))$;. We have the display we came for.
    Bugs by responsibility:
    ==================================================
    <<<Owned by Jeff Davis>>>
    6-7; 9-13
    ==================================================
    <<< Owned by Abe Lincoln >>>
    26-28

This completes the example. To better understand these operators and other things you can do with them, consult the operator pages according to the type of data you see being operated on.