Przejdź do głównej zawartości

Limit WIP

Although Scrum Guide does not mention this explicitely, it is an important part of sprint planning and the sprint work itself to limit the amount of Work In Progress. Let's look at this aspect in detail and consider some examples.

Without the notion of WIP, several team members may just start work on several backlog items, say 6 developers start 6 different backlog items. In practice, this apporach often goes together with the phenomenon of one developer working on a single backlog item for several days - either because they are too big for one person to complete them quickly or because they are too big in general. If the backlog items are too big, each developer may work on their backlog item even for the whole duration of the sprint. Now, there are some disfunctions in a team that does this:

Teamwork
Each developer is focused on their backlog item, so there is no really teamwork there. If at least 2-3 developers focus together on one backlog item, it fosters collaboration and gives people common aim. Developers who work together on one item are also more exposed to changes being made in the code, because nobody is developing in a silo.

Predictability
It is very difficult to say if the team is going to each the spring goal at any point during the sprint - everything is in progress, everything is assigned, but what will actually be Done - this is unknown almost until the very last day. With smaller backlog items and 2-3 developers working on each, a substantial part of sprint backlog is completed during the sprint, so it is much easier for the team to gauge what will be completed by the end of the sprint (at least the items that are Done now wil be Done at the end of the sprint).

Sprint planning
With silo work and big backlog items the team is bound to miss important aspects of the spring planning meeting. After all, a developer that is going to work alone on backlog item A for 10 days will not have much to say about his plan. On the contrary, if a few developers work on each backlog item and the backlog items are rather small (say, doable withing 1-5 days each), the sequence of work is becoming very important during the planning. The team will not plan to start the bigger backlog items late in the sprint. They will consider the order of sprint backlog and the order of their planned work during the sprint to maximize the probability of achieving the sprint goal. They may even notice that what the Product Owner desires is not achievable in a sprint - not because there is too much work to be done but because the sequence of work puts constraints on the delivery.

In a well performing team, there should typically be more than one developer working on a regular backlog item. The backlog items should flow quickly from In Progress to Done, because they are small and two or more people usually work on each. The team may choose to set official WIP and put it on the corkboard - no more than 3 backlog items In Progress at the same time. Or they may just pay attention to it without setting the official limit. Finally, a good Scrum Team will pay attention to defining and splitting the backlog items so that they are small. It is not enough that a backlog item is just doable within a sprint. Smaller backlog items give the team more flexibility in the way they plan to sequence their work and allow them to start work on next backlog items even near the sprint end.

Komentarze

Popularne posty z tego bloga

Unit Testing code with IO file operations (in Python)

We may often come across a piece of code that was written without Unit Tests at all. In addition, the piece of code may be dealing with IO like file writing and reading, which makes it more difficult to Unit Test it when we are trying to refactor and modify. Let's suppose the code in question looks like this:

def writeInitialsToFile(filename, name, surname):
    initials = name[0] + '.' + surname[0] + '.'
    with open(filename, 'w') as file:
        file.write(initials)

def readInitials(filename):
    initials = None
    with open(filename, 'r') as file:
        initials = file.readline()
    return initials

A straightforward and bad idea would be to write a couple of Unit Tests that make use of a real file and simply test the reading and writing. Is therea a better way to test this code?

First of all, we need a way to replace the real file with something else. For both reading and writing we will now have a couple of functions, one that expects a stream fo…

Piotr's Less Obvious Advice on Google Mock: State maintenance

Google Mock provides several ways to maintain state inside mock objects. One way of implementing state maintenance is with SaveArg. Consider the following example.

We have a class Configurator, which allows a caller to set and get values of a parameter:

class Configurator
{
    public:

    virtual ~Configurator() {}

    virtual void setParamX(int n) = 0;
    virtual int getParamX() = 0;
};

And we have a class Client that calls Configurator's methods and it also has a method incParamXBy, that can be used to increase the current value of paramX by a certain value.

class Client
{
    public:

    Client(Configurator & cfg);
    virtual ~Client() {}

    void setParamX(int n);
    void incParamXBy(int n);
    int getParamX();

    private:

    Configurator & _cfg;
};

incParamXBy internally calls setParamX and getParamX on Configurator:

void Client::incParamXBy(int n)
{
    _cfg.setParamX(_cfg.getParamX() + n);
}

Let's assume that the initial value of paramX is A and that we want to increase paramX by…

Piotr's Less Obvious Advice on Google Mock: Returning new objects from a mock

Google Mock provides a way to return newly created objects from a mock method. Suppose we have a  Generator class that is supposed to generate new objects when createNewRecord method is called:

class Generator
{
    public:
    virtual ~Generator() {}
    virtual Record * createNewRecord() = 0;
};

...and suppose we want to mock this class:

class MockGenerator : public Generator
{
    public:
    MOCK_METHOD0(createNewRecord, Record * ());
};

Suppose the caller class Client has run method defined as follows:

void Client::run()
{
    for(int i = 0; i < 3; i++)
    {
        rec_tab[i] = gen.createNewRecord();
    }
}

We want the mock to return a pointer to a new object each time createNewRecord is called. This is how we can express this in the test code:

TEST(ClientTest, CanRun)
{
    MockGenerator gen;
    Client c(gen);

    EXPECT_CALL(gen, createNewRecord())
        .Times(3)
                 //this is equivalent of returning new Record(1,2,3)
        .WillOnce(ReturnNew<Record>(1,2,3))
        .Will…