Today I started adding GitHub issues for all my next tasks for the mob coding app, took a long midday break, went for a couple walks, and stayed up late to do a little refactoring.
Real-time notes
10:19am: Despite staying up late and waking up early and then going rock climbing with friends, I’m actually feeling somewhat awake! Still a bit anxious, but also looking forward to jumping back into some fun work. My first task for today: print out my flowchart from yesterday and check if I missed anything. Then I’ll start to make a state diagram for this mob coding app.
10:36pm: I couldn’t stop myself from searching for stuff about state machines, and now I’m watching some of these MATLAB Tech Talks on State Machines for a quick review.
Today I learned about state machines:
-
Mealy state machines define output on transitions, while Moore state machines define output inside each state. (I’m used to Mealy state machines, which are more flexible.)
-
Harel state machines combine aspects of both Mealy and Moore state machines but with more functionality, like creating a hiearchy of state machines that run in parallel and allowing each one to broadcast events to the others.
10:47am: Well, that was fun! I’m going to take a quick break, get a bit more tea, and then review my flowchart to see if it covers everything.
11:10am: That was a nice break. I walked around a bit, did some stretches, got more tea, and shared my flowchart on Twitter to see if it might give me an extra boost of motivation:
Yesterday's nerdy art therapy: flowcharting my mob coding app (https://t.co/WUF62Rv9d4)! Very relaxing. :) Ready to start refactoring now! pic.twitter.com/KfBguxmdgI
— Liz Krane (@LearningNerd) June 27, 2017
11:28am: The flowchart looks all good! Just one minor edit so far: I left out an arrow pointing from the end condition to the start condition (to show that this app can always start up again after it “ends”). Fixing that now. I also noticed one more issue with my code: there’s no server-side verification for the newGistLink
event, so clients could potentially cheat and screw up the game! I’ll have to add that to my list of issues and while I’m at it, I should post those issues on GitHub instead of leaving them scattered throughout my notes. But first, time for the state machine diagram! First question to answer is: what variables make up the state of this application?
11:41am: Reviewed my code and took another quick break. I’m not sure why I decided to use both an array and an object to track information about the players… Oh, that’s right, because arrays are easier to iterate through! I wonder if I can refactor it to just use one data structure that also tracks the order of the players. For example, why didn’t I just create an array of objects? I’m also curious about how I might go about creating a general framework for turn-based systems. Maybe that’s where I’ll start with my state diagram. But first I’ll just make a quick outline of my data model.
Server data model and state
-
playerList: an array of players’ SocketIO IDs
-
playerData: an object containing keys matching each player’s SocketIO ID, which each point to an object containing the player’s username and profile photo URL
-
editorContent: a string of all the text in the shared Ace Editor
-
editorCursorAndSelection: an object containing two nested objects, one with the column and row of the shared cursor (
{column, row}
), and one with the shared selection range object:{ end: {column, row}, start: {column, row} }
-
editorScroll: an object containing the shared scroll position, with properties for
scrollLeft
andscrollTop
-
currentGist: an object containing the ID and URL of the current Gist
-
timerId: the ID for the server’s
setInterval
instance used for the repeating turn timer -
nextTurnChangeTimestamp: an integer for the timestamp of the next turn change, for keeping clients in sync
-
currentPlayerIndex: an integer for the index of the current player, which iterates on each turn, pointing to the corresponding player’s SocketIO ID in the
playerList
array
Client data model and state
-
currentPlayerId: the SocketIO ID of the current player
-
nextPlayerId: the SocketIO ID of the next player
-
animationId: the ID for the client’s timer animation
-
currentGist: an object containing the ID and URL of the current Gist
-
currentAccessToken: the current user’s GitHub access token (this is probably very bad in terms of security!)
-
gistNewlyCreated: a Boolean to check if the Gist was just created, switched to
true
on creation, then switched back tofalse
once the first edit is made (not even sure if I need this at all!) -
turnData: an object containing
{millisRemaining: nextTurnChangeTimestamp - Date.now(), current: {id: currentPlayerId, name: currentPlayerName}, next: {id: nextPlayerId, name: nextPlayerName}, gist: currentGist}
12:01pm: Whew! I think that’s everything. What a mess! Why do I model the game data differently on the client than on the server? Why didn’t I consolidate more of these variables into objects to group things together?
12:56pm: I lost a few notes because of a Windows update (my laptop always seems to crash without warning whenever a new update is pending), but I’ve just been sketching out ideas for state diagrams for both the server and the client and the Gist process itself. All the conditions are encompassed well enough in my previous flowchart for when to create, edit, and fork/edit the Gists, but I still feel like there’s something in this state diagram sketch I just made that isn’t in the flowchart… I just lost my train of thought, though. Here’s the tricky bit: why did I create that condition to check if the Gist was newly created or not? Do I need it? This is driving me crazy right now! I’m pretty sure I don’t need it, but then I don’t know what bug it fixed back when I added it in. Well, time for a lunch break.
…
4:01pm: Back after a lunch break and a trip on the Metro to go to my second therapist appointment, then straight back again. I stopped at the nearby bakery for a sweet treat and an iced matcha latte. I guess I just felt like I deserved a treat! That meeting felt like a waste of time (I already know all about cognitive behavioral therapy!), but I guess maybe it was helpful just to talk to someone about it again and remind myself that all of my work towards developing healthy coping mechanisms for my anxiety are indeed paying off. That’s all I’ll say about that right now, though. I didn’t learn anything new. But I do have some homework: to plan a self-care activity in advance for every single day, write them down, and share them with my therapist at our next meeting in three weeks. I already assign myself similar tasks, but I don’t usually talk about it with other people, so maybe that’s all I need: an accountability buddy. I’ve tried it before but haven’t been proactive about it in a long time. Anyway, so that’s where the last three hours went. Oh, I also just answered a few emails and scheduled my Wednesday night web dev study group meetups for July.
While I was on the subway, I read over some of my previous mob coding notes in this blog and discovered two interesting things. First, the newlyCreatedGist
Boolean was intended to be a temporary solution, according to my notes from April 12, 2017. Second, and more importantly, that solution came about because I had made the incorrect assumption that the decision about whether to fork/edit or only edit a Gist depended on whether or not it was the first turn of the game, but I was so wrong! If the original user disconnects before their turn is over, the Gist would need to be forked by the next player. And if there’s only one player in the game, they would never fork the Gist at all!
That led me to another idea so obvious that I don’t know why I didn’t think of it before: what if I just didn’t change the turn if there’s only one player? I could change the game to have a single-player mode! That would probably simplify the logic quite a bit. But would I lose any functionality? Hmm.
Another thought: in my state machine diagrams, I forgot to write down that the turn change logic depends on the current and next (or previous and current) users, and I need to make it clear in what order the state will change! Bleh, so that’s plenty to think about, except sleepiness is really catching up to me now. Those sugary treats didn’t help, either. I guess it’s time for my siesta, and then maybe a shower too.
…
6:28pm: I napped for longer than I originally intended to, because it just felt so nice! Then I took a shower and had a bite to eat (more of that chicken tikka masala). I feel another surge of anxiety all over again, almost as strong as yesterday, even though nothing new has happened. I’m going to deal with it just like I did last night: by taking a few deep breaths, reminding myself that the feeling is OK and it will go away soon enough, and pushing through it by working on something I’m interested in. If I need to, I’ll go for a long walk in a little while. But first, I’ll try just diving right back in where I left off. First, more sketching! What would the app be like if there was a single-player mode so that the turn didn’t change unless there was more than one player?
6:43pm: I think that might work nicely! I wouldn’t need to change much about the UI (basically just leave stuff blank or put a “waiting for players” message), and it will probably make more sense than to try to implement turn logic for a game with only one user. It does seem a bit silly, I guess.
Changes for single-player mode:
-
Only start the game and the turn timer and initialize client UI if at least two players are logged in.
-
To decide: Create the gist when the second player joins and the timer begins, or create the gist as soon as the first player joins (but don’t make any edits until after the end of the first game turn).
-
UI changes: hide timer, hide current/next player name section, maybe display “waiting for players” message.
I don’t want to make a feature change just yet, though. I’ll do some refactoring first! Not sure what I should do next: sketch out the state machine diagram in Draw.io, or start listing out my refactoring tasks in the GitHub issues? Leaning towards the latter. First I’m going to take another quick break to stretch my legs and get more water.
7:00pm: I actually feel a lot better now. Maybe the anxiety was just a result of grogginess after that nap. Stretching my legs (and arms) felt great! I’m going to listen to some music now and throw up all my GitHub issues.
7:10pm Going to take another walking break with my partner-in-crime here, in search of Danishes.
…
8:23pm: Had a nice walk, looked at yummy sweet treats but didn’t buy anything, had some more chicken tikka masala for dinner (it’s really not very good, but edible), made myself some tea, pushed through another wave of anxiety, answered some messages, and now I’m back. I moved downstairs because a group of tipsy late-night coworkers were distracting. OK, back to GitHub! I made a milestone and a couple labels and opened up some browser tabs with my previous notes. Time to pull out all those ideas and organize them a bit.
9:37pm: Made some progress, then took a break to chat with a friend who happened to be here for a tech meetup tonight. He just ran an unconference called Sustain, “a one day conference for open source sustainers” that was hosted by GitHub and apparently was a huge success! Sounds cool! Anyway, back to documenting all my issues in GitHub.
10:00pm: Yay, finished! All the tasks from my recent notes are now in GitHub issues, organized in a somewhat coherent way and organized with those nice little color-coded labels. (I’ll admit it: I even spent a few minutes searching for just the right shade of purple for the “research” label, since I didn’t like GitHub’s default purple.) I guess I’ll start on the refactoring tasks now! The simplest one is to just rename some events and functions. First I’ll take a quick break, though.
10:42pm: Not sure how that break took so long, but I took some free leftover food from the meetup that was here tonight and then I got lost in thought while taking a bathroom break. More anxious thoughts. Anyway, I’m back again. Oh yeah, I found out how to automatically close GitHub issues from commit messages and you can apparently close GitHub issues from pull requests too! OK, so what should I name these events and functions…
10:57pm: A bit distracted, but I did a search-and-replace and settled on these new event names: editorTextChange
, editorScrollChange
, and editorCursorChange
. I even practiced using Vim to create a longer commit message, and it’s beautiful! Now for those badly-named functions…
11:11pm: I settled on these wordy but descriptive function names: handleLocalEditorTextChange
, handleServerEditorTextChange
, handleLocalEditorCursorChange
, etc. I made a couple more notes in the issue for other things to rename. More search-and-replace action!
11:28pm: I also renamed the loggedIn
event to userLogin
in keeping with my convention to name events as noun phrases, and I renamed the createNewGist
function to handleCreateNewGist
in keeping with the other event handlers. I also looked up and learned how to change the message for a commit older than the most recent commit with interactive rebasing! In order to do that, I also had to relearn how to stash my unstaged changes and apply them again afterwards.
11:47pm: While editing the flowchart to reflect the new names, I found another mistake: right now it looks like the server only emits updateState
and playerListChange
when initializing the game, but that isn’t accurate! I’ll just draw another line to reflect that. Much better! Now I’ll update the list of events and finally put it in the project repo where it belongs.
12:05am: Done! I even used this trick to move commits to a new branch since I forgot to create a new branch! I created a pull request for myself, noted the issue it closed, and GitHub did indeed automatically close the issue for me! So cool! OK, now before I make some final changes to the README and upload the new flowchart, I want to make one more change that will affect how it looks: simplifying the code for determining when to fork/edit a Gist!
12:26am: I didn’t get to actually start on that next task yet, but now is probably a good time to walk back home. I’ll pick up from here in the morning. I feel like I didn’t get much done, but at least I did something and my anxiety went away again, thankfully. If nothing else, at least I’m practicing this habit of sticking it out and proving to myself that anxiety doesn’t have to stop me from working towards me goals, and hopefully my brain will eventually develop some new connections to reinforce that habit and break my old habits of running away from things whenever anxiety returns. Anyway, this is a good stoppinig point.
Gathering string
-
Project idea: create a general framework for turn-based systems, especially for real-time collaborative games, since they all must have some common issues!
-
Coding class research: Saw a good idea from another organization that teaches paid programming workshops: anyone who pays for their weekend workshop can repeat the class for free up to five times (though priority goes to first-time students)
-
Follow up with my friend Justin who organized the Sustain unconference, because he’s great at connecting people and finding sponsors for events, and we both love the unconference philosophy. (The website for his event says “No keynotes, expo halls or talks. Only discussions about how to get more resources to support digital infrastructure.”)