Thursday, May 14, 2020

Declaring a TArray parameter in a BlueprintImplementableEvent

After a long day of programming in UE4, I ran into a problem that caused me quite a headache. I have a custom PlayerController subclass in a project I'm working on, and I wanted to add a method to trigger the need for the player to choose from among a list of options. The method should look something like this:
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
void ChooseFrom(TArray<UScenarioAction*> Actions);

I spent too long hitting my head against the resulting error message, which looks like this:
'void AMyPlayerController::ChooseFrom(const TArray<UScenarioAction *,FDefaultAllocator> &)': overloaded member function not found in 'AMyPlayerController'

This should work: I just want a function stub that the blueprint subclass implements. I tried every conceivable combination of annotations to the UPROPERTY and tried adding empty implementations in the cpp file, knowing that there really should be nothing wrong with the code.
It wasn't until I sat on the couch in the living room that I thought that the problem might be the parameter. Sure enough, if I took out the TArray parameter, everything worked as expected. I little poking around the web inspired me to try passing the array by constant reference:
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
    void ChooseFrom(const TArray<UScenarioAction*>& Actions);

Sure enough, that did the trick. This seems like a place where the compiler could give a much friendlier message; there's nothing about the message it provides that makes me think that the parameter needs modification.
Hopefully writing this quick note on my blog will help save someone else an hour's aggravation—even if that someone is just future-me.

Monday, May 11, 2020

Post-semester thoughts on new CS222 achievements: incentivize good behavior

Since the semester ended and I wrote up my thoughts on Spring's CS222 course, I have had a few passing ideas about how I could use the achievement system to reward virtuous behavior. These can all be categorized as things that I think students should be doing, but evidence (and my memory of being a student) tells me that they are not doing. The main idea here is to give students credit for deploying the techniques that are taught in class but that are not otherwise directly assessed. The names and descriptions are unedited drafts, but they are enough for me to leave a mark for future self next time I teach the course.

  • First Responder: Consider the instructor's feedback given to you on the first iteration of the final project. Pick a part of it that you do not understand after having discussed it with your team and respond to it, by either emailing or meeting with the instructor. Once you have resolved the feedback, write a paragraph or two to share the experience with your classmates.*
  • Code Reviewer: Conduct a formal code review of your project following the format introduced in class. Submit a summary of who took which roles, when and where the review was conducted, the checklist you used, and the resulting artifacts such as a list of potential defects.
  • Yes, I Am a Model: Do a CRC analysis of your final project at the beginning of the second or third iteration. Compare and contrast this against the initial one developed for the first iteration.

I would be remiss not to acknowledge a perennial difference of opinion that my respected colleague David Largent and I have had about a particular CS222 achievement: his Re-reader achievement, which a student can earn by re-reading a portion of the textbook after it was already assigned. I've pushed back against this, arguing that of course the students have to be going back to the textbook in order to succeed. Dave's point, I think, has been that the system can incentivize the behaviors we want of them. So, ... thanks, David—I'll probably add that one next time, too.

I'm not assigned to teach CS222 in the Fall, so now I just need to remember to read my blog next time I am assigned it.

* Note that this achievement makes it clear that not all the feedback given on an assignment is of the same grain. Some of it will be small and actionable; some of it will push students to having to learn new things that are specific to their project or their implementation.

Sunday, May 10, 2020

Something like a Summer DevLog, Part 2: Gameplay Ability Systems and Me

After tinkering with simple burndown charts for the Web, I found myself thinking about whether and what kind of game I could make over the summer. I was inspired by A Short Hike recently. It was a freebie from Epic Games Store, and I played it to see if it would be appropriate for my kids. I was surprised at how it pulled me in. After finishing it, a GDC video was posted about it, and the original release of the game was made in only three months. There's an inspiration! Of course, as with Kaiju Kaboom, I don't think I can afford a success, so my exploration will likely be more academic, in the good sense of the word.

I have been intrigued by Unreal Engine's Gameplay Abilities System (GAS) since watching a livestream about it over a year ago. It sounded fascinating, and at the same time, the dearth of scaffolded instruction gave it a sort of mystic air, like some arcane wisdom that's just out of reach. Several times, I glanced through some docs or watched a video and thought, "That sounds really interesting," but it never fit what I was trying to accomplish. Enter the summer, and I'm thinking about some of the digital RPG bugs that have been crawling around my head for years. Could the Gameplay Ability System be the kind of technology that, if I invested in learning it, would reap the benefits of faster iteration times, or would it be a sunk cost?

Let me take a step back for a moment and explain briefly why GAS is interesting to me from a scholarly point of view. I've been studying games, design, and patterns for around fifteen years now. It's certainly the case that traditional OO design patterns can be applied, as explained in Bob Nystrom's amazing book that I wish I had written. There are also patterns specific to games, including such fundamentals as the main game loop. Game engines provide solutions to stock problems like loading assets, rendering, networking, and accessing the operating system; there is a sense in which these building blocks are also patterns. Beyond that, though, there always seemed to me to be something of a grey area in game development. That is, there seemed to be a point where there likely were patterns, but in practice, it seemed like each thing had to be built anew each time, in contrast with what the engines generally provided. GAS, then, is intriguing because it is an engine's attempt to grasp at this ephemeral thing of game design. I think this, fundamentally, is why GAS is so hard to learn, as every presentation and document I've seen about it echoes. It's a much bigger thing than, say, an Observer or a Builder. Perhaps it's a reification of an architectural pattern, but one that has not been widely grasped, from what I can tell. (Caveat: There are limits to my professional network here, and if there's a community of practitioners already addressing this, I'm outside of it. Perhaps, at some point, when I get my head more around GAS, I will reach out to the engineers at Epic and see if we can have a more serious conversation about any of this.)

Bringing it back to my summer project, I spent around a week oscillating between a few different states. First, I would excited explore some aspect of GAS, get it barely working, and then get excited about using it. Then, I would think that GAS is overkill and that I should just write the minimal system that gives me what I want so I can determine if the project itself is worth pursuing. Then, I would realize that my hand-written approach was so inspired by what I had just read about GAS that I should buckle down and use it. Wash, rinse, repeat.

As I repeated this process, I was able to find the absolute best resource for learning GAS: Dan Kestranek's GASDocumentation project. After finding that, I only rarely had to go look for supplemental information from other sources. Matt Edmond's talk from Unreal Fest Europe 2019 is also good for approaching the concepts and business case, but it's Kestranek's work that really gives you the details you need to build something from scratch.

My experience last week was complicated by the fact that I didn't really know what I was building: I was doing feasibility analysis but only for ideas that were in my imagination. At first, I was thinking of my project as a tech demo for a single-player computer RPG with deckbuilding mechanisms. There are some great inspirations in this area, including of course Slay the Spire and Griftlands, which is technically still in alpha but which I bought and thoroughly enjoyed. Both of these take a tabletop mechanism and wrap it in some ideas that are only possible in digital, especially Griftlands' use of cards that gain experience and level up. 

As I kept tinkering and oscillating, I found myself reflecting on the positive experience my boys and I have been having with For the King and comparing that to some of the cooperative board games we have played. This caught my fancy, so by the end of last week, I had a tech demo built of a four-player cooperative game that runs on my Steam Link. It's really raw, but it shows how each player is connected to its own controller, which each separately control a UMG-driven action menu, and the actions themselves have cooldowns that are shown in progress bars. You can't even really "play" it, but it all the pieces are in place to be able to explore this direction.

I did encounter something strange that I will share here, in part so that I can remember it later. When my son and I made Disarmed for Global Game Jam 2020, we had local multiplayer working fine on a Windows PC, but when we tried running it on the Steam Link at home, it did not work at all. I am not entirely sure why it doesn't work, but even more strangely, with a slightly different approach, I was able to get last week's tech demo working. When the game starts up, in the default game mode, my tech demo creates four players using the Create Player node. Then, it finds the Player Start on the map with corresponding Player Start Tag that corresponds to the player number, spawns a pawn, grabs the Player Controller with that index, and possesses the pawn. The only major difference I can see between this and Disarmed is that in the tech demo, the game mode has no default pawn class specified but creates them manually, whereas in Disarmed, we rely on the default pawn class specified in the game mode. I have not (yet?) gone back into Disarmed to see if this change would make it work, but I was delighted to get my tech demo working in my living room, even though testing it took several runs up and down the stairs.

My next step is to more seriously sketch the design of the game project itself. Over the weekend, I've been reading rulebooks and online threads and talking to a limited number of people about what I'm trying to do. I started writing some notes in an old notebook, though they are pretty haphazard. This coming week, I want to try to organize them to more carefully articulate some design goals, then see if I can turn my tech demo into a minimally playable game. I was thinking also about throwing together a one-man project for the seasonal Epic Jam, in which I have never participated, but it looks like the Spring one has been postponed.

Saturday, May 9, 2020

Something like a Summer Devlog, Part 1: Exploring simple burndown charts for the Web

The past two weeks, I have had the freedom to explore some new territory, and it seemed like a good idea to try to leave some notes about it. Two weeks ago was finals week, during which time I could work on my own explorations between grading and report-writing; this past week had me wrapping up the last loose ends from the Spring semester while taking some deep dives. What I'll do in this post is write about what I was working on two weeks ago, since I made a significant pivot in my attention around last weekend.

I wrote about how my CS490 students did not use burndown charts as effectively as I would have liked, but how there was also no easy tools I could put into their hands to do them the way that I prefer. I started looking into building something myself. My first thought was to go back to my staple for Web development, lit-html and the PWA Starter Kit that uses it. I was surprised to see that the PWA Starter Kit has been discontinued, but the authors suggested trying open-wc, which I did. It's an impressive project, and exploring this got me looking into several other interesting pieces, especially Storybook for testing web components. I suspect that, once we get to summer's Fall Course Planning phase, I'll turn back to open-wc as a new generator for my course sites.

The major complication of a web-component-based burndown chart generator was the unexpected complexity of handling dates and times. The Javascript Date object works as expected, but there is no standard widget for reading a date from the user. Vaadin has a nice one, but I was surprised that the Material design component developer documentation is still only "planned". The documentation for the "date" type for the standard HTML input element says, basically, don't use it. None of this was a showstopper of course, but also, none of it was fun. Using Vaadin's input component, I built a minimum working prototype that draws a steady line using the web component version of Google's chart API.

Around this time, something inspired me to check again whether Flutter had incorporated their HTML5 support. It's been on my radar for a while, but last I checked, Web support was being developed while Android and iOS were the clear "real" targets. As of last week, you could do HTML5 output with Flutter through the beta channel, so I decided to check this out as well. I was impressed by how tight all the tooling worked together, but unfortunately I ran into a problems with hot reload working on Linux. Again, on the flip side, the tooling made it painless to get everything set up again on Windows, although I much prefer to develop in Linux. I enjoyed tinkering with Flutter, and there are some nice aspects to the Dart language. I was also able to make a minimum working demo for the Web in Flutter of a burndown chart with a steady line and sample data using the charts_flutter library.

In both cases, I was able to get demos up and running very quickly. Both were just technology demos though: I did not put any real thought into the UI design, just assembling pieces to understand how they would work together. I feel like I got out of this project everything I needed for now, since there's no imminent need for something that makes simple burndown charts. I may return to this project later in the summer, or even in the semester as a teaching and service project, but I set them aside at the end of last week so I could turn toward some game development ideas. That's a topic for another time.

Sunday, May 3, 2020

Family Painting: Arcadia Quest - Riders

In March, I wrote about how much fun my family had painting Arcadia Quest. We had so much fun, in fact, that when I found the Riders expansion on sale, I jumped on it. This set contains several miniatures in conventional scale, but its raison d'etre is really the giant mounts. One of the first challenges I faced, then, was how to prime, paint, and varnish these without handling them? Unlike the other figures, the mounts have no bases that could just be easily glued to a cork or a block.

Looking around the Web, I came across a post that showed how a painter had pinned his figure to some kind of block. This seemed to me to be the best way to go, so I looked around for something to use as a handle. I had a spare square of exercise mat foam that my son and I had prepped to be used as Frostgrave terrain years ago, but we stopped playing that game before making the scenery. Unbelievably, no one had tossed it in the interim, so I cut out a chunk to try. I stuck a paperclip into it, but it didn't hold fast until I superglued it into place. I proceeded to drill holes in the figures and secure both ends of the pin with a dot of superglue. This worked well, being surprisingly steady. I did try to splay out the pins slightly so that the angle would give a little extra strength, but I didn't have an orthogonal test model to verify whether this helped.

Mounting Mounts
Mounted Mounts after zenithal prime
After deliberation and consideration, we decided that my two older boys and I would each paint two mounts, we three would split the heroes and big bad, and each member of the family would paint one of the jacklols. A lot of this set then was done in evening painting sessions with the big boys while my wife sat with us and worked on other crafts. 

We started with the trio of BawkBawk, Luda, and Tianlong. The boys picked theirs first, and I took BawkBawk not because I was particularly excited to paint it. Rather, I knew that yellow was a tricky color to paint, and I figured I was most prepared for the challenge. I took the following WIP image after spending the first night just trying to get the yellows in place. I think there's three coats of just the base color there, and then I used two-brush blending to layer in the shadows and then the highlights. I'm really happy with the result. Maybe it's kind of silly to spend this much time on a knock-off chocobo, but hey, it's a hobby.

BawkBawk WIP after the first painting session
Here are the finished first trio:
BawkBawk, Tianlong, and Luda
These are in descending age order by painter. After the first night, we talked about our progress and I gave them some advice on how to proceed. In both cases, I was really encouraging them to increase the contrast. Luda—who is a little washed out in that picture—was essentially all one tone originally. I showed #2 Son how to thin out some shade and paint it into the recesses, and it looks a lot better. I think #1 Son knocked Tianlong out of the park. Notice the spot of white he put into the eyes to make them look reflective: that's a pro move from a 13-year-old.

Here is the second set of mounts:
Beka, Toshi, and Hornsteady
These are also in descending age order by painter. I had been kind of excited to paint Hornsteady for a similar reason to my interest in BawkBawk: it's basically all armor with very little sculpted detail, and that seemed like an interesting painting challenge. However, #2 Son decided that was the one for him. Fortunately, #1 Son took Toshi, which was the only one I was really uninterested in.

Once again, we painted in two nights, and they checked in with me after the first night. And, once again, I encouraged contrast. Like Luda before him, Hornsteady was basically all one tone: silver paint over the whole thing. We talked again about thinning out shades and painting them into the recesses. After that, Hornsteady was much improved, and accenting the contrast on Toshi helped make him more visually interesting as well.

I am actually really proud of Beka, which is kind of silly, because it's some kind of battle owl in a bra. Why is it wearing a bra? To have a "feminine" mount? Do they know that birds are not mammals? One of my sons pointed out that what I described as a bra could actually be goggles that are hung around the neck. I suppose that's possible, but if so, the goggles wouldn't work at all: they are not shaped to Beka's head, nor is there a cutout for the beak. End rant.

The point is, I'm proud of the work I did on the feathers. I think I got a nice slightly-brown grey tone, similar to what one would find on a real bird. Mostly, I am proud of the texture on the wings. Unlike BawkBawk's smooth shading, I used brushtrokes to imply a texture that's not sculpted in, and I think it really sells. The spots I added are much smaller than the ones in the card art, and of course I was afraid to go in and drop spots over something I was so happy with, but these too turned out well.

For reference, and because it is my blog after all, here are the two I did, next to each other.
BawkBawk and Beka: The Mounts I Painted
I was not eager to paint Malkhor, the Big Bad, but #1 Son said he would do it. Let's look at him next.
Makhor, front 
Malkhor, Back

I think he did a great job with this one. He got some nice shade into the muscles to help them stand out. You can see some of the transitions on the cape, but that's OK: a nigh-featureless cape that large is hard to paint, and it shows his progression in the use of blending. Keep in mind that, as before, we're just using the Vallejo Basic Colors, so no fancy glaze mediums or anything like that.

Meanwhile, #2 Son and I worked on the two heroes from this expansion: Gaston and Colette.
Gaston and Colette
I was excited to try my hand at Gaston, following the theme of "Let's try painting some challenging colors." I worked on practically just the black and white during our first painting session, while my son nearly finished Colette. She was looking pretty stark, in solid whites and blacks. In the next session though, he did some much nicer work adding greys to highlight the black and shade the white. I think he did a nice job with this. Also, it's an easy detail to miss, but I think he did a nice job on the scarf.

Here are a few more close-ups of Gaston:
No one fronts like Gaston

Faces back like Gaston
The big chunky tail was tricky to paint around, but I am happy with how it turned out. Normally, I take an inside-out approach—painting the skin, then the lowest layer of clothes, and working outward. With him, this was tricky, because the colors of his fur are the same in the innermost levels like his arms and the outermost level of his tail. I am happy with how the blends came together. As usual, I copied the colors from the card art, and I think the artist did a good job accenting the black, white, and browns with bursts of saturated red, green, and orange.

 As I mentioned above, I find myself generally turning to two-brush blending these days, starting with a mid color, painting in shades, and then adding highlights. I like being able to see the basic colors in place before shading and highlighting, and this has been working for me better than starting with the shade layers like I used to.

Finally, we get to the whole family painting part: Jacklols! In truth, I thought they were "Jackols" and wondered why my son was pronouncing it so strangely, until I read the card name more carefully.

Jacklols, just lolling around
Each member of the family got one, and the photo shows them in increasing order by painter age. My wife and I spent the longest on ours, and by the end, we both felt the palette was a bit dull. Still, it was a good place to practice some fundamental techniques.

This is a good place to mention the strange lighting in the cards. Here's an image from the Kickstarter campaign:
Jacklol Cart Art
Notice how they all have a sort of magenta backlighting whose impact varies a bit depending on which background is used for the figure. Indeed, the other art has this design as well, which I think contributes to different interpretations of figures like Beka: I saw it as a grey owl with reddish light, while others have seen it as brown or red itself. In any case, it was interesting to hear how my boys were surprised at #3 Son's interpretation of the Jacklol fur as being pink. My wife and I agreed that this was a reasonable interpretation of the art. Whether #4 Son really thought the armor should be reddish-purple—or if that's just what the five-year-old ended up with on his palette—is lost to history. In any case, they give us a nice bit of variation on the table. Indeed, it is a variation that has me eyeballing my boxes of unpainted Massive Darkness mobs.

Here are some close-ups of my Jacklol:
Jacklol, out of clever caption ideas

Jacklol turning his backlol on us
It's kind of a combination of smooth blending of light colors as an BawkBawk with the random dark spots of Beka. I thought I had finished all the fur when one of my sons commented about the "eyebrows" on his own miniature, that he had thought they were part of the helmet. I had done the same thing, and fortunately, my fur colors were still wet, so I could go in and add the eyebrows. Truly, the eyebrows-over-helmet design adds a lot of life to what would otherwise be a less interesting face.

That's all for today's painting write-up. Thanks for coming along!

Wednesday, April 29, 2020

Reflection on teaching CS222 in Spring 2020

The most shocking thing about this past semester's CS222 class was how very normal it was. Just after the first iteration of the final project, campus closed down, but the overall arc of the semester was the same as it usually is.

I used the first three weeks to get the students started in Clean Code, TDD, and OOP as I usually do, transitioning into the two-week project from there. The one wrinkle in this plan was that the person teaching the prerequisite course did not introduce any GUI programming, which I didn't know until the third week of the semester or so. I expected them to have some exposure to it, and I thought about pulling back on some of the two-week project requirements. After reviewing them, though, and knowing how the purpose of the two-week project is more about setting them up for the final project than anything else, I decided to keep it as-is.

Their lack of GUI experience did not end up being insurmountable for such a simple project as the two-week project. The bigger impediment was that I started with the assumption that we would use GSON to parse some JSON data, but the JSON data we were getting from Wikipedia was arduous to parse in this way. It wasn't until near the end of the two-week project that I discovered and tinkered with JsonPath and found it much more fit for purpose. I need to remember, if I do a project like this again, to use JsonPath from the beginning.

Right after the two-week project, teams formed around four project ideas: a D&D character generator, a simple card game, and two variations on comparing data about professional NBA basketball players. RPG character creation tools show up periodically in the class, but I never really engaged this group with one of my favorite issues: the philosophy of character generation. Like every other team, they made something with no real soul, as far as I am concerned. It's not that the idea was bad: their killer feature was that the program filled out a PDF for you to print in the end. It's just that I find this kind of thing uninteresting from a design point of view. It was odd to have two separate groups doing NBA data analysis, but this was convenient for sharing tips between teams. The card game team essentially took a drinking game and digitized it, and there's nothing wrong with that.

The coincidence of two NBA teams brings me to another lesson learned. I could have had more interaction with these teams, and fostered more convenient interteam interactions, if I had set up a shared Slack server for all of us. Some of the teams used Discord and some just used text messages, but there was no convenient way for me to either monitor their discussions nor get teams talking to each other. I talked about this a bit in my Gane Studio reflection yesterday, and I think I could adopt a similar kind of idea here.

Once I made the decision to adopt an asynchronous, distributed approach: the teams had to keep working together on their projects, but I did not want to do remote lectures or require "attendance." Normally, what I would do in class during the last six weeks of the semester is set up exercises to help them succeed in the final project; I was able to accomplish these goals through graded assignments rather than in-class exercises. It's not the same, of course, but I feel like it accomplished the goals well enough.

There were corners that I cut, of course. The one I am saddest about is the discussions of design theory and human-centric computing. I would normally do more in-class exercises to help the students think about what it means to be user-centered vs engineer-centered, to reflect on their own processes, and to think about usability. We covered the minimal amount required by the syllabus, but I do feel like this is an area where sometimes students start to gain some insight into professional development or into the nature of design.

One of the things I had kind of forgotten about, or at least had not steeled myself for, was how very disappointing this class can be around week 12. This is the end of the second iteration of the projects, and I tend to be overwhelmed with a sense of confusion. I spend hours typing up feedback for the students and creating video tutorials (some public on Youtube, others privately shared). When I look at what the students submit, it makes me question the whole enterprise. Why bother writing up grading criteria and advice when students are not following it? Still, weeks later, it puzzles me, in a similar way to how students don't understand checklists in CS315.

One idea that's crossed my mind this semester is that I found myself describing the course as "giving students enough rope to hang themselves with." There's something both true and morbid about that. It's a course with a lot of freedom, and irresponsible students will cause themselves trouble—and worse, cause trouble for their teams. However, I don't think you can really address the course's essential questions without this freedom: you cannot explore what it means to be a professional unless you have the freedom to choose to act like one.

My colleague Huseyin Ergin taught the other section of CS222 this semester, in what I think may just be his second time teaching it. He has tried something new this semester, where every Friday he does a tutorial on a different topic, and students complete it with a concrete deliverable. In a sense, he has made every Friday into a lab day. I think this is a great idea, in part because CS222 is the first programming-oriented class without a lab in the curriculum. By putting in these tutorial days, he's not just teaching practical skills: he is helping transition them toward being more independent but without such a steep drop-off. I need to talk to him about how that went, and I'll think about if that's something I want to bring in.

I'm not scheduled to teach CS222 in the Fall. I'll have three different courses, so I feel like I have to once again abandon this course to memory. The blog is useful for this process, since I can come back and read these notes next time I teach it. However, it is a bit frustrating to think about improving a course but then have to just set it aside.

Those are my notes from the semester. The students are taking their final exams tomorrow, so I can post an addendum if there are any surprises. Otherwise, it's time for me to transition to thinking about what I'm doing this Summer and how I'll prepare for Fall.

Tuesday, April 28, 2020

What We Learned in CS222: Spring 2020 Edition

For many years now, when teaching CS222, I have started the final exam by having the students make a list of what they learned. This small, reflective, timeboxed exercise is conveniently executed during a conventional final exam slot, and we normally then transition to compiling our lists. This compilation process starts out with students simply reciting what they have on their lists, but inevitably, one person's comment spurs the memory of another, and new ideas emerge that were not written down. It also can get a bit silly, in a very good way.

I wanted to keep as much of this exercise in tact as I could despite the closing of campus. I ended up creating a final assignment for the students, due on the last regular meeting day of class, in which they each had to post a list of what they learned to a Canvas discussion board. Canvas discussion boards have an interesting feature in which you can prevent students from seeing others' posts until they themselves post, and this seemed the right option for the assignment. The result is that each student got to share an unadulterated list for their classmates to see. Unfortunately, this lost the fun of compiling the list together, but at least it got the reflective part.

I went through all of the posts and compiled a spreadsheet to count what was most common. Of course, there was a possibility of interpretive error here, but I think on the whole that it is representative. I only found one item among all those shared that I couldn't really classify at all. In the end, I counted 73 distinct learning outcomes. Here are the top six, with their number of occurrences:

  • Clean Code (9)
  • Single-Responsibility Principle (8)
  • Test-Driven Development (8)
  • Model-View Separation (7)
  • GitHub (7)
  • Making GUIs in JavaFX (6)
This is not significantly different from a normal semester's outcome. The ones most often mentioned tend to be the generic ones, such as "Clean Code," whereas specific Clean Code practices or theories are less frequently represented (and counted separately). Curiously, items relating to distributed development were sparse. Many people wrote about working on a team, but only one explicitly mentioned remote collaboration.

That's enough blogging for today, since I already wrote up my reflection on the Spring 2020 Game Studio this morning. I expect I will be back tomorrow with a reflection on the CS222 course.