Today I finally returned to my mob coding app (for real this time!), reviewing my code and organizing my notes. It was a slow day, but I did enjoy a couple interesting conversations, a free lunch, and a late night celebration!
10:00am: Starting late today since I slept in a bit late, and then I had a nice conversation with a friend at the coworking space, and then I added some more notes to yesterday’s blog post. I also read some stuff online and discussed these links on Slack: “How to Write a Git Commit Message” by Chris Beams and “When to Make a Git Commit” by Jason McCreary. Time for a quick break and then I hope to focus on my mob coding app for the rest of the day, with just a short break at 12pm to take care of some emails.
10:37am: Well that was a long break. Oops! I got distracted by the internet and by people in meatspace. OK, so I opened up the GitHub repo for my mob coding app and two things jump out at me: 1) the description could be much better, and 2) I have way too many notes in the README file that should be their own blog posts! I think I’ll take care of that first and move those notes to posts in this blog.
10:59am: Much better! Now I have a project log in the README file with key milestones listed for each day that I worked on the project, with links to my blog posts for more detailed notes.
11:20am: Following the breadcrumbs to see when I last worked on this project and when I introduced those bugs that I discovered last week on June 14th while at the web dev study group. I know I’ve seen some of those bugs before, but I never wrote about it in my blog post! On GitHub and on my local copy of the project, my last commit was made on April 13th. I’m going to check my other branches both locally and on GitHub to see if I made more changes elsewhere.
11:32am: OK, I cannot for the life of me figure out where these bugs were introduced! The only thing I can think of now is that they were already there, but for some reason they didn’t appear in my previous local tests or my live user tests. Now it’s time to dig in and do some bug hunting. First, I’ll try running the app locally again and try to replicate some the bugs.
11:42am: Oh great, now my internet connection isn’t working! Bleh!
11:46am: Bug found: “Uncaught TypeError: Cannot read property ‘url’ of undefined” at line 527 of local.js
, and it only occurs the first time that updateCurrentGistView
runs – in other words, when creating the initial Gist, something is causing an error! Maybe I’m trying to display the gist link before it’s had a chance to be created? Interesting. I can’t seem to replicate the other bug I saw on Cloud9 where the access token is initially undefined, but it works if I then remove the URL params and refresh the page. How weird! That didn’t happen on Heroku either. Oh, I have an idea! If I update my dependencies on my local copy of the project, maybe then I can replicate the bug.
11:58am: Well, running npm install
didn’t do anything so maybe my dependencies are all up to date. But I did discover a new bug: my post-install script creates a .env
file that overwrites the existing .env
file! That’s not what I want! I should be able to just throw in another if statement to fix it. Let’s see… Looks like I could use the fs.access()
method to check if a file exists, but I shouldn’t because it could lead to a possible race condition. Instead, this answer on StackOverflow points out that fs.writeFile
has a 'wx'
flag: “Like 'w'
but fails if path exists.” But I was using fs.createWriteStream
so I wonder if that has the same flag… Nope, no luck. Back to searching.
12:15pm: I found this alternate solution and I’m going to test it in a minute. First, I need to send out a couple quick emails!
12:31pm: I just heard there’s free lunch at a lunch-and-learn event. Oh, I should totally try hosting a few of those with Learn Teach Code! Why didn’t I think of that before?
…
1:14pm: Back from lunch. That was delicious! OK, now I’m looking into that code again…
1:29pm: Had a couple short interruptions. Now I’m back, for real this time! I checked the documentation and learned a couple new things. First, fs.open
does indeed create a new file if the specified path doesn’t exist. And it does accept the 'wx'
flag. I also learned that fd
in the code example I found stands for file descriptor, which is used by all sorts of file-reading and file-writing things! That’s what links the fs.open
call to the fs.createWriteStream
call, because it seems to contain lots of information about the file that’s currently being accessed.
Side note: I’d like to try making it a habit to start each day by reviewing my notes from the previous day and maybe writing a summary of key lessons learned and stuff like that, so they don’t get buried in my real-time notes. It’s harder to structure my notes while I’m writing them, but after a day of setting it aside and then looking at it with a fresh perspective, it’s easier to summarize what I learned!
OK, I fixed up the code to work with my particular use case. Let’s test it!
1:34pm: It works! It no longer overwrites my .env
file if it already exists. Now, before I try deleting it and running my script again, I want to retrieve the previous version of the file that I had accidentally overwritten. Oh wait, I can’t! Because the .env
file is listed in .gitignore
so I don’t accidentally publish my private keys! Good to know it works, haha. Well, I can just get that info from GitHub again or generate a new key if needed. OK, I’ll delete my .env
file and test the script again… It works! Phew!
1:49pm: I ran npm update
and that did indeed update a couple of my dependencies. Now I have express version 4.15.3 and socket.io version 1.7.4. Another package called debug, which is being used by something called finalhandler, was updated to version 2.6.3. Time to test the app again and see if that replicates the bug.
1:57pm: Still don’t see that bug! Oh well, I’ll just focus on the main bug with the gist creation code. I’m not sure what I need to do next, though! Oh right, I was going to draw or write down some kind of flowchart to try to visualize what’s happening within my app. Eh, first I need some coffee and a quick break to wake myself up.
2:07pm: First I need to send some more emails for some meetup stuff, before I forget!
2:19pm: Done with that. Before I forget, I’ll create a category in my Jekyll blog for the mob coding project so I can better organize all of my associated notes.
2:40pm: Done. Now, time for that break! My legs are falling asleep. Bleh, I’m frustrated at how quickly the day is passing by. Oh well. I can stay up late tonight if I feel like working more.
…
3:00pm: Back for more! With coffee! Except I just noticed my personal website is down. Is my SSL certificate no longer work? It worked earlier today! I already shared one of my recent blog posts on Twitter! Hmm. I tried searching for some clues, but no luck. I give up for now. Back to the mob coding app! I’m sketching out the lifecycle of each game, one version for a high-level overview and another version for more details. I guess I should have a sketch for each event loop that could occur. In the most detailed version, I’d like to have a sketch of every method call and when it should happen.
3:31pm: I reviewed a bunch of my notes and now I feel like I’ve finally loaded most of this stuff back into my working memory. I’m going to start with repurposing/rewriting my list of steps for the GitHub authentication flow, based on my notes from
User login flow
-
Client connects to server and establishes a WebSocket connection. (Note: for now, client generates initial GitHub login link after getting the app’s client ID from my server via AJAX.)
-
User clicks login link, gets redirected to GitHub, and accepts permissions to authorize the app.
-
GitHub redirects user to
/github-auth
route with a temporary code as a URL parameter. -
Server makes a POST request to GitHub to exchange that temporary code (along with the client ID and client secret) for an access token.
-
Upon receiving GitHub’s response, my server redirects the client back to the app homepage with the access token. (Note: first I implemented this using a URL parameter, which is bad! I’ll send the auth token as a header instead, or just handle all API calls from the server.)
- As soon as the client hits the homepage again, if the access token is present, the client:
- saves the access token locally (currently just as a global variable for now, even though that’s probably bad!)
- and makes an AJAX request to GitHub to get their username and profile photo.
- Upon recieving the response from GitHub, the client:
- updates the views to show their username and profile photo
- and emits the “loggedIn” event to pass the GitHub user data to the server.
- Upon receiving the “loggedIn” event, the server:
- starts the game if this is the first user to connect since the last game ended (see separate flowchart/list for game lifecycle!),
- adds the user’s data to its list of current players,
- sends the current game state to the new user,
- and sends events to update every connected client.
Game lifecycle
- Game starts when first user logs in if the list of players is empty. (See user login flow above for login process details!) When the game starts, the server:
- Starts the turn timer
- Adds the user’s data to list of current players
- Sends the current game state to the new user
-
List of current players is updated every time a user logs in or disconnects and turn changes are controlled by the server’s timer.
- Game ends when last user logs out and list of players is empty again. When the game ends:
- Removes the user’s data from the list of current players
- Server turns off the turn timer
Gist creation and forking
-
Create new gist as soon as the game starts, on behalf of the first player.
-
Once the gist has been successfully created, broadcast its URL to all (other) clients to update their views.
-
At the end of every turn, if the player has changed since the previous turn, then fork and edit the gist on behalf of the player whose turn just ended. Otherwise, just edit the gist on behalf of that player.
-
Every time the gist has been forked (but not if it’s only been edited!), broadcast the new URL to all (other) clients to update their views.
3:59pm: Time to meet with my friend to talk about tech nonprofits for a little while!
…
5:00pm: Back at my computer. That was a good brainstorming session! This friend is currently in the process of forming a nonprofit organization, which is something I’m very much interested in, so I need to remember to check back in later for some advice. For now though, back to this mob coding app! Maybe I should just make a comprehensive list of all my functions and events to get an idea of what I’m dealing with here.
5:13pm: I think I need to format the list of events in a table, so first I need to figure out how to create a table in Markdown! But this should pay off later. Here’s the Kramdown tables quick reference and then here’s more details on tables in Kramdown with some more examples. Time to test it! OK, looks good. Time to review all the events in my app and describe them all…
5:34pm: Well, I got a decent start on it. Time to stop at the bank and then walk over to the other coworking space to host tonight’s web dev study group again!
…
9:52pm: The meetup tonight was fun, very chatty. I just helped a few people out with some general questions and website setup type stuff, no actual coding. But I got to catch up with a couple friends who I hadn’t seen in a long time, and I met some cool new people and saw a couple interesting project demos. It was a nice break, too! Now I’m back at my usual coworking space, hanging out with friends. A big moment awaits, but it’s a secret right now! (And I’m not about to spoil someone else’s secret. Suffice it to say, I’m very excited for them!) Anyway, I had a quick snack and now I’m going to pick up where I left off, reviewing my code and adding onto a table of all events, what they do, and what methods they’re all triggering.
10:12pm: I’m not sure if it’s because I’m tired and hungry, or because I just didn’t think this through, but I’m realizing that Markdown tables will not work here! The raw text is unreadable because the lines are too long. I may as well just use HTML here! I think I will. I’m also realizing that there isn’t any clear one-to-one mapping of events and the actions that follow from each, because there’s all this other logic too! Maybe that just means my code is messy and needs more functions. Maybe I should start with the flowchart of this entire mess before I try to condense it into a nice clean table.
Wrapping up: Well, I didn’t get any more work done tonight, but my partner-in-crime and his partner-in-crime just launched their first product for their startup company! We all watched while the app deployed to the Ethereum Mainnet, messages streaming all hacker-like in the terminal window (tmux, specifically!). We all took some video and photos and were being all silly. Anyway, then we went out to an all-you-can-eat Korean BBQ and got a little drunk on soju and didn’t get back home until almost 2am.