Wednesday, December 20, 2023

Enable Sub-Game Selection

 

Overview

I'm continuing to learn how to develop a game within Board Game Arena. In this section I'm working on the next step in the game I'm building out which involves the dealer picking a specific game to play. Ultimately, each game can only be selected once, but this is just going to focus on making the selection possible and ensuring that I can tell that the selection was made.

I realize I haven't named the game I'm working to implement and as I kept typing things like "the game I'm building out" it started to seem silly. The game is Guillotine. A game that my brother taught me years ago and now I play with a group of friends regularly. Here's a link to the rules if you're interested.

For some context, you might want to read the previous post about getting a hand of cards to show.

Create a state for selecting a game

After a hand is dealt the dealer must select the game to play. These directly translate to states to be implemented. So we need to create a new state for handling game selection and update the state for dealing a new hand to transition to the newly created one.
2 => [
  "name" => "newHand",
  "description" => "",
  "type" => "game",
  "action" => "stNewHand",
  "updateGameProgression" => true,
  "transitions" => ["selectGame" => 10]
],
 
10 => [
  "name" => "gameSelection",
  "description" => clienttranslate('${actplayer} must select the game to play'),
  "descriptionmyturn" => clienttranslate('${you} must select the game to play'),
  "type" => "activeplayer",
  "args" => "argSelectGame",
  "possibleactions" => ["gameSelection"],
  "transitions" => []
],

Since the only thing we want to happen is for the game to transition from "newHand" to "gameSelection" we need to invoke the transition in the "newHand" action. So at the end of the stNewHand function we do just that with the following that references the name of the transition, "selectGame".
$this->gamestate->nextState("selectGame");

Some things to note about the new state (see documentation for complete details):
  • "type" => "activeplayer" indicates that a single player is active and must do something to continue the game.
  • "description" and "descriptionmyturn" provide the text to display in the main action bar of the game.
  • "args" exposes information to the client side from the declared function.
  • "possibleactions" defines the possible actions the player can take and allows for them to be enforced so the functions aren't called at unexpected times.

State args

Guillotine has six games a player must select during the game with each one being selected only once. So ultimately we want to provide the list of available games for the current player to select. Though to simplify things, I'm going to ignore how the played games are tracked and just worry about making the six games available to select from.
function argSelectGame() {
  $available_games = [];
  foreach ($this->games as $game_type => $game) {
    $available_games[] = ['type' => $game_type, 'name' => $game['name']];
  }
 
  return [
    "available_games" => $available_games
  ];
}

I initially had the names of the games just hard-coded into this function, but I ran into issues keeping track of the current game since game state values can only be integers instead of strings. So I pulled the game details out to the material.inc.php file so they can be referenced everywhere.
$this->games = [
  'parliament' => [
    'id' => 1,
    'name' => clienttranslate('Parliament')
  ],
  'spades' => [
    'id' => 2,
    'name' => clienttranslate('Spades')
  ],
  'queens' => [
    'id' => 3,
    'name' => clienttranslate('Queens')
  ],
  'royalty' => [
    'id' => 4,
    'name' => clienttranslate('Royalty')
  ],
  'dominoes' => [
    'id' => 5,
    'name' => clienttranslate('Dominoes')
  ],
  'guillotine' => [
    'id' => 6,
    'name' => clienttranslate('Guillotine')
  ],
];

Prompt current user

Now things shift to the client side and we need to allow the user to select the game they want to play. Within the <game_name>.js file there should already exist a function onUpdateActionButtons which I just updated to handle this case.
onUpdateActionButtons: function( stateName, args )
{
  console.log( 'onUpdateActionButtons: '+stateName );
 
  if( this.isCurrentPlayerActive() )
  {
    switch( stateName )
    {
      case 'gameSelection':
        args.available_games?.forEach(game => {
          this.addActionButton(game.type, _(game.name), () => this.onGameSelection(game.type))
        });
        break;
    }
  }
},

The args.available_games along with type and name are direct references to what was returned from the argSelectGame function above. Currently it will error out because the onGameSelection function isn't defined, so let's add that to the "Player's action" section of the file.
onGameSelection: function(game_type) {
  const action = "gameSelection";
  if (!this.checkAction(action)) return;

  this.ajaxcall(
    "/" + this.game_name + "/" + this.game_name + "/" + action + ".html",
    {lock: true, selected_game: game_type}, this, function (result) {}, function (is_error) {}
  );
},

The call to checkAction is used to protect against the method being called when not expected and the action must match the name in the "possibleactions" in the state definition. The call to ajaxcall sends the selected game to the back end. (See the documentation for details on the function.)

Now we should get prompted to select the game with this



Keep track of selected game

For the back end to be able to accept the call that gives it the selected game an action needs to be defined. This is done the in <game_name>.action.php file. The details of the file and the functions used in it are defined in the documentation.
public function gameSelection() {
  self::setAjaxMode();

  $selected_game = self::getArg("selected_game", AT_alphanum, true);
  $this->game->gameSelection($selected_game);

  self::ajaxResponse();
}

As noted in the documentation for actions, they are just serving as a bridge from the front end to the main game logic. So this just extracts the "selected_game" argument that was passed along and calls a gameSelection function in the main <game_name>.game.php file. The function should go in the "Player actions" section.
function gameSelection($selected_game) {
  self::checkAction("gameSelection");

  $game_id = $this->games[$selected_game]['id'];
  self::setGameStateValue(SELECTED_GAME, $game_id);

  $game_name = $this->games[$selected_game]['name'];
  self::notifyAllPlayers('gameSelection',
    clienttranslate('${player_name} selects ${game_name} as the game to play'), [
      'i18n' => ['game_name'],
      'player_name' => self::getActivePlayerName(),
      'game_name' => $game_name,
    ]);
}

This keeps track of the selected game by calling setGameStateValue with the id defined in the game details defined in the first section. It also notifies all of the players in the game log which game was selected. SELECTED_GAME is a constant that I defined in a new file models\constants.inc.php. I like using a constant as I find it helps me avoid typos that I don't notice until testing.
<?php
// Game State Variables
define('SELECTED_GAME', 'selected_game');

Additionally, the game state needs to be initialized in a couple of sections of the <game_name>.game.php file. In the __construct function it needs to be defined.
self::initGameStateLabels([
  SELECTED_GAME => 10,
]);

If I didn't want a default value of 0 for the starting value I'd need to initialize it in the setupNewGame function, but since I am I can skip that. However, I know I'm going to have to reset the value for each new hand so I'll update the stNewHand function that was created for dealing out the cards. This won't be used until we play through a hand, but I feel like adding it in this case. :)
self::setGameStateValue(SELECTED_GAME, 0);

Wrap up

I'm still trying to understand how translations work and if everything I've done will be able to be translated appropriately. From what I understand my call to notifyAllPlayers should be good because the ${game_name} variable in the message is specified in the i18n parameter. I'm less certain about the addActionButton call in the front end as I'm passing in a variable to it. Something I'll need to dig further into to make sure I'm doing that correctly.

Monday, December 18, 2023

Getting a Hand of Cards to Show

Overview

This is the next step in my learning how to develop a game for the online platform Board Game Arena (BGA). This skips over some things that are necessary for development that are covered in the Hearts tutorial as well as duplicating parts of it. The intent is to capture things with a different focus and to help reinforce some connections that I missed when I was going through the tutorial.

The game I'm working on through this uses a poker deck of cards, but the tooling is designed to work with all sorts of card types that are used in various games. Some naming of things might not make as much sense in this context, but there's a reason behind it. :)

Initialize a deck of cards

The Deck component (see documentation) provides the basics for the back end side of things. This allows you to define and work with a deck in the abstract as the card images are not needed until we get to the front end. To use the Deck you need a database table to hold details about each card.

CREATE TABLE IF NOT EXISTS `card` (
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `card_type` varchar(16) NOT NULL,
  `card_type_arg` int(11) NOT NULL,
  `card_location` varchar(16) NOT NULL,
  `card_location_arg` int(11) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

Initialize a deck and point it at this table as part of the construction of the game.
$this->cards = self::getNew("module.common.deck");
$this->cards->init("card"); // The string passed here must match the name of the table created.

Create the card definitions and put them in a location.
$cards = [];
foreach ($this->suits as $suit_id => $suit) {
  for ($value=7; $value<=14; $value++) { // The game I'm working on is only using 7 - A
    $cards[] = ['type' => $suit_id, 'type_arg' => $value, 'nbr' => 1); // create one card of each type
  }
}
$this->cards->createCards($cards, 'deck'); // 'deck' is the location to put them in

The $this->suits needs to be defined somewhere and since it's value never changes the suggestion is to put it in material.inc.php (see documentation) so it can be referenced everywhere in the game logic.
$this->suits = [
  1 => ['name' => clienttranslate('spade'),
        'nametr' => self::_('spade')],
  2 => ['name' => clienttranslate('heart'),
        'nametr' => self::_('heart')],
  3 => ['name' => clienttranslate('club'),
        'nametr' => self::_('club')],
  4 => ['name' => clienttranslate('diamond'),
        'nametr' => self::_('diamond')],
];

Deal out the initial hand of cards

The heart and soul of a game created in BGA is the state machine as it controls the flow of the game and what is possible at each. It's important to consider when the cards should be dealt out and what should happen. The game I'm working on is a trick taking game that will need to the cards dealt out at the start of each hand. Therefore, I created a state for a newHand that goes in the states.inc.php file (see documentation). Be sure the initial state, "gameState", transitions to this new state with "transitions" => ["" => 2]".
2 => [
  "name" => "newHand",
  "description" => "",
  "type" => "game",
  "action" => "stNewHand",
  "updateGameProgression" => true,
  "transitions" => []
],

That state references an action function, stNewHand, that will deal the cards out.
$this->cards->shuffle('deck');
// Deal 8 cards to each player
$players = self::loadPlayersBasicInfos();
foreach ($players as $player_id => $player) {
  $cards = $this->cards->pickCards(8, 'deck', $player_id);
  // Notify player about their cards
  self::notifyPlayer($player_id, 'newHand', '', ['cards' => $cards]);
}

The call to self::notifyPlayer isn't strictly necessary to get the cards to show up, but it will be necessary as the game progresses and future hands are dealt out.

Finally, in terms of the backend, the hands of cards need to be made available to the front end, so it can know what to show for the hand. There is a function called getAllDatas that is used for making that happen. Adding the following to it will get the player's hand that is logged into the app.
$result['hand'] = $this->cards->getCardsInLocation('hand', $current_player_id);

Show the player's hand

The first thing is to add an image of the deck to your project. Ideally, it should be a single image to reduce loading time. I added the file img\cards.jpg to my project which you'll see referenced in the code later on. (See general advice around this in the documentation.)

Then the view needs to be updated to have a place to show the player's hand. This goes in the <game_name>_<game_name>.tpl file - something like the following will work:
<div id="myhand_wrap" class="whiteblock">
  <h3>{MY_HAND}</h3>
  <div id="myhand">
  </div>
</div>

Which then needs to be populated using javascript, so in the <game_name>.js file add a function like:
displayHand: function(cards) {
  for (var i in cards) {
    var card = cards[i];
    var suit = card.type;
    var value = card.type_arg;
    this.playerHand.addToStockWithId(this.getCardUniqueId(suit, value), card.id);
  }
},

However, for this to work requires a couple of things to be set up. BGA provides a component called Stock to help with this (see documentation). Add it to the define block at the top of the file by adding "ebg/stock".
define([
  "dojo","dojo/_base/declare",
  "ebg/core/gamegui",
  "ebg/counter",
  "ebg/stock"
],

Next, as part of the setup function define the player's hand and create the cards that can go in it. Note, when creating the hand (the call to this.playerHand.create) it expects the id of the container in the view (we defined that as 'myhand' at the beginning of this section) and the width and height of a single card in the image we added. I'm making use of a full poker deck image, though the game I'm building only makes use of the cards 7 and up, so I note there are 13 images per row, but only create values 7 through 14.
this.playerHand = new ebg.stock();
this.playerHand.create(this, $('myhand'), 72, 96);
this.playerHand.image_items_per_row = 13;
this.playerHand.setSelectionMode(1);

// Create card types
for (var suit = 1; suit <= 4; suit++) {
  for (var value = 7; value <= 14; value++) {
    var card_type_id = this.getCardUniqueId(suit, value);
    this.playerHand.addItemType(card_type_id, card_type_id, g_gamethemeurl + 'img/cards.jpg', card_type_id);
  }
}

Finally, we display the cards that are in the player's hand that we did on the backend. The setup function has a gamedatas parameter that has all the details in it, so we can refer to 'hand' that we used in the previous section when we dealt out the cards ($result['hand']). Additionally, we'll just call the displayHand function we created earlier.
this.displayHand(this.gamedatas.hand);

Conclusion

Now we have a hand of cards showing! Though, this is still only the very beginning of things as the only thing that can be done is see the first hand.

Thursday, November 30, 2023

Learning to Develop Games in BoardGameArena

Getting Started

The first thing to do is create a studio account - though there's a decent bit on that page to read through if you're unsure if you want to actually create an account. After creating the account you should go through some initial steps to make sure everything is set up well and some suggestions if you use an Integrated Development Environment (for instance, VS Code). Finally, there are some tutorials for how to start developing some basic games.

Tutorial

I played a bunch of hearts while growing up so that seemed a no-brainer to start with. The walkthrough initially does a nice job of slowly adding things and showing how to build things up. As it goes further along it takes bigger steps, so you have to remember to slow down and make sure you understand what's being done if you need to - which all seems appropriate. Remember that finishing the tutorial is less about getting the game to completion than it is about making sure you understand the concepts and how to develop things for future games.

What the Hearts tutorial taught me

Some opinions I've started forming

Many parts of the flow of the code are connected by string references. For instance, the name of the game state values. This is less useful for the action and transition names used in defining states as those are used in JavaScript and PHP.

I prefer doing test-driven development and while there are some notes on testing I found it awkward to test things in the main class as there are a lot of helper methods that would require the behavior to be mocked out. I'm currently leaning towards extracting logic to separate classes that can be tested separately. My biggest concern with this is finding the right seams.

Random other things

I found a code-sharing page that I appreciated being able to poke around other projects.

Wednesday, September 25, 2019

Why smaller stories work better for me

I have a strong preference for smaller stories, though I sometimes struggle to make them smaller. Because of that (and the desire to be flexible) I'm willing to entertain other options. Though everytime I allow myself to do larger stories I keep coming back to wishing for smaller stories. So here's my attempt to expose my reasoning and consider what prompts moving away from smaller stories.
How I imagine stories being broken down to smaller ones has always been a whole team iterative approach. During a grooming session the Product Owner, after ensure things are good for the upcoming sprint, will bring up an upcoming story with the team. The team asks questions and works with the Product Owner to refine the acceptance criteria and figure out if there are some significant outstanding questions that need to be answered. Out of this discussion some smaller stories might be created to help answer the questions that came up or perhaps do some part of the work that can be done in isolation - or maybe there's enough details to get a skeleton of work that will provide additional information. While some stories might have been carved off, the rest of the story still remains and stays further down in the backlog waiting for another time to revisit. It can take several sessions for a story to be broken down and it's even possible that a story that was initially broken off was just a clean separator to reduce risk and now it needs to be broken down further. Keep on a regular cadence of viewing the story until it's been broken down enough and gets to done.
Reality doesn't always give you the time to revisit a story multiple times - sometimes the work is the most critical thing you can do. However, the sentiment of the above thinking seems like it should still be there - just shorter iterations.

Benefits I see with smaller stories...

Less variance

The more things there are involved in a single story the more variance there will be. It just seems that you're more likely to be able to see everything that needs to get done when there's less to do. With a large story it's much more likely that you'll gloss over parts of it thinking of it as one thing, but once you start digging into it you realize there's more to unpack. That's not to say that smaller stories are a cure all of this - we're human and will miss things - it's just trying to help decrease the variance.
I find variance important because it helps with developing a cadence - this ties into morale which I'll touch on later.

Greater understanding of the story

Having multiple conversations around a story allows for repeating the details. This might play into repetition learning, but not every story keeps the same focus. Some need to change as questions are answered or feedback is obtained. I think the greater value is the ability to get your subconscious in on the problem. This isn't always going to pay off, but giving the opportunity for it to surface other connections is important.
Even without either of those in play by having to break things down you're required to get a better understanding of the problem. Maybe even shining a light into some areas that would've been problematic, but you couldn't see until you got to smaller chunks of work.
The biggest counter I have to this thinking is the concern of distracting the team or wasting their time. It certainly wouldn't be appreciated if a stories keep getting shelved after they go through a couple iterations. I also don't think having a handful of stories in this process would be good. Though I've only experienced it with one story and I think that there's room for some experimentation with this.

Faster feedback

Feedback doesn't just come from the end user. It also comes in the form of passing tests, integrated code, and even non-broken code. I completely agree that it is important to keep track of what is important to the end user and releasing something that doesn't provide them with what they want shouldn't be announced. That doesn't mean it shouldn't be released to get what feedback there is for it.
I've met many people who think that Continuous Deployment is a goal worth attaining. At the heart of this is the need for small batches (various articles from: Atlassian, SD Times, SAFe) so that the release is quick and easy to troubleshoot in case of issues. For me this all ties together - Continuous Deployment is just another way to get faster feedback on your code in production.

Morale

How many times have you had a story carry into another sprint and while you knew there were good reasons why it didn't get closed you were just sick of working on it. Yes, you found an interaction that you hadn't considered and it needs to be tested. Yes, it would be better if you refactored it to be more encapsulated. Everything makes sense to your rational mind, but you're just done with it and need a break.
I don't recall having this feeling with small stories. Whenever I've been able to break things down I've felt a greater sense of movement and less dread about the release of the work. I'll concede that your milage may vary and this is really more of a gut feeling - though I know of several people who've lamented the carry over story and how much it stinks.

The flip side...

New story is top priority

While this certainly makes it harder to walk away from and let it simmer, you could just make faster iterations. Maybe visit the story in the morning and revisit in the afternoon or the next day. I don't think this changes the process - just makes it easier to fall back to previous habits. :)

Breaking up (a story) is hard...

When I'm thinking of breaking up a story I want something that can show progress, but not necessarily something that should be turned on for customers. This is something I still feel I require practice at. A flowchart was shared with a couple teams I've been on, but I'll confess to feeling intimidated by it and never giving it a fair shake. A different take is Tracer Bullet Development, which tries framing in the overall architecture and letting the details be filled in later. Another example that I suspect many will find extreme (I haven't tried it, but keep wanting to) is breaking things down to around one hour stories, by focusing on acceptance criteria.
In the end, this really comes down to the fact that to get the work done you need to break it down regardless. You either do it ahead of time with smaller stories or you do it later when you're splitting up the tasks (...or I guess you can even do it later when you're doing the coding). Given the reasons I like smaller stories makes me think I want to figure this out and not back away from it.

Managing the additional stories

This one intimidates me. Having stepped into the Product Owner role once and trying to keep stories small and up to date, I didn't enjoy this. Which, incidentally, is why I've never pushed for one hour stories as I linked to above. The idea of trying to manage that number of stories seemed ridiculous - which makes me think I'm still missing something or making something too complex.
Though, at its heart, this seems more of a tradeoff between managing stories or managing tasks. This seems to be driven because managing tasks is easier than stories - they are often created ad-hoc by the team, where stories are often managed in some application. Maybe it would be good to explore that and consider if there is a way to make things easier to manage?
Another variation on this challenge is stopping a story when it should be stopped. I've had a number of cases where the team gets on a roll and realizes that they forgot to finish a story and the code is now blended with the next one. In some cases this is because the stories aren't well broken down and to be able to release the code it required the additional work. Other times it's excitement or just trying to help out the team by working on the next item. While this isn't against small stories per se, it does create confusion and make people wonder why they shouldn't keep things as one big story to avoid this.

Conclusion

The reality is that not every story needs this type of treatment. Some are straight forward and have little ambiguity that would prevent them from being worked on right away. It's those other ones that require you to be a little more thoughtful on how you get them started.

I'm sure I'm not covering all of the thinking around this topic, but this is what's currently bouncing around my head. Hopefully it will provoke some comments or get me to talk with others about it, so I can continue to challenge my built in preference. 

Friday, August 16, 2019

The Case of the Disappearing Slack Notifications

We happened to notice that slack messages that we were used to getting were no longer showing up. This is a walk through of how they were setup, what we figured out, and what our next steps are.

Getting an app to send slack notifications

To start with you need to configure an Incoming Webhook, the essence of which involves:
  • creating a Slack app
  • getting the app approved
  • enabling Incoming Webhooks
  • then add a webhook by specifying a channel messages are sent to
Next you need to have your app generate a JSON message and post it to the url provided by the webhook. Then, violá, you have a notification in slack from your application.

So why did we stop getting some of our notifications?

We noticed that we no longer were getting notifications when some of or processes failed. We'd get success messages, so we knew some notifications were working fine, just not some of the failures.

What happens when a message is sent to a non-existant webhook?

It seems that slack has several error response. This doesn't help much if the apps aren't expecting this. So this is one thing to improve, but why would a webhook that was working start returning "no_service"?
We have had changes on the team and one notification was put together by an intern working on our team who's account was recently deactivated...

So what happens when your account is deactivated?

Slack provides some details on this, with a small teasing statement:
Apps the members set up may be disabled. You can manage and re-enable these apps if you'd like to reconnect them.
Following the link in that statement, but isn't as precise as we'd like:
...some apps they've installed (whether third-party or custom) will automatically disable. Some features remain active (bot users, slash commands, incoming webhooks, etc.), but apps that require member-specific permissions will disable entriely.
Finally, after a bit more digging some details were found in the Installing apps section of Managing Slack apps. Under the "A pleasant vacation from unexpected uninstallation" it notes how apps will not be automatically uninstalled if they limit their scope, but then it mentions a caveat:
One caveat: this exception doesn't apply to the folks who created an app or were added as an App Collaborator. When they leave, the app is still uninstalled.
So that explains why our notifications went away. Though I'm not sure how to avoid or alert on that.

Maybe collaborators?

My first thought was adding other team members to the collaborators so that more people could do the work, but the previous section implies that it might also delete it. Regardless, that's a stop gap at best.

Maybe notification on deletion?

I'm not sure who manages removing slack users, but I'm curious if it is possible to notify their former team of the apps that will be deactivated?
At least, Admins and Owners of our slack Workspace are able to reenable apps that have been deacivated.  So if we remember who set it up or to ask if anything recently got deactivated after someone has left..

Next steps


  1. Improve the error handling when posting a slack message.
  2. Add alerting if our apps cannot post a slack message (not just a log message).
  3. Follow up with Slack Workspace Admins / Management on:
    1. If they can find apps owned by deactivated users
      • Unfortunately, they can only see the list of deactivated apps in chronological order.
    2. If we can get notified of apps that were deactivated when an account is inactivated.
      • The Slack Admins weren't aware of this process so more digging needs to happen to figure this out.
    3. Also worth asking these questions of Slack if I can find out where to ask them. 

Monday, July 11, 2016

Rearranging Desk to Change Behavior

Recently a coworker made the suggestion that while we talk a lot on our team we could do better.  Sometimes don’t pair as much as we could and end up working in silos.

So he took a look at desk arrangements that were suggested for pairing and proposed arranging our desks in a square.  The purpose be to help with conversations with the people on either side of you.  We talked about it some and there was some concerns with foot room and if we’d be looking at each other, but in the end we all felt it would be worth trying.

So we moved our desks to this:

One of the other things we wanted to explore is a way to pair without needing to bring my laptop and chair around the desks and throw away our ergonomics.  I’d used screenhero in the past, which allowed for sharing the mice and keyboard on shared screens.  Turns out join.me, which is provided for us by our company, has that exact feature.  So we’re hoping to pair using this as a way to help increase communication even while we’re in the same room.

We’re still new to this arrangement, but so far I’ve noticed a distinct improvement in my ability to hear everyone else.



We've made use of join.me a couple times, but getting into isn't as quick or seamless as we'd like.

Friday, April 3, 2015

Concerned with HIP sprints

During our planning I very often hear maintenance or architecture work come up and immediately be deferred with "that's a HIP sprint item."  Ultimately this feels like a cop out.  Granted that's not what the Scaled Agile Framework (SAFe) is going for with it's advocation of them.  It seems more of a place for preparing for a release and dealing with those things that can't be done before hand.

Granted my company is mostly focused on updates to existing applications and adding features to them.  (That's not to say that new things are being developed, just that the number of brand new things is less than existing.)  So while we'll occasionally have those items it seems that should be some stories in your iteration instead of the focus of an entire iteration.  Though even if it took over an iteration - does it need a special name?

I guess it's making me think this is a situation that some teams have found themselves in where they need a HIP sprint and it's being generalized as a rule to help protect others.  In the end I feel it flies in the face of sustainable pace since it gives a dumping ground for things that should be done in each sprint.  Granted we're supposed to have a mix of these items in each sprint already, but it seems the HIP sprint provides the illusion of a crutch to fall back on.  (To be sure - there's some coaching that is needed to ensure that we're not too focused on product development with no regard for keeping the system working.) 

I'm certainly giving short shrift to a topic that has had some thoughtful discussion, but it's something that's currently on my mind.