Daily Learning Notes for July 3rd, 2017

Today I mostly just struggled with anxiety, but I felt better in the evening thanks to coworking with some friends and indulging in a lot of caffeine. I made a little progress on refactoring the mob coding app, cooked some food, and had a nice evening at home – and more late-night coding!

Real-time notes

12:51pm: Starting late today, struggling with a very high level of anxiety today that feels like just a continuation of the panic attack I was starting to have last Friday. Today I can’t even seem to finish a single normal thought without having a negative or overwhelming thought interrupt it, and even though the physical symptoms aren’t too bad right now, I feel this general sense of not being in my own body, like nothing is real. Needless to say, it’s hard to get any work done when in this state, but I’m at the coworking space with some coworking friends around, and I was hoping to treat today like a normal work day. Or at least try. I took a shower here when I arrived at 11am this morning, and I took care of a couple emails and meetup event stuff. I finished up yesterday’s blog post and I’ll post it now. I was hoping to at least make a little progress on the mob coding app before giving up, which I feel like is only a matter of time today… Yesterday I knew I wasn’t ready to start another work week yet, and this morning I felt even less ready. I keep flip-flopping, first telling myself it’s better to try to push through it and treat this as just another opportunity to practice digging into work in response to my anxiety (instead of running away from it), and then telling myself there’s nothing wrong with treating a holiday weekend like an actual holiday weekend. But I know that spending an extra day with my family probably won’t actually make me feel any better.

1:15pm: Still feeling stuck and haven’t taken any steps forward yet, but at least I did find out a friend is planning to stop by this afternoon to get something he left behind on Saturday, and he wanted to hang out and maybe do some pair programming or something. I’m hoping that might cheer me up! But that’s not for a couple more hours. I think I’ll take a quick bathroom break now, and then try again to do a little work, even if that means I need to move upstairs. I feel so agitated though, I’m not sure I’ll be able to sit back down again once I get up. There are lots of distractions here, too.

2:01pm: After a long break just walking around and then meditating for probably 20 minutes while freshening up in the shower room, I am experiencing a brief burst of acceptance and confidence that this feeling will pass. But it’s already fading, just as quickly as it appeared. I’m putting on headphones, since sometimes music helps.

2:35pm: Trying all over again, after being foiled once again by anxiety. I had a bite to eat, which might help. OK, so I published my previous blog posts. I need something small and specific to hold onto, like a little life raft for my brain. If I can lose myself in making something or learning something, that usually is one of the first steps towards feeling like myself again.

I left off on a bunch of questions the other day, and I think yesterday I answered the last one I left off on: which condition should I use for starting the game? I’ll go with checking the list of players, because that just seems more intuitive than using the turn index. It probably doesn’t matter. OK, so that’s one task right there! Maybe I can check my issues on GitHub and update one with these new changes. Oh, I already have an issue for this! And apparently I already decided this before. Well, I guess there’s no reason not to go ahead and make this quick change. Same goes for some of those other small issues. I just can’t seem to keep any thoughts in my mind for very long, so even something this small feels a bit overwhelming right now. But I can go through the motions. First, make a new branch. Then look through my JavaScript to find where I need to make that change. Make a commit. And so on. That should be OK.

2:50pm: Oh, my friend is here now! I didn’t even get to actually start writing any code. Got distracted again. Will jump back in soon.

3:07pm: Back to it! Coworking for a while before we switch to pair programming or collaborating on something new for a while. OK, I updated my project README with the state chart from the other day. I’m really happy with how that diagram turned out! Anyway, now I’m taking care of that quick update.

3:23pm Taking a break to go for a walk with friends to get boba tea and maybe other sugary treats.

4:02pm: Back from a nice walk, and I got another one of those 85 cent sea salt coffee drinks, yummy! This will probably backfire of course since it’s pretty late in the day for me to be drinking coffee. Oh well. I guess this is basically my lunch. Anyway, back to testing out my one or two tiny edits to my code. Uh oh, there’s a new bug! This must have been introduced from some other previous changes. When the last user logs out and the game ends, some variable is undefined and it’s crashing the server. Let’s see…

When there’s only one player in the game, it works fine. Let’s try it again with two players… Oh, it worked fine this time! There must be some specific timing issue happening here. Maybe the turn changed right as the last player disconnected. I’ll add a quick issue for that and worry about it later.

4:34pm: Bug fixed! I did a pull request and everything, which is overkill for such a small change, but at least it’s keeping me organized and on track. Better to work slowly than not at all. Now I’m going to check if another previous bug is still an issue, and I’ll do a quick fix! Yup, this bug is still there and I should be able to fix it simply by initializing Ace Editor to start in read-only mode. Oh yeah, but I need to set when the new client is initialized. Hmm… I need a quick bathroom break first.

4:51pm: I’m back, and I see the problem now: the turnChange event doesn’t fire when the game starts! This problem will be solved by the bigger refactoring work I wanted to do, so I think I’ll scrap my changes and just plan to solve this issue along with a couple others… I’m trying to get this straight in my head….

5:12pm: OK, I updated Issue #16: Simplify the game state data model and events on client and server and merged in issue #5, so now I’m going to refactor the data model and events all in one go! (I’ll still make modular commits, of course!) This will be the main refactoring task that will basically restructure the entire app. I was hoping I could break it up into a few different smaller issues, but then I realized I can’t easily test the changes to one without making changes to the others. May as well do it all in one go. So now I’ll list all the changes in that issue so hopefully I can cover all the bases before I start messing with my code.

5:37pm: Made some progress documenting the changes I want to make. Another friend joined us to do some coworking, so I’m sort of alternating between chatting and looking at their code and then looking at what I was working on. All this caffeine is definitely starting to affect me now. I feel weird! Probably need to eat a proper dinner at some point. Hopefully I don’t start to feel sick. I do want to finish what I started, though! Next step: finish documenting what data should be sent with each event in this new refactored version.

6:45pm: I got into the zone for a while (finally!), but I’m still super indecisive about a few things (even just naming variables). Here’s my initial stab at the new data model for the game state and the new list of events:

Updated mob coding game state data model

{
  nextTurnChangeTimestamp,  // or millisRemaining for clients
  currentPlayerIndex,  // or maybe rename to turnIndex?
  currentGist: {id, url, owner},
  playerList:
    [
      {id, login,avatar_url}, { ... }, { ... }, ...
    ],
  editor:
    {
      editorContent,
      editorCursorAndSelection: { cursor: {column, row}, range: { end: {column, row}, start: {column, row} },
      editorScroll: {scrollLeft, scrollTop}
    }
}

Updated mob coding events list

I do like this table structure much better than my original version! I picked some new event names, too.

Event Name Sent By Sent To Data Description
playerJoined Client Server {login, avatar_url} When new player completes login process
playerJoined Server All other clients {id, login, avatar_url} Update other clients with new player data
gameState Server One client See game state model in section above! Initialize game state for new player that just logged in, and trigger new gist creation if game is just starting!
playerLeft Server All other clients id Update other clients to remove disconnected player
turnChange Server All clients null ??? Trigger clients to change the turn
newGist Client Server {id, url, owner} Broadcast new Gist data
editorTextChange Client Server "current content, just a string!" Broadcast changes to code editor content
editorCursorChange Client Server { cursor: {column, row}, range: { end: {column, row}, start: {column, row} } Broadcast cursor moves or selection changes
editorScrollChange Client Server {scrollLeft, scrollTop} Broadcast changes to code editor content
disconnect Client Server When clients disconnect from server (SocketIO function)
connection Client Server When clients connect to server (SocketIO function)

Next questions:

  • Can I really use the gameState event alone to both update all newly-connected clients and trigger the creation of a new Gist only when the game is just starting? I should be able to just check if the Gist data inside the game state object is null or not, right?

  • Is it OK that I’m recycling the playerJoined event? (Before I was leaning towards “no”, but now I’m leaning towards “yes”!)

  • Should I just structure the player list as an array of objects, or is there something else I can do to make it easier to access a player’s data via their ID?

7:09pm: I’m back after a break and a few distractions, including having a bucket of candy poured down the back of my shirt. (I laughed, but that was still annoying!) Anyway, I’m going to look into that last question a bit more now: is there a better way to basically have an ordered list of objects? Yup, looks like maps might be very useful here!

Notes on JavaScript maps:

  • Unlike objects, the keys of a map can be anything, not just strings!
  • Unlike objects, it’s easy to get the size of a map (so more like an array that way)
  • They’re meant to be used for hash tables I guess?
  • See “ES6 In Depth: Collections” for a nice overview!

7:26pm: Before I dive any farther into learning about maps, I should just test out what my code looks like with a simple array of objects! I could even compare that to my current implementation (an object and a separate array), and then later I could compare them both to a map-based implementation.

7:34pm: I did start on it, but now I’m walking home to go cook a bunch of meat, al pastor style!

8:32pm: Sitting on the couch with my laptop on my lap, meat cooking in the oven, dishes done. Since I still feel really caffeinated and somewhat relieved after having survived a day of unusually high levels of anxiety, I guess I’m in a good mood. And I feel like working on this code some more!

Current player list implementation:

// playerData object:
// { 'socket-id-here': {login: 'username-here', avatar_url: 'user-avatar-url-here'} }

// Separate object (hash table) and array!
var playerData = {};
var playerList = [];
var currentPlayerIndex;

// Add new player: 
playerData[socket.id] = {};
playerData[socket.id].login = userData.login;
playerData[socket.id].avatar_url = userData.avatar_url;
playerList.push(socket.id);

// Remove disconnected player:
delete playerData[socket.id];
playerList.splice( playerList.indexOf(socket.id), 1);

// Check when to start game:
if (playerList.length === 1) { ... }

// Check when to end the game:
if (playerList.length === 0) { ... }

// Double check that this user is allowed to type:
if (socket.id === playerList[currentPlayerIndex]) { ... }

// Get current player data
var currentPlayerId = playerList[currentPlayerIndex];
var currentPlayerName = playerData[currentPlayerId].login;

New implementation using an array of objects:

// playerData object:
// {id: 'socket-id-here', login: 'username-here', avatar_url: 'user-avatar-url-here'} }

// Array of player objects
var playerList = [ { ...}, { ... }, { ... }, ...];
var currentPlayerIndex;

// Add new player: 
playerList.push({id: socket.id, login: userData.login, avatar_url: userData.avatar_url});

// Remove disconnected player:
removePlayer(id, playerList);

function removePlayer (id, playerList) {
    for (var i = 0; i < playerList.length; i++) {
        if (playerList[i].id === id) {
            playerList.splice(i, 1);
        }
    }
}

// Check when to start game:
if (playerList.length === 1) { ... }

// Check when to end the game:
if (playerList.length === 0) { ... }

// Double check that this user is allowed to type:
if (socket.id === playerList[currentPlayerIndex].id) { ... }

// Get current player data
var currentPlayerId = playerList[currentPlayerIndex].id;
var currentPlayerName = playerList[currentPlayerIndex].login;

// Helper functions, just in case:
function getPlayerById(id, playerList){
    for (var i = 0; i < playerList.length; i++) {
        if (playerList[i].id === id) {
            return playerList[i];
        }
    }
}
function getPlayerIndexById(id, playerList) {
    for (var i = 0; i < playerList.length; i++) {
        if (playerList[i].id === id) {
            return i;
        }
    }
}

9:10pm: Took another break, and now I’m stuck on how to remove the recently-disconnected player because I need to access a player by their ID, not by the array index. Everything else is easy, though! I’ll tinker with this in my browser console for a bit. I could use the handy new find method, but I guess I’ll just make a helper function that loops through the array, or I could use the filter method… yeah, I’ll just use a loop.

10:19pm: Had a nice break to eat dinner and watch a bit of TV. I still feel like working on this, but I forget what I was going to do next… I sort of feel like learning more about maps and other collections, but I know that isn’t important right now. I guess maybe I’m ready to start actually refactoring! Not sure why I feel nervous about modifying my code. I’ll make a new branch and start chipping away at it. Wouldn’t it be cool if I finished this tonight? OK, branch made. First step: change the event names, or rewrite the game state?

11:14pm: I did forget a couple small things earlier, like checking if a player exists in the list of players or not. That was easy enough to implement with those helper functions, though! (Now they return -1 if no match was found.) Back to carefully rewriting and copy-pasting and search-and-replacing…

12:14am I guess I’ll try to sleep now. This is a good enough stopping point.

Gathering string