Feedback and growth as a team activity

Feedback is key to any successful organisation but in my experience the way formal feedback is handled is not always optimal or doesn’t suit everyone. Below you can read about an experiment I’ve done to try to make things a bit better in my current setting.

The “normal” way of doing feedback

The way this traditionally works where I’m active at the moment is that people send out feedback requests to their teams and the feedback is handed back via email or an internal tool following this structure:

  • Achievements
  • Mastery
  • Behaviour

Each category has the sub sections:

  • Things to be proud of
  • Things to improve

When feedback is sent, the manager is cc:ed on the email or can see the feedback in the tool, later on the person receiving the feedback sits down to go through the feedback together with the manager and come up with a plan for the next 6 months. At this point the feedback from the managers is also incorporated and any additional feedback that the manager might have solicited.

Flaws

I’ve found that this way of handling the feedback has some flaws:

  • Unless asked for, there is no face to face communication about the feedback that the person receives.
  • There is always room for misunderstandings in written feedback, especially in a multi-language organisation.
  • There’s often a shotgun effect to the feedback you receive, since those giving feedback do not necessarily know what areas the person wants feedback on.
  • Often people send out feedback requests to mailing lists. This means that everyone would receive 10-15 or more feedback requests. This can be overwhelming as it takes quite a bit of time to write well thought through feedback.

Personal growth as a team activity

As an experiment for improving the situation we are doing some significant changes to how feedback is done in the teams I’m working with at the moment.

Growth areas

First, we wanted to make sure everyone in the teams are aware of what their teammates have as their growth goals. To kick it off we had a session where everyone listed:

  • Top 3 growth areas. This could be anything from Java, testing frameworks, Cassandra and BigTable knowledge to public speaking or mentoring.
  • Up to 2 behaviours that they wanted feedback on. This could for instance be if they were interrupting too much, not speaking up enough or not being specific enough when doing code reviews.

Once everyone had written down their own improvement areas we went around the table and everyone told the team about the areas they wanted to improve in. This creates an opportunity for  a valuable conversation if several people had the same thing noted down. A consequence of this is that people could start looking after each other as new tasks came up. For instance, someone wants to grow their Cassandra skills a change was needed in the Cassandra cluster. The team could then help that person by giving them space and support when performing the task instead of having the person with the most knowledge pick it up and just get the job done.

Effectiveness Reviews

The inspiration for this part has come from Peer Reviews in S3 but we adjusted it to interface with the way we normally do feedback (see above). This was the process:

  1. Think about 5-6 people who you would like feedback from. This can be members on your team, people you have collaborated with and preferably your manager.
  2. Invite them all to a 1 hour meeting in a place and time of your choosing.
  3. In preparation for the meeting a few things should happen.
    1. As the recipient of the feedback you should remind the feedback givers of your growth areas.
    2. Evereone (including the recipient) should start thinking about feedback.
    3. The recipient should consider inviting a neutral facilitator that can explain the setup and make sure the session stays on track.
  4. The review would typically run like this:
    1. The facilitator starts by drawing the grid below on a whiteboard or several flip chart papers and explains the rules of engagement (see below).
      Effectiveness Review 1
    2. Appreciations:
      1. Everyone (including the recipient) is given 4 minutes to write appreciations connected to the 3 themes. 1 appreciation per post-it.
      2. The recipient goes first and puts up the appreciations for themselves and explains what the post-it says and what they mean.
      3. The feedback givers do the same and cluster appreciations that are similar. Here there is also the possibility to build on what have already brought up.
    3. Improvement areas are bigger themes where the person could improve to have an even greater impact (note that these are not actions that the person could take – that comes in the next step). The setup here is the same as for appreciations, write post-its, the recipient goes first and then the rest. Ideally the growth areas that you brought to the session should now be on the board.
    4. The time has now come to be concrete. For another 4 minutes the participants write up suggestions for actions connected to the improvement areas. Say for instance that you have an improvement area that is public speaking then suggested actions might be: “Do lunch and learns for the team”, “Take this public speaking class that I’ve heard is really good” or “Watch this TED talk that really helped me improve”.
    5. The session is now over. Time to thank the feedback givers for their contributions.
  5. Following up from this session the person receiving the feedback creates a document where all the input is gathered and grouped into categories. You then book a time with your manager where you look at the feedback and decide what you want to focus on improving. It’s important to note here that just because someone else says you should improve in an area it doesn’t mean you need to. It’s up to you to decide how you want to grow.

Rules of engagement for the session

There should be a positive spirit to all pieces of feedback. If people start bringing up negative feedback and other people start building on it the session can quite easily turn into a bullying session that would be highly uncomfortable for the person receiving the feedback. Trust is key for the feedback to be received well. It’s the facilitators responsibility to bring the conversation back on track again if things are starting to go off the rails.

People in the session are welcome to ask clarifying questions if anything is unclear. They should however not start debating or question the feedback someone is giving.

How time consuming is this going to be?

Say that you are part of a team of 7 people and you are invited to the Effectiveness Review for 4 of them (probably the people you work closest with), then you have 1 hour spent on your own and 4 hours in the reviews for other people. You should spent a bit of time preparing for the sessions thinking about what feedback you want to give and then you need to summarise the feedback you receive. In total, in this scenario, I would guess you spend about 6 hours per person.

It’s worth noting though that this process was not designed to optimise the time people spend on feedback. It’s optimised to produce better and more meaningful feedback coupled with help with how to proceed with you own development. All of this in a setting where you as team members care, boost and look out for each other.

Learnings and next steps

When it was introduced, a few people on the team were skeptical and because of that wanted to stick with the old format. This was perfectly fine. What I wanted to provide was a variety of ways to gather feedback where people would pick the one they were most comfortable with. However, after attending the sessions for others people generally changed their minds and booked their Effectiveness Reviews.

Based on a survey I did with the team, I found out that the format above works really well and people want to keep doing it. When people had attended a session the need for a facilitator went down as people were familiar with the format and knew what to do. I’d still recommend having a facilitator to keep an eye on the rules of engagement and to be the time keeper.

We did this as a replacement for the annual feedback sessions that happens every 6 months. I can really see this being done more frequently (quarterly or even monthly) to have more continuous feedback. If you go for that you probably want to tweak the format a bit and feed in what you are currently working on and perhaps use your team to help guide you and keep you accountable to what you said you would do.

Retro Kit

Continuous improvement is important for any team but sometimes it is hard to know how to start. To make it getting started easier me and a couple of Agile Coaches at Spotify have created the Retro Kit. We have been testing it internally and the reception has been very positive and since we have drawn knowledge from the community to create it we figured that it would only be right to share it back. Hope you find it useful! 🙂

The Retro Kit has been published on Spotify’s external blog, Spotify Labs.

 

Image

Epic Kick Off Cheat Sheet

A team I’ve been working with had a hard time gaining focus and having the sense of being a team. One of the reasons for this was that they were just working off the top of the backlog in their flow based workflow and the backlog was quite fragmented with a bunch of different initiatives and support for other teams tangled up. It was hard to get a sense of collaboration as a team and that they were achieving some bigger value together. To remedy this we introduced the practice of working on one (or sometimes two) epics at a time.

To kick off the work on the epic we introduced kick off meetings. In those we clarify why the epic is important, who the stakeholders are, risks and other important factors that are good to align on. Over time we have created a checklist of topics that we should cover and I have now compiled that checklist into a new Cheat Sheet that I thought may prove to be useful to others.

Please keep in mind that the kick off meeting shouldn’t take much more than 1 hour and the work you are planning shouldn’t span more than a few months. If it’s more you should probably ask yourself if you are making decisions too early.

One other thing worth noting is that we sometimes use tools like Impact Mapping “inside” of the epic when we are working towards an impact rather than a deliverable.

This tool has been useful to us and I hope it can be useful to you as well. 🙂

Automated Slack reminders for your meetings with Google Apps Script

In a leadership group that I am working with we have the policy of rotating who facilitates the meeting and who takes notes. I think this is a great way of running the meeting as it gives us a collective ownership of it rather than the formal leader of the group running it. Practically we did this by having a table with the facilitator and note taker on top of the document with the notes so everyone could see who was up next. One challenge we faced was however that people didn’t check the document ahead of the meeting and because of that forgot to bring their laptops or if one of the two people where missing they forgot to delegate the responsibilities. This lead to frustration within the group as we lost time as people needed to run off to fetch laptops or where unprepared to facilitate the meeting.

After observing this a few of times I figured: Why not use the same thinking as with software? If something is boring, frustrating and you need to do it over and over again (check the doc) you automate it!

After a bit of looking around I settled with using a Google Spreadsheet and Google Apps Script to integrate that with Slack to get a reminder to the group and a personal ping for the facilitator and note taker in the morning of the day of the meeting.

After a couple of hours of hacking away I had something in place that looks like this in our Slack channel:

Skärmavbild 2017-07-08 kl. 22.52.23.png

It requires no manual steps for us except for if someone leaves the group and requires people to be taken off the rotation. Below I’m going to walk you through how you can create this for your team as well.

Step 1: Setting up Slack

The first thing we want to do is to prepare Slack for receiving  messages from the outside. For this you will need to set up an Incoming WebHook. Start by going to this url: https:// [your Slack team name].slack.com/apps/manage/custom-integrations (if you can’t access this you will need to seek help from an admin). Go to Custom Integrations and then Incoming WebHooks.

Skärmavbild 2017-07-08 kl. 21.32.11

In the dialog for Incoming WebHooks you will click the button Add Configuration. You can then select the channel you want to post to and then click Add Incoming WebHooks Configuration. At the top of the next page you will find the WebHook url. It looks like this: https:// hooks.slack.com/services/[a bunch of characters] and you will need it in the later steps. Except for Descriptive Label (where I’d advice you to enter something like “Meeting integration”) you can leave everything with the default values. Click Save Settings and let’s move on to the next step.

Step 2: Moving on to the spreadsheet

Now it’s time to move the data from the document where we had the list of facilitators and note takers to the spreadsheet where we will pull the data from. The first thing you will need is to make sure you have a G Suite account set up. Use your account to create a new spreadsheet and create a sheet called “data” (the naming is important in later steps). The layout should look like this:

Skärmavbild 2017-07-08 kl. 21.05.46

The smeared out data in the sheet are the Slack handles of all the people on the team. This is the same lists that were previously found at the top of the meeting notes.

Step 3: Notifying Slack

What I want to do now is to take the top names, the people on row 2, and send that as a message to our channel in Slack. Time to do some scripting with Google Apps Script.

To access the script editor you go to Tools -> Script editor…

Let’s do the sending of messages step by step. All of these functions could be merged to one but if you want to extend the script it’s a good idea to keep them separated for reusability. Also, it’s going to be easier to explain them one by one.

Step 3.1: Creating the message

function createMeetingMessage(sheet) {
 var facilitatorCell = "data!A2";
 var noteTakerCell = "data!B2";
 var message = ">>> *TODAY'S MEETING*\n"
 + ":speaking_head_in_silhouette: *Facilitator:* @" +sheet.getRange(facilitatorCell).getValue() +"\n"
 + ":computer: *Note taker:* @" +sheet.getRange(noteTakerCell).getValue() +" (don't forget to bring a laptop)";
 
 return message;
}

The function takes a SpreadSheet as input (more on where this comes from in later steps)

The first two rows in the function pull data from the spreadsheet in the sheet “data” and shell A2 (facilitator) and B2 (note taker). On the next row the message is put together. Here you can use the same formatting as you would in a normal Slack message. I’m using quote, bold font in a couple of places and emojis. The “\n” is to insert line breaks.

Step 3.2: Sending things to Slack

function triggerSlackRequest(channel, msg) {
 var slackWebhook = "https://hooks.slack.com/services/[a bunch of characters]";
 var payload = { "channel": channel, "text": msg, "link_names": 1, "username": "Meeting Bot", "icon_emoji": ":robot_face:" };
 var options = { "method": "post", "contentType": "application/json", "muteHttpExceptions": true, "payload": JSON.stringify(payload) };

Logger.log(UrlFetchApp.fetch(slackWebhook, options));
}

This function takes a channel to send the message to and a message as input.

In the first row of the function you should enter your WebHook url that you got in Step 1.

On the second row the payload is put together with the channel, the message, name for the sender (Meeting bot in this case) and an icon to appear next to the message (I choose :robot_face:). Feel free to change the name and the icon if you prefer something else.

The next row is about how the message will be sent and then the last row is where the message is actually sent to Slack.

Step 3.3: Putting it together

function notifySlackChannelOfFacilitatorAndNoteTaker() {
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("data");
 var channel = getChannel();

var msg = createPotlacMeetingMessage(sheet);
 triggerSlackRequest(channel, msg);
}

This function is where it is all pulled together.

On the first row you get the sheet you want to work with. The sheet you created in step 2. On the next row you get the name of the channel you want to send the message to. I use a separate function for this for debugging purposes. That way, if you want to play around with it, you avoid spamming the rest of your team. More about this function in the next step.

The third line is getting the message from 3.1 and on row four that message is sent.

Step 3.4: Safe play

function isTest() {
 return false;
}

function getChannel() {
 if(isTest()) {
 return "name of your test channel";
 } else {
 return "year teams channel";
 }
}

As mentioned above you don’t want to spam your team when you play around with these things.

The function isTest()  determines if you are testing or not. If it says false you send messages to your team. If it says true you send the messages to your test channel.

The function getChannel() gets the name of the channel you want to send your messages to. Replace the names above with the names of your channels.

Step 3.5: The complete thing

Putting it all together this is what it looks like.

function isTest() {
 return false;
}

function notifySlackChannelOfFacilitatorAndNoteTaker() {
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("data");
 var channel = getChannel();

var msg = createPotlacMeetingMessage(sheet);
 triggerSlackRequest(channel, msg);
}


function getChannel() {
 if(isTest()) {
 return "name of your test channel";
 } else {
 return "year teams channel";
 }
}

function triggerSlackRequest(channel, msg) {
 var slackWebhook = "https://hooks.slack.com/services/[a bunch of characters]";
 var payload = { "channel": channel, "text": msg, "link_names": 1, "username": "Meeting Bot", "icon_emoji": ":robot_face:" };
 var options = { "method": "post", "contentType": "application/json", "muteHttpExceptions": true, "payload": JSON.stringify(payload) };

Logger.log(UrlFetchApp.fetch(slackWebhook, options));
}

function createMeetingMessage(sheet) {
 var facilitatorCell = "data!A2";
 var noteTakerCell = "data!B2";
 var message = ">>> *TODAY'S MEETING*\n"
 + ":speaking_head_in_silhouette: *Facilitator:* @" +sheet.getRange(facilitatorCell).getValue() +"\n"
 + ":computer: *Note taker:* @" +sheet.getRange(noteTakerCell).getValue() +" (don't forget to bring a laptop)";
 
 return message;
}

Step 3.6: Triggering sending the message

There is a tool i Google Apps Script called triggers that are pretty neat. We area going to use them to automatically send the message.

Skärmavbild 2017-07-08 kl. 22.23.44

You access the triggers by clicking the button above or by going to Edit -> Current Project’s Triggers. Here you select the function you want to run and at what time you want to run it. As we have our meeting on Thursdays it looks like this:

Skärmavbild 2017-07-08 kl. 22.27.49

Step 4: Rotating the list

Hang on a second! If we just go by this the same people will always be pinged as we never change the spreadsheet. We need to rotate the rows a bit.

Step 4.1: Adding a time for rotating out

function addRotationTime(sheet, row, column) {
 var time = new Date();
 time = Utilities.formatDate(time, "GMT+02:00", "yyyy-MM-dd HH:mm:ss");
 sheet.getRange(row, column).setValue(time); 
}

This function takes a sheet as input and adds a timestamp to the row and column from the input parameters.

Step 4.2: Swapping rows

function moveTopRowToBottom(sheet, firstRow) {
 var rowAfterLast = sheet.getLastRow() + 1;
 var lastRowRange = sheet.getRange(rowAfterLast, 1);
 sheet.getRange(firstRow).moveTo(lastRowRange);
 sheet.deleteRow(2);
 sheet.insertRows(rowAfterLast);
}

The function takes a sheet and the first row as input. The reason we send the first row is to avoid swapping down the header row.

The function finds the row after the last row with data and moves the first row to it. Once that is done the fist row is deleted (as it is now empty).

Step 4.3: Putting it together

function rotateFacilitator() {
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("data");
 addRotationTime(sheet, 2,3);
 moveTopRowToBottom(sheet, "Data!A2:C2");
}

As with the sending of messages this is where it is put together. The function gets the sheet, adds the rotation time to the first row and then does the rotation.

Step 4.4: The complete thing

The three functions put together then look like this:

function rotateFacilitator() {
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("data");
 addRotationTime(sheet, 2,3);
 moveTopRowToBottom(sheet, "Data!A2:C2");
}

function moveTopRowToBottom(sheet, firstRow) {
 var rowAfterLast = sheet.getLastRow() + 1;
 var lastRowRange = sheet.getRange(rowAfterLast, 1);
 
 sheet.getRange(firstRow).moveTo(lastRowRange);
 
 sheet.deleteRow(2);
 sheet.insertRows(rowAfterLast);
}
 
function addRotationTime(sheet, row, column) {
 var time = new Date();
 time = Utilities.formatDate(time, "GMT+02:00", "yyyy-MM-dd HH:mm:ss");
 sheet.getRange(row, column).setValue(time); 
}

Step 4.5: Triggers… more triggers

As with the sending we want to trigger the rotation automatically. We do this at the start of the week.

Skärmavbild 2017-07-08 kl. 22.43.05.png

Wrapping up

We have been using this for a couple of months now and it has helped us a lot. We have automated away a lot of unnecessary frustration within the team.

The code above can surely be made much cleaner. My excuse is that it’s been a while since I was coding last and it is my first stab at doing something in Apps Script. Also, this is only part of the code. We use the same data for some other automated things as well.

When I did this I had huge help from this post about how to automate stand-ups. If something in this post is unclear I’m sure you will find the answer there.

 

Image

Stand-up Cheat Sheet

Since the Planning Cheat Sheet seems to have been useful to a few people I figured I’d go ahead and share another Cheat Sheet I put together a while ago. This time around it’s the Stand-up Cheat Sheet. The way I’ve used this is by printing it and posting it next to the boards of a few teams I’ve been helping lately.

The first bit under “How we do it” assumes you are doing Walk the board rather the old “what I did yesterday, what I’m going to today, impediments” style.

If you want more good ideas on how to improve your stand-ups I really recommend the blog post It’s Not Just Standing Up: Patterns for Daily Standup Meetings by my colleague at Spotify Jason Yip.

Image

Planning Cheat Sheet

A while ago I got approached by a team that was struggling with their sprint plannings. To help them help themselves I put together a Planning Cheat Sheet to give them some pointers. It has come to good use since and has caught some attention where I’m working so I thought I would share it here as well for others to use.

Please comment if you found it useful and/or if you would like some tweaks to it.